实现钉钉部门同步功能:递归获取所有部门并保存ding_dept_id,修复类型转换错误

This commit is contained in:
Your Name 2026-01-02 13:34:51 +08:00
parent 949eecaf37
commit ff1363f55d
2 changed files with 150 additions and 8 deletions

View File

@ -152,6 +152,17 @@ public class DingTalkController {
return Result.success(dingTalkService.getDepartmentList());
}
@Operation(summary = "同步钉钉部门")
@PostMapping("/sync-departments")
public Result<Integer> syncDepartments() {
try {
return Result.success(dingTalkService.syncDepartments());
} catch (Exception e) {
log.error("同步钉钉部门失败", e);
return Result.error("同步钉钉部门失败: " + e.getMessage());
}
}
@Operation(summary = "同步钉钉用户")
@PostMapping("/sync-users")
public Result<Integer> syncUsers() {

View File

@ -2,8 +2,10 @@ package com.designhub.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.designhub.common.ResultCode;
import com.designhub.entity.Department;
import com.designhub.entity.DingTalkConfig;
import com.designhub.exception.BusinessException;
import com.designhub.mapper.DepartmentMapper;
import com.designhub.mapper.DingTalkConfigMapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@ -32,6 +34,7 @@ public class DingTalkService {
private final DingTalkConfigMapper configMapper;
private final ObjectMapper objectMapper;
private final RestTemplate restTemplate = new RestTemplate();
private final DepartmentMapper departmentMapper;
private static final String DINGTALK_API_BASE = "https://oapi.dingtalk.com";
@ -441,17 +444,24 @@ public class DingTalkService {
Map<String, Object> result = (Map<String, Object>) body.get("result");
// 获取部门信息
List<Long> deptIdList = (List<Long>) result.get("dept_id_list");
if (deptIdList != null && !deptIdList.isEmpty()) {
Object deptIdListObj = result.get("dept_id_list");
if (deptIdListObj != null) {
List<Map<String, Object>> departments = new ArrayList<>();
for (Long deptId : deptIdList) {
Map<String, Object> deptInfo = getDepartmentInfo(deptId.toString());
if (deptInfo != null) {
departments.add(deptInfo);
List<?> deptIdList = (List<?>) deptIdListObj;
if (!deptIdList.isEmpty()) {
for (Object deptIdObj : deptIdList) {
// 处理Integer或Long类型
String deptIdStr = deptIdObj != null ? deptIdObj.toString() : null;
if (deptIdStr != null) {
Map<String, Object> deptInfo = getDepartmentInfo(deptIdStr);
if (deptInfo != null) {
departments.add(deptInfo);
}
}
}
result.put("departments", departments);
log.info("获取到用户部门信息: userId={}, departments={}", userId, departments.size());
}
result.put("departments", departments);
log.info("获取到用户部门信息: userId={}, departments={}", userId, departments.size());
}
return result;
@ -503,6 +513,127 @@ public class DingTalkService {
}
}
/**
* 同步钉钉部门到系统数据库
* 递归获取所有部门,保存或更新到数据库,并设置ding_dept_id
*/
@Transactional(rollbackFor = Exception.class)
public int syncDepartments() {
DingTalkConfig config = getConfig();
if (config == null) {
throw new BusinessException(ResultCode.PARAM_ERROR, "钉钉未配置");
}
log.info("开始同步钉钉部门...");
int syncCount = 0;
try {
String accessToken = getAccessToken(config);
if (accessToken == null) {
throw new BusinessException(ResultCode.PARAM_ERROR, "获取钉钉访问令牌失败");
}
// 递归获取所有部门(从根部门开始)
List<Map<String, Object>> allDepartments = getAllDepartmentsRecursive(accessToken, 1L);
log.info("从钉钉获取到 {} 个部门", allDepartments.size());
// 同步每个部门到数据库
for (Map<String, Object> dingDept : allDepartments) {
Object deptIdObj = dingDept.get("dept_id");
String dingDeptId = deptIdObj != null ? deptIdObj.toString() : null;
String deptName = (String) dingDept.get("name");
Object parentIdObj = dingDept.get("parent_id");
String parentDingDeptId = parentIdObj != null ? parentIdObj.toString() : null;
if (dingDeptId == null || deptName == null) {
log.warn("跳过无效的部门信息: {}", dingDept);
continue;
}
// 查找系统部门(通过ding_dept_id或名称)
com.designhub.entity.Department sysDept = departmentMapper.selectOne(
new LambdaQueryWrapper<com.designhub.entity.Department>()
.eq(com.designhub.entity.Department::getDingDeptId, dingDeptId)
.eq(com.designhub.entity.Department::getDeleted, 0)
.last("LIMIT 1")
);
if (sysDept == null) {
// 通过名称查找
sysDept = departmentMapper.selectOne(
new LambdaQueryWrapper<com.designhub.entity.Department>()
.eq(com.designhub.entity.Department::getDeptName, deptName)
.eq(com.designhub.entity.Department::getDeleted, 0)
.last("LIMIT 1")
);
}
if (sysDept != null) {
// 更新现有部门:设置ding_dept_id
sysDept.setDingDeptId(dingDeptId);
departmentMapper.updateById(sysDept);
log.info("更新部门: id={}, name={}, ding_dept_id={}", sysDept.getId(), deptName, dingDeptId);
} else {
// 部门不存在,可以选择创建或跳过
// 这里选择跳过,因为部门应该先在系统中创建
log.warn("系统部门不存在,跳过同步: name={}, ding_dept_id={}", deptName, dingDeptId);
}
syncCount++;
}
log.info("同步钉钉部门完成,共处理 {} 个部门", syncCount);
return syncCount;
} catch (Exception e) {
log.error("同步钉钉部门失败", e);
throw new BusinessException(ResultCode.DINGTALK_API_ERROR, "同步钉钉部门失败: " + e.getMessage());
}
}
/**
* 递归获取所有部门
*/
private List<Map<String, Object>> getAllDepartmentsRecursive(String accessToken, Long parentDeptId) {
List<Map<String, Object>> allDepartments = new ArrayList<>();
try {
String url = String.format("%s/topapi/v2/department/listsub?access_token=%s",
DINGTALK_API_BASE, accessToken);
Map<String, Object> request = new HashMap<>();
request.put("dept_id", parentDeptId);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(request, headers);
ResponseEntity<Map> response = restTemplate.postForEntity(url, entity, Map.class);
Map<String, Object> body = response.getBody();
if (body != null) {
Object errcode = body.get("errcode");
if (errcode != null && (errcode.equals(0) || errcode.equals(0L) || "0".equals(errcode.toString()))) {
List<Map<String, Object>> subDepts = (List<Map<String, Object>>) body.get("result");
if (subDepts != null) {
for (Map<String, Object> dept : subDepts) {
allDepartments.add(dept);
// 递归获取子部门
Object deptIdObj = dept.get("dept_id");
if (deptIdObj != null) {
Long deptId = deptIdObj instanceof Long ? (Long) deptIdObj : Long.parseLong(deptIdObj.toString());
allDepartments.addAll(getAllDepartmentsRecursive(accessToken, deptId));
}
}
}
}
}
} catch (Exception e) {
log.error("获取部门列表失败: parentDeptId={}", parentDeptId, e);
}
return allDepartments;
}
/**
* 同步钉钉用户
*/