package com.doumee.core.dingTalk; import com.alibaba.fastjson.JSONObject; import com.aliyun.dingtalkoauth2_1_0.Client; import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenRequest; import com.aliyun.dingtalkoauth2_1_0.models.GetAccessTokenResponse; import com.aliyun.tea.TeaException; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.dingtalk.api.DefaultDingTalkClient; import com.dingtalk.api.DingTalkClient; import com.dingtalk.api.request.*; import com.dingtalk.api.response.*; import com.doumee.biz.system.SystemDictDataBiz; import com.doumee.core.constants.ResponseStatus; import com.doumee.core.exception.BusinessException; import com.doumee.core.utils.Constants; import com.doumee.dao.business.dao.CompanyMapper; import com.doumee.dao.business.model.Company; import com.doumee.dao.system.model.SystemDictData; import com.doumee.service.business.CompanyService; import com.github.xiaoymin.knife4j.core.util.CollectionUtils; import com.taobao.api.ApiException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; import java.util.stream.Collectors; /** * Created by IntelliJ IDEA. * * @Author : Rk * @create 2025/9/24 16:25 */ @Slf4j @Service public class DingTalk { @Autowired private SystemDictDataBiz systemDictDataBiz; @Autowired private CompanyMapper companyMapper; /** * 使用 Token 初始化账号Client * @return Client com.aliyun.dingtalkoauth2_1_0. * @throws Exception */ public static Client createClient() throws Exception { com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config(); config.protocol = "https"; config.regionId = "central"; return new Client(config); } public void updTokenInfo() throws Exception { String appKey = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_KEY).getCode(); String appSecret = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.APP_SECRET).getCode(); Client client = DingTalk.createClient(); GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest() .setAppKey(appKey) .setAppSecret(appSecret); try { GetAccessTokenResponse getAccessTokenResponse = client.getAccessToken(getAccessTokenRequest); //返参描述 例:{"body":{"accessToken":"76a248ea72ba3f359b39c9e70073d642","expireIn":7200},"headers":{"access-control-allow-origin":"*","date":"Wed, 24 Sep 2025 08:39:36 GMT","server":"DingTalk/1.0.0","transfer-encoding":"chunked","x-acs-request-id":"9E8AF053-04DD-7031-9766-14DFFB087A79","access-control-allow-headers":"X-Requested-With, X-Sequence, _aop_secret, _aop_signature, x-acs-dingtalk-access-token","connection":"keep-alive","content-type":"application/json;charset=utf-8","access-control-expose-headers":"*","x-acs-trace-id":"96e7cf1f3c0e059779a6d581d4b5fca7"},"statusCode":200} if(Constants.equalsInteger(getAccessTokenResponse.statusCode,Constants.DD_STATUS_SUCCESS_CODE)){ //解析token信息 存储 String accessToken = getAccessTokenResponse.getBody().getAccessToken(); //更新token信息存储 SystemDictData systemDictData = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.ACCESS_TOKEN); systemDictData.setCode(accessToken); systemDictData.setUpdateTime(new Date()); systemDictDataBiz.updateByIdNew(systemDictData); } //更新Token信息 System.out.println(JSONObject.toJSONString(getAccessTokenResponse)); } catch (TeaException err) { if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题 log.error("更新钉钉Token失败:{}" + err.message); } } catch (Exception _err) { TeaException err = new TeaException(_err.getMessage(), _err); if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题 log.error("更新钉钉Token失败:{}" + err.message); } } } /** * 获取钉钉Token * @return */ public String getToken(){ String accessToken = systemDictDataBiz.queryByCode(Constants.DD_TALK,Constants.ACCESS_TOKEN).getCode(); return accessToken; } /** * 全量同步 部门信息 * 接口文档地址 https://open.dingtalk.com/document/orgapp/obtain-the-department-list-v2 * 本接口只支持获取当前部门的下一级部门基础信息,不支持获取当前部门下所有层级子部门 * @throws ApiException */ public List syncAllDDDepartmentList() throws ApiException { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub"); List headList = new ArrayList<>(); headList.add(1L); List deptBaseResponseList = new ArrayList<>(); List thisLevelList = getDepartmentList(client,headList); deptBaseResponseList.addAll(thisLevelList); while (CollectionUtils.isNotEmpty(thisLevelList)){ headList = thisLevelList.stream().map(i->i.getDeptId()).collect(Collectors.toList()); thisLevelList = getDepartmentList(client,headList); if(CollectionUtils.isNotEmpty(thisLevelList)){ deptBaseResponseList.addAll(thisLevelList); } } List getResponseList = new ArrayList<>(); if(CollectionUtils.isNotEmpty(deptBaseResponseList)){ for (OapiV2DepartmentListsubResponse.DeptBaseResponse deptBaseResponse:deptBaseResponseList) { OapiV2DepartmentGetResponse.DeptGetResponse deptGetResponse = syncDepartmentInfo(deptBaseResponse.getDeptId()); getResponseList.add(deptGetResponse); } } return getResponseList; } /** * 获取部门下级数据 * @param client * @param deptIdList * @return * @throws ApiException */ public List getDepartmentList (DingTalkClient client, List deptIdList) throws ApiException{ List thisLevelList = new ArrayList<>(); for (Long deptId:deptIdList) { OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest(); req.setDeptId(deptId); req.setLanguage("zh_CN"); OapiV2DepartmentListsubResponse rsp = client.execute(req, this.getToken()); if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ if(CollectionUtils.isNotEmpty(rsp.getResult())){ thisLevelList.addAll(rsp.getResult()); } }else{ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); } } return thisLevelList; } /** * 创建组织部门 暂不使用 * 接口文档地址:https://open.dingtalk.com/document/orgapp/create-a-department-v2 * @param ddParentId 钉钉上级部门主键 如果没有则入null * @param name 部门名称 * @param sn 序号 * @param id 系统部门主键 * @throws ApiException */ public void pushCreatDepartment(Integer ddParentId,String name,Long sn,Integer id) throws ApiException { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/create"); OapiV2DepartmentCreateRequest req = new OapiV2DepartmentCreateRequest(); //必入参数 //如果无父级 则默认跟组织 1L req.setParentId(Objects.isNull(ddParentId)?1L:ddParentId); req.setName(name); req.setOrder(sn); //外部部门字段 req.setSourceIdentifier(id.toString()); //默认参数 req.setHideDept(false); req.setOuterDept(false); req.setCreateDeptGroup(false); OapiV2DepartmentCreateResponse rsp = client.execute(req, getToken()); if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ }else{ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); } System.out.println(rsp.getBody()); } /** * 更新组织部门 暂不使用 * 接口文档地址:https://open.dingtalk.com/document/orgapp/update-a-department-v2 * @param deptId 钉钉部门主键 * @param name 部门名称 * @param parentId 父级钉钉部门主键 * @param sn 序号 * @throws ApiException */ public void pushUpdDepartment(Integer deptId,String name,Integer parentId,Long sn) throws ApiException { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/update"); OapiV2DepartmentUpdateRequest req = new OapiV2DepartmentUpdateRequest(); req.setDeptId(deptId.longValue()); //如果无父级 则默认跟组织 1L req.setParentId(Objects.isNull(parentId)?1L:parentId.longValue()); req.setOrder(sn); req.setName(name); OapiV2DepartmentUpdateResponse rsp = client.execute(req, getToken()); if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ }else{ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); } } /** * 删除组织部门 暂不使用 * 接口文档地址:https://open.dingtalk.com/document/orgapp/delete-a-department-v2 * @param deptId 钉钉部门主键 * @throws ApiException */ public void pushDelDepartment(Integer deptId) throws ApiException { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/delete"); OapiV2DepartmentDeleteRequest req = new OapiV2DepartmentDeleteRequest(); req.setDeptId(deptId.longValue()); OapiV2DepartmentDeleteResponse rsp = client.execute(req, getToken()); System.out.println(rsp.getBody()); if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ }else{ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); } } public OapiV2DepartmentGetResponse.DeptGetResponse syncDepartmentInfo(Long deptId) throws ApiException { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/get"); OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest(); req.setDeptId(deptId); req.setLanguage("zh_CN"); OapiV2DepartmentGetResponse rsp = client.execute(req, getToken()); System.out.println(rsp.getBody()); if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ return rsp.getResult(); }else{ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); } } public List syncAllUserInfo() throws ApiException { List deptList = companyMapper.selectList(new QueryWrapper().lambda() .eq(Company::getIsdeleted,Constants.ZERO) .eq(Company::getType,Constants.ONE) .isNotNull(Company::getErpId) ); if(CollectionUtils.isEmpty(deptList)){ return null; } List allUserIdList = new ArrayList<>(); DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid"); OapiUserListidRequest req = new OapiUserListidRequest(); for (Company company:deptList) { req.setDeptId(Long.valueOf(company.getErpId())); OapiUserListidResponse rsp = client.execute(req, getToken()); if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ if(CollectionUtils.isNotEmpty(rsp.getResult().getUseridList())){ allUserIdList.addAll(rsp.getResult().getUseridList()); } }else{ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); } } if(CollectionUtils.isEmpty(allUserIdList)){ return null; } Set setUserIdList = new HashSet<>(allUserIdList); return syncUserInfo(setUserIdList); } public List syncUserInfo(Set setUserIdList) throws ApiException { List userList = new ArrayList<>(); DefaultDingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/get"); OapiV2UserGetRequest req = new OapiV2UserGetRequest(); for (String userId:setUserIdList) { req.setUserid(userId); req.setLanguage("zh_CN"); OapiV2UserGetResponse rsp = client.execute(req, getToken()); if(rsp.getErrcode().equals(Constants.DD_ERR_CODE)){ OapiV2UserGetResponse.UserGetResponse userGetResponse = rsp.getResult(); userList.add(userGetResponse); }else{ throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),rsp.getMessage()); } } return userList; } public static void main(String[] args) throws Exception { String appKey = "dingkfglaktqmfd2dmo2";//systemDictDataBiz.queryByCode("","").getCode(); String appSecret = "0e22TT2s794Yj49Exgvq8nU2ulpXmxlw9ThBh5s-vDv5Cfspv-f8HPmta4cg2evk";//systemDictDataBiz.queryByCode("","").getCode(); Client client = DingTalk.createClient(); GetAccessTokenRequest getAccessTokenRequest = new GetAccessTokenRequest() .setAppKey(appKey) .setAppSecret(appSecret); try { GetAccessTokenResponse getAccessTokenResponse = client.getAccessToken(getAccessTokenRequest); //更新Token信息 System.out.println(JSONObject.toJSONString(getAccessTokenResponse)); } catch (TeaException err) { if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题 log.error("更新钉钉Token失败:{}" + err.message); } } catch (Exception _err) { TeaException err = new TeaException(_err.getMessage(), _err); if (!com.aliyun.teautil.Common.empty(err.code) && !com.aliyun.teautil.Common.empty(err.message)) { // err 中含有 code 和 message 属性,可帮助开发定位问题 log.error("更新钉钉Token失败:{}" + err.message); } } } }