Просмотр исходного кода

华为WeLink同步组织用户功能

fancy 5 лет назад
Родитель
Сommit
0bbebda057
24 измененных файлов с 1850 добавлено и 2 удалено
  1. 8 0
      o2server/configSample/welink.json
  2. 18 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Config.java
  3. 12 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ExceptionWeLinkAccessToken.java
  4. 199 0
      o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/WeLink.java
  5. 32 2
      o2server/x_organization_core_entity/src/main/java/com/x/organization/core/entity/Person.java
  6. 29 0
      o2server/x_organization_core_entity/src/main/java/com/x/organization/core/entity/Unit.java
  7. 10 0
      o2server/x_program_center/src/main/java/com/x/program/center/ThisApplication.java
  8. 14 0
      o2server/x_program_center/src/main/java/com/x/program/center/factory/PersonFactory.java
  9. 14 0
      o2server/x_program_center/src/main/java/com/x/program/center/factory/UnitFactory.java
  10. 2 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/ActionApplication.java
  11. 10 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/WeLinkJaxrsFilter.java
  12. 40 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/ActionPullSync.java
  13. 29 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/ActionSyncOrgnaizationCallback.java
  14. 7 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/BaseAction.java
  15. 12 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/ExceptionNotPullSync.java
  16. 69 0
      o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/WeLinkAction.java
  17. 36 0
      o2server/x_program_center/src/main/java/com/x/program/center/schedule/WeLinkSyncOrganization.java
  18. 20 0
      o2server/x_program_center/src/main/java/com/x/program/center/schedule/WeLinkSyncOrganizationTrigger.java
  19. 90 0
      o2server/x_program_center/src/main/java/com/x/program/center/welink/Department.java
  20. 12 0
      o2server/x_program_center/src/main/java/com/x/program/center/welink/ExceptionListOrg.java
  21. 12 0
      o2server/x_program_center/src/main/java/com/x/program/center/welink/ExceptionListUser.java
  22. 680 0
      o2server/x_program_center/src/main/java/com/x/program/center/welink/SyncOrganization.java
  23. 219 0
      o2server/x_program_center/src/main/java/com/x/program/center/welink/User.java
  24. 276 0
      o2server/x_program_center/src/main/java/com/x/program/center/welink/WeLinkFactory.java

+ 8 - 0
o2server/configSample/welink.json

@@ -0,0 +1,8 @@
+{
+  "enable": false,
+  "clientId": "",
+  "clientSecret": "",
+  "syncCron": "10 0/10 * * * ?",
+  "forceSyncCron": "10 45 8,12 * * ?",
+  "oapiAddress": "https://open.welink.huaweicloud.com/api"
+}

+ 18 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/Config.java

@@ -61,6 +61,7 @@ public class Config {
 	public static final String PATH_CONFIG_PROCESSPLATFORM = "config/processPlatform.json";
 	public static final String PATH_CONFIG_QUERY = "config/query.json";
 	public static final String PATH_CONFIG_DINGDING = "config/dingding.json";
+	public static final String PATH_CONFIG_WELINK = "config/welink.json";
 	public static final String PATH_CONFIG_ZHENGWUDINGDING = "config/zhengwuDingding.json";
 	public static final String PATH_CONFIG_QIYEWEIXIN = "config/qiyeweixin.json";
 	public static final String PATH_CONFIG_LOGLEVEL = "config/logLevel.json";
@@ -1041,6 +1042,23 @@ public class Config {
 		return instance().dingding;
 	}
 
+	private WeLink weLink;
+
+	public static WeLink weLink() throws Exception {
+		if (null == instance().weLink) {
+			synchronized (Config.class) {
+				if (null == instance().weLink) {
+					WeLink obj = BaseTools.readConfigObject(PATH_CONFIG_WELINK, WeLink.class);
+					if (null == obj) {
+						obj = WeLink.defaultInstance();
+					}
+					instance().weLink = obj;
+				}
+			}
+		}
+		return instance().weLink;
+	}
+
 	private Qiyeweixin qiyeweixin;
 
 	public static Qiyeweixin qiyeweixin() throws Exception {

+ 12 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ExceptionWeLinkAccessToken.java

@@ -0,0 +1,12 @@
+package com.x.base.core.project.config;
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionWeLinkAccessToken extends PromptException {
+
+	private static final long serialVersionUID = -3439770681867963457L;
+
+	ExceptionWeLinkAccessToken(String code, String message) {
+		super("获取WeLink  access token 失败,错误代码:{}, 错误消息:{}.", code, message);
+	}
+}

+ 199 - 0
o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/WeLink.java

@@ -0,0 +1,199 @@
+package com.x.base.core.project.config;
+
+import com.x.base.core.project.annotation.FieldDescribe;
+import com.x.base.core.project.connection.HttpConnection;
+import com.x.base.core.project.gson.XGsonBuilder;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Calendar;
+import java.util.Date;
+
+/**
+ * Created by fancyLou on 2020-07-24.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+public class WeLink extends ConfigObject {
+
+    @FieldDescribe("是否启用")
+    private Boolean enable;
+
+    @FieldDescribe("WeLink应用的client_id")
+    private String clientId;
+
+    @FieldDescribe("WeLink应用的client_secret")
+    private String clientSecret;
+
+
+    @FieldDescribe("组织同步cron,默认每10分钟同步一次.")
+    private String syncCron;
+
+    @FieldDescribe("强制拉入同步cron,默认在每天的8点和12点强制进行同步.")
+    private String forceSyncCron;
+
+    @FieldDescribe("WeLink api服务器地址")
+    private String oapiAddress;
+
+
+
+    public static WeLink defaultInstance() {
+        return new WeLink();
+    }
+
+    public static final Boolean default_enable = false;
+    public static final String default_clientId = "";
+    public static final String default_clientSecret = "";
+    public static final String default_syncCron = "10 0/10 * * * ?";
+    public static final String default_forceSyncCron = "10 45 8,12 * * ?";
+    public static final String default_oapiAddress = "https://open.welink.huaweicloud.com/api";
+
+
+    public WeLink() {
+        this.enable = default_enable;
+        this.clientId = default_clientId;
+        this.clientSecret = default_clientSecret;
+        this.syncCron = default_syncCron;
+        this.forceSyncCron = default_forceSyncCron;
+        this.oapiAddress = default_oapiAddress;
+    }
+
+    private static String cachedAccessToken;
+    private static Date cachedAccessTokenDate;
+
+    public static class AccessTokenReq {
+       private String client_id;
+       private String client_secret;
+
+        public String getClient_id() {
+            return client_id;
+        }
+
+        public void setClient_id(String client_id) {
+            this.client_id = client_id;
+        }
+
+        public String getClient_secret() {
+            return client_secret;
+        }
+
+        public void setClient_secret(String client_secret) {
+            this.client_secret = client_secret;
+        }
+    }
+    public static class AccessTokenResp {
+
+        private String access_token;
+        private String code;
+        private String message;
+        private Integer expires_in;
+
+        public String getAccess_token() {
+            return access_token;
+        }
+
+        public void setAccess_token(String access_token) {
+            this.access_token = access_token;
+        }
+
+        public String getCode() {
+            return code;
+        }
+
+        public void setCode(String code) {
+            this.code = code;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public void setMessage(String message) {
+            this.message = message;
+        }
+
+        public Integer getExpires_in() {
+            return expires_in;
+        }
+
+        public void setExpires_in(Integer expires_in) {
+            this.expires_in = expires_in;
+        }
+    }
+
+    /**
+     * 获取WeLink AccessToken
+     * @return
+     * @throws Exception
+     */
+    public String accessToken() throws Exception {
+        if ((StringUtils.isNotEmpty(cachedAccessToken) && (null != cachedAccessTokenDate))
+                && (cachedAccessTokenDate.after(new Date()))) {
+            return cachedAccessToken;
+        } else {
+            String address = this.getOapiAddress() + "/auth/v2/tickets";
+            AccessTokenReq req = new AccessTokenReq();
+            req.setClient_id(this.getClientId());
+            req.setClient_secret(this.getClientSecret());
+            AccessTokenResp resp = HttpConnection.postAsObject(address, null, XGsonBuilder.instance().toJson(req), AccessTokenResp.class);
+            if (!resp.getCode().equals("0")) {
+                throw new ExceptionWeLinkAccessToken(resp.getCode(), resp.getMessage());
+            }
+            cachedAccessToken = resp.getAccess_token();
+            Integer second = resp.expires_in;//过期时间 秒
+            Calendar cal = Calendar.getInstance();
+            cal.add(Calendar.SECOND, (second - 300));
+            cachedAccessTokenDate = cal.getTime();
+            return cachedAccessToken;
+        }
+    }
+
+
+
+    public Boolean getEnable() {
+        return BooleanUtils.isTrue(this.enable);
+    }
+
+    public void setEnable(Boolean enable) {
+        this.enable = enable;
+    }
+
+    public String getClientId() {
+        return StringUtils.isEmpty(this.clientId) ? default_clientId : this.clientId;
+    }
+
+    public void setClientId(String clientId) {
+        this.clientId = clientId;
+    }
+
+    public String getClientSecret() {
+        return StringUtils.isEmpty(this.clientSecret) ? default_clientSecret : this.clientSecret;
+    }
+
+    public void setClientSecret(String clientSecret) {
+        this.clientSecret = clientSecret;
+    }
+
+    public String getSyncCron() {
+        return StringUtils.isEmpty(this.syncCron) ? default_syncCron : this.syncCron;
+    }
+
+    public void setSyncCron(String syncCron) {
+        this.syncCron = syncCron;
+    }
+
+    public String getForceSyncCron() {
+        return StringUtils.isEmpty(this.forceSyncCron) ? default_forceSyncCron : this.forceSyncCron;
+    }
+
+    public void setForceSyncCron(String forceSyncCron) {
+        this.forceSyncCron = forceSyncCron;
+    }
+
+    public String getOapiAddress() {
+        return StringUtils.isEmpty(this.oapiAddress) ? default_oapiAddress : this.oapiAddress;
+    }
+
+    public void setOapiAddress(String oapiAddress) {
+        this.oapiAddress = oapiAddress;
+    }
+}

+ 32 - 2
o2server/x_organization_core_entity/src/main/java/com/x/organization/core/entity/Person.java

@@ -180,7 +180,7 @@ public class Person extends SliceJpaObject {
 	@FieldDescribe("工号,不可重复.")
 	@Column(length = length_255B, name = ColumnNamePrefix + employee_FIELDNAME)
 	@Index(name = TABLE + IndexNameMiddle + employee_FIELDNAME)
-	@CheckPersist(allowEmpty = true, simplyString = true, citationNotExists = @CitationNotExist(fields = employee_FIELDNAME, type = Person.class))
+	@CheckPersist(allowEmpty = true, simplyString = false, citationNotExists = @CitationNotExist(fields = employee_FIELDNAME, type = Person.class))
 	private String employee;
 
 	public static final String unique_FIELDNAME = "unique";
@@ -188,7 +188,7 @@ public class Person extends SliceJpaObject {
 	@FieldDescribe("唯一标识,不可重复,为空则使用自动填充值")
 	@Column(length = length_255B, name = ColumnNamePrefix + unique_FIELDNAME)
 	@Index(name = TABLE + IndexNameMiddle + unique_FIELDNAME)
-	@CheckPersist(allowEmpty = true, simplyString = true, citationNotExists = @CitationNotExist(fields = unique_FIELDNAME, type = Person.class))
+	@CheckPersist(allowEmpty = true, simplyString = false, citationNotExists = @CitationNotExist(fields = unique_FIELDNAME, type = Person.class))
 	private String unique;
 
 	public static final String distinguishedName_FIELDNAME = "distinguishedName";
@@ -343,6 +343,21 @@ public class Person extends SliceJpaObject {
 	@CheckPersist(allowEmpty = true)
 	private String dingdingHash;
 
+
+	public static final String weLinkId_FIELDNAME = "weLinkId";
+	@FieldDescribe("WeLikn人员ID.")
+	@Column(length = length_255B, name = ColumnNamePrefix + weLinkId_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + weLinkId_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String weLinkId;
+
+	public static final String weLinkHash_FIELDNAME = "weLinkHash";
+	@FieldDescribe("WeLink人员哈希特征.")
+	@Column(length = length_255B, name = ColumnNamePrefix + weLinkHash_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + weLinkHash_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String weLinkHash;
+
 	public static final String zhengwuDingdingId_FIELDNAME = "zhengwuDingdingId";
 	@FieldDescribe("政务钉钉人员ID.")
 	@Column(length = length_255B, name = ColumnNamePrefix + zhengwuDingdingId_FIELDNAME)
@@ -788,4 +803,19 @@ public class Person extends SliceJpaObject {
 		this.hiddenMobile = hiddenMobile;
 	}
 
+	public String getWeLinkId() {
+		return weLinkId;
+	}
+
+	public void setWeLinkId(String weLinkId) {
+		this.weLinkId = weLinkId;
+	}
+
+	public String getWeLinkHash() {
+		return weLinkHash;
+	}
+
+	public void setWeLinkHash(String weLinkHash) {
+		this.weLinkHash = weLinkHash;
+	}
 }

+ 29 - 0
o2server/x_organization_core_entity/src/main/java/com/x/organization/core/entity/Unit.java

@@ -215,6 +215,20 @@ public class Unit extends SliceJpaObject {
 	@CheckPersist(allowEmpty = true)
 	private String dingdingHash;
 
+	public static final String weLinkId_FIELDNAME = "weLinkId";
+	@FieldDescribe("WeLink部门ID.")
+	@Column(length = length_255B, name = ColumnNamePrefix + weLinkId_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + weLinkId_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String weLinkId;
+
+	public static final String weLinkHash_FIELDNAME = "weLinkHash";
+	@FieldDescribe("WeLink部门哈希特征.")
+	@Column(length = length_255B, name = ColumnNamePrefix + weLinkHash_FIELDNAME)
+	@Index(name = TABLE + IndexNameMiddle + weLinkHash_FIELDNAME)
+	@CheckPersist(allowEmpty = true)
+	private String weLinkHash;
+
 	public static final String qiyeweixinId_FIELDNAME = "qiyeweixinId";
 	@FieldDescribe("企业微信人员ID.")
 	@Column(length = length_255B, name = ColumnNamePrefix + qiyeweixinId_FIELDNAME)
@@ -409,4 +423,19 @@ public class Unit extends SliceJpaObject {
 		this.zhengwuDingdingHash = zhengwuDingdingHash;
 	}
 
+	public String getWeLinkId() {
+		return weLinkId;
+	}
+
+	public void setWeLinkId(String weLinkId) {
+		this.weLinkId = weLinkId;
+	}
+
+	public String getWeLinkHash() {
+		return weLinkHash;
+	}
+
+	public void setWeLinkHash(String weLinkHash) {
+		this.weLinkHash = weLinkHash;
+	}
 }

+ 10 - 0
o2server/x_program_center/src/main/java/com/x/program/center/ThisApplication.java

@@ -24,6 +24,8 @@ public class ThisApplication {
 
 	public static List<Object> dingdingSyncOrganizationCallbackRequest = new ArrayList<>();
 
+	public static List<Object> weLinkSyncOrganizationCallbackRequest = new ArrayList<>();
+
 	public static List<Object> zhengwuDingdingSyncOrganizationCallbackRequest = new ArrayList<>();
 
 	public static List<Object> qiyeweixinSyncOrganizationCallbackRequest = new ArrayList<>();
@@ -61,6 +63,14 @@ public class ThisApplication {
 				/* 添加一个强制同步任务 */
 				context().scheduleLocal(DingdingSyncOrganizationTrigger.class, Config.dingding().getForceSyncCron());
 			}
+			/* WeLink同步 */
+			if (Config.weLink().getEnable()) {
+				/* 启动同步任务 */
+				context().scheduleLocal(WeLinkSyncOrganization.class, Config.weLink().getSyncCron());
+				/* 添加一个强制同步任务 */
+				context().scheduleLocal(WeLinkSyncOrganizationTrigger.class, Config.weLink().getForceSyncCron());
+			}
+
 			context().scheduleLocal(RefreshApplications.class, CenterQueue.REFRESHAPPLICATIONSINTERVAL,
 					CenterQueue.REFRESHAPPLICATIONSINTERVAL);
 			// 运行间隔由300秒缩减到120秒

+ 14 - 0
o2server/x_program_center/src/main/java/com/x/program/center/factory/PersonFactory.java

@@ -40,6 +40,20 @@ public class PersonFactory extends AbstractFactory {
 		}
 	}
 
+	public Person getWithWeLinkIdObject(String weLinkId) throws Exception {
+		EntityManager em = this.entityManagerContainer().get(Person.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+		Root<Person> root = cq.from(Person.class);
+		Predicate p = cb.equal(root.get(Person_.weLinkId), weLinkId);
+		List<Person> os = em.createQuery(cq.select(root).where(p)).setMaxResults(1).getResultList();
+		if (os.isEmpty()) {
+			return null;
+		} else {
+			return os.get(0);
+		}
+	}
+
 	public Person getWithZhengwuDingdingIdObject(String zhengwuDingdingId) throws Exception {
 		EntityManager em = this.entityManagerContainer().get(Person.class);
 		CriteriaBuilder cb = em.getCriteriaBuilder();

+ 14 - 0
o2server/x_program_center/src/main/java/com/x/program/center/factory/UnitFactory.java

@@ -41,6 +41,20 @@ public class UnitFactory extends AbstractFactory {
 		}
 	}
 
+	public Unit getWithWeLinkDeptCodeObject(String weLinkDeptCode) throws Exception {
+		EntityManager em = this.entityManagerContainer().get(Unit.class);
+		CriteriaBuilder cb = em.getCriteriaBuilder();
+		CriteriaQuery<Unit> cq = cb.createQuery(Unit.class);
+		Root<Unit> root = cq.from(Unit.class);
+		Predicate p = cb.equal(root.get(Unit_.weLinkId), weLinkDeptCode);
+		List<Unit> os = em.createQuery(cq.select(root).where(p)).setMaxResults(1).getResultList();
+		if (os.isEmpty()) {
+			return null;
+		} else {
+			return os.get(0);
+		}
+	}
+
 	public Unit getWithZhengwuDingdingIdObject(String zhengwuDingdingId) throws Exception {
 		EntityManager em = this.entityManagerContainer().get(Unit.class);
 		CriteriaBuilder cb = em.getCriteriaBuilder();

+ 2 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/ActionApplication.java

@@ -34,6 +34,7 @@ import com.x.program.center.jaxrs.test.TestAction;
 import com.x.program.center.jaxrs.unexpectederrorlog.UnexpectedErrorLogAction;
 import com.x.program.center.jaxrs.validation.ValidationAction;
 import com.x.program.center.jaxrs.warnlog.WarnLogAction;
+import com.x.program.center.jaxrs.welink.WeLinkAction;
 import com.x.program.center.jaxrs.zhengwudingding.ZhengwuDingdingAction;
 
 @ApplicationPath("jaxrs")
@@ -60,6 +61,7 @@ public class ActionApplication extends AbstractActionApplication {
 		classes.add(AppStyleAction.class);
 		classes.add(ConfigAction.class);
 		classes.add(DingdingAction.class);
+		classes.add(WeLinkAction.class);
 		classes.add(ZhengwuDingdingAction.class);
 		classes.add(QiyeweixinAction.class);
 		classes.add(ScheduleAction.class);

+ 10 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/WeLinkJaxrsFilter.java

@@ -0,0 +1,10 @@
+package com.x.program.center.jaxrs;
+
+import com.x.base.core.project.jaxrs.AnonymousCipherManagerUserJaxrsFilter;
+
+import javax.servlet.annotation.WebFilter;
+
+@WebFilter(urlPatterns = "/jaxrs/welink/*", asyncSupported = true)
+public class WeLinkJaxrsFilter extends AnonymousCipherManagerUserJaxrsFilter {
+
+}

+ 40 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/ActionPullSync.java

@@ -0,0 +1,40 @@
+package com.x.program.center.jaxrs.welink;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.project.config.Config;
+import com.x.base.core.project.exception.ExceptionAccessDenied;
+import com.x.base.core.project.gson.XGsonBuilder;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.program.center.Business;
+
+import com.x.program.center.welink.SyncOrganization;
+import org.apache.commons.lang3.BooleanUtils;
+
+class ActionPullSync extends BaseAction {
+
+	ActionResult<Wo> execute(EffectivePerson effectivePerson) throws Exception {
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+			if (effectivePerson.isNotManager()) {
+				throw new ExceptionAccessDenied(effectivePerson);
+			}
+			ActionResult<Wo> result = new ActionResult<>();
+			Wo wo = null;
+			if (BooleanUtils.isTrue(Config.weLink().getEnable())) {
+				Business business = new Business(emc);
+				SyncOrganization o = new SyncOrganization();
+				SyncOrganization.PullResult pullResult = o.execute(business);
+				wo = XGsonBuilder.convert(pullResult, Wo.class);
+			}else{
+				throw new ExceptionNotPullSync();
+			}
+			result.setData(wo);
+			return result;
+		}
+	}
+
+	public static class Wo extends SyncOrganization.PullResult {
+	}
+
+}

+ 29 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/ActionSyncOrgnaizationCallback.java

@@ -0,0 +1,29 @@
+package com.x.program.center.jaxrs.welink;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.project.config.Config;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.jaxrs.WrapBoolean;
+import com.x.program.center.ThisApplication;
+import org.apache.commons.lang3.BooleanUtils;
+
+class ActionSyncOrgnaizationCallback extends BaseAction {
+
+	ActionResult<Wo> execute(EffectivePerson effectivePerson, JsonElement jsonElement) throws Exception {
+		ActionResult<Wo> result = new ActionResult<>();
+		if (BooleanUtils.isTrue(Config.weLink().getEnable())) {
+			ThisApplication.weLinkSyncOrganizationCallbackRequest.add(new Object());
+		} else {
+			throw new ExceptionNotPullSync();
+		}
+		Wo wo = new Wo();
+		wo.setValue(true);
+		result.setData(wo);
+		return result;
+	}
+
+	public static class Wo extends WrapBoolean {
+	}
+
+}

+ 7 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/BaseAction.java

@@ -0,0 +1,7 @@
+package com.x.program.center.jaxrs.welink;
+
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+
+abstract class BaseAction extends StandardJaxrsAction {
+
+}

+ 12 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/ExceptionNotPullSync.java

@@ -0,0 +1,12 @@
+package com.x.program.center.jaxrs.welink;
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionNotPullSync extends PromptException {
+
+	private static final long serialVersionUID = -3439770681867963457L;
+
+	ExceptionNotPullSync() {
+		super("没有启用从WeLink的拉入同步.");
+	}
+}

+ 69 - 0
o2server/x_program_center/src/main/java/com/x/program/center/jaxrs/welink/WeLinkAction.java

@@ -0,0 +1,69 @@
+package com.x.program.center.jaxrs.welink;
+
+import com.google.gson.JsonElement;
+import com.x.base.core.project.annotation.JaxrsDescribe;
+import com.x.base.core.project.annotation.JaxrsMethodDescribe;
+import com.x.base.core.project.http.ActionResult;
+import com.x.base.core.project.http.EffectivePerson;
+import com.x.base.core.project.http.HttpMediaType;
+import com.x.base.core.project.jaxrs.ResponseFactory;
+import com.x.base.core.project.jaxrs.StandardJaxrsAction;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+
+
+import javax.servlet.http.HttpServletRequest;
+import javax.ws.rs.*;
+import javax.ws.rs.container.AsyncResponse;
+import javax.ws.rs.container.Suspended;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+
+/**
+ * Created by fancyLou on 2020-07-24.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+@Path("welink")
+@JaxrsDescribe("WeLink接口")
+public class WeLinkAction extends StandardJaxrsAction {
+
+
+    private static Logger logger = LoggerFactory.getLogger(WeLinkAction.class);
+
+    @JaxrsMethodDescribe(value = "发送一个拉入同步请求.", action = ActionSyncOrgnaizationCallback.class)
+    @POST
+    @Path("request/pull/sync")
+    @Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void requestPullSync(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request,
+                                JsonElement jsonElement) {
+        EffectivePerson effectivePerson = this.effectivePerson(request);
+        ActionResult<ActionSyncOrgnaizationCallback.Wo> result = new ActionResult<>();
+        try {
+            result = new ActionSyncOrgnaizationCallback().execute(effectivePerson, jsonElement);
+        } catch (Exception e) {
+            logger.error(e, effectivePerson, request, jsonElement);
+            result.error(e);
+        }
+        asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+    }
+
+    @JaxrsMethodDescribe(value = "立即同步.", action = ActionPullSync.class)
+    @GET
+    @Path("pull/sync")
+    @Produces(HttpMediaType.APPLICATION_JSON_UTF_8)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public void pullSync(@Suspended final AsyncResponse asyncResponse, @Context HttpServletRequest request) {
+        EffectivePerson effectivePerson = this.effectivePerson(request);
+        ActionResult<ActionPullSync.Wo> result = new ActionResult<>();
+        try {
+            result = new ActionPullSync().execute(effectivePerson);
+        } catch (Exception e) {
+            logger.error(e, effectivePerson, request, null);
+            result.error(e);
+        }
+        asyncResponse.resume(ResponseFactory.getEntityTagActionResultResponse(request, result));
+    }
+
+
+}

+ 36 - 0
o2server/x_program_center/src/main/java/com/x/program/center/schedule/WeLinkSyncOrganization.java

@@ -0,0 +1,36 @@
+package com.x.program.center.schedule;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.container.factory.EntityManagerContainerFactory;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.program.center.Business;
+import com.x.program.center.ThisApplication;
+import com.x.program.center.welink.SyncOrganization;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+
+
+public class WeLinkSyncOrganization implements Job {
+
+	private static Logger logger = LoggerFactory.getLogger(WeLinkSyncOrganization.class);
+
+	@Override
+	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+		try (EntityManagerContainer emc = EntityManagerContainerFactory.instance().create()) {
+
+			if (!ThisApplication.weLinkSyncOrganizationCallbackRequest.isEmpty()) {
+				ThisApplication.weLinkSyncOrganizationCallbackRequest.clear();
+				Business business = new Business(emc);
+				SyncOrganization o = new SyncOrganization();
+				o.execute(business);
+			}
+		} catch (Exception e) {
+			logger.error(e);
+			throw new JobExecutionException(e);
+		}
+	}
+
+}

+ 20 - 0
o2server/x_program_center/src/main/java/com/x/program/center/schedule/WeLinkSyncOrganizationTrigger.java

@@ -0,0 +1,20 @@
+package com.x.program.center.schedule;
+
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.program.center.ThisApplication;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+public class WeLinkSyncOrganizationTrigger implements Job {
+
+	private static Logger logger = LoggerFactory.getLogger(WeLinkSyncOrganizationTrigger.class);
+
+	/* 向列表发送一个同步信号 */
+	@Override
+	public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+		ThisApplication.weLinkSyncOrganizationCallbackRequest.add(new Object());
+	}
+
+}

+ 90 - 0
o2server/x_program_center/src/main/java/com/x/program/center/welink/Department.java

@@ -0,0 +1,90 @@
+package com.x.program.center.welink;
+
+import com.x.base.core.project.gson.GsonPropertyObject;
+
+public class Department extends GsonPropertyObject {
+
+	//{
+	//        "deptCode": "1",
+	//        "deptNameCn": "产品销售部",
+	//        "deptNameEn": "Sales Dept",
+	//        "fatherCode": "0",
+	//        "deptLevel": "2",
+	//        "orderNo": 1,
+	//        "hasChildDept": 1,
+	//        "corpDeptCode": ""
+	//      }
+
+	private String deptCode;
+	private String deptNameCn;
+	private String deptNameEn;
+	private String fatherCode;
+	private String deptLevel;
+	private String corpDeptCode;
+	private Long orderNo;
+	private Long hasChildDept;
+
+	public String getDeptCode() {
+		return deptCode;
+	}
+
+	public void setDeptCode(String deptCode) {
+		this.deptCode = deptCode;
+	}
+
+	public String getDeptNameCn() {
+		return deptNameCn;
+	}
+
+	public void setDeptNameCn(String deptNameCn) {
+		this.deptNameCn = deptNameCn;
+	}
+
+	public String getDeptNameEn() {
+		return deptNameEn;
+	}
+
+	public void setDeptNameEn(String deptNameEn) {
+		this.deptNameEn = deptNameEn;
+	}
+
+	public String getFatherCode() {
+		return fatherCode;
+	}
+
+	public void setFatherCode(String fatherCode) {
+		this.fatherCode = fatherCode;
+	}
+
+	public String getDeptLevel() {
+		return deptLevel;
+	}
+
+	public void setDeptLevel(String deptLevel) {
+		this.deptLevel = deptLevel;
+	}
+
+	public String getCorpDeptCode() {
+		return corpDeptCode;
+	}
+
+	public void setCorpDeptCode(String corpDeptCode) {
+		this.corpDeptCode = corpDeptCode;
+	}
+
+	public Long getOrderNo() {
+		return orderNo;
+	}
+
+	public void setOrderNo(Long orderNo) {
+		this.orderNo = orderNo;
+	}
+
+	public Long getHasChildDept() {
+		return hasChildDept;
+	}
+
+	public void setHasChildDept(Long hasChildDept) {
+		this.hasChildDept = hasChildDept;
+	}
+}

+ 12 - 0
o2server/x_program_center/src/main/java/com/x/program/center/welink/ExceptionListOrg.java

@@ -0,0 +1,12 @@
+package com.x.program.center.welink;
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionListOrg extends PromptException {
+
+	private static final long serialVersionUID = 4132300948670472899L;
+
+	ExceptionListOrg(String retCode, String retMessage) {
+		super("WeLink获取下级组织失败,错误代码:{},错误消息:{}.", retCode, retMessage);
+	}
+}

+ 12 - 0
o2server/x_program_center/src/main/java/com/x/program/center/welink/ExceptionListUser.java

@@ -0,0 +1,12 @@
+package com.x.program.center.welink;
+
+import com.x.base.core.project.exception.PromptException;
+
+class ExceptionListUser extends PromptException {
+
+	private static final long serialVersionUID = 4132300948670472899L;
+
+	ExceptionListUser(String retCode, String retMessage) {
+		super("WeLink获取组织成员失败,错误代码:{},错误消息:{}.", retCode, retMessage);
+	}
+}

+ 680 - 0
o2server/x_program_center/src/main/java/com/x/program/center/welink/SyncOrganization.java

@@ -0,0 +1,680 @@
+package com.x.program.center.welink;
+
+import com.x.base.core.container.EntityManagerContainer;
+import com.x.base.core.entity.annotation.CheckPersistType;
+import com.x.base.core.entity.annotation.CheckRemoveType;
+import com.x.base.core.entity.type.GenderType;
+import com.x.base.core.project.cache.ApplicationCache;
+import com.x.base.core.project.config.Config;
+import com.x.base.core.project.gson.GsonPropertyObject;
+import com.x.base.core.project.gson.XGsonBuilder;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.script.ScriptFactory;
+import com.x.base.core.project.tools.ListTools;
+import com.x.organization.core.entity.*;
+import com.x.program.center.Business;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.collections4.ListUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.StringEscapeUtils;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.SimpleScriptContext;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+/**
+ * Created by fancyLou on 2020-07-24.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+public class SyncOrganization {
+
+    private static Logger logger = LoggerFactory.getLogger(SyncOrganization.class);
+
+
+
+    public PullResult execute(Business business) throws Exception {
+        logger.print("开始与WeLink同步人员组织,方向:拉入.");
+        PullResult result = new PullResult();
+        String accessToken = Config.weLink().accessToken();
+        logger.print("accessToken:" + accessToken);
+        List<Unit> units = new ArrayList<>();
+        List<Person> people = new ArrayList<>();
+        List<PersonAttribute> personAttributes = new ArrayList<>();
+        List<Identity> identities = new ArrayList<>();
+        WeLinkFactory factory = new WeLinkFactory(accessToken);
+        for (Department root : factory.roots()) {
+            this.check(business, result, units, people, personAttributes, identities, accessToken, factory, null, root);
+        }
+        this.clean(business, result, units, people, identities);
+        ApplicationCache.notify(Person.class);
+        ApplicationCache.notify(PersonAttribute.class);
+        ApplicationCache.notify(Unit.class);
+        ApplicationCache.notify(UnitAttribute.class);
+        ApplicationCache.notify(UnitDuty.class);
+        ApplicationCache.notify(Identity.class);
+        result.end();
+        if (!result.getCreateUnitList().isEmpty()) {
+            logger.print("创建组织({}):{}.", result.getCreateUnitList().size(),
+                    StringUtils.join(result.getCreateUnitList(), ","));
+        }
+        if (!result.getUpdateUnitList().isEmpty()) {
+            logger.print("修改组织({}):{}.", result.getUpdateUnitList().size(),
+                    StringUtils.join(result.getUpdateUnitList(), ","));
+        }
+        if (!result.getRemoveUnitList().isEmpty()) {
+            logger.print("删除组织({}):{}.", result.getRemoveUnitList().size(),
+                    StringUtils.join(result.getRemoveUnitList(), ","));
+        }
+        if (!result.getCreatePersonList().isEmpty()) {
+            logger.print("创建个人({}):{}.", result.getCreatePersonList().size(),
+                    StringUtils.join(result.getCreatePersonList(), ","));
+        }
+        if (!result.getUpdatePersonList().isEmpty()) {
+            logger.print("修改个人({}):{}.", result.getUpdatePersonList().size(),
+                    StringUtils.join(result.getUpdatePersonList(), ","));
+        }
+        if (!result.getRemovePersonList().isEmpty()) {
+            logger.print("删除个人({}):{}.", result.getRemovePersonList().size(),
+                    StringUtils.join(result.getRemovePersonList(), ","));
+        }
+        if (!result.getCreateIdentityList().isEmpty()) {
+            logger.print("创建身份({}):{}.", result.getCreateIdentityList().size(),
+                    StringUtils.join(result.getCreateIdentityList(), ","));
+        }
+        if (!result.getUpdateIdentityList().isEmpty()) {
+            logger.print("修改身份({}):{}.", result.getUpdateIdentityList().size(),
+                    StringUtils.join(result.getUpdateIdentityList(), ","));
+        }
+        if (!result.getRemoveIdentityList().isEmpty()) {
+            logger.print("删除身份({}):{}.", result.getRemoveIdentityList().size(),
+                    StringUtils.join(result.getRemoveIdentityList(), ","));
+        }
+        logger.print("从钉钉同步人员结束.");
+        return result;
+    }
+
+    private void check(Business business, PullResult result, List<Unit> units, List<Person> people,
+                       List<PersonAttribute> personAttributes, List<Identity> identities, String accessToken,
+                       WeLinkFactory factory, Unit sup, Department org) throws Exception {
+        Unit unit = this.checkUnit(business, result, sup, org);
+        units.add(unit);
+        for (User o : factory.listUser(org)) {
+            Person person = this.checkPerson(business, result, accessToken, o);
+            /* 如果人员没有手机号,那么就先跳过这个人 */
+            if (null != person) {
+                people.add(person);
+                Identity identity = this.checkIdentity(business, result, person, unit, o);
+                identities.add(identity);
+
+            }
+        }
+        for (Department o : factory.listSub(org)) {
+            this.check(business, result, units, people, personAttributes, identities, accessToken, factory, unit, o);
+        }
+    }
+
+    private void clean(Business business, PullResult result, List<Unit> units, List<Person> people,
+                       List<Identity> identities) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        List<Identity> allIdentities = this.listIdentity(business);
+        /* 删除身份 */
+        for (Identity identity : ListUtils.subtract(allIdentities, identities)) {
+            Person person = emc.find(identity.getPerson(), Person.class);
+            if (null == person || StringUtils.isNotEmpty(person.getWeLinkId())) {
+                List<UnitDuty> uds = emc.listIsMember(UnitDuty.class, UnitDuty.identityList_FIELDNAME,
+                        identity.getId());
+                if (ListTools.isNotEmpty(uds)) {
+                    emc.beginTransaction(UnitDuty.class);
+                    uds.stream().forEach(o -> {
+                        o.getIdentityList().remove(identity.getId());
+                    });
+                    emc.commit();
+                }
+                emc.beginTransaction(Identity.class);
+                emc.remove(identity, CheckRemoveType.all);
+                emc.commit();
+            }
+        }
+        /* 组织单独方法删除 */
+        List<Unit> allUnit = this.listUnit(business);
+        List<Unit> removeUnits = ListUtils.subtract(allUnit, units).stream()
+                .sorted(Comparator.comparing(Unit::getLevel, Comparator.nullsLast(Integer::compareTo)))
+                .collect(Collectors.toList());
+        for (Unit unit : removeUnits) {
+            this.removeSingleUnit(business, result, unit);
+        }
+        List<Person> allPeople = this.listPerson(business);
+        /* 删除个人 */
+        for (Person person : ListUtils.subtract(allPeople, people)) {
+            this.removePerson(business, result, person);
+        }
+    }
+
+
+
+    private Identity checkIdentity(Business business, PullResult result, Person person, Unit unit, User user)
+            throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        EntityManager em = emc.get(Identity.class);
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<Identity> cq = cb.createQuery(Identity.class);
+        Root<Identity> root = cq.from(Identity.class);
+        Predicate p = cb.equal(root.get(Identity_.person), person.getId());
+        p = cb.and(p, cb.equal(root.get(Identity_.unit), unit.getId()));
+        List<Identity> os = em.createQuery(cq.select(root).where(p).distinct(true)).setMaxResults(1).getResultList();
+        Identity identity = null;
+        Long order = null;
+//        if (StringUtils.isNotEmpty(user.getOrderInDepts())) {
+//            Map<Long, Long> map = new HashMap<Long, Long>();
+//            map = XGsonBuilder.instance().fromJson(user.getOrderInDepts(), map.getClass());
+//            for (Entry<Long, Long> en : map.entrySet()) {
+//                if (Objects.equals(Long.parseLong(unit.getDingdingId()), en.getKey())) {
+//                    order = en.getValue();
+//                }
+//            }
+//        }
+        if (os.size() == 0) {
+            identity = this.createIdentity(business, result, person, unit, user, order);
+        } else {
+            identity = os.get(0);
+            identity = this.updateIdentity(business, result, unit, identity, user, order);
+        }
+        return identity;
+    }
+
+
+    private Identity createIdentity(Business business, PullResult result, Person person, Unit unit, User user,
+                                    Long order) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        emc.beginTransaction(Identity.class);
+        Identity identity = new Identity();
+        identity.setName(person.getName());
+        identity.setPerson(person.getId());
+        identity.setUnit(unit.getId());
+        identity.setUnitLevel(unit.getLevel());
+        identity.setUnitLevelName(unit.getLevelName());
+        identity.setUnitName(unit.getName());
+        if (order != null) {
+            identity.setOrderNumber(order.intValue());
+        }
+        emc.persist(identity, CheckPersistType.all);
+        emc.commit();
+        result.getCreateIdentityList().add(identity.getDistinguishedName());
+        return identity;
+    }
+
+    private Identity updateIdentity(Business business, PullResult result, Unit unit, Identity identity, User user,
+                                    Long order) throws Exception {
+        if (null != order) {
+            if (!StringUtils.equals(Objects.toString(identity.getOrderNumber(), ""), Objects.toString(order, ""))) {
+                EntityManagerContainer emc = business.entityManagerContainer();
+                emc.beginTransaction(Identity.class);
+                if (order != null) {
+                    identity.setOrderNumber(order.intValue());
+                }
+                emc.commit();
+                result.getUpdateIdentityList().add(identity.getDistinguishedName());
+            }
+        }
+        return identity;
+    }
+
+    private Person checkPerson(Business business, PullResult result, String accessToken, User user) throws Exception {
+        Person person = business.person().getWithWeLinkIdObject(user.getUserId());
+        if (null == person) {
+            if ((StringUtils.isNotEmpty(user.getMobileNumber())) && StringUtils.isNotEmpty(user.getUserNameCn())) {
+                person = this.createOrLinkPerson(business, result, user);
+            }
+        } else {
+            if (!StringUtils.equals(DigestUtils.sha256Hex(XGsonBuilder.toJson(user)), person.getWeLinkHash())) {
+                person = this.updatePerson(business, result, person, user);
+            }
+        }
+        return person;
+    }
+
+    private Person updatePerson(Business business, PullResult result, Person person, User user) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        emc.beginTransaction(Person.class);
+        person.setWeLinkHash(DigestUtils.sha256Hex(XGsonBuilder.toJson(user)));
+        String employee = user.getCorpUserId();
+        if(StringUtils.isNotEmpty(employee)){
+            if(business.person().employeeExists(employee, person.getUnique())){
+                employee = "";
+            }
+        }
+        person.setEmployee(employee);
+        person.setName(user.getUserNameCn());
+        person.setMobile(user.getMobileNumber());
+        person.setMail(user.getUserEmail());
+        person.setOfficePhone(user.getLandlineNumber());
+        emc.check(person, CheckPersistType.all);
+        emc.commit();
+        result.getUpdatePersonList().add(person.getDistinguishedName());
+        return person;
+    }
+
+    private Person createOrLinkPerson(Business business, PullResult result, User user) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        emc.beginTransaction(Person.class);
+        Person person = emc.flag(user.getMobileNumber(), Person.class);
+        if (null != person) {
+            person.setWeLinkId(Objects.toString(user.getUserId()));
+            person.setWeLinkHash(DigestUtils.sha256Hex(XGsonBuilder.toJson(user)));
+            person.setName(user.getUserNameCn());
+            person.setMobile(user.getMobileNumber());
+            person.setUnique(user.getUserId());
+            String employee = user.getCorpUserId();
+            if(StringUtils.isNotEmpty(employee)){
+                if(business.person().employeeExists(employee, person.getUnique())){
+                    employee = "";
+                }
+            }
+            person.setEmployee(employee);
+            person.setMail(user.getUserEmail());
+            person.setOfficePhone(user.getLandlineNumber());
+            person.setGenderType(GenderType.d);
+            emc.check(person, CheckPersistType.all);
+            result.getUpdatePersonList().add(person.getDistinguishedName());
+        } else {
+            person = new Person();
+            person.setWeLinkId(Objects.toString(user.getUserId()));
+            person.setWeLinkHash(DigestUtils.sha256Hex(XGsonBuilder.toJson(user)));
+            person.setName(user.getUserNameCn());
+            person.setMobile(user.getMobileNumber());
+            person.setUnique(user.getUserId());
+            String employee = user.getCorpUserId();
+            if(StringUtils.isNotEmpty(employee)){
+                if(business.person().employeeExists(employee, person.getUnique())){
+                    employee = "";
+                }
+            }
+            person.setEmployee(employee);
+            person.setMail(user.getUserEmail());
+            person.setOfficePhone(user.getLandlineNumber());
+            person.setGenderType(GenderType.d);
+            /* 新增人员需要增加密码 */
+            business.person().setPassword(person, this.initPassword(business, person));
+            emc.persist(person, CheckPersistType.all);
+            result.getCreatePersonList().add(person.getDistinguishedName());
+        }
+        emc.commit();
+        return person;
+    }
+
+    private String initPassword(Business business, Person person) throws Exception {
+        String str = Config.person().getPassword();
+        Pattern pattern = Pattern.compile(com.x.base.core.project.config.Person.REGULAREXPRESSION_SCRIPT);
+        Matcher matcher = pattern.matcher(str);
+        if (matcher.matches()) {
+            String eval = ScriptFactory.functionalization(StringEscapeUtils.unescapeJson(matcher.group(1)));
+            ScriptContext scriptContext = new SimpleScriptContext();
+            Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
+            bindings.put("person", person);
+            Object o = ScriptFactory.scriptEngine.eval(eval, scriptContext);
+            return o.toString();
+        } else {
+            return str;
+        }
+    }
+
+    private Unit checkUnit(Business business, PullResult result, Unit sup, Department org) throws Exception {
+        Unit unit = business.unit().getWithWeLinkDeptCodeObject(Objects.toString(org.getDeptCode()));
+        if (null != unit) {
+            if ((null == sup) && (StringUtils.isNotEmpty(unit.getSuperior()))) {
+                /* 不是一个顶层组织所以只能删除重建 */
+                removeUnit(business, result, unit);
+                unit = null;
+            }
+            if ((null != sup) && (!StringUtils.equals(sup.getId(), unit.getSuperior()))) {
+                /* 指定的上级部门和预期不符 */
+                removeUnit(business, result, unit);
+                unit = null;
+            }
+        }
+        if (null == unit) {
+            unit = this.createUnit(business, result, sup, org);
+        } else {
+            if (!StringUtils.equals(unit.getWeLinkHash(), DigestUtils.sha256Hex(XGsonBuilder.toJson(org)))) {
+                unit = this.updateUnit(business, result, unit, org);
+            }
+        }
+        return unit;
+    }
+
+
+    private Unit createUnit(Business business, PullResult result, Unit sup, Department org) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        Unit unit = new Unit();
+        emc.beginTransaction(Unit.class);
+        unit.setName(org.getDeptNameCn());
+        unit.setUnique(org.getDeptCode());
+        unit.setWeLinkId(org.getDeptCode());
+        unit.setWeLinkHash(DigestUtils.sha256Hex(XGsonBuilder.toJson(org)));
+        if (null != sup) {
+            unit.setSuperior(sup.getId());
+        }
+        if (null != org.getOrderNo()) {
+            unit.setOrderNumber(org.getOrderNo().intValue());
+        }
+        business.unit().adjustInherit(unit);
+        emc.persist(unit);
+        emc.commit();
+        result.getCreateUnitList().add(unit.getDistinguishedName());
+        return unit;
+    }
+
+    private Unit updateUnit(Business business, PullResult result, Unit unit, Department department) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        emc.beginTransaction(Unit.class);
+        unit.setWeLinkHash(DigestUtils.sha256Hex(XGsonBuilder.toJson(department)));
+        unit.setName(department.getDeptNameCn());
+        if (null != department.getOrderNo()) {
+            unit.setOrderNumber(department.getOrderNo().intValue());
+        }
+        business.unit().adjustInherit(unit);
+        emc.check(unit, CheckPersistType.all);
+        emc.commit();
+        this.updateIdentityUnitNameAndUnitLevelName(business, unit);
+        result.getUpdateUnitList().add(unit.getDistinguishedName());
+        return unit;
+    }
+
+    private void removeUnit(Business business, PullResult result, Unit unit) throws Exception {
+        logger.print("正在删除组织{}.", unit.getDistinguishedName());
+        List<Unit> os = new ArrayList<>();
+        os.add(unit);
+        os.addAll(business.unit().listSupNestedObject(unit));
+        os = os.stream().sorted(Comparator.comparing(Unit::getLevel, Comparator.nullsLast(Integer::compareTo)))
+                .collect(Collectors.toList());
+        for (Unit o : os) {
+            this.removeSingleUnit(business, result, o);
+        }
+    }
+
+
+    private void updateIdentityUnitNameAndUnitLevelName(Business business, Unit unit) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        List<Unit> os = new ArrayList<>();
+        os.add(unit);
+        os.addAll(business.unit().listSubNestedObject(unit));
+
+        for (Unit u : os) {
+            List<Identity> identityList = this.pickIdentitiesByUnit(business, u.getId());
+            if (ListTools.isNotEmpty(identityList)) {
+                String _unitName = u.getName();
+                String _unitLevelName = u.getLevelName();
+
+                emc.beginTransaction(Identity.class);
+                for (Identity i : identityList) {
+                    i.setUnitName(_unitName);
+                    i.setUnitLevelName(_unitLevelName);
+                    emc.check(i, CheckPersistType.all);
+                }
+                emc.commit();
+            }
+
+        }
+    }
+
+    private List<Identity> pickIdentitiesByUnit(Business business, String unit) throws Exception {
+        EntityManager em = business.entityManagerContainer().get(Identity.class);
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<Identity> cq = cb.createQuery(Identity.class);
+        Root<Identity> root = cq.from(Identity.class);
+        Predicate p = cb.equal(root.get(Identity_.unit), unit);
+        return em.createQuery(cq.select(root).where(p)).getResultList();
+    }
+
+
+
+    private List<Identity> listIdentity(Business business) throws Exception {
+        return business.entityManagerContainer().listAll(Identity.class);
+    }
+
+    private List<Unit> listUnit(Business business) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        EntityManager em = emc.get(Unit.class);
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<Unit> cq = cb.createQuery(Unit.class);
+        Root<Unit> root = cq.from(Unit.class);
+        Predicate p = cb.notEqual(root.get(Unit_.weLinkId), "");
+        p = cb.and(p, cb.isNotNull(root.get(Unit_.weLinkId)));
+        List<Unit> os = em.createQuery(cq.select(root).where(p).distinct(true)).getResultList();
+        return os;
+    }
+
+    private List<Person> listPerson(Business business) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        EntityManager em = emc.get(Person.class);
+        CriteriaBuilder cb = em.getCriteriaBuilder();
+        CriteriaQuery<Person> cq = cb.createQuery(Person.class);
+        Root<Person> root = cq.from(Person.class);
+        Predicate p = cb.notEqual(root.get(Person_.weLinkId), "");
+        p = cb.and(p, cb.isNotNull(root.get(Person_.weLinkId)));
+        List<Person> os = em.createQuery(cq.select(root).where(p).distinct(true)).getResultList();
+        return os;
+    }
+
+    private void removeSingleUnit(Business business, PullResult result, Unit unit) throws Exception {
+        logger.print("正在删除单个组织{}.", unit.getDistinguishedName());
+        EntityManagerContainer emc = business.entityManagerContainer();
+        emc.beginTransaction(UnitAttribute.class);
+        emc.beginTransaction(UnitDuty.class);
+        emc.beginTransaction(Identity.class);
+        for (UnitAttribute o : emc.listEqual(UnitAttribute.class, UnitAttribute.unit_FIELDNAME, unit.getId())) {
+            emc.remove(o, CheckRemoveType.all);
+            result.getRemoveUnitAttributeList().add(o.getDistinguishedName());
+        }
+        for (UnitDuty o : emc.listEqual(UnitDuty.class, UnitDuty.unit_FIELDNAME, unit.getId())) {
+            emc.remove(o, CheckRemoveType.all);
+            result.getRemoveUnitDutyList().add(o.getDistinguishedName());
+        }
+        for (Identity o : emc.listEqual(Identity.class, Identity.unit_FIELDNAME, unit.getId())) {
+            emc.remove(o, CheckRemoveType.all);
+            result.getRemoveIdentityList().add(o.getDistinguishedName());
+        }
+        emc.commit();
+
+        emc.beginTransaction(Unit.class);
+        emc.remove(unit, CheckRemoveType.all);
+        emc.commit();
+        result.getRemoveUnitList().add(unit.getDistinguishedName());
+    }
+
+    private void removePerson(Business business, PullResult result, Person person) throws Exception {
+        EntityManagerContainer emc = business.entityManagerContainer();
+        emc.beginTransaction(PersonAttribute.class);
+        for (PersonAttribute o : emc.listEqual(PersonAttribute.class, PersonAttribute.person_FIELDNAME,
+                person.getId())) {
+            result.getRemovePersonAttributeList().add(o.getDistinguishedName());
+            emc.remove(o, CheckRemoveType.all);
+        }
+        emc.commit();
+
+        emc.beginTransaction(Person.class);
+        emc.remove(person, CheckRemoveType.all);
+        emc.commit();
+        result.getRemovePersonList().add(person.getDistinguishedName());
+    }
+
+
+    public static class PullResult extends GsonPropertyObject {
+
+        private Date start = new Date();
+
+        private Date end;
+
+        private Long elapsed;
+
+        private List<String> createUnitList = new ArrayList<>();
+        private List<String> updateUnitList = new ArrayList<>();
+        private List<String> removeUnitList = new ArrayList<>();
+
+        private List<String> createPersonList = new ArrayList<>();
+        private List<String> updatePersonList = new ArrayList<>();
+        private List<String> removePersonList = new ArrayList<>();
+
+        private List<String> createIdentityList = new ArrayList<>();
+        private List<String> updateIdentityList = new ArrayList<>();
+        private List<String> removeIdentityList = new ArrayList<>();
+
+        private List<String> createPersonAttributeList = new ArrayList<>();
+        private List<String> updatePersonAttributeList = new ArrayList<>();
+        private List<String> removePersonAttributeList = new ArrayList<>();
+
+        private List<String> removeUnitDutyList = new ArrayList<>();
+        private List<String> removeUnitAttributeList = new ArrayList<>();
+
+        public void end() {
+            this.end = new Date();
+            this.elapsed = end.getTime() - start.getTime();
+        }
+
+        public Date getStart() {
+            return start;
+        }
+
+        public void setStart(Date start) {
+            this.start = start;
+        }
+
+        public Date getEnd() {
+            return end;
+        }
+
+        public void setEnd(Date end) {
+            this.end = end;
+        }
+
+        public List<String> getCreateUnitList() {
+            return createUnitList;
+        }
+
+        public void setCreateUnitList(List<String> createUnitList) {
+            this.createUnitList = createUnitList;
+        }
+
+        public List<String> getUpdateUnitList() {
+            return updateUnitList;
+        }
+
+        public void setUpdateUnitList(List<String> updateUnitList) {
+            this.updateUnitList = updateUnitList;
+        }
+
+        public List<String> getCreatePersonList() {
+            return createPersonList;
+        }
+
+        public void setCreatePersonList(List<String> createPersonList) {
+            this.createPersonList = createPersonList;
+        }
+
+        public List<String> getUpdatePersonList() {
+            return updatePersonList;
+        }
+
+        public void setUpdatePersonList(List<String> updatePersonList) {
+            this.updatePersonList = updatePersonList;
+        }
+
+        public List<String> getCreateIdentityList() {
+            return createIdentityList;
+        }
+
+        public void setCreateIdentityList(List<String> createIdentityList) {
+            this.createIdentityList = createIdentityList;
+        }
+
+        public List<String> getRemoveUnitList() {
+            return removeUnitList;
+        }
+
+        public void setRemoveUnitList(List<String> removeUnitList) {
+            this.removeUnitList = removeUnitList;
+        }
+
+        public List<String> getRemovePersonList() {
+            return removePersonList;
+        }
+
+        public void setRemovePersonList(List<String> removePersonList) {
+            this.removePersonList = removePersonList;
+        }
+
+        public List<String> getRemoveIdentityList() {
+            return removeIdentityList;
+        }
+
+        public void setRemoveIdentityList(List<String> removeIdentityList) {
+            this.removeIdentityList = removeIdentityList;
+        }
+
+        public List<String> getRemoveUnitDutyList() {
+            return removeUnitDutyList;
+        }
+
+        public void setRemoveUnitDutyList(List<String> removeUnitDutyList) {
+            this.removeUnitDutyList = removeUnitDutyList;
+        }
+
+        public List<String> getRemoveUnitAttributeList() {
+            return removeUnitAttributeList;
+        }
+
+        public void setRemoveUnitAttributeList(List<String> removeUnitAttributeList) {
+            this.removeUnitAttributeList = removeUnitAttributeList;
+        }
+
+        public List<String> getRemovePersonAttributeList() {
+            return removePersonAttributeList;
+        }
+
+        public void setRemovePersonAttributeList(List<String> removePersonAttributeList) {
+            this.removePersonAttributeList = removePersonAttributeList;
+        }
+
+        public Long getElapsed() {
+            return elapsed;
+        }
+
+        public void setElapsed(Long elapsed) {
+            this.elapsed = elapsed;
+        }
+
+        public List<String> getUpdateIdentityList() {
+            return updateIdentityList;
+        }
+
+        public void setUpdateIdentityList(List<String> updateIdentityList) {
+            this.updateIdentityList = updateIdentityList;
+        }
+
+        public List<String> getCreatePersonAttributeList() {
+            return createPersonAttributeList;
+        }
+
+        public void setCreatePersonAttributeList(List<String> createPersonAttributeList) {
+            this.createPersonAttributeList = createPersonAttributeList;
+        }
+
+        public List<String> getUpdatePersonAttributeList() {
+            return updatePersonAttributeList;
+        }
+
+        public void setUpdatePersonAttributeList(List<String> updatePersonAttributeList) {
+            this.updatePersonAttributeList = updatePersonAttributeList;
+        }
+    }
+}

+ 219 - 0
o2server/x_program_center/src/main/java/com/x/program/center/welink/User.java

@@ -0,0 +1,219 @@
+package com.x.program.center.welink;
+
+import com.x.base.core.project.gson.GsonPropertyObject;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+
+public class User extends GsonPropertyObject {
+
+	//{
+	//          "userStatus": "1",                     //状态, 1:未开户,2:开户中,3:已开户,4:已销户
+	//          "userId": "zhangsan1@welink",       //用户帐号, Key值
+	//          "deptCode": "10001",                   //部门Id, Key值, 必填
+	//          "deptNameCn": "72270测试部门",
+	//          "deptNameEn": "72270Test Dept",
+	//          "mobileNumber": "+86-15811847236",     //绑定手机号码, 必填
+	//          "phoneNumber": "+86-15811847236",      //手机号码
+	//          "landlineNumber": "0755-88888888",     //电话号码(座机)
+	//          "userNameCn": "张三",                  //用户中文名称, 必填
+	//          "userNameEn": "zhangshan",            //用户英文名称, 必填
+	//          "sex": "M",                           //性别, 仅:M/F, M: 男, F: 女, 必填
+	//          "corpUserId": "36188",                //用户工号(集成用的字段,如果在开户时没有维护则为空)
+	//          "userEmail": "zhangshan4@126.com",    //用户邮箱, 必填
+	//          "secretary": "zhangshan@welink",   //秘书(用户帐号)
+	//          "address": "广东省深圳",               //地址
+	//          "remark": "欢迎加入WeLink",        //备注
+	//          "creationTime": "2018-05-03 13:58:02",  //创建时间
+	//          "lastUpdatedTime": "2018-05-03 13:58:02"  //最后更新时间
+	//        }
+
+	private String userStatus;
+	private String userId;
+	private String deptCode;
+	private String deptNameCn;
+	private String deptNameEn;
+	private String mobileNumber;
+	private String phoneNumber;
+	private String landlineNumber;
+	private String userNameCn;
+	private String userNameEn;
+	private String sex;
+	private String corpUserId;
+	private String userEmail;
+	private String secretary;
+	private String address;
+	private String remark;
+	private String creationTime;
+	private String lastUpdatedTime;
+
+	public String getUserStatus() {
+		return userStatus;
+	}
+
+	public void setUserStatus(String userStatus) {
+		this.userStatus = userStatus;
+	}
+
+	public String getUserId() {
+		return userId;
+	}
+
+	public void setUserId(String userId) {
+		this.userId = userId;
+	}
+
+	public String getDeptCode() {
+		return deptCode;
+	}
+
+	public void setDeptCode(String deptCode) {
+		this.deptCode = deptCode;
+	}
+
+	public String getDeptNameCn() {
+		return deptNameCn;
+	}
+
+	public void setDeptNameCn(String deptNameCn) {
+		this.deptNameCn = deptNameCn;
+	}
+
+	public String getDeptNameEn() {
+		return deptNameEn;
+	}
+
+	public void setDeptNameEn(String deptNameEn) {
+		this.deptNameEn = deptNameEn;
+	}
+
+	public String getMobileNumber() {
+		return mobileNumber;
+	}
+
+	public void setMobileNumber(String mobileNumber) {
+		this.mobileNumber = mobileNumber;
+	}
+
+	public String getPhoneNumber() {
+		return phoneNumber;
+	}
+
+	public void setPhoneNumber(String phoneNumber) {
+		this.phoneNumber = phoneNumber;
+	}
+
+	public String getLandlineNumber() {
+		return landlineNumber;
+	}
+
+	public void setLandlineNumber(String landlineNumber) {
+		this.landlineNumber = landlineNumber;
+	}
+
+	public String getUserNameCn() {
+		return userNameCn;
+	}
+
+	public void setUserNameCn(String userNameCn) {
+		this.userNameCn = userNameCn;
+	}
+
+	public String getUserNameEn() {
+		return userNameEn;
+	}
+
+	public void setUserNameEn(String userNameEn) {
+		this.userNameEn = userNameEn;
+	}
+
+	public String getSex() {
+		return sex;
+	}
+
+	public void setSex(String sex) {
+		this.sex = sex;
+	}
+
+	public String getCorpUserId() {
+		return corpUserId;
+	}
+
+	public void setCorpUserId(String corpUserId) {
+		this.corpUserId = corpUserId;
+	}
+
+	public String getUserEmail() {
+		return userEmail;
+	}
+
+	public void setUserEmail(String userEmail) {
+		this.userEmail = userEmail;
+	}
+
+	public String getSecretary() {
+		return secretary;
+	}
+
+	public void setSecretary(String secretary) {
+		this.secretary = secretary;
+	}
+
+	public String getAddress() {
+		return address;
+	}
+
+	public void setAddress(String address) {
+		this.address = address;
+	}
+
+	public String getRemark() {
+		return remark;
+	}
+
+	public void setRemark(String remark) {
+		this.remark = remark;
+	}
+
+	public String getCreationTime() {
+		return creationTime;
+	}
+
+	public void setCreationTime(String creationTime) {
+		this.creationTime = creationTime;
+	}
+
+	public String getLastUpdatedTime() {
+		return lastUpdatedTime;
+	}
+
+	public void setLastUpdatedTime(String lastUpdatedTime) {
+		this.lastUpdatedTime = lastUpdatedTime;
+	}
+
+	@Override
+	public int hashCode() {
+		final int prime = 31;
+		int result = 1;
+		result = prime * result + ((userId == null) ? 0 : userId.hashCode());
+		return result;
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		if (this == obj)
+			return true;
+		if (obj == null)
+			return false;
+		if (getClass() != obj.getClass())
+			return false;
+		User other = (User) obj;
+		if (userId == null) {
+			if (other.userId != null)
+				return false;
+		} else if (!userId.equals(other.userId))
+			return false;
+		return true;
+	}
+
+}

+ 276 - 0
o2server/x_program_center/src/main/java/com/x/program/center/welink/WeLinkFactory.java

@@ -0,0 +1,276 @@
+package com.x.program.center.welink;
+
+import com.x.base.core.project.bean.NameValuePair;
+import com.x.base.core.project.config.Config;
+import com.x.base.core.project.connection.HttpConnection;
+import com.x.base.core.project.gson.GsonPropertyObject;
+import com.x.base.core.project.logger.Logger;
+import com.x.base.core.project.logger.LoggerFactory;
+import com.x.base.core.project.tools.ListTools;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * Created by fancyLou on 2020-07-24.
+ * Copyright © 2020 O2. All rights reserved.
+ */
+public class WeLinkFactory {
+
+    private static Logger logger = LoggerFactory.getLogger(WeLinkFactory.class);
+
+    private String accessToken;
+
+    private List<Department> orgs = new ArrayList<>();
+
+    private List<User> users = new ArrayList<>();
+
+
+    public WeLinkFactory(String accessToken) throws Exception {
+        this.accessToken = accessToken;
+        this.orgs();
+        for (Department d: this.orgs) {
+            this.usersWithDept(d.getDeptCode());
+        }
+        users = ListTools.trim(users, true, true);
+    }
+
+
+    public List<Department> roots() {
+        return orgs.stream().filter(o -> "0".equals(o.getFatherCode())).collect(Collectors.toList());
+    }
+
+
+
+    public List<User> listUser(Department org) throws Exception {
+        return users.stream().filter(o -> o.getDeptCode().equals(org.getDeptCode()))
+                .collect(Collectors.toList());
+    }
+
+    public List<Department> listSub(Department org) throws Exception {
+        return orgs.stream().filter(o -> {
+            return Objects.equals(o.getFatherCode(), org.getDeptCode());
+        }).collect(Collectors.toList());
+    }
+
+    private void orgs() throws Exception {
+        OrgListResp root = this.orgs("0", "0", 1); //跟目录不能递归
+        if (root.getDepartmentInfo()!=null && !root.getDepartmentInfo().isEmpty()) {
+            for (int i = 0; i < root.getDepartmentInfo().size(); i++) {
+                Department department = root.getDepartmentInfo().get(i);
+                this.orgs.add(department);
+                int offset = 1;
+                int totalCount = 0;
+                this.recursiveOrgs(department.getDeptCode(), offset, totalCount); //递归查询有所的组织
+            }
+        }
+    }
+
+    private void recursiveOrgs(String deptCode, int offset, int totalCount) throws Exception {
+        logger.info("recursiveOrgs deptCode:"+deptCode+", offset:"+offset+" ,totalCount:"+totalCount);
+        OrgListResp subDepts = this.orgs(deptCode, "1", offset); //递归查询有所的组织
+        if (!subDepts.getCode().equals("0") && !subDepts.getCode().equals("47009") && !subDepts.getCode().equals("47012")) {
+            throw new ExceptionListOrg(subDepts.getCode(), subDepts.getMessage());
+        }
+        if (subDepts.getDepartmentInfo()!=null && !subDepts.getDepartmentInfo().isEmpty()) {
+            this.orgs.addAll(subDepts.getDepartmentInfo());
+            totalCount += subDepts.getDepartmentInfo().size();
+            if (totalCount < subDepts.getTotalCount()) {
+                offset++;
+                recursiveOrgs(deptCode, offset, totalCount);
+            }
+        }
+    }
+
+    /**
+     * 组织
+     * @param deptCode 父组织id  顶级的父是0
+     * @param recursiveflag 是否递归 0不递归 1递归
+     * @return
+     * @throws Exception
+     */
+    private OrgListResp orgs(String deptCode, String recursiveflag, Integer offset) throws Exception {
+        String address = Config.weLink().getOapiAddress() + "/contact/v3/departments/list?recursiveflag="+recursiveflag+"&deptCode="+deptCode+"&offset="+offset;
+        //deptCode
+        //recursiveflag 0 :查询下级部门信息 1 :查询递归获取所有子部门
+        List<NameValuePair> heads = new ArrayList<>();
+        heads.add(new NameValuePair("x-wlk-Authorization", this.accessToken));
+        OrgListResp resp = HttpConnection.getAsObject(address, heads, OrgListResp.class);
+        logger.info("orgs response:{}.", resp);
+        if (!resp.getCode().equals("0") && !resp.getCode().equals("47009") && !resp.getCode().equals("47012")) {
+            throw new ExceptionListOrg(resp.getCode(), resp.getMessage());
+        }
+        return resp;
+    }
+
+    private void usersWithDept(String deptCode) throws Exception {
+        int pageNo = 1;
+        this.usersPages(deptCode, pageNo);
+    }
+
+    //分页查询
+    private void usersPages(String deptCode, int pageNo) throws Exception {
+        UserListResp resp = this.users(deptCode, pageNo);
+        if (resp.getData() != null && !resp.getData().isEmpty()) {
+            this.users.addAll(resp.data);
+            if (resp.getPages() > pageNo) {
+                pageNo ++;
+                usersPages(deptCode, pageNo);
+            }
+        }
+
+    }
+
+    /**
+     * 查询用户
+     * @param deptCode 所属组织id
+     * @param pageNo 页码
+     * @return
+     * @throws Exception
+     */
+    private UserListResp users(String deptCode, int pageNo) throws Exception {
+        String address = Config.weLink().getOapiAddress() + "/contact/v1/user/users?deptCode="+deptCode+"&pageNo="+pageNo+"&pageSize=50";
+        List<NameValuePair> heads = new ArrayList<>();
+        heads.add(new NameValuePair("x-wlk-Authorization", this.accessToken));
+        UserListResp resp = HttpConnection.getAsObject(address, heads, UserListResp.class);
+        logger.info("users response:{}.", resp);
+        if (!resp.getCode().equals("0") && !resp.getCode().equals("47009") && !resp.getCode().equals("47012")) {
+            throw new ExceptionListUser(resp.getCode(), resp.getMessage());
+        }
+        return resp;
+    }
+
+    public static class OrgListResp extends GsonPropertyObject {
+        //{ "code": "0",
+        //  "message": "OK",
+        //  "offset": 100,
+        //  "limit": 25,
+        //  "totalCount": 327,
+        //  "departmentInfo": []
+        //}
+        private String code; //数据正常返回“0”,如果发生错误,会返回对应的错误码。
+        private String message;
+        private Long offset;
+        private Long limit;
+        private Long totalCount; //当前部门下所有部门数,如果当前部门为0级,仅能获取下一级的所有部门。
+        private List<Department> departmentInfo;
+
+        public String getCode() {
+            return code;
+        }
+
+        public void setCode(String code) {
+            this.code = code;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public void setMessage(String message) {
+            this.message = message;
+        }
+
+        public Long getOffset() {
+            return offset;
+        }
+
+        public void setOffset(Long offset) {
+            this.offset = offset;
+        }
+
+        public Long getLimit() {
+            return limit;
+        }
+
+        public void setLimit(Long limit) {
+            this.limit = limit;
+        }
+
+        public Long getTotalCount() {
+            return totalCount;
+        }
+
+        public void setTotalCount(Long totalCount) {
+            this.totalCount = totalCount;
+        }
+
+        public List<Department> getDepartmentInfo() {
+            return departmentInfo;
+        }
+
+        public void setDepartmentInfo(List<Department> departmentInfo) {
+            this.departmentInfo = departmentInfo;
+        }
+    }
+
+    public static class UserListResp extends GsonPropertyObject {
+        //{
+        //    "code": "0",
+        //    "message": "OK",
+        //    "pageNo": 1,
+        //    "pages": 1,
+        //    "pageSize": "10",
+        //    "total": 2,
+        //    "data": []
+        //}
+        private String code; //数据正常返回“0”,如果发生错误,会返回对应的错误码。
+        private String message;
+        private Long pageNo; //当前页码
+        private Long pages; //总共页数
+        private Long total; //总用户数
+        private List<User> data;
+
+
+        public String getCode() {
+            return code;
+        }
+
+        public void setCode(String code) {
+            this.code = code;
+        }
+
+        public String getMessage() {
+            return message;
+        }
+
+        public void setMessage(String message) {
+            this.message = message;
+        }
+
+        public Long getPageNo() {
+            return pageNo;
+        }
+
+        public void setPageNo(Long pageNo) {
+            this.pageNo = pageNo;
+        }
+
+        public Long getPages() {
+            return pages;
+        }
+
+        public void setPages(Long pages) {
+            this.pages = pages;
+        }
+
+        public Long getTotal() {
+            return total;
+        }
+
+        public void setTotal(Long total) {
+            this.total = total;
+        }
+
+        public List<User> getData() {
+            return data;
+        }
+
+        public void setData(List<User> data) {
+            this.data = data;
+        }
+    }
+
+}