You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

81 lines
4.3 KiB

# dt-java SDK 部门与用户拉取 API 调研
Label: wayfinder:research
Type: research
Status: resolved
Blocked by: (无)
## Question
调研第三方库 `com.github.tingyugetc520:dt-java:0.1.2`(钉钉 OpenAPI 的 Java SDK,钉钉官方 dingtalk-java 的社区分支)的用法,产出票据 03 实现所需的 API 结论:
1. 如何用 Client ID/Client Secret(企业内部应用凭证)初始化 client 并获取企业级 access token
2. 拉取部门树列表的 API(部门 ID/名称/父部门/负责人 dept_manager_userid 字段)
3. 按部门拉取用户详情列表的 API(姓名/手机号/unionId/userid 字段),分页方式
4. 与现有 `DingTalkAuthClient` 手写 HTTP + Hutool 方式的关系:是否直接用 SDK 替换手写调用,还是仅在同步端点内使用 SDK(倾向后者,不动已验证的登录链路)
5. Maven 仓库可用性(中央仓库是否有 0.1.2 版本)与传递依赖冲突风险
产出:一页结论(含关键类名、调用示例、API 端点对照),供票据 03 直接照抄实现。
## Answer
调研完成(源码已克隆到 `tmp/DtJava/` 可直接查阅)。结论如下:
### 1. 可用性与形态
- Maven Central 确认存在 `com.github.tingyugetc520:dt-java:0.1.2`(2021-03-08 发布)。封装的是**旧版 oapi.dingtalk.com** 接口(非新版 api.dingtalk.com),5 年未更新但旧版接口仍在服务。
### 2. 初始化(凭证)
```java
DtDefaultConfigImpl config = new DtDefaultConfigImpl();
config.setCorpId("xxx"); // ⚠️ yml 目前没有,需新增配置
config.setAgentId(123L); // ⚠️ yml 目前没有,需新增配置
config.setAppKey(clientId); // = 现有 crm.auth.dingtalk.client-id
config.setAppSecret(clientSecret); // = 现有 client-secret
DtServiceImpl dtService = new DtServiceImpl();
dtService.setDtConfigStorage(config);
// SDK 自管企业 token(旧版 gettoken 接口,内部自动刷新)
```
包名根:`com.github.tingyugetc520.ali.dingtalk.*`(注意不是 com.github.....dtjava)。
### 3. 部门树:`DtDepartmentService`
```java
List<DtDepart> depts = dtService.getDepartmentService().list(null, true); // 递归全量
```
`DtDepart` 字段仅 `id / name / parentId / order`——**没有 dept_manager_userid**。
### 4. 部门负责人:从用户侧反查(关键修正)
部门负责人不在 DtDepart,而在 `DtUser.isLeaderInDeparts: Map<deptId, Boolean>`(获取部门用户详情接口返回)。同步逻辑应为:拉用户时聚合 `isLeaderInDeparts`,反写对应部门的负责人字段。
### 5. 用户:`DtUserService`
```java
// 部门用户详情(offset/size 分页,循环拉到不足一页为止)
List<DtUser> users = dtService.getUserService().listByDepartment(deptId, offset, size, null);
// 单个详情
DtUser u = dtService.getUserService().getById(userId);
```
`DtUser` 关键字段:`userId / unionId / name / mobile / position / jobNumber / email / avatar / departIds(多部门) / active / isAdmin / isLeaderInDeparts / hiredDate`——同步到 `auth_user`(account=userId,username=name,mobile,部门挂载 departIds,在职状态可看 active)完全够用。
### 6. 与现有 DingTalkAuthClient 的关系
SDK 用旧版 oapi + 自管 token;现有登录链路用新版 api.dingtalk.com + 手写 HTTP。两套并存无冲突,**同步端点单独用 SDK,不动已验证的登录链路**(维持倾向结论)。
### 7. 传递依赖风险(需在票据 03 处理)
pom 传递依赖较旧:okhttp 4.5.0、httpclient、guava 29.0-jre、gson 2.8.0、**xstream 1.4.15(有已知 CVE,仅事件回调 XML 反序列化用到,同步链路不触碰)**、commons-io 2.5、commons-lang3 3.10。与 Spring Boot 3 BOM 管理的版本存在降级竞争(Maven 最近优先,Boot BOM 在父 POM 通常胜出)。建议:引入时对 xstream、guava、gson 做 exclusions 或显式锁定 Boot 版本,验证 `mvn dependency:tree` 无降级后再用。
### 给票据 03 的落地清单
1. yml `crm.auth.dingtalk` 新增 `corp-id`、`agent-id` 两项(用户提供值)
2. crm-auth pom 引 dt-java(带 exclusions)
3. 同步:`list(null,true)` 拉部门树 → sys_dept(parentId 挂树);逐部门 `listByDepartment` 分页拉用户 → auth_user;聚合 `isLeaderInDeparts` 反写部门负责人
4. 部门循环注意钉钉限流(建议每请求间隔 ~100ms,或并发 2~3 线程 + 限流)