Kaynağa Gözat

feature(人员增量同步开发): 人员增量同步开发

人员增量同步开发
mazq 3 yıl önce
ebeveyn
işleme
2dfac17935
32 değiştirilmiş dosya ile 1340 ekleme ve 181 silme
  1. 14 0
      dcuc-auth-api/src/main/java/com/dragoninfo/dcuc/auth/sub/facade/IUserCenterApiFacade.java
  2. 7 0
      dcuc-auth-service/pom.xml
  3. 5 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/config/DcucAuthConfig.java
  4. 69 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/config/RedissonClientConfig.java
  5. 29 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/config/RedissonConfig.java
  6. 28 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/constance/AddSyncContance.java
  7. 13 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/business/ISubSyncBusiness.java
  8. 554 125
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/business/impl/SubSyncBusinessImpl.java
  9. 46 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AddSyncRecord.java
  10. 43 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthOrgAddOriginal.java
  11. 35 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthUserAddOriginal.java
  12. 46 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthUserOriginalBase.java
  13. 1 31
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthUserOriginalData.java
  14. 10 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/facade/UserCenterApiFacade.java
  15. 13 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AddSyncRecordRepo.java
  16. 9 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AuthUserContactRepository.java
  17. 26 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AuthUserInfoRepository.java
  18. 19 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AuthUserOrgRelRepository.java
  19. 17 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAddSyncRecordService.java
  20. 40 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthOrgAddOriginalService.java
  21. 46 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthUserAddOriginalService.java
  22. 6 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthUserContactService.java
  23. 15 1
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthUserInfoService.java
  24. 13 1
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthUserOrgRelService.java
  25. 37 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AddSyncRecordServiceImpl.java
  26. 8 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AuthUserContactServiceImpl.java
  27. 28 13
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AuthUserInfoService.java
  28. 23 8
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AuthUserOrgRelServiceImpl.java
  29. 25 0
      dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/task/AddSyncTask.java
  30. 5 0
      dcuc-auth-service/src/main/resources/application-auth.yml
  31. 108 0
      dcuc-auth-service/src/main/resources/config/mysql/V4_3_0024__OrgUserAddSync.sql
  32. 2 2
      dcuc-auth-service/src/test/java/com/dragoninfo/dcuc/auth/auth/service/IAuthSyncTest.java

+ 14 - 0
dcuc-auth-api/src/main/java/com/dragoninfo/dcuc/auth/sub/facade/IUserCenterApiFacade.java

@@ -34,6 +34,20 @@ public interface IUserCenterApiFacade {
     @GetMapping("orgSync")
     ResponseStatus orgSync();
 
+    /**
+     * 人员数据增量同步
+     * @return
+     */
+    @GetMapping("userAddSync")
+    ResponseStatus userAddSync();
+
+    /**
+     * 机构数据增量同步
+     * @return
+     */
+    @GetMapping("orgAddSync")
+    ResponseStatus orgAddSync();
+
     /**
      * 获取所有业务域标签
      * @return

+ 7 - 0
dcuc-auth-service/pom.xml

@@ -154,6 +154,13 @@
             </exclusions>
         </dependency>
 
+        <!-- 分布式锁 -->
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson</artifactId>
+            <version>3.5.4</version>
+        </dependency>
+
         <!--配置第三方组件结束-->
     </dependencies>
     <packaging>${project.packaging}</packaging>

+ 5 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/config/DcucAuthConfig.java

@@ -93,4 +93,9 @@ public class DcucAuthConfig {
      */
     private String rootOrgId;
 
+    /**
+     * 人员机构同步定时任务请求头中携带的idcard
+     */
+    private String syncTaskIdcard;
+
 }

+ 69 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/config/RedissonClientConfig.java

@@ -0,0 +1,69 @@
+package com.dragoninfo.dcuc.auth.config;
+
+import cn.hutool.core.util.StrUtil;
+import com.dragonsoft.duceap.commons.util.string.StringUtils;
+import org.redisson.Redisson;
+import org.redisson.api.RedissonClient;
+import org.redisson.config.ClusterServersConfig;
+import org.redisson.config.Config;
+import org.redisson.config.SentinelServersConfig;
+import org.redisson.config.SingleServerConfig;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * redissonClient配置类
+ * @author mazq
+ * @date 2021/12/21
+ */
+@EnableConfigurationProperties(RedissonConfig.class)
+@Configuration
+public class RedissonClientConfig {
+
+    @Autowired
+    RedissonConfig redissonConfig;
+
+    @Bean
+    public RedissonClient redissonClient() {
+        Config config = new Config();
+        String address = redissonConfig.getAddress();
+        String password = redissonConfig.getPassword();
+        List<String> sentinelAddresses = redissonConfig.getSentinelAddresses();
+        List<String> collect = Stream.of(address.split(StrUtil.COMMA)).map(e -> {
+            if (e.startsWith("redis://")) {
+                return e;
+            } else {
+                return "redis://" + e;
+            }
+        }).collect(Collectors.toList());
+        if(null != sentinelAddresses) {
+            SentinelServersConfig sentinelServersConfig = config.useSentinelServers();
+            sentinelServersConfig.setDatabase(redissonConfig.getDatebase());
+            sentinelAddresses.forEach(sentinelServersConfig::addSentinelAddress);
+            if(StringUtils.isNotBlank(password)) {
+              sentinelServersConfig.setPassword(password);
+          }
+        } else if(address.contains(StrUtil.COMMA)) {
+            ClusterServersConfig clusterConfig = config.useClusterServers();
+            collect.forEach(clusterConfig::addNodeAddress);
+            if(StringUtils.isNotBlank(password)) {
+                clusterConfig.setPassword(password);
+            }
+        } else {
+            SingleServerConfig singleServerConfig = config.useSingleServer();
+            singleServerConfig.setAddress(collect.get(0));
+            if(StringUtils.isNotBlank(password)) {
+                singleServerConfig.setPassword(password);
+            }
+        }
+
+        return Redisson.create(config);
+     }
+
+ }

+ 29 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/config/RedissonConfig.java

@@ -0,0 +1,29 @@
+package com.dragoninfo.dcuc.auth.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+/**
+ * 分布式锁配置类
+ * @author mazq
+ * @date 2021/12/21
+ */
+@ConfigurationProperties(prefix = "dcuc.auth.redisson")
+@Data
+@Configuration
+public class RedissonConfig {
+
+    private String address;
+
+    private String password;
+
+    private int datebase = 0;
+
+    private List<String> sentinelAddresses;
+
+    private String masterName;
+
+}

+ 28 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/constance/AddSyncContance.java

@@ -0,0 +1,28 @@
+package com.dragoninfo.dcuc.auth.constance;
+
+/**
+ * @author mazq
+ * @date 2021/12/20
+ */
+public class AddSyncContance {
+
+    /**
+     * 增量同步类型-人员
+     */
+    public static final String ADD_SYNC_TYPE_USER = "USER";
+
+    /**
+     * 增量同步类型-机构
+     */
+    public static final String ADD_SYNC_TYPE_ORG = "ORG";
+
+    /**
+     * 机构同步时分布式锁的key
+     */
+    public static final String ORG_SYNC_KEY = "DCUC:AUTH:ORG-SYNC";
+
+    /**
+     * 人员同步时分布式锁的key
+     */
+    public static final String USER_SYNC_KEY = "DCUC:AUTH:USER-SYNC";
+}

+ 13 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/business/ISubSyncBusiness.java

@@ -21,4 +21,17 @@ public interface ISubSyncBusiness {
      */
     ResponseStatus orgSync();
 
+    /**
+     * 用户增量同步
+     * @return
+     */
+    ResponseStatus userAddSync();
+
+    /**
+     * 机构增量同步
+     * @return
+     */
+    ResponseStatus orgAddSync();
+
+
 }

+ 554 - 125
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/business/impl/SubSyncBusinessImpl.java

@@ -11,6 +11,7 @@ import com.dragoninfo.dcuc.app.facade.IApplyInfoFacade;
 import com.dragoninfo.dcuc.auth.auth.constance.CommonCons;
 import com.dragoninfo.dcuc.auth.config.DcucAuthConfig;
 import com.dragoninfo.dcuc.auth.config.SubSyncConfig;
+import com.dragoninfo.dcuc.auth.constance.AddSyncContance;
 import com.dragoninfo.dcuc.auth.constance.UserApiConstance;
 import com.dragoninfo.dcuc.auth.sub.business.ISubSyncBusiness;
 import com.dragoninfo.dcuc.auth.sub.entity.*;
@@ -22,6 +23,7 @@ import com.dragoninfo.dcuc.common.http.HttpUtil;
 import com.dragoninfo.dcuc.duceap.enums.UserTypeEnum;
 import com.dragoninfo.duceap.core.enums.ResultEnum;
 import com.dragonsoft.duceap.base.entity.http.ResponseStatus;
+import com.dragonsoft.duceap.base.entity.security.SecurityUser;
 import com.dragonsoft.duceap.base.enums.BooleanEnum;
 import com.dragonsoft.duceap.base.utils.UserContextUtils;
 import com.dragonsoft.duceap.commons.util.collections.CollectionUtils;
@@ -31,15 +33,18 @@ import com.dragonsoft.duceap.core.search.enums.SearchOperator;
 import com.google.common.base.Joiner;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.http.Header;
+import org.redisson.api.RLock;
+import org.redisson.api.RedissonClient;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Sort;
 import org.springframework.stereotype.Component;
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.util.StopWatch;
 
 import java.util.*;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -53,6 +58,16 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
 
     public static Logger logger = LoggerFactory.getLogger(ISubSyncBusiness.class);
 
+    private final String syncAllFail = "000";
+
+    private final String syncSuccessStatus = "2";
+
+    private final String syncS_FStatus = "1";
+
+    private final String syncFailStatus = "0";
+
+
+
     @Autowired
     private IAuthOrgInfoService authOrgInfoService;
 
@@ -83,32 +98,94 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
     @Autowired
     private IApplyInfoFacade applyInfoFacade;
 
+    @Autowired
+    private RedissonClient redissonClient;
+
+    @Autowired
+    private IAddSyncRecordService addSyncRecordService;
+
+    @Autowired
+    private IAuthUserAddOriginalService userAddOriginalService;
+
+    @Autowired
+    private IAuthOrgAddOriginalService orgAddOriginalService;
+
     @Override
     public ResponseStatus userSync() {
-        //因为子线程中需要调用总线需要用到请求头中的信息
-        //需要将requestAttributes设置到子线程中的RequestContextHolder
-        //SpringWeb暂时未提供RequestContextHolder父子线程共享ThreadLocal中的数据的配置,需要手动设置
-        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
-        //开启父子线程
-        //方法内部有从ThreadLocal获取信息
-        //CompletableFuture默认使用ForkJoin线程池,不要使用1.8的新线程开启方法
-        //如果使用线程池需要用包装类将线程包装后设置RequestContextHolder
-        Runnable r = ()->{
-            RequestContextHolder.setRequestAttributes(requestAttributes);
-            try {
-                //同步用户信息
-                getUserInfoFromRemote(1, subSyncConfig.getPageSize());
-                userInfoSync();
-            } finally {
-                RequestContextHolder.resetRequestAttributes();
-            }
-        };
+        //不使用线程池
+        //currentUser在线程环境中才能清除
+        SecurityUser currentUser = UserContextUtils.getCurrentUser();
+        String idcard = currentUser.getIdcard();
+        List<Header> headers = getHeads(idcard);
+        Runnable r = getUserSyncTask(currentUser, headers);
         Thread t = new Thread(r);
         t.start();
         return ResponseStatus.success();
     }
 
-    private void saveUserOrgRel(List<AuthUserOriginalData> content, Map<String, AuthUserInfo> idcardMap, UserTypeEnum userType) {
+    private Runnable getUserSyncTask(SecurityUser currentUser, List<Header> headers) {
+        return ()->{
+                UserContextUtils.setCurrentUser(currentUser);
+                RLock lock = redissonClient.getLock(AddSyncContance.USER_SYNC_KEY);
+                try {
+                    //加锁
+                    boolean tryLock = lock.tryLock(0, 20, TimeUnit.MINUTES);
+                    if (!tryLock) {
+                        log.info("try lock fail");
+                        return ;
+                    }
+                    StopWatch watch = new StopWatch("userSync");
+
+                    //获取用户信息
+                    watch.start("getUserInfoFromRemote");
+                    getUserInfoFromRemote(1, subSyncConfig.getPageSize(), headers);
+                    watch.stop();
+
+                    //同步用户信息
+                    watch.start("userInfoSync");
+                    userInfoSync();
+                    watch.stop();
+
+                    //更新同步记录
+                    updateAddSyncRecord(AddSyncContance.ADD_SYNC_TYPE_USER, true, null, null);
+                } catch (Exception e){
+                    log.error("userSync error.", e);
+                    updateAddSyncRecord(AddSyncContance.ADD_SYNC_TYPE_USER, false, null, null);
+                }finally {
+                    lock.unlock();
+                }
+            };
+    }
+
+    private void updateAddSyncRecord(String type, boolean success, Date updateTime, String result) {
+        if(null == updateTime) {
+            updateTime = new Date();
+        }
+        AddSyncRecord record = addSyncRecordService.getRecordByType(type);
+        if(null == record) {
+            record = new AddSyncRecord();
+            record.setType(type);
+        }
+        if(success) {
+            record.setSuccessTime(updateTime);
+            record.setSuccessResult(result);
+        }else {
+            record.setFailTime(updateTime);
+            record.setFailResult(result);
+        }
+        if(record.getId() != null) {
+            addSyncRecordService.update(record);
+        } else {
+            addSyncRecordService.save(record);
+        }
+
+    }
+
+    private void saveUserOrgRel(List<? extends AuthUserOriginalBase> content, Map<String, AuthUserInfo> idcardMap, UserTypeEnum userType) {
+        if(CollectionUtils.isEmpty(content)) {
+            log.info("saveUserOrgRel content is empty");
+            return ;
+        }
         Boolean rel = subSyncConfig.getUserOrgRel();
         if(null != rel && rel) {
             saveUserOrgRelFromRemote(content, idcardMap, userType);
@@ -134,7 +211,7 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
             rel.setRelStatus(JobTypeEnum.ZZ.getValue());
             return rel;
         }).collect(Collectors.toList());
-        authUserOrgRelService.saveOneRelByOrgId(collect);
+        authUserOrgRelService.saveOneRelByOrgCode(collect);
     }
 
     /**
@@ -143,11 +220,8 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
      * @param idcardMap
      * @param userType
      */
-    private void saveUserOrgRelFromRemote(List<AuthUserOriginalData> content, Map<String, AuthUserInfo> idcardMap, UserTypeEnum userType) {
+    private void saveUserOrgRelFromRemote(List<? extends AuthUserOriginalBase> content, Map<String, AuthUserInfo> idcardMap, UserTypeEnum userType) {
         logger.info("-------------saveUserOrgRelFromRemote START-----------");
-        if(CollectionUtils.isEmpty(content)) {
-            return ;
-        }
         List<AuthUserOrgRel> relList = new ArrayList<>();
         if(UserTypeEnum.POLICE.equals(userType)) {
             List<AuthUserOrgRel> collect = getAuthUserOrgRelsFromPolice(idcardMap, content);
@@ -171,7 +245,7 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
         logger.info("-------------saveUserOrgRelFromRemote END-----------");
     }
 
-    private List<AuthUserOrgRel> getAuthUserOrgRelsFromExternal(Map<String, AuthUserInfo> idcardMap, List<AuthUserOriginalData> externalGroup) {
+    private List<AuthUserOrgRel> getAuthUserOrgRelsFromExternal(Map<String, AuthUserInfo> idcardMap, List<? extends AuthUserOriginalBase> externalGroup) {
         //收集所有的应用id,批量查询应用信息
         //通过appCode查询应用所属机构code
         //然后录入机构关联信息
@@ -187,6 +261,7 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
         Map<String, String> appCodeKeyOrgCodeMap = applyInfoList
                 .stream()
                 .filter(e->StringUtils.isNotBlank(e.getOrgCode()))
+                .distinct()
                 .collect(Collectors.toMap(ApplyInfo::getApplyCode, ApplyInfo::getOrgCode));
         List<String> orgCodes = new ArrayList<>(appCodeKeyOrgCodeMap.values());
         List<AuthOrgInfo> orgInfoList = authOrgInfoService.getOrgByCodes(orgCodes);
@@ -207,24 +282,23 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
                 rel.setUserId(userInfo.getId());
                 rel.setIdcard(userInfo.getIdcard());
                 rel.setUserType(UserTypeEnum.EXTERNAL.getValue());
+                rel.setRelStatus(JobTypeEnum.ZZ.getValue());
                 String orgCode = appCodeKeyOrgCodeMap.get(appCode);
                 if (StringUtils.isBlank(orgCode)) {
                     return null;
                 }
+                rel.setOrgCode(orgCode);
                 AuthOrgInfo authOrgInfo = orgCodeKeyOrgMap.get(orgCode);
-                if (null == authOrgInfo) {
-                    return null;
+                if (null != authOrgInfo) {
+                    rel.setOrgId(authOrgInfo.getId());
                 }
-                rel.setOrgCode(authOrgInfo.getCode());
-                rel.setOrgId(authOrgInfo.getId());
-                rel.setRelStatus(JobTypeEnum.ZZ.getValue());
                 return rel;
             }).filter(Objects::nonNull).collect(Collectors.toList());
             return rels;
         }).filter(Objects::nonNull).flatMap(List::stream).collect(Collectors.toList());
     }
 
-    private List<AuthUserOrgRel> getAuthUserOrgRelsFromAuxiliry(Map<String, AuthUserInfo> idcardMap, List<AuthUserOriginalData> auxiliryGroup) {
+    private  List<AuthUserOrgRel> getAuthUserOrgRelsFromAuxiliry(Map<String, AuthUserInfo> idcardMap, List<? extends AuthUserOriginalBase> auxiliryGroup) {
         return auxiliryGroup.stream().map(e -> {
                     AuthUserInfo userInfo = idcardMap.get(e.getIdcard());
                     if (null == userInfo) {
@@ -246,7 +320,7 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
                 }).filter(Objects::nonNull).collect(Collectors.toList());
     }
 
-    private List<AuthUserOrgRel> getAuthUserOrgRelsFromPolice(Map<String, AuthUserInfo> idcardMap, List<AuthUserOriginalData> policeGroup) {
+    private List<AuthUserOrgRel> getAuthUserOrgRelsFromPolice(Map<String, AuthUserInfo> idcardMap, List<? extends AuthUserOriginalBase> policeGroup) {
         List<AuthUserOrgRel> collect = policeGroup.stream().map(e -> convertPostInfoToRel(idcardMap, e))
                 .filter(Objects::nonNull)
                 .flatMap(List::stream).collect(Collectors.toList());
@@ -269,9 +343,9 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
         return collect;
     }
 
-    private List<AuthUserOrgRel> convertPostInfoToRel(Map<String, AuthUserInfo> idcardMap, AuthUserOriginalData e) {
-        String orgRelData = e.getOrgRelData();
-        String idcard = e.getIdcard();
+    private <T extends AuthUserOriginalBase> List<AuthUserOrgRel> convertPostInfoToRel(Map<String, AuthUserInfo> idcardMap, T t) {
+        String orgRelData = t.getOrgRelData();
+        String idcard = t.getIdcard();
         AuthUserInfo userInfo = idcardMap.get(idcard);
         if (userInfo == null) {
             return null;
@@ -282,13 +356,17 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
         }
         return jsonArray.stream().map(json -> {
             JSONObject jsonObject = (JSONObject) json;
+            String orgCode = jsonObject.getString("orgCode");
+            if(StringUtils.isBlank(orgCode)) {
+                return null;
+            }
             AuthUserOrgRel rel = new AuthUserOrgRel();
             rel.setUserId(userInfo.getId());
             rel.setUserType(UserTypeEnum.POLICE.getValue());
             rel.setIdcard(idcard);
             rel.setRelName(jsonObject.getString("postType"));
             rel.setRelStatus(jsonObject.getString("jobType"));
-            rel.setOrgCode(jsonObject.getString("orgCode"));
+            rel.setOrgCode(orgCode);
             return rel;
         }).collect(Collectors.toList());
     }
@@ -296,13 +374,14 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
 
     /**
      * 从用户中心获取用户信息并保存到用户原始数据表
-     * @param pageSize
      * @param currentPage
+     * @param pageSize
+     * @param headers
      */
-    public void getUserInfoFromRemote(Integer currentPage,Integer pageSize) {
-        getDiffTypeUserInfo(currentPage, pageSize, UserApiConstance.POLICE_SYNC_API, UserTypeEnum.POLICE);
-        getDiffTypeUserInfo(currentPage, pageSize, UserApiConstance.AUXILIRY_SYNC_API, UserTypeEnum.HELPER);
-        getDiffTypeUserInfo(currentPage, pageSize, UserApiConstance.EXTERNAL_SYNC_API, UserTypeEnum.EXTERNAL);
+    public void getUserInfoFromRemote(Integer currentPage, Integer pageSize, List<Header> headers) {
+        getDiffTypeUserInfo(currentPage, pageSize, UserApiConstance.POLICE_SYNC_API, UserTypeEnum.POLICE, headers);
+        getDiffTypeUserInfo(currentPage, pageSize, UserApiConstance.AUXILIRY_SYNC_API, UserTypeEnum.HELPER, headers);
+        getDiffTypeUserInfo(currentPage, pageSize, UserApiConstance.EXTERNAL_SYNC_API, UserTypeEnum.EXTERNAL, headers);
     }
 
     /**
@@ -311,15 +390,22 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
      * @param pageSize
      * @param userInfoApi
      * @param userType
+     * @param headers
      */
-    private void getDiffTypeUserInfo(Integer currentPage, Integer pageSize, String userInfoApi, UserTypeEnum userType) {
+    private void getDiffTypeUserInfo(Integer currentPage, Integer pageSize, String userInfoApi,
+                                     UserTypeEnum userType, List<Header> headers) {
         Date now = new Date();
         Integer totalPage = null;
-        List<Header> headers = getHeads();
         ApiSearchReq apiSearchReq = new ApiSearchReq();
         ApiPageReq pageReq = new ApiPageReq();
         pageReq.setSize(pageSize);
         apiSearchReq.setPage(pageReq);
+        Map<String, SearchParam> filters = new HashMap<>();
+        SearchParam searchParam = new SearchParam();
+        searchParam.setValue(BooleanEnum.FALSE.value);
+        searchParam.setOperator(SearchOperator.eq.name());
+        filters.put("deleted", searchParam);
+        apiSearchReq.setFilters(filters);
         String url = Joiner.on("").join(authConfig.getUserCenterUrl(), userInfoApi);
         logger.info("-------------getUserInfoFromRemote START-----------");
         do {
@@ -354,43 +440,25 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
         return totalPage;
     }
 
-    private List<Header> getHeads() {
-        String idcard = UserContextUtils.getCurrentUser().getIdcard();
+    private List<Header> getHeads(String idcard) {
+        if(StringUtils.isBlank(idcard)) {
+            idcard = authConfig.getSyncTaskIdcard();
+        }
         return UserCenterBusiUtil.getHeads(idcard, authConfig.getAppCode());
     }
 
     private void saveUserOri(Date now, ApiResultPage<JSONObject> syncResult, UserTypeEnum userType) {
         List<JSONObject> content = syncResult.getContent();
         List<AuthUserOriginalData> originals = new ArrayList<>();
-        for (JSONObject jsonObject : content) {
+        for (JSONObject json : content) {
             AuthUserOriginalData userOri = new AuthUserOriginalData();
-            userOri.setIdcard(jsonObject.getString("idcard"));
+            userOri.setIdcard(json.getString("idcard"));
             userOri.setDeleted(BooleanEnum.FALSE.value);
             userOri.setSync(BooleanEnum.FALSE.value);
             userOri.setSyncDate(now);
             userOri.setUserType(userType.getValue());
             //保存联系方式json
-            JSONObject userContact = jsonObject.getJSONObject("userContact");
-            if(null != userContact && !userContact.isEmpty()) {
-                userOri.setContactData(userContact.toJSONString());
-            }
-            jsonObject.remove("userContact");
-            //保存人员和机构关系json
-            if (userType.equals(UserTypeEnum.POLICE)) {
-                JSONArray jsonArray = jsonObject.getJSONArray("postInfos");
-                if (CollectionUtils.isNotEmpty(jsonArray)) {
-                    userOri.setOrgRelData(jsonArray.toJSONString());
-                    jsonObject.remove("postInfos");
-                }
-            } else if (userType.equals(UserTypeEnum.EXTERNAL)) {
-                String projectCodes = jsonObject.getString("projectCode");
-                if(StringUtils.isNotBlank(projectCodes)) {
-                    userOri.setOrgRelData(projectCodes);
-                }
-                jsonObject.remove("projectCode");
-            }
-            //保存人员数据json
-            userOri.setJsonData(jsonObject.toJSONString());
+            setJSONData(userType, json, userOri);
             originals.add(userOri);
         }
         //过程数据保存
@@ -433,7 +501,11 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
         }while (true);
     }
 
-    private void saveContact(List<AuthUserOriginalData> content, Map<String, AuthUserInfo> idcardMap) {
+    private void saveContact(List<? extends AuthUserOriginalBase> content, Map<String, AuthUserInfo> idcardMap) {
+        if(CollectionUtils.isEmpty(content)) {
+            log.info("saveContact content is empty");
+            return ;
+        }
         logger.info("-------------saveUserContact START-----------");
         List<AuthUserContact> collect = content.stream().map(e -> {
             String contactData = e.getContactData();
@@ -454,6 +526,10 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
     }
 
     private List<AuthUserInfo> saveUserInfo(List<AuthUserOriginalData> content, UserTypeEnum userType) {
+        if(CollectionUtils.isEmpty(content)) {
+            log.info("saveUserInfo content is empty");
+            return Collections.emptyList();
+        }
         List<AuthUserInfo> userInfoList = content.stream().map(item -> {
             String jsonData = item.getJsonData();
             AuthUserInfo authUserInfo = JSON.parseObject(jsonData, AuthUserInfo.class);
@@ -464,12 +540,40 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
         }).collect(Collectors.toList());
 
         //设置人员的机构字段信息
-        setUserOrgInfos(content, userType, userInfoList);
+        if(UserTypeEnum.POLICE.equals(userType)) {
+            setPoliceOrgCode(content, userType, userInfoList);
+        }
+        setUserOrgInfos(userType, userInfoList);
         authUserInfoService.batchSaveByIdcard(userInfoList);
         return userInfoList;
     }
 
-    private void setUserOrgInfos(List<AuthUserOriginalData> content, UserTypeEnum userType, List<AuthUserInfo> userInfoList) {
+    private void setPoliceOrgCode(List<? extends AuthUserOriginalBase> content, UserTypeEnum userType, List<AuthUserInfo> userInfoList) {
+        //警员根据职务排序,取职务序号小的为主机构
+        Map<String, AuthUserInfo> idcardMap = userInfoList
+                .stream()
+                .collect(Collectors.toMap(AuthUserInfo::getIdcard, e -> e));
+        content.forEach(e->{
+            String orgRelData = e.getOrgRelData();
+            JSONArray jsonArray = JSON.parseObject(orgRelData, JSONArray.class);
+            if(!jsonArray.isEmpty()) {
+                String orgCode = jsonArray.stream()
+                        .map(json -> (JSONObject) json).min((x, y) -> {
+                            String xJobType = x.getString("jobType");
+                            String yJobType = y.getString("jobType");
+                            return xJobType.compareTo(yJobType);
+                        }).orElse(new JSONObject()).getString("orgCode");
+                if(StringUtils.isNotBlank(orgCode)) {
+                    AuthUserInfo userInfo = idcardMap.get(e.getIdcard());
+                    if(null != userInfo) {
+                        userInfo.setOrgCode(orgCode);
+                    }
+                }
+            }
+        });
+    }
+
+    private void setUserOrgInfos(UserTypeEnum userType, List<AuthUserInfo> userInfoList) {
         if(UserTypeEnum.EXTERNAL.equals(userType)) {
             //施工人员不关联主机构
             userInfoList.forEach(e->{
@@ -477,7 +581,7 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
                 e.setOrgCode(null);
                 e.setOrgName(null);
             });
-        } else if (UserTypeEnum.HELPER.equals(userType)) {
+        } else {
             //修改orgId
             List<String> orgCodes = userInfoList.stream()
                     .map(AuthUserInfo::getOrgCode).distinct()
@@ -486,33 +590,6 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
                 List<AuthOrgInfo> authOrgInfos = authOrgInfoService.getOrgByCodes(orgCodes);
                 setUpOrgInfo(userInfoList, authOrgInfos);
             }
-        } else if(UserTypeEnum.POLICE.equals(userType)) {
-            //警员根据职务排序,取职务序号小的为主机构
-            Map<String, AuthUserInfo> idcardMap = userInfoList
-                    .stream()
-                    .collect(Collectors.toMap(AuthUserInfo::getIdcard, e -> e));
-            Set<String> orgCodes = new HashSet<>();
-            content.forEach(e->{
-                String orgRelData = e.getOrgRelData();
-                JSONArray jsonArray = JSON.parseObject(orgRelData, JSONArray.class);
-                if(!jsonArray.isEmpty()) {
-                    String orgCode = jsonArray.stream()
-                            .map(json -> (JSONObject) json).min((x, y) -> {
-                                String xJobType = x.getString("jobType");
-                                String yJobType = y.getString("jobType");
-                                return xJobType.compareTo(yJobType);
-                            }).orElse(new JSONObject()).getString("orgCode");
-                    if(StringUtils.isNotBlank(orgCode)) {
-                        AuthUserInfo userInfo = idcardMap.get(e.getIdcard());
-                        userInfo.setOrgCode(orgCode);
-                        orgCodes.add(orgCode);
-                    }
-                }
-            });
-            if(!orgCodes.isEmpty()) {
-                List<AuthOrgInfo> authOrgInfos = authOrgInfoService.getOrgByCodes(new ArrayList<>(orgCodes));
-                setUpOrgInfo(userInfoList, authOrgInfos);
-            }
         }
     }
 
@@ -525,7 +602,6 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
             if(StringUtils.isBlank(orgCode) || null == (authOrgInfo = orgCodeMap.get(orgCode))) {
                 e.setOrgName(null);
                 e.setOrgId(null);
-                e.setOrgCode(null);
                 return ;
             }
             e.setOrgId(authOrgInfo.getId());
@@ -536,30 +612,383 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
 
     @Override
     public ResponseStatus orgSync() {
-        //因为子线程中需要调用总线需要用到请求头中的信息
-        //需要将requestAttributes设置到子线程中的RequestContextHolder
-        //SpringWeb暂时未提供RequestContextHolder父子线程共享ThreadLocal中的数据的配置,需要手动设置
-        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
-        //开启父子线程
-        //方法内部有从ThreadLocal获取信息
-        //CompletableFuture默认使用ForkJoin线程池,不要使用1.8的新线程开启方法
-        //如果使用线程池需要用包装类将线程包装后设置RequestContextHolder
-        Runnable r = ()->{
-            RequestContextHolder.setRequestAttributes(requestAttributes);
-            try {
-                getOrgInfoFromRemote(1, subSyncConfig.getPageSize());
-                orgInfoSync();
-                setPathAndUpId();
-                orgTreeService.reInitTrees();
-            } finally {
-                RequestContextHolder.resetRequestAttributes();
-            }
-        };
+        //不使用线程池
+        //currentUser在线程环境中才能清除
+        SecurityUser currentUser = UserContextUtils.getCurrentUser();
+        List<Header> heads = getHeads(currentUser.getIdcard());
+        Runnable r = getOrgSyncTask(currentUser, heads);
+        Thread t = new Thread(r);
+        t.start();
+        return ResponseStatus.success();
+    }
+
+    private Runnable getOrgSyncTask(SecurityUser currentUser, List<Header> heads) {
+        return ()->{
+                UserContextUtils.setCurrentUser(currentUser);
+                //分布式锁
+                RLock lock = redissonClient.getLock(AddSyncContance.ORG_SYNC_KEY);
+                try {
+                    boolean tryLock = lock.tryLock(0, 20, TimeUnit.MINUTES);
+                    if (!tryLock) {
+                        log.info("try lock fail");
+                        return ;
+                    }
+                    StopWatch watch = new StopWatch("orgSync");
+
+                    watch.start("getOrgInfoFromRemote");
+                    getOrgInfoFromRemote(1, subSyncConfig.getPageSize(), heads);
+                    watch.stop();
+
+                    watch.start("orgInfoSync");
+                    orgInfoSync();
+                    watch.stop();
+
+                    //修改人员信息中保留了机构code但是机构id为空的字段
+                    watch.start("updateOrgInfoInUser");
+                    updateOrgInfoInUser();
+                    watch.stop();
+
+                    watch.start("reInitTrees");
+                    setPathAndUpId();
+                    orgTreeService.reInitTrees();
+                    watch.stop();
+
+                    log.info("orgSync total time:{}", watch.prettyPrint());
+                    updateAddSyncRecord(AddSyncContance.ADD_SYNC_TYPE_ORG, true, null, null);
+                } catch (Exception e){
+                    log.error("orgSync error.", e);
+                    updateAddSyncRecord(AddSyncContance.ADD_SYNC_TYPE_ORG, false, null, null);
+                }finally {
+                    //解锁
+                    lock.unlock();
+                }
+            };
+    }
+
+    private void updateOrgInfoInUser() {
+        authUserInfoService.updateOrgInfoInUser();
+        authUserOrgRelService.updateOrgInfoInUser();
+    }
+
+    @Override
+    public ResponseStatus userAddSync() {
+        SecurityUser currentUser = UserContextUtils.getCurrentUser();
+        String idcard = null;
+        if(null != currentUser) {
+            idcard = currentUser.getIdcard();
+        }
+        List<Header> headers = getHeads(idcard);
+        Runnable r = getUserAddSyncTask(currentUser, headers);
         Thread t = new Thread(r);
         t.start();
         return ResponseStatus.success();
     }
 
+    private Runnable getUserAddSyncTask(SecurityUser currentUser, List<Header> headers) {
+        return ()->{
+            RLock lock = redissonClient.getLock(AddSyncContance.USER_SYNC_KEY);
+            UserContextUtils.setCurrentUser(currentUser);
+            try {
+                boolean tryLock = lock.tryLock(0, 5, TimeUnit.MINUTES);
+                if (!tryLock) {
+                    log.info("try lock fail");
+                    return ;
+                }
+                StopWatch watch = new StopWatch("userAddSync");
+
+                watch.start("onUserInfoAddStart");
+                //获取上次同步成功的时间
+                Date syncStartTime = getSyncStartTime(AddSyncContance.ADD_SYNC_TYPE_USER);
+                if(null == syncStartTime) {
+                    log.info("userAddSync syncStartTime is null");
+                    return ;
+                }
+                //删除增量同步的数据
+                deleteUserAddInfo();
+                watch.stop();
+
+                //在同步前记录时间
+                //避免同步时用户中心更新的数据未被同步过来
+                //被同步的会在下次同步时再更新一次
+                Date updateTime = new Date();
+
+                watch.start("getUserInfoAddFromRemote");
+                //增量同步用户信息
+                String addUserInfoStatus = getAddUserInfo(subSyncConfig.getPageSize(), syncStartTime, headers);
+                watch.stop();
+                if(syncAllFail.equals(addUserInfoStatus)) {
+                    log.info("getUserInfoAddFromRemote all failed");
+                    updateAddSyncRecord(AddSyncContance.ADD_SYNC_TYPE_USER, false, null, addUserInfoStatus);
+                    return ;
+                }
+
+                //如果有任意人员同步失败记录同步时间
+                if(addUserInfoStatus.contains(syncFailStatus) || addUserInfoStatus.contains(syncS_FStatus)) {
+                    log.info("getUserInfoAddFromRemote something failed");
+                    updateAddSyncRecord(AddSyncContance.ADD_SYNC_TYPE_USER, false, null, addUserInfoStatus);
+                }
+
+                //同步用户信息
+                watch.start("userInfoAddSync");
+                addUserInfoSync();
+                watch.stop();
+
+                //记录同步成功时间
+                updateAddSyncRecord(AddSyncContance.ADD_SYNC_TYPE_USER, true, updateTime, addUserInfoStatus);
+            } catch (Exception e) {
+                log.error("userAddSync error.", e);
+                //记录同步失败时间
+                updateAddSyncRecord(AddSyncContance.ADD_SYNC_TYPE_USER, false, null, syncAllFail);
+            }finally {
+                lock.unlock();
+            }
+        };
+    }
+
+    private void addUserInfoSync() {
+        diffTypeAddUserSync(UserTypeEnum.POLICE);
+        diffTypeAddUserSync(UserTypeEnum.HELPER);
+        diffTypeAddUserSync(UserTypeEnum.EXTERNAL);
+
+    }
+
+    private void diffTypeAddUserSync(UserTypeEnum userType) {
+        int currentPage = 0;
+        Searchable searchable = Searchable.newSearchable();
+        searchable.addSort(Sort.Direction.ASC, "userUpdateTime");
+        do {
+            searchable.setPage(currentPage, 1000);
+            Page<AuthUserAddOriginal> page = userAddOriginalService.pageSearch(searchable);
+            if(page.isEmpty()) {
+                break;
+            }
+            List<AuthUserAddOriginal> content = page.getContent();
+
+            //保存人员信息
+            //返回最终需要新增的或修改的人员信息
+            List<AuthUserInfo> userInfoList = saveAddUserInfo(content, userType);
+            Map<String, AuthUserInfo> idcardMap = userInfoList
+                    .stream()
+                    .collect(Collectors.toMap(AuthUserInfo::getIdcard, e -> e, (old, last) -> last));
+
+            //过滤删除人员的身份证号
+            List<String> delIdcards = content.stream()
+                    .filter(e -> BooleanEnum.TRUE.value.equals(e.getUserDeleted()))
+                    .map(AuthUserAddOriginal::getIdcard)
+                    .distinct().collect(Collectors.toList());
+            //保存人员联系方式
+            saveAddContact(content, idcardMap, delIdcards);
+            //保存人员和机构关系
+            saveAddUserOrgRel(content, idcardMap, userType, delIdcards);
+            ++currentPage;
+        }while (true);
+    }
+
+    /**
+     * 保存人员与机构的关系
+     * @param content       人员与机构关系json数据
+     * @param idcardMap     最终同步后存在的人员map key:idcard  value:userInfo
+     * @param userType      人员类型枚举
+     * @param delIdcards    需要删除的人员的id
+     */
+    private void saveAddUserOrgRel(List<AuthUserAddOriginal> content, Map<String, AuthUserInfo> idcardMap,
+                                   UserTypeEnum userType, List<String> delIdcards) {
+        if(CollectionUtils.isEmpty(content)) {
+            log.info("saveAddUserOrgRel content is empty");
+            return ;
+        }
+        //先删除人员与机构的关系
+        //人员删除后添加userId发生变化,人员与机构的关系也需要重新添加
+        authUserOrgRelService.delByIdcards(delIdcards);
+        List<AuthUserAddOriginal> collect = content.stream()
+                .filter(e -> BooleanEnum.FALSE.value.equals(e.getUserDeleted())
+                        && idcardMap.keySet().contains(e.getIdcard())).collect(Collectors.toList());
+
+        Boolean rel = subSyncConfig.getUserOrgRel();
+        if(null != rel && rel) {
+            saveUserOrgRelFromRemote(collect, idcardMap, userType);
+        }else {
+            saveUserOrgRelFromUserInFo(new ArrayList<>(idcardMap.values()));
+        }
+
+    }
+
+    /**
+     * 保存人员联系方式
+     * @param idcardMap     最终同步后存在的人员map key:idcard  value:userInfo
+     * @param delIdcards    需要删除的人员的id
+     * @param content       联系方式json数据
+     */
+    private void saveAddContact(List<AuthUserAddOriginal> content, Map<String, AuthUserInfo> idcardMap, List<String> delIdcards) {
+        if(CollectionUtils.isEmpty(content)) {
+            log.info("saveAddContact content is empty");
+            return ;
+        }
+        //先删除人员联系方式
+        //人员删除后添加userId发生变化,联系方式也需要重新添加
+        authUserContact.delByIdcards(delIdcards);
+        List<AuthUserAddOriginal> collect = content.stream()
+                .filter(e -> BooleanEnum.FALSE.value.equals(e.getUserDeleted())
+                        && idcardMap.keySet().contains(e.getIdcard())).collect(Collectors.toList());
+        //保存或修改联系方式
+        saveContact(collect, idcardMap);
+    }
+
+    private List<AuthUserInfo> saveAddUserInfo(List<AuthUserAddOriginal> content, UserTypeEnum userType) {
+        if(CollectionUtils.isEmpty(content)) {
+            return  Collections.emptyList();
+        }
+        List<AuthUserInfo> userInfoList = content.stream().map(e -> {
+            String userDeleted = e.getUserDeleted();
+            String jsonData = e.getJsonData();
+            AuthUserInfo authUserInfo;
+            if (BooleanEnum.FALSE.value.equals(userDeleted)) {
+                authUserInfo = JSON.parseObject(jsonData, AuthUserInfo.class);
+                authUserInfo.setSource(CommonCons.USER_SOURCE_SYNC);
+                authUserInfo.setUserType(userType.getValue());
+                authUserInfo.setDeleted(BooleanEnum.FALSE.value);
+            } else {
+                authUserInfo = new AuthUserInfo();
+                authUserInfo.setIdcard(e.getIdcard());
+                authUserInfo.setDeleted(BooleanEnum.TRUE.value);
+            }
+            return authUserInfo;
+        }).collect(Collectors.toList());
+        //设置人员的机构字段信息
+        //警员根据职务排序,取职务序号小的为主机构
+        if(UserTypeEnum.POLICE.equals(userType)) {
+            setPoliceOrgCode(content, userType, userInfoList);
+        }
+        setUserOrgInfos(userType, userInfoList);
+        return authUserInfoService.batchSaveByIdcard(userInfoList);
+    }
+
+
+    private String getAddUserInfo(Integer pageSize, Date syncStartTime, List<Header> headers) {
+        String policeStatus = getAddDiffTypeUserInfo(pageSize, syncStartTime, UserApiConstance.POLICE_SYNC_API, UserTypeEnum.POLICE, headers);
+        String helpStatus = getAddDiffTypeUserInfo(pageSize, syncStartTime, UserApiConstance.AUXILIRY_SYNC_API, UserTypeEnum.HELPER, headers);
+        String externalStatus = getAddDiffTypeUserInfo(pageSize, syncStartTime, UserApiConstance.EXTERNAL_SYNC_API, UserTypeEnum.EXTERNAL, headers);
+        String status = policeStatus + helpStatus + externalStatus;
+        log.info("getAddUserInfo status :{}",status);
+        return status;
+    }
+
+    private String getAddDiffTypeUserInfo(Integer pageSize, Date syncStartTime, String userInfoApi, UserTypeEnum userTypeEnum, List<Header> headers) {
+        int currentPage = 1;
+        Integer totalPage = null;
+        ApiSearchReq apiSearchReq = new ApiSearchReq();
+        //设置分页参数
+        ApiPageReq pageReq = new ApiPageReq();
+        pageReq.setSize(pageSize);
+        //设置同步时间
+        SearchParam searchParam = new SearchParam();
+        Map<String, SearchParam> filters = new HashMap<>();
+        filters.put("updateTime", searchParam);
+        searchParam.setOperator(SearchOperator.gt.name());
+        searchParam.setValue(syncStartTime);
+        apiSearchReq.setFilters(filters);
+        apiSearchReq.setPage(pageReq);
+        String url = Joiner.on("").join(authConfig.getUserCenterUrl(), userInfoApi);
+        logger.info("-------------getAddUserInfoFromRemote START-----------");
+        do {
+            logger.info("getAddUserInfoFromRemote currentPage:{}", currentPage);
+            pageReq.setFrom(currentPage);
+            String result = HttpUtil.postJSON(url, JSON.toJSONString(apiSearchReq), headers,null);
+            if (StringUtils.isBlank(result)) {
+                logger.info("result is null");
+                if(currentPage == 1) {
+                    return syncFailStatus;
+                }else {
+                    return syncS_FStatus;
+                }
+            }
+            //从结果解析用户数据保存到原始数据表
+            ApiResult apiResult = JSON.parseObject(result, ApiResult.class);
+            if(!ResultEnum.SUCCESS.getKey().equals(apiResult.getStatusCode())) {
+                logger.info("getAddUserInfoFromRemote ERROR:{}, PAGE NO:{}",apiResult.getMessage(), currentPage);
+                if(currentPage == 1) {
+                    return syncFailStatus;
+                }else {
+                    return syncS_FStatus;
+                }
+            }
+            JSONObject obj = (JSONObject) apiResult.getResult();
+            ApiResultPage<JSONObject> page = JSON.parseObject(obj.toJSONString(), new TypeReference<ApiResultPage<JSONObject>>(){});
+            //从结果解析总页数
+            totalPage = getTotalPage(pageSize, totalPage, page.getTotal().intValue());
+            //解析请求结果
+            saveAddUserOri(page, userTypeEnum);
+        } while (++currentPage <= totalPage);
+        logger.info("-------------getUserInfoFromRemote END-----------");
+        return syncSuccessStatus;
+    }
+
+    private void saveAddUserOri(ApiResultPage<JSONObject> page, UserTypeEnum userType) {
+        List<JSONObject> content = page.getContent();
+        List<AuthUserAddOriginal> originals = new ArrayList<>();
+        for (JSONObject json : content) {
+            AuthUserAddOriginal userOri = new AuthUserAddOriginal();
+            String idcard = json.getString("idcard");
+            String userDeleted = json.getString("deleted");
+            Date updateTime = json.getDate("updateTime");
+            userOri.setIdcard(idcard);
+            userOri.setUserType(userType.getValue());
+            userOri.setUserDeleted(userDeleted);
+            userOri.setUserUpdateTime(updateTime);
+            if(BooleanEnum.TRUE.value.equals(userDeleted)) {
+                originals.add(userOri);
+                continue ;
+            }
+            setJSONData(userType, json, userOri);
+            originals.add(userOri);
+        }
+        //过程数据保存
+        userAddOriginalService.batchSave(originals);
+    }
+
+    private <T extends AuthUserOriginalBase> void setJSONData(UserTypeEnum userType, JSONObject json, T userOri) {
+        //保存联系方式json
+        JSONObject userContact = json.getJSONObject("userContact");
+        if(null != userContact && !userContact.isEmpty()) {
+            userOri.setContactData(userContact.toJSONString());
+        }
+        json.remove("userContact");
+        //保存人员和机构关系json
+        if (userType.equals(UserTypeEnum.POLICE)) {
+            JSONArray jsonArray = json.getJSONArray("postInfos");
+            if (CollectionUtils.isNotEmpty(jsonArray)) {
+                userOri.setOrgRelData(jsonArray.toJSONString());
+                json.remove("postInfos");
+            }
+        } else if (userType.equals(UserTypeEnum.EXTERNAL)) {
+            String projectCodes = json.getString("projectCode");
+            if(StringUtils.isNotBlank(projectCodes)) {
+                userOri.setOrgRelData(projectCodes);
+            }
+            json.remove("projectCode");
+        }
+        //保存人员数据json
+        userOri.setJsonData(json.toJSONString());
+    }
+
+    private void deleteUserAddInfo() {
+        userAddOriginalService.deleteAll();
+    }
+
+    private Date getSyncStartTime(String type) {
+        AddSyncRecord record = addSyncRecordService.getRecordByType(type);
+        Date syncStartTime = null;
+        if(null != record) {
+            syncStartTime = record.getSuccessTime();
+        }
+        return syncStartTime;
+    }
+
+    @Override
+    public ResponseStatus orgAddSync() {
+        return null;
+    }
+
     /**
      * 同步完成后设置机构的path和upGovId
      */
@@ -595,16 +1024,16 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
      * 从用户中心获取机构数据
      * @param currentPage
      * @param pageSize
+     * @param heads
      */
-    public void getOrgInfoFromRemote(int currentPage, Integer pageSize) {
+    public void getOrgInfoFromRemote(int currentPage, Integer pageSize, List<Header> heads) {
         Date now = new Date();
         Integer totalPage = null;
-        List<Header> headers = getHeads();
         ApiSearchReq apiSearchReq = new ApiSearchReq();
-        HashMap<String, SearchParam> filters = new HashMap<>();
         SearchParam searchParam = new SearchParam();
         searchParam.setOperator(SearchOperator.eq.name());
         searchParam.setValue(BooleanEnum.FALSE.value);
+        Map<String, SearchParam> filters = new HashMap<>();
         filters.put("deleted", searchParam);
         apiSearchReq.setFilters(filters);
         ApiPageReq pageReq = new ApiPageReq();
@@ -614,7 +1043,7 @@ public class SubSyncBusinessImpl implements ISubSyncBusiness {
         logger.info("-------------getOrgInfoFromRemote START-----------");
         do {
             pageReq.setFrom(currentPage);
-            String result = HttpUtil.postJSON(url, JSON.toJSONString(apiSearchReq), headers,null);
+            String result = HttpUtil.postJSON(url, JSON.toJSONString(apiSearchReq), heads,null);
             if(StringUtils.isBlank(result)) {
                 logger.info("result is null");
                 break;

+ 46 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AddSyncRecord.java

@@ -0,0 +1,46 @@
+package com.dragoninfo.dcuc.auth.sub.entity;
+
+import com.dragonsoft.duceap.base.entity.persistent.IdEntity;
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * 增量同步记录表
+ * @author mazq
+ * @date 2021/12/20
+ */
+@Entity
+@Table(name = "T_AUTH_ADD_SYNC_REC")
+@Data
+public class AddSyncRecord implements IdEntity<String>  {
+
+    /** ID;主键id */
+    @Id
+    @GeneratedValue(generator="idGenerator")
+    @GenericGenerator(name="idGenerator", strategy="uuid")
+    @Column(name = "ID")
+    private String id ;
+
+    /** TYPE;同步类型ORG:机构USER:人员 */
+    @Column(name = "TYPE")
+    private String type ;
+
+    /** SUCCEE_TIME;上次成功时间 */
+    @Column(name = "SUCCESS_TIME")
+    private Date successTime ;
+
+    /** FAIL_TIME;上次失败时间 */
+    @Column(name = "FAIL_TIME")
+    private Date failTime ;
+
+    /** MSG;失败信息 */
+    @Column(name = "FAil_RESULT")
+    private String failResult ;
+
+    /** RESULT;最近一次同步结果0:失败1:成功 */
+    @Column(name = "SUCCESS_RESULT")
+    private String successResult ;
+}

+ 43 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthOrgAddOriginal.java

@@ -0,0 +1,43 @@
+package com.dragoninfo.dcuc.auth.sub.entity;
+
+import com.dragonsoft.duceap.base.entity.persistent.IdEntity;
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * 机构增量同步实体类
+ * @author mazq
+ * @date 2021/12/20
+ */
+@Entity
+@Table(name = "T_AUTH_ORG_ADD_ORIGINAL")
+@Data
+public class AuthOrgAddOriginal implements IdEntity<String> {
+
+    /** ID;主键id */
+    @Id
+    @GeneratedValue(generator="idGenerator")
+    @GenericGenerator(name="idGenerator", strategy="uuid")
+    @Column(name = "ID")
+    private String id ;
+
+    /** CODE;机构code */
+    @Column(name = "CODE")
+    private String code ;
+
+    /** ORG_DELETED;机构是否被删除 */
+    @Column(name = "ORG_DELETED")
+    private String orgDeleted ;
+    /** JSON_DATA;机构数据 */
+
+    @Column(name = "JSON_DATA")
+    private String jsonData ;
+
+    /** ORG_UPDATE_TIME;机构数据更新时间 */
+    @Column(name = "ORG_UPDATE_TIME")
+    private Date orgUpdateTime ;
+
+}

+ 35 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthUserAddOriginal.java

@@ -0,0 +1,35 @@
+package com.dragoninfo.dcuc.auth.sub.entity;
+
+import com.dragonsoft.duceap.base.entity.persistent.IdEntity;
+import lombok.Data;
+import org.hibernate.annotations.GenericGenerator;
+
+import javax.persistence.*;
+import java.util.Date;
+
+/**
+ * 人员增量同步实体类
+ * @author mazq
+ * @date 2021/12/17
+ */
+@Entity
+@Table(name = "T_AUTH_USER_ADD_ORIGINAL")
+@Data
+public class AuthUserAddOriginal extends AuthUserOriginalBase implements IdEntity<String> {
+
+    /** ID;主键id */
+    @Id
+    @GeneratedValue(generator="idGenerator")
+    @GenericGenerator(name="idGenerator", strategy="uuid")
+    @Column(name = "ID")
+    private String id ;
+
+    /** USER_DELETED;用户是否被删除 */
+    @Column(name = "USER_DELETED")
+    private String userDeleted ;
+
+    /** USER_UPDATE_TIME;用户数据更新时间 */
+    @Column(name = "USER_UPDATE_TIME")
+    private Date userUpdateTime ;
+
+}

+ 46 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthUserOriginalBase.java

@@ -0,0 +1,46 @@
+package com.dragoninfo.dcuc.auth.sub.entity;
+
+import lombok.Data;
+
+import javax.persistence.Column;
+import javax.persistence.MappedSuperclass;
+
+/**
+ * @author mazq
+ * @date 2021/12/28
+ */
+@Data
+@MappedSuperclass
+public class AuthUserOriginalBase {
+
+    /**
+     * 身份证号
+     */
+    @Column(name = "IDCARD")
+    private String idcard;
+
+    /**
+     * 用户类型
+     */
+    @Column(name = "USER_TYPE")
+    private String userType;
+
+    /**
+     * 人员json数据
+     */
+    @Column(name = "JSON_DATA")
+    private String jsonData;
+
+    /**
+     * 联系方式json数据
+     */
+    @Column(name = "CONTACT_DATA")
+    private String contactData;
+
+    /**
+     * 人员和机构关系数据
+     */
+    @Column(name = "ORG_REL_DATA")
+    private String orgRelData;
+
+}

+ 1 - 31
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/entity/AuthUserOriginalData.java

@@ -24,7 +24,7 @@ import java.util.Date;
 @Entity
 @Table(name = "T_AUTH_USER_ORIGINAL_DATA")
 @Data
-public class AuthUserOriginalData implements LogicDeleteable, IdEntity<String> {
+public class AuthUserOriginalData extends AuthUserOriginalBase implements LogicDeleteable, IdEntity<String> {
     /**
      * 主键id
      */
@@ -34,18 +34,6 @@ public class AuthUserOriginalData implements LogicDeleteable, IdEntity<String> {
     @Column(name = "ID")
     private String id;
 
-    /**
-     * 身份证号
-     */
-    @Column(name = "IDCARD")
-    private String idcard;
-
-    /**
-     * 用户类型
-     */
-    @Column(name = "USER_TYPE")
-    private String userType;
-
     /**
      * 同步时间
      */
@@ -64,24 +52,6 @@ public class AuthUserOriginalData implements LogicDeleteable, IdEntity<String> {
     @Column(name = "DELETED")
     private String deleted;
 
-    /**
-     * 人员json数据
-     */
-    @Column(name = "JSON_DATA")
-    private String jsonData;
-
-    /**
-     * 联系方式json数据
-     */
-    @Column(name = "CONTACT_DATA")
-    private String contactData;
-
-    /**
-     * 人员和机构关系数据
-     */
-    @Column(name = "ORG_REL_DATA")
-    private String orgRelData;
-
     /**
      * 新增时间
      */

+ 10 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/facade/UserCenterApiFacade.java

@@ -36,6 +36,16 @@ public class UserCenterApiFacade implements IUserCenterApiFacade {
         return subSyncBusiness.orgSync();
     }
 
+    @Override
+    public ResponseStatus userAddSync() {
+        return subSyncBusiness.userAddSync();
+    }
+
+    @Override
+    public ResponseStatus orgAddSync() {
+        return subSyncBusiness.orgAddSync();
+    }
+
 
     @Override
     public List<LabelVO> findAllLabels() {

+ 13 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AddSyncRecordRepo.java

@@ -0,0 +1,13 @@
+package com.dragoninfo.dcuc.auth.sub.repo;
+
+import com.dragoninfo.dcuc.auth.sub.entity.AddSyncRecord;
+import com.dragonsoft.duceap.core.persistent.repository.BaseRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * @author mazq
+ * @date 2021/12/20
+ */
+@Repository
+public interface AddSyncRecordRepo extends BaseRepository<AddSyncRecord,String> {
+}

+ 9 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AuthUserContactRepository.java

@@ -2,7 +2,9 @@ package com.dragoninfo.dcuc.auth.sub.repo;
 
 import com.dragoninfo.dcuc.auth.sub.entity.AuthUserContact;
 import com.dragonsoft.duceap.core.persistent.repository.BaseRepository;
+import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
 import java.util.List;
@@ -17,4 +19,11 @@ public interface AuthUserContactRepository extends BaseRepository<AuthUserContac
     @Query("SELECT DISTINCT new com.dragoninfo.dcuc.auth.sub.entity.AuthUserContact(id,userId) FROM AuthUserContact")
     List<AuthUserContact> getIdAndUserIds();
 
+    /**
+     * 根据身份证号删除
+     * @param delIdcards
+     */
+    @Modifying
+    @Query("DELETE FROM AuthUserContact WHERE idcard IN :delIdcards ")
+    void delByIdcards(@Param("delIdcards") List<String> delIdcards);
 }

+ 26 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AuthUserInfoRepository.java

@@ -5,6 +5,7 @@ import com.dragonsoft.duceap.base.annotations.query.NativeQuery;
 import com.dragonsoft.duceap.core.persistent.repository.BaseRepository;
 import com.dragonsoft.duceap.core.search.Searchable;
 import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.repository.Modifying;
 import org.springframework.data.jpa.repository.Query;
 import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
@@ -25,6 +26,15 @@ public interface AuthUserInfoRepository extends BaseRepository<AuthUserInfo, Str
     @Query(value = "select distinct new com.dragoninfo.dcuc.auth.sub.entity.AuthUserInfo(id,idcard) from AuthUserInfo where deleted = '0'")
     List<AuthUserInfo> getIdAndIdcards();
 
+    /**
+     * 查询部分人员的id和身份证号
+     * @param idcards
+     * @return
+     */
+    @Query(value = "select distinct new com.dragoninfo.dcuc.auth.sub.entity.AuthUserInfo(id,idcard) from AuthUserInfo where idcard in :queryIdcards")
+    List<AuthUserInfo> getIdAndIdcards(@Param("queryIdcards") List<String> idcards);
+
+
     /**
      * 根据查询条件查询列表
      * 返回值只有id和orgId字段
@@ -37,6 +47,14 @@ public interface AuthUserInfoRepository extends BaseRepository<AuthUserInfo, Str
             " FROM T_AUTH_USER_INFO WHERE u.deleted = '0'")
     List<UserIdAndOrgDO> getIdAndOrgId(Searchable searchable);
 
+    /**
+     * 根据idcard删除人员
+     * @param idcard
+     */
+    @Modifying
+    @Query("DELETE FROM AuthUserInfo WHERE idcard = :idcard")
+    void deleteByIdcard(@Param("idcard") String idcard);
+
     /**
      * 角色授权模块
      * 人员视图-人员列表查询
@@ -87,4 +105,12 @@ public interface AuthUserInfoRepository extends BaseRepository<AuthUserInfo, Str
             " u.USER_TYPE as userType, u.POLICE_CATEGORY as policeCategory, r.ORG_ID as orgId, r.REL_STATUS as relStatus" +
             " FROM T_AUTH_USER_INFO u INNER JOIN T_AUTH_USER_ORG_REL r ON u.ID = r.USER_ID WHERE u.deleted = '0'")
     List<AuthUserInfo> roleAuthRoleViewList(Searchable searchable);
+
+    /**
+     * 机构同步后更新人员机构信息
+     */
+    @Modifying
+    @NativeQuery("update t_auth_user_info u inner join t_auth_org_info o on u.org_code = o.code " +
+            "set u.org_id = o.id where u.deleted='0' and u.org_id is null and u.org_code is not null")
+    void updateOrgInfoInUser();
 }

+ 19 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/repo/AuthUserOrgRelRepository.java

@@ -4,6 +4,9 @@ import com.dragoninfo.dcuc.auth.sub.entity.AuthUserOrgRel;
 import com.dragonsoft.duceap.base.annotations.query.NativeQuery;
 import com.dragonsoft.duceap.core.persistent.repository.BaseRepository;
 import com.dragonsoft.duceap.core.search.Searchable;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
 import org.springframework.stereotype.Repository;
 
 import java.util.List;
@@ -25,4 +28,20 @@ public interface AuthUserOrgRelRepository extends BaseRepository<AuthUserOrgRel,
             " u.USER_TYPE as userType, r.ORG_ID as orgId, r.REL_STATUS as relStatus, u.NAME, u.IDCARD, u.DELETED" +
             " FROM T_AUTH_USER_ORG_REL r INNER JOIN T_AUTH_USER_INFO u ON r.USER_ID = u.ID WHERE u.deleted = '0'")
     List<AuthUserOrgRel> getRoleAuthUserRels(Searchable searchable);
+
+    /**
+     * 机构增量同步后修改机构id
+     */
+    @Modifying
+    @NativeQuery("update t_auth_user_org_rel r inner join t_auth_org_info o on r.org_code = o.code " +
+            "set r.org_id = o.id where r.org_code is not null and r.org_id is null")
+    void updateOrgInfoInUser();
+
+    /**
+     * 根据身份证号删除人员和机构的关联关系
+     * @param delIdcards
+     */
+    @Modifying
+    @Query("DELETE FROM AuthUserOrgRel WHERE idcard IN :delIdcards")
+    void delByIdcards(@Param("delIdcards") List<String> delIdcards);
 }

+ 17 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAddSyncRecordService.java

@@ -0,0 +1,17 @@
+package com.dragoninfo.dcuc.auth.sub.service;
+
+import com.dragoninfo.dcuc.auth.sub.entity.AddSyncRecord;
+
+/**
+ * 增量同步记录业务类
+ * @author mazq
+ * @date 2021/12/20
+ */
+public interface IAddSyncRecordService {
+
+    AddSyncRecord getRecordByType(String type);
+
+    void update(AddSyncRecord record);
+
+    void save(AddSyncRecord record);
+}

+ 40 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthOrgAddOriginalService.java

@@ -0,0 +1,40 @@
+package com.dragoninfo.dcuc.auth.sub.service;
+
+import com.dragoninfo.dcuc.auth.sub.entity.AuthOrgAddOriginal;
+import com.dragonsoft.duceap.core.search.Searchable;
+import org.springframework.data.domain.Page;
+
+import java.util.List;
+
+/**
+ * 机构增量同步业务类
+ * @author mazq
+ * @date 2021-12-27
+ */
+public interface IAuthOrgAddOriginalService {
+
+    /**
+     * 根据身份证号,批量保存
+     * @param originals
+     */
+    void batchSave(List<AuthOrgAddOriginal> originals);
+
+    /**
+     * 分页查询
+     * @param searchable
+     * @return
+     */
+    Page<AuthOrgAddOriginal> pageSearch(Searchable searchable);
+
+    /**
+     * 删除增量同步记录
+     */
+    void deleteAll();
+
+    /**
+     * 获取增量同步的机构code
+     * @return
+     */
+    List<String> getCodes();
+
+}

+ 46 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthUserAddOriginalService.java

@@ -0,0 +1,46 @@
+package com.dragoninfo.dcuc.auth.sub.service;
+
+import com.dragoninfo.dcuc.auth.sub.entity.AuthUserAddOriginal;
+import com.dragonsoft.duceap.core.search.Searchable;
+import org.springframework.data.domain.Page;
+
+import java.util.List;
+
+/**
+ * 人员增量同步业务类
+ * @author mazq
+ * @date 2021-12-27
+ */
+public interface IAuthUserAddOriginalService {
+
+    /**
+     * 根据身份证号,批量保存
+     * @param originals
+     */
+    void batchSave(List<AuthUserAddOriginal> originals);
+
+    /**
+     * 分页查询
+     * @param searchable
+     * @return
+     */
+    Page<AuthUserAddOriginal> pageSearch(Searchable searchable);
+
+    /**
+     * 获取增量同步人员的id、idcard、deleted字段信息
+     * @return
+     */
+    List<AuthUserAddOriginal> getIdcards();
+
+    /**
+     * 删除增量同步数据
+     */
+    void deleteAll();
+
+    /**
+     * 获取需要删除的人员身份证号
+     * @return
+     */
+    List<String> getDeleteUserIdcards();
+
+}

+ 6 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthUserContactService.java

@@ -24,4 +24,10 @@ public interface IAuthUserContactService {
      * @return
      */
     AuthUserContact getByUserId(String userId);
+
+    /**
+     * 根据身份证号删除用户联系方式
+     * @param delIdcards
+     */
+    void delByIdcards(List<String> delIdcards);
 }

+ 15 - 1
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthUserInfoService.java

@@ -50,8 +50,9 @@ public interface IAuthUserInfoService {
      * 根据身份证id批量保存或是更新
      *
      * @param userInfoList
+     * @return
      */
-    void batchSaveByIdcard(List<AuthUserInfo> userInfoList);
+    List<AuthUserInfo> batchSaveByIdcard(List<AuthUserInfo> userInfoList);
 
     /**
      * 根据身份证id保存或是更新
@@ -114,6 +115,13 @@ public interface IAuthUserInfoService {
      */
     List<AuthUserInfo> getIdAndIdcards();
 
+    /**
+     * 根据身份证号查询人员id和身份证号
+     * @param idcards
+     * @return
+     */
+    List<AuthUserInfo> getIdAndIdcards(List<String> idcards);
+
     /**
      * 角色授权模块
      * 人员视图-人员列表查询
@@ -153,4 +161,10 @@ public interface IAuthUserInfoService {
      * @return
      */
     List<UserIdAndOrgDO> getIdAndOrgId(Searchable searchable);
+
+    /**
+     * 机构增量同步后填充orgId为空、orgCode字段不为空的数据
+     */
+    void updateOrgInfoInUser();
+
 }

+ 13 - 1
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/IAuthUserOrgRelService.java

@@ -52,7 +52,7 @@ public interface IAuthUserOrgRelService {
      * 根据机构id判断是否重复或更新
      * @param relations
      */
-    void saveOneRelByOrgId(List<AuthUserOrgRel> relations);
+    void saveOneRelByOrgCode(List<AuthUserOrgRel> relations);
 
     void batchUpdate(List<AuthUserOrgRel> updateList);
 
@@ -63,4 +63,16 @@ public interface IAuthUserOrgRelService {
      * @return
      */
     List<AuthUserOrgRel> getRoleAuthUserRels(Searchable searchable);
+
+    /**
+     * 机构增量同步后填充orgId为空、orgCode字段不为空的数据
+     */
+    void updateOrgInfoInUser();
+
+    /**
+     * 根据身份证号删除人员和机构的关系
+     * @param delIdcards
+     */
+    void delByIdcards(List<String> delIdcards);
+
 }

+ 37 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AddSyncRecordServiceImpl.java

@@ -0,0 +1,37 @@
+package com.dragoninfo.dcuc.auth.sub.service.impl;
+
+import com.dragoninfo.dcuc.auth.sub.entity.AddSyncRecord;
+import com.dragoninfo.dcuc.auth.sub.repo.AddSyncRecordRepo;
+import com.dragoninfo.dcuc.auth.sub.service.IAddSyncRecordService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Example;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author mazq
+ * @date 2021/12/20
+ */
+@Service
+public class AddSyncRecordServiceImpl implements IAddSyncRecordService {
+
+    @Autowired
+    private AddSyncRecordRepo recordRepo;
+
+    @Override
+    public AddSyncRecord getRecordByType(String type) {
+        AddSyncRecord record = new AddSyncRecord();
+        record.setType(type);
+        Example<AddSyncRecord> of = Example.of(record);
+        return recordRepo.findOne(of).orElse(null);
+    }
+
+    @Override
+    public void update(AddSyncRecord record) {
+        recordRepo.update(record);
+    }
+
+    @Override
+    public void save(AddSyncRecord record) {
+        recordRepo.save(record);
+    }
+}

+ 8 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AuthUserContactServiceImpl.java

@@ -58,6 +58,14 @@ public class AuthUserContactServiceImpl implements IAuthUserContactService {
         return contactRepository.findOne(example).orElse(null);
     }
 
+    @Override
+    public void delByIdcards(List<String> delIdcards) {
+        if(CollectionUtils.isEmpty(delIdcards)) {
+            return ;
+        }
+        contactRepository.delByIdcards(delIdcards);
+    }
+
     private List<AuthUserContact> getIdAndUserIds() {
        return contactRepository.getIdAndUserIds();
     }

+ 28 - 13
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AuthUserInfoService.java

@@ -22,10 +22,7 @@ import org.springframework.data.jpa.domain.Specification;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -73,27 +70,35 @@ public class AuthUserInfoService implements IAuthUserInfoService {
     }
 
     @Override
-    public void batchSaveByIdcard(List<AuthUserInfo> userInfoList) {
+    public List<AuthUserInfo> batchSaveByIdcard(List<AuthUserInfo> userInfoList) {
         if(CollectionUtils.isEmpty(userInfoList)) {
-            return;
+            return Collections.emptyList();
         }
-        List<AuthUserInfo> idAndIdcards = getIdAndIdcards();
+        List<AuthUserInfo> list = new ArrayList<>();
+        List<String> idcards = userInfoList.stream().map(AuthUserInfo::getIdcard).distinct().collect(Collectors.toList());
+        List<AuthUserInfo> idAndIdcards = getIdAndIdcards(idcards);
         Map<String, AuthUserInfo> existMap = idAndIdcards.stream()
                 .collect(Collectors.toMap(AuthUserInfo::getIdcard, e -> e, (old, last) -> last));
-        Date createTime = new Date();
         for (AuthUserInfo authUserInfo : userInfoList) {
             String idcard = authUserInfo.getIdcard();
             AuthUserInfo exist = existMap.get(idcard);
+            //删除人员信息
+            if (BooleanEnum.TRUE.value.equals(authUserInfo.getDeleted())) {
+                userInfoRepository.deleteByIdcard(idcard);
+                continue;
+            }
+            //新增或更新人员信息
             if(null == exist) {
-                authUserInfo.setCreateTime(createTime);
                 authUserInfo.setDeleted(BooleanEnum.FALSE.value);
-                userInfoRepository.save(authUserInfo);
+                AuthUserInfo save = userInfoRepository.save(authUserInfo);
+                list.add(save);
             } else {
-                authUserInfo.setId(exist.getId());
-                BeanUtils.copyProperties(authUserInfo, exist, "createTime","createUser");
-                userInfoRepository.update(exist);
+                BeanUtils.copyProperties(authUserInfo, exist, "id","createTime","createUser");
+                AuthUserInfo update = userInfoRepository.update(exist);
+                list.add(update);
             }
         }
+        return list;
     }
 
     @Override
@@ -165,6 +170,11 @@ public class AuthUserInfoService implements IAuthUserInfoService {
         return userInfoRepository.getIdAndIdcards();
     }
 
+    @Override
+    public List<AuthUserInfo> getIdAndIdcards(List<String> idcards) {
+        return userInfoRepository.getIdAndIdcards(idcards);
+    }
+
     @Override
     public Page<AuthUserInfo> roleAuthUserViewPage(Searchable searchable) {
         return userInfoRepository.roleAuthUserViewPage(searchable);
@@ -207,6 +217,11 @@ public class AuthUserInfoService implements IAuthUserInfoService {
         return userInfoRepository.getIdAndOrgId(searchable);
     }
 
+    @Override
+    public void updateOrgInfoInUser() {
+        userInfoRepository.updateOrgInfoInUser();
+    }
+
     private List<AuthUserInfo> getPageContent(int pageSize, int pageNumber, List<AuthUserInfo> list) {
         return list.stream().skip(pageNumber * pageSize).limit(pageSize).collect(Collectors.toList());
     }

+ 23 - 8
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/service/impl/AuthUserOrgRelServiceImpl.java

@@ -51,20 +51,22 @@ public class AuthUserOrgRelServiceImpl implements IAuthUserOrgRelService {
             saveAll(relations);
             return;
         }
-        //根据OrgId和RelName区别新增和删除的关联关系
+        //根据OrgCode、RelName、RelStatus区别新增和删除的关联关系
+        //三者修改任何一个都会被删除,然后新增一条记录
+        //人员和机构关系记录的id暂时没有其他表关联,可以直接删除然后新增记录
         Map<String, AuthUserOrgRel> collect = relations
                 .stream()
-                .collect(Collectors.toMap(e -> e.getOrgId() + StrUtil.COMMA + e.getRelName(), e -> e, (old, last) -> last));
+                .collect(Collectors.toMap(e -> e.getOrgCode() + StrUtil.COMMA + e.getRelName() + StrUtil.COMMA + e.getRelStatus(), e -> e, (old, last) -> last));
         Map<String, AuthUserOrgRel> existCollect = existRels
                 .stream()
-                .collect(Collectors.toMap(e -> e.getOrgId() + StrUtil.COMMA + e.getRelName(), e -> e, (old, last) -> last));
-        Set<String> idNameSet = collect.keySet();
+                .collect(Collectors.toMap(e -> e.getOrgCode() + StrUtil.COMMA + e.getRelName() + StrUtil.COMMA + e.getRelStatus() , e -> e, (old, last) -> last));
+        Set<String> codeNameSet = collect.keySet();
         Set<String> existKeySet = existCollect.keySet();
         List<String> deleteKey = existKeySet
                 .stream()
-                .filter(e -> !idNameSet.contains(e))
+                .filter(e -> !codeNameSet.contains(e))
                 .collect(Collectors.toList());
-        List<String> addKey = idNameSet
+        List<String> addKey = codeNameSet
                 .stream()
                 .filter(e->!existKeySet.contains(e))
                 .collect(Collectors.toList());
@@ -107,7 +109,7 @@ public class AuthUserOrgRelServiceImpl implements IAuthUserOrgRelService {
             return ;
         }
         Map<String, List<AuthUserOrgRel>> map = relations.stream()
-                .filter(e->!StringUtils.isAnyBlank(e.getUserId(), e.getOrgId()))
+                .filter(e->!StringUtils.isAnyBlank(e.getUserId(), e.getOrgCode()))
                 .collect(Collectors.groupingBy(AuthUserOrgRel::getUserId));
         for (Map.Entry<String, List<AuthUserOrgRel>> entry : map.entrySet()) {
             String userId = entry.getKey();
@@ -120,7 +122,7 @@ public class AuthUserOrgRelServiceImpl implements IAuthUserOrgRelService {
     }
 
     @Override
-    public void saveOneRelByOrgId(List<AuthUserOrgRel> relations) {
+    public void saveOneRelByOrgCode(List<AuthUserOrgRel> relations) {
         if(CollectionUtils.isEmpty(relations)) {
             return;
         }
@@ -161,4 +163,17 @@ public class AuthUserOrgRelServiceImpl implements IAuthUserOrgRelService {
     public List<AuthUserOrgRel> getRoleAuthUserRels(Searchable searchable) {
         return userOrgRelRepository.getRoleAuthUserRels(searchable);
     }
+
+    @Override
+    public void updateOrgInfoInUser() {
+        userOrgRelRepository.updateOrgInfoInUser();
+    }
+
+    @Override
+    public void delByIdcards(List<String> delIdcards) {
+        if(CollectionUtils.isEmpty(delIdcards)) {
+            return ;
+        }
+        userOrgRelRepository.delByIdcards(delIdcards);
+    }
 }

+ 25 - 0
dcuc-auth-service/src/main/java/com/dragoninfo/dcuc/auth/sub/task/AddSyncTask.java

@@ -0,0 +1,25 @@
+package com.dragoninfo.dcuc.auth.sub.task;
+
+import com.dragoninfo.dcuc.auth.sub.business.ISubSyncBusiness;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+/**
+ * 人员、机构定时任务配置类
+ * @author mazq
+ * @date 2021/12/20
+ */
+@Component
+public class AddSyncTask {
+
+    @Autowired
+    private ISubSyncBusiness subSyncBusiness;
+
+    @Scheduled(cron = "${dcuc.auth.add-sync-corn}")
+    private void userAddSyncTasks() {
+        subSyncBusiness.userAddSync();
+        subSyncBusiness.orgAddSync();
+    }
+
+}

+ 5 - 0
dcuc-auth-service/src/main/resources/application-auth.yml

@@ -49,6 +49,11 @@ dcuc:
     user-center-url: http://10.11.1.237:8860/dcuc
     root-user-id: 402881cb4era66f4014b0ghd0b875485
     root-org-id: 7F08CCC3C4984A2586C9D3F0A6B804E5
+    sync-task-idcard: 000000000000000001
+    add-sync-corn: 0 0/10 * * * ?
+    redisson:
+      address: redis://127.0.0.1:6379
+      password:
 app:
   audit:
     qmtj:

+ 108 - 0
dcuc-auth-service/src/main/resources/config/mysql/V4_3_0024__OrgUserAddSync.sql

@@ -0,0 +1,108 @@
+CREATE TABLE T_AUTH_USER_ADD_ORIGINAL(
+    ID VARCHAR(32) NOT NULL   COMMENT 'ID 主键id' ,
+    IDCARD VARCHAR(32)    COMMENT 'IDCARD 身份证号' ,
+    USER_DELETED VARCHAR(5)    COMMENT 'USER_DELETED 用户是否被删除' ,
+    JSON_DATA VARCHAR(3072)    COMMENT 'JSON_DATA 用户数据' ,
+    USER_UPDATE_TIME DATETIME    COMMENT 'USER_UPDATE_TIME 用户数据更新时间' ,
+    PRIMARY KEY (ID)
+) COMMENT = '人员增量同步原始信息表';
+
+CREATE TABLE T_AUTH_ORG_ADD_ORIGINAL(
+    ID VARCHAR(32) NOT NULL   COMMENT 'ID 主键id' ,
+    CODE VARCHAR(32)    COMMENT 'CODE 机构code' ,
+    ORG_DELETED VARCHAR(5)    COMMENT 'ORG_DELETED 机构是否被删除' ,
+    JSON_DATA VARCHAR(3072)    COMMENT 'JSON_DATA 机构数据' ,
+    ORG_UPDATE_TIME DATETIME    COMMENT 'ORG_UPDATE_TIME 机构数据更新时间' ,
+    PRIMARY KEY (ID)
+) COMMENT = '机构增量同步原始信息表';
+
+CREATE TABLE T_AUTH_ADD_SYNC_REC(
+    ID VARCHAR(32)    COMMENT 'ID 主键id' ,
+    TYPE VARCHAR(10)    COMMENT 'TYPE 同步类型ORG:机构USER:人员' ,
+    SUCCESS_TIME DATETIME    COMMENT 'SUCCESS_TIME 上次成功时间' ,
+    FAIL_TIME DATETIME    COMMENT 'FAIL_TIME 上次失败时间' ,
+    MSG VARCHAR(1024)    COMMENT 'MSG 失败信息' ,
+    RESULT VARCHAR(10)    COMMENT 'RESULT 最近一次同步结果0:失败1:成功'
+) COMMENT = '机构和人员增量同步记录表 ';
+
+ALTER TABLE T_AUTH_USER_ADD_ORIGINAL ADD INDEX USER_ADD_ORI_INX_IDCARD(IDCARD);
+ALTER TABLE T_AUTH_USER_ADD_ORIGINAL ADD INDEX USER_ADD_ORI_INX_USER_UPDATE_TIME(USER_UPDATE_TIME);
+
+ALTER TABLE T_AUTH_ORG_ADD_ORIGINAL ADD INDEX ORG_ADD_ORI_INX_CODE(CODE);
+ALTER TABLE T_AUTH_ORG_ADD_ORIGINAL ADD INDEX ORG_ADD_ORI_INX_ORG_UPDATE_TIME(ORG_UPDATE_TIME);
+
+INSERT INTO `t_auth_menu_info` (
+	`ID`,
+	`NAME`,
+	`CODE`,
+	`APP_ID`,
+	`PARENT_ID`,
+	`URL`,
+	`SHOW_MODE`,
+	`IS_ACTIVE`,
+	`SEQ`,
+	`CREATE_TIME`,
+	`CREATOR`,
+	`MODIFIED_TIME`,
+	`MODIFIER`,
+	`REMARK`,
+	`IS_SYSTEM`,
+	`IS_HIDE`
+)
+VALUES
+	(
+		'a47317ef617111ec88a1005056bd458f',
+		'人员增量同步',
+		'QXGL_SQGL_ZTGL_RYZLTB',
+		'00000000000000000000000000000000',
+		'e9351549a10541cbb8f7d368fcdc4dd6',
+		NULL,
+		'1',
+		'1',
+		'4',
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		'0',
+		'0'
+	);
+
+INSERT INTO `t_auth_menu_info` (
+	`ID`,
+	`NAME`,
+	`CODE`,
+	`APP_ID`,
+	`PARENT_ID`,
+	`URL`,
+	`SHOW_MODE`,
+	`IS_ACTIVE`,
+	`SEQ`,
+	`CREATE_TIME`,
+	`CREATOR`,
+	`MODIFIED_TIME`,
+	`MODIFIER`,
+	`REMARK`,
+	`IS_SYSTEM`,
+	`IS_HIDE`
+)
+VALUES
+	(
+		'9b751c67617111ec88a1005056bd458f',
+		'机构增量同步',
+		'QXGL_SQGL_ZTGL_JGZLTB',
+		'00000000000000000000000000000000',
+		'e9351549a10541cbb8f7d368fcdc4dd6',
+		NULL,
+		'1',
+		'1',
+		'4',
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		NULL,
+		'0',
+		'0'
+	);

+ 2 - 2
dcuc-auth-service/src/test/java/com/dragoninfo/dcuc/auth/auth/service/IAuthSyncTest.java

@@ -35,7 +35,7 @@ public class IAuthSyncTest {
 
     @Test
     public void userGet() {
-        subSyncBusinessImpl.getUserInfoFromRemote(1,1);
+        subSyncBusinessImpl.getUserInfoFromRemote(1,1, null);
 
     }
 
@@ -46,7 +46,7 @@ public class IAuthSyncTest {
 
     @Test
     public void orgGet() {
-        subSyncBusinessImpl.getOrgInfoFromRemote(1,1);
+        subSyncBusinessImpl.getOrgInfoFromRemote(1,1, null);
 
     }