yuanzhi_kuang 1 неделя назад
Родитель
Сommit
23fc125b84

+ 243 - 91
src/main/java/com/gtiit/shr/service/impl/ADSyncServiceImpl.java

@@ -4,7 +4,6 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.util.StringUtil;
-import com.gtiit.shr.config.InsertBatchMethod;
 import com.gtiit.shr.entity.enums.TaskNameEnum;
 import com.gtiit.shr.entity.enums.TaskStatusEnum;
 import com.gtiit.shr.entity.enums.TypeEnum;
@@ -32,8 +31,6 @@ import javax.naming.directory.DirContext;
 import javax.naming.directory.ModificationItem;
 import javax.naming.directory.SearchControls;
 import javax.naming.directory.SearchResult;
-
-
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -43,7 +40,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.util.StringUtils;
 
-
 /**
  * AD同步服务实现类
  */
@@ -52,9 +48,12 @@ import org.springframework.util.StringUtils;
 public class ADSyncServiceImpl implements ADSyncService {
     private static final Logger logger = LoggerFactory.getLogger(ADSyncServiceImpl.class);
     // 定义需要同步的AD域用户字段
-    public static final String[] fileds = new String[]{"sAMAccountName", "manager", "givenName", "sn",  "extensionAttribute6", "displayName", "userPrincipalName", "mail", "telephoneNumber", "title", "department", "employeeID", "employeeType", "extensionAttribute3", "extensionAttribute4", "extensionAttribute5","AccountExpirationDate", "extensionAttribute8", "extensionAttribute9",
-            "extensionAttribute10", "extensionAttribute11", "extensionAttribute12","extensionAttribute14","extensionAttribute15","Division"};
+//    public static final String[] fileds = new String[]{"sAMAccountName", "manager", "givenName", "sn",  "extensionAttribute6", "displayName", "userPrincipalName", "mail", "telephoneNumber", "title", "department", "employeeID", "employeeType", "extensionAttribute3", "extensionAttribute4", "extensionAttribute5","AccountExpirationDate", "extensionAttribute8", "extensionAttribute9",
+//            "extensionAttribute10", "extensionAttribute11", "extensionAttribute12","extensionAttribute14","extensionAttribute15","Division"};
 
+    //删除"AccountExpirationDate",属性  202511
+    public static final String[] fileds = new String[]{"sAMAccountName", "manager", "givenName", "sn",  "extensionAttribute6", "displayName", "userPrincipalName", "mail", "telephoneNumber", "title", "department", "employeeID", "employeeType", "extensionAttribute3", "extensionAttribute4", "extensionAttribute5", "extensionAttribute8", "extensionAttribute9",
+            "extensionAttribute10", "extensionAttribute11", "extensionAttribute12","extensionAttribute14","extensionAttribute15","Division"};
     @Autowired
     FinalParamUtil finalParamUtil;
     @Autowired
@@ -67,6 +66,8 @@ public class ADSyncServiceImpl implements ADSyncService {
     private String root;
     @Value("${api.ad.top}")
     private String top;
+    @Value("${api.ad.alumni}")
+    private String alumniRoot; // 新增:Alumni根路径配置
     @Value("${api.ad.userPassword}")
     private String userPassword;
     @Value("${scheduled.ad.person.able}")
@@ -75,17 +76,13 @@ public class ADSyncServiceImpl implements ADSyncService {
     public String responeParamJson;
     public SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
 
-
-
     @Scheduled(
             cron = "${scheduled.ad.person.cron}"
     )
-
     public void doSyncUsers() throws Exception {
         if (TaskStatusEnum.ABLE.getValue().equals(this.adcronStatus)) {
             this.synADUserToType((String)null, (String)null, (String)null, TypeEnum.AUTO.getValue());
         }
-
     }
 
     // 手动同步AD域用户
@@ -93,8 +90,6 @@ public class ADSyncServiceImpl implements ADSyncService {
         return this.synADUserToType(startDate, endDate, personNumber, TypeEnum.MANUAL.getValue());
     }
 
-
-
     // 同步AD域用户到指定类型
     private JSONObject synADUserToType(String startDate, String endDate, String personNumber, String type) throws Exception {
         JSONObject result = new JSONObject();
@@ -122,7 +117,6 @@ public class ADSyncServiceImpl implements ADSyncService {
             try {
                 this.dc = this.adUtils.getDirContext();
 
-
                 Iterator dataIter = datas.iterator();
 
                 while(dataIter.hasNext()) {
@@ -134,7 +128,22 @@ public class ADSyncServiceImpl implements ADSyncService {
                         this.insertLog("同步日志:AD域用户同步失败!原因:【sAMAccountName】属性不能为空!", "否", type);
                     } else {
                         String name = "";
-                        String originName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", this.sAMAccountName);
+                        String originName = "";
+
+                        // 修改点:先搜索Alumni OU及其所有子OU
+                        if (StringUtil.isNotEmpty(alumniRoot)) {
+                            originName = this.searchUserInAlumniAndSubtree(this.dc, this.sAMAccountName);
+                            if (StringUtil.isNotEmpty(originName)) {
+                                logger.info("在Alumni路径中找到用户: {} -> {}", this.sAMAccountName, originName);
+                            }
+                        }
+
+                        // 如果在Alumni中找到用户,使用Alumni中的路径
+                        if (StringUtils.isEmpty(originName)) {
+                            // 如果在Alumni中没找到,使用原来的搜索逻辑
+                            originName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", this.sAMAccountName);
+                        }
+
                         if (StringUtils.isEmpty(originName)) {
                             name = "CN=" + this.sAMAccountName + "," + this.root;
                         } else {
@@ -152,6 +161,14 @@ public class ADSyncServiceImpl implements ADSyncService {
                             Attributes attributes = this.dc.getAttributes(name);
                             StringBuilder sb = new StringBuilder();
                             sb.append("同步日志:AD域用户【").append(this.sAMAccountName).append("】同步,");
+
+                            // 修改点:添加来源标识
+                            if (name.contains("OU=Alumni")) {
+                                sb.append("(来自Alumni路径) ");
+                            } else {
+                                sb.append("(来自常规路径) ");
+                            }
+
                             String[] filedArr = fileds;
                             int arrlen = filedArr.length;
                             boolean isContinue = false;
@@ -163,24 +180,27 @@ public class ADSyncServiceImpl implements ADSyncService {
                             String  extensionAttribute6Str = extensionAttribute6 != null ? (String)extensionAttribute6.get() : null;
 
                             try {
-                                String managerStr = dataMap.get("manager").toString();
-                                managerName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", managerStr);
+                                String managerStr = dataMap.get("manager") == null ? "" : dataMap.get("manager").toString();
+                                // 修改点:manager搜索也要支持Alumni路径
+                                if (StringUtil.isNotEmpty(managerStr)) {
+                                    managerName = this.searchUserInAllPaths(this.dc, managerStr);
+                                }
                             } catch (NamingException var38) {
-                                sb.append("同步“manager”属性失败,上级负责人【").append(dataMap.get("manager").toString()).append("】在AD域中不存在;");
+                                String managerAccount = dataMap.get("manager") != null ? dataMap.get("manager").toString() : "null";
+                                sb.append("同步manager属性失败,上级负责人【").append(managerAccount).append("】在AD域中不存在;");
                             }
                             //202506 针对兼职身份(extensionAttribute6 值为Part Time)且在AD中已有帐号的中国员工(extensionAttribute8 chinese),
                             //job title 和 department 属性值不变
-                            if (  null  != extensionAttribute6Str  && "Part Time".equals(extensionAttribute6Str) &&  null != extensionAttribute8Str &&
+                            if (null != extensionAttribute6Str && "Part Time".equals(extensionAttribute6Str) && null != extensionAttribute8Str &&
                                     "Chinese".equals(extensionAttribute8Str)) {
                                 isContinue = true;
                                 //15 Part Time 将兼职职位名称同步至 AD的extensionAttribute15
                                 Attribute att15 = attributes.get("extensionAttribute15");
-                                String titleVal  =  dataMap.get("extensionAttribute15") == null ? "" : (String)dataMap.get("extensionAttribute15") ;
-                                if(null == att15 || StringUtil.isEmpty((String)att15.get())){
+                                String titleVal = dataMap.get("extensionAttribute15") == null ? "" : (String)dataMap.get("extensionAttribute15");
+                                if (null == att15 || StringUtil.isEmpty((String) att15.get())) {
                                     msg = this.addInformation(name, "extensionAttribute15", titleVal, managerName);
-//                                    msg = "新增extensionAttribute15属性成功!";
                                     sb.append(msg);
-                                }else{
+                                } else {
                                     this.modifyInformation(name, "extensionAttribute15", titleVal, managerName);
                                     msg = "更新extensionAttribute15属性成功!";
                                     sb.append(msg);
@@ -188,12 +208,11 @@ public class ADSyncServiceImpl implements ADSyncService {
 
                                 //Division 兼职所属部门同步到AD的Division属性
                                 Attribute divisionAtt = attributes.get("Division");
-                                String departmentVal  = (String)dataMap.get("Division");
-                                if(null == divisionAtt || StringUtil.isEmpty((String)divisionAtt.get())){
-                                    msg =  addInformation(name, "Division", departmentVal, managerName);
-//                                    msg = "新增Division属性成功!";
+                                String departmentVal = (String) dataMap.get("Division");
+                                if (null == divisionAtt || StringUtil.isEmpty((String) divisionAtt.get())) {
+                                    msg = addInformation(name, "Division", departmentVal, managerName);
                                     sb.append(msg);
-                                }else{
+                                } else {
                                     this.modifyInformation(name, "Division", departmentVal, managerName);
                                     msg = "更新Division属性成功!";
                                     sb.append(msg);
@@ -201,34 +220,36 @@ public class ADSyncServiceImpl implements ADSyncService {
 
                                 //将用户的manager属性更新到新的AD属性 extensionAttribute14
                                 Attribute extensionAttribute14 = attributes.get("extensionAttribute14");
-                                String extensionAttribute14Str  = (String)dataMap.get("extensionAttribute14");
-                                if(null == extensionAttribute14 || StringUtil.isEmpty((String)extensionAttribute14.get())){
-                                    msg =  addInformation(name, "extensionAttribute14", extensionAttribute14Str, managerName);
-//                                    msg = "新增extensionAttribute14Str属性成功!";
+                                String extensionAttribute14Str = (String) dataMap.get("extensionAttribute14");
+                                if (null == extensionAttribute14 || StringUtil.isEmpty((String) extensionAttribute14.get())) {
+                                    msg = addInformation(name, "extensionAttribute14", extensionAttribute14Str, managerName);
                                     sb.append(msg);
-                                }else{
+                                } else {
                                     this.modifyInformation(name, "extensionAttribute14", extensionAttribute14Str, managerName);
-                                    msg = "更新extensionAttribute14Str属性成功!";
+                                    msg = "更新extensionAttribute14属性成功!";
                                     sb.append(msg);
                                 }
-
                             }
 
-                            for(int  ii = 0; ii < arrlen; ++ii) {
+                            // 修复bug:将userAccountControl的更新移到循环外部,避免重复设置
+                            boolean userAccountControlUpdated = false;
+
+                            for (int ii = 0; ii < arrlen; ++ii) {
                                 field = filedArr[ii];
                                 Attribute attribute = attributes.get(field);
-                                shr_value = (String)dataMap.get(field);
-                                ad_value = attribute != null ? (String)attribute.get() : null;
+                                shr_value = (String) dataMap.get(field);
+                                ad_value = attribute != null ? (String) attribute.get() : null;
 
                                 if (("givenName".equals(field) || "displayName".equals(field)) && StringUtil.isNotEmpty(shr_value)) {
                                     shr_value = shr_value.substring(0, 1).toUpperCase() + shr_value.substring(1);
                                 }
 
                                 //保留 这些人员AD 中现有的 job title 和 department 属性值不变
-                                if(isContinue && ("title".equals(field) || "department".equals(field) || "manager".equals(field)) ) {
+                                if (isContinue && ("title".equals(field) || "department".equals(field) || "manager".equals(field))) {
                                     continue;
                                 }
-                                if("extensionAttribute14".equals(field) && "extensionAttribute15".equals(field) && "Division".equals(field)){
+                                // 修复bug:使用||而不是&&,这样任何一个字段匹配都会跳过
+                                if ("extensionAttribute14".equals(field) || "extensionAttribute15".equals(field) || "Division".equals(field)) {
                                     continue;
                                 }
 
@@ -236,11 +257,11 @@ public class ADSyncServiceImpl implements ADSyncService {
                                     if (!shr_value.equals(ad_value)) {
                                         try {
                                             this.modifyInformation(name, field, shr_value, managerName);
-                                            msg = "更新" + field + "属性成功!";
+                                            msg = "更新" + field + "属性成功!";
                                             sb.append(msg);
                                         } catch (NamingException var33) {
                                             message = var33.getMessage();
-                                            msg = "更新" + field + "属性失败,原因:" + message + ";";
+                                            msg = "更新" + field + "属性失败,原因:" + message + ";";
                                             sb.append(msg);
                                         }
                                     }
@@ -251,34 +272,41 @@ public class ADSyncServiceImpl implements ADSyncService {
                                         }
 
                                         this.removeInformation(name, field, shr_value, managerName);
-                                        msg = "删除" + field + "属性成功!";
+                                        msg = "删除" + field + "属性成功!";
                                         sb.append(msg);
                                     } catch (NamingException var37) {
                                         message = var37.getMessage();
-                                        msg = "删除" + field + "属性失败,原因:" + message + ";";
+                                        msg = "删除" + field + "属性失败,原因:" + message + ";";
                                         sb.append(msg);
                                     }
                                 } else if (StringUtil.isNotEmpty(shr_value) && StringUtil.isEmpty(ad_value)) {
                                     try {
                                         msg = addInformation(name, field, shr_value, managerName);
-//                                        msg = "新增“" + field + "”属性成功!";
                                         sb.append(msg);
                                     } catch (NamingException var32) {
+                                        // 修复bug:当addInformation失败时,不应该再调用modifyInformation
+                                        // 因为modifyInformation需要属性已存在,而这里属性不存在
                                         message = var32.getMessage();
-                                        msg = "新增“" + field + "”属性失败,原因:" + message + ";";
+                                        msg = "新增" + field + "属性失败,原因:" + message + ";";
                                         sb.append(msg);
                                     }
                                 }
+                            }
 
-                                try {
+                            // 修复bug:userAccountControl只在循环外设置一次
+                            try {
+                                Attribute uacAttribute = attributes.get("userAccountControl");
+                                String currentUAC = uacAttribute != null ? (String) uacAttribute.get() : null;
+                                if (!"544".equals(currentUAC)) {
                                     this.modifyInformation(name, "userAccountControl", "544", managerName);
-                                    msg = "添加“userAccountControl”属性成功!";
-                                    sb.append(msg);
-                                } catch (NamingException var31) {
-                                    message = var31.getMessage();
-                                    msg = "添加“userAccountControl”属性失败,原因:" + message + ";";
+                                    msg = "更新userAccountControl属性成功!";
                                     sb.append(msg);
+                                    userAccountControlUpdated = true;
                                 }
+                            } catch (NamingException var31) {
+                                message = var31.getMessage();
+                                msg = "更新userAccountControl属性失败,原因:" + message + ";";
+                                sb.append(msg);
                             }
 
                             info = sb.toString();
@@ -289,44 +317,68 @@ public class ADSyncServiceImpl implements ADSyncService {
                             this.insertLog(sb.toString(), "是", type);
                         } catch (NamingException var39) {
                             try {
+                                // 修复bug:创建用户时需要设置完整的objectClass
                                 Attributes attrs = new BasicAttributes(true);
+//                                attrs.put("objectClass", new String[]{"top", "person", "organizationalPerson", "user"});
                                 attrs.put("objectClass", "user");
                                 attrs.put("sAMAccountName", dataMap.get("sAMAccountName"));
+                                // 设置必须的属性
+//                                attrs.put("cn", dataMap.get("sAMAccountName")); // Common Name是必须的
+
                                 this.dc.createSubcontext(name, attrs);
                                 StringBuilder sb = new StringBuilder();
                                 sb.append("同步日志:AD域用户【").append(this.sAMAccountName).append("】新增成功!");
 
+                                // 修改点:新增用户时也标识来源
+                                if (name.contains("OU=Alumni")) {
+                                    sb.append("(新增到Alumni路径) ");
+                                } else {
+                                    sb.append("(新增到常规路径) ");
+                                }
+
                                 String[] filedArr = fileds;
                                 int arrlen = filedArr.length;
 
-                                for(int i = 0; i < arrlen; i++) {
+                                for (int i = 0; i < arrlen; i++) {
                                     String filed = filedArr[i];
-                                    shr_value = (String)dataMap.get(filed);
-                                    if (!"sAMAccountName".equals(filed) && StringUtil.isNotEmpty((String)dataMap.get(filed))) {
+                                    shr_value = (String) dataMap.get(filed);
+                                    if (!"sAMAccountName".equals(filed) && StringUtil.isNotEmpty(shr_value)) {
                                         try {
                                             if ("manager".equals(filed)) {
-                                                managerName = this.searchUser(this.dc, this.top, "sAMAccountName={0}", shr_value);
-                                                msg = addInformation(name, filed, shr_value, managerName);
+                                                // 修改点:manager搜索也要支持Alumni路径
+                                                String managerAccount = (String) dataMap.get(filed);
+                                                if (StringUtil.isNotEmpty(managerAccount)) {
+                                                    managerName = this.searchUserInAllPaths(this.dc, managerAccount);
+                                                    if (StringUtil.isNotEmpty(managerName)) {
+                                                        msg = addInformation(name, filed, shr_value, managerName);
+                                                    } else {
+                                                        msg = "AD域中未找到manager账户: " + managerAccount;
+                                                    }
+                                                } else {
+                                                    msg = "manager账户名为空";
+                                                }
                                             } else {
                                                 msg = addInformation(name, filed, shr_value, managerName);
                                             }
-                                            sb.append(msg);
-
+                                            if (msg != null) {
+                                                sb.append(msg);
+                                            }
                                         } catch (NamingException var30) {
                                             msg = var30.getMessage();
-                                            message = "添加“" + filed + "”属性失败,原因:" + msg + ";";
+                                            message = "添加" + filed + "属性失败,原因:" + msg + ";";
                                             sb.append(message);
                                         }
                                     }
                                 }
 
+                                // 为新创建的用户设置userAccountControl
                                 try {
                                     this.modifyInformation(name, "userAccountControl", "544", managerName);
-                                    msg = "添加userAccountControl属性成功!";
+                                    msg = "添加userAccountControl属性成功!";
                                     sb.append(msg);
                                 } catch (NamingException var29) {
                                     message = var29.getMessage();
-                                    field = "添加userAccountControl属性失败,原因:" + message + ";";
+                                    field = "添加userAccountControl属性失败,原因:" + message + ";";
                                     sb.append(field);
                                 }
 
@@ -342,7 +394,7 @@ public class ADSyncServiceImpl implements ADSyncService {
                 result.put("code", "500");
                 result.put("msg", "AD服务器连接失败,失败原因为:" + var34.getMessage());
                 return result;
-            }finally {
+            } finally {
                 if (this.dc != null) {
                     try {
                         this.dc.close();
@@ -362,24 +414,106 @@ public class ADSyncServiceImpl implements ADSyncService {
         return result;
     }
 
-
     // 搜索用户,返回用户在AD域中的...
     public String searchUser(DirContext ctx, String searchBase, String searchFilter, String username) throws Exception {
+        if (StringUtil.isEmpty(username)) {
+            return "";
+        }
+
         SearchControls searchControls = new SearchControls();
         searchControls.setSearchScope(2);
-        NamingEnumeration<SearchResult> results = ctx.search(searchBase, searchFilter, new Object[]{username}, searchControls);
-        String managerName = "";
-
-        String mangerDN;
-        SearchResult searchResult;
-        for(mangerDN = ""; results.hasMoreElements(); mangerDN = searchResult.getNameInNamespace()) {
-            searchResult = (SearchResult)results.nextElement();
-            Attributes attributes = searchResult.getAttributes();
+
+        NamingEnumeration<SearchResult> results = null;
+        String mangerDN = "";
+
+        try {
+            results = ctx.search(searchBase, searchFilter, new Object[]{username}, searchControls);
+
+            if (results.hasMoreElements()) {
+                SearchResult searchResult = results.nextElement();
+                mangerDN = searchResult.getNameInNamespace();
+
+                // 记录重复用户(如果有)
+                while (results.hasMoreElements()) {
+                    SearchResult additionalResult = results.nextElement();
+                    logger.warn("在路径 {} 中找到重复用户 {}: {}", searchBase, username, additionalResult.getNameInNamespace());
+                }
+            }
+        } catch (NamingException e) {
+            logger.error("搜索用户 {} 时发生错误: {}", username, e.getMessage());
+            throw e;
+        } finally {
+            // 修复bug:正确关闭结果集
+            if (results != null) {
+                try {
+                    results.close();
+                } catch (NamingException e) {
+                    logger.debug("关闭搜索结果集时发生错误: {}", e.getMessage());
+                }
+            }
         }
 
         return mangerDN;
     }
 
+    // 新增方法:在Alumni OU及其所有子OU中搜索用户
+    private String searchUserInAlumniAndSubtree(DirContext ctx, String username) throws Exception {
+        if (StringUtil.isEmpty(alumniRoot) || StringUtil.isEmpty(username)) {
+            return "";
+        }
+
+        SearchControls searchControls = new SearchControls();
+        searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); // 搜索整个子树
+
+        NamingEnumeration<SearchResult> results = null;
+        try {
+            results = ctx.search(alumniRoot,
+                    "(&(objectClass=user)(sAMAccountName={0}))",
+                    new Object[]{username}, searchControls);
+
+            if (results.hasMoreElements()) {
+                SearchResult searchResult = results.nextElement();
+                String foundPath = searchResult.getNameInNamespace();
+                logger.info("在Alumni路径中找到用户 {}: {}", username, foundPath);
+
+                // 记录重复用户(如果有)
+                while (results.hasMoreElements()) {
+                    SearchResult additionalResult = results.nextElement();
+                    logger.warn("在Alumni路径中找到重复用户 {}: {}", username, additionalResult.getNameInNamespace());
+                }
+                return foundPath;
+            }
+        } catch (NamingException e) {
+            logger.warn("在Alumni OU中搜索用户{}时发生错误: {}", username, e.getMessage());
+        } finally {
+            // 修复bug:正确关闭结果集
+            if (results != null) {
+                try {
+                    results.close();
+                } catch (NamingException e) {
+                    logger.debug("关闭搜索结果集时发生错误: {}", e.getMessage());
+                }
+            }
+        }
+
+        return "";
+    }
+
+    // 新增方法:在所有路径中搜索用户(先常规路径,后Alumni路径)
+    private String searchUserInAllPaths(DirContext ctx, String username) throws Exception {
+        if (StringUtil.isEmpty(username)) {
+            return "";
+        }
+
+        // 先在常规路径中搜索
+        String result = this.searchUser(ctx, this.top, "sAMAccountName={0}", username);
+        if (StringUtil.isNotEmpty(result)) {
+            return result;
+        }
+
+        // 如果在常规路径中没找到,在Alumni路径中搜索
+        return this.searchUserInAlumniAndSubtree(ctx, username);
+    }
 
     // 插入同步日志
     private void insertLog(String errorReason, String sucess, String type) {
@@ -405,53 +539,71 @@ public class ADSyncServiceImpl implements ADSyncService {
     }
 
     // 添加用户信息到AD域
-    public String  addInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
+    public String addInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
+        // 首先检查 fieldValue 是否为空
+        if (StringUtil.isEmpty(fieldValue)) {
+            logger.warn("跳过添加属性 {},因为值为空", field);
+            return "跳过添加属性 " + field + ",因为值为空";
+        }
+
         if ("manager".equals(field)) {
-            ModificationItem item = new ModificationItem(1, new BasicAttribute("manager", managerName));
-            this.dc.modifyAttributes(name, new ModificationItem[]{item});
+            if (StringUtil.isNotEmpty(managerName)) {
+                ModificationItem item = new ModificationItem(1, new BasicAttribute("manager", managerName));
+                this.dc.modifyAttributes(name, new ModificationItem[]{item});
+                return "新增manager属性成功!";
+            } else {
+                logger.warn("managerName为空,不设置manager属性");
+                return "managerName为空,无法设置manager属性";
+            }
         } else {
             BasicAttributes basicAttributes = new BasicAttributes();
             basicAttributes.put(field, fieldValue);
-            //为空则不处理
-            if(StringUtil.isEmpty(fieldValue)){
-                return  "新增"+field + "的值为空不进行处理";
+
+            try {
+                this.dc.modifyAttributes(name, 1, basicAttributes);
+                return "新增" + field + "属性成功!";
+            } catch (NamingException e) {
+                // 如果ADD失败,可能是因为属性已存在,尝试使用REPLACE
+                try {
+                    this.dc.modifyAttributes(name, 2, basicAttributes);
+                    return "更新" + field + "属性成功!";
+                } catch (NamingException e2) {
+                    logger.error("添加属性 {} 失败: {}", field, e2.getMessage());
+                    throw e2;
+                }
             }
-            this.dc.modifyAttributes(name, 1, basicAttributes);
         }
-        return  "新增"+field + "的值为"+fieldValue+"已同步成功!";
     }
 
-
     // 修改AD域中的用户信息
     public void modifyInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
         if ("manager".equals(field)) {
-            ModificationItem item = new ModificationItem(2, new BasicAttribute("manager", managerName));
-            this.dc.modifyAttributes(name, new ModificationItem[]{item});
+            if (StringUtil.isNotEmpty(managerName)) {
+                ModificationItem item = new ModificationItem(2, new BasicAttribute("manager", managerName));
+                this.dc.modifyAttributes(name, new ModificationItem[]{item});
+            }
         } else {
             BasicAttributes basicAttributes = new BasicAttributes();
-            basicAttributes.put(field, fieldValue);
+            basicAttributes.put(field, StringUtil.isEmpty(fieldValue) ? null : fieldValue);
             //如果为空则删除
-            if(StringUtil.isEmpty(fieldValue)){
+            if (StringUtil.isEmpty(fieldValue)) {
                 this.dc.modifyAttributes(name, 3, basicAttributes);
-            }else{
+            } else {
                 this.dc.modifyAttributes(name, 2, basicAttributes);
             }
         }
-
     }
 
-
     // 从AD域中移除用户信息
     public void removeInformation(String name, String field, String fieldValue, String managerName) throws NamingException {
         if ("manager".equals(field)) {
-            ModificationItem item = new ModificationItem(3, new BasicAttribute("manager", managerName));
+            ModificationItem item = new ModificationItem(3, new BasicAttribute("manager", null));
             this.dc.modifyAttributes(name, new ModificationItem[]{item});
         } else {
             BasicAttributes basicAttributes = new BasicAttributes();
-            basicAttributes.put(field, fieldValue);
+            basicAttributes.put(field, null);
             this.dc.modifyAttributes(name, 3, basicAttributes);
         }
-
     }
 
     public long getNTLongTimestamp(Date date) {
@@ -461,4 +613,4 @@ public class ADSyncServiceImpl implements ADSyncService {
         timestamp += 116445312000000000L;
         return timestamp;
     }
-}
+}

+ 1 - 0
src/main/resources/application-prod.yml

@@ -61,6 +61,7 @@ api:
     password: ENC(FUTMvvMNgXyxqXWhgXPmLWQq9c2BpJVp)
     root: OU=ERPUsers,OU=Staff,OU=Users,OU=GTIIT,DC=gtiit,DC=edu,DC=cn
     top: OU=Users,OU=GTIIT,DC=gtiit,DC=edu,DC=cn
+    alumni: OU=Alumni,OU=GTIIT,DC=gtiit,DC=edu,DC=cn
     userPassword: Qwert1234%
 
 

+ 2 - 1
src/main/resources/application-sit.yml

@@ -10,7 +10,7 @@ spring:
 #shr接口地址
 api:
   shr:
-    address: https://gtiit.test.kdeascloud.com/shr
+    address: https://gtiit.kdeascloud.com/shr
     #考勤打卡
     transmitPunchCardRecord: transmitPunchCardRecord
     #部门组织
@@ -65,6 +65,7 @@ api:
     password: Gtiit@2025
     root: OU=ERPUsers,OU=Staff,OU=Users,OU=GTIIT,DC=uat-gt,DC=local  # 统一域名
     top: OU=Users,OU=GTIIT,DC=uat-gt,DC=local  # 与root一致
+    alumni: OU=Alumni,OU=GTIIT,DC=uat-gt,DC=local  # 统一域名
     userPassword: Gtiit@2025
 
 mybatis: