写点什么

开源一夏 |企业内部应用接入钉钉获取部门及人员信息

  • 2022 年 8 月 22 日
    北京
  • 本文字数:12682 字

    阅读完需:约 42 分钟

开源一夏 |企业内部应用接入钉钉获取部门及人员信息

开发者后台配置

1.登录开发者后台并配置

首先需要登录开发者后台,配置企业内部应用,如图

可以点击【返回旧版】,个人比较习惯了旧版的操作风格,旧版风格如下

2.创建应用

选中【H5 微应用】,点击【创建应用】

应用创建完成之后可以看到如图

记录下对应的 AgentIdAppKeyAppSecret,上面步骤都操作完成之后需要开启对应权限,由于我们需要获取部门及人员信息,因此需要开启对应权限,点击【权限管理】选择需要的权限点击【申请权限】即可,如图

java 开发阶段

1.所需钉钉接口文档

完成了【开发者后台】配置后,就可以进入开发阶段了,首先确定需要两个接口,文档为获取部门列表和获取部门用户详情,仔细阅读完文档后进入后面操作。

2.springboot 项目配置类

添加配置类 DingDingProperties.java 读取配置信息,代码中给出的对应 key 信息为默认信息,后面可通过配置文件设置

package com.dongao.project.config.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;
/** * @ClassName:DingDingProperties * @author:dongao * @date 2022/1/27 10:23 */@Component@ConfigurationProperties(prefix = "dingtalk.msg")public class DingDingProperties {
public String agentId = "1111111";
public String appKey = "dingbmxxxggddfdf";
public String appSecret = "KIy8DasdfghbbdhghdvgfdfC5gztU-m1nFYQfiUUil-6pnHJN-wU_Xv";
public String getAgentId() { return agentId; }
public void setAgentId(String agentId) { this.agentId = agentId; }
public String getAppKey() { return appKey; }
public void setAppKey(String appKey) { this.appKey = appKey; }
public String getAppSecret() { return appSecret; }
public void setAppSecret(String appSecret) { this.appSecret = appSecret; }}
复制代码

代码中的配置参数可以通过 application.properties 文件进行更改

dingtalk.msg.agentId=12345345dingtalk.msg.appKey=fggsfhnhhjsdfdsfdingtalk.msg.appSecret=234dfgfhbvbhsdfdsgsf-fgdfhghbbdhjj-6pnHJN-wU_Xv
复制代码

3.pom.xml

pom.xml 文件引入钉钉 jar 包依赖

<dependency>        <groupId>com.aliyun</groupId>        <artifactId>alibaba-dingtalk-service-sdk</artifactId>        <version>2.0.0</version></dependency>
复制代码

4.编写接口及实现类

编写钉钉接口 IDingDingService.java,这里面也包括了发送钉钉消息相关的内容,此文可以忽略,只关注获取钉钉部门及部门下人员信息即可

package com.dongao.project.common.dingding;
import com.dingtalk.api.response.*;import com.taobao.api.ApiException;import org.springframework.web.multipart.MultipartFile;
/** * Created by nao'nao on 2020/3/31. * @author dingding * 工作通知消息的发送限制 *(1)企业开发者每分钟最多可调用接口1500次,ISV开发者每分钟最多可调用接口1000次 *(2)企业发送消息单次最多只能给5000人发送,ISV发送消息单次最多能给1000人发送 *(3)给同一员工发送内容相同的消息,一天只能发一次 *(4)企业发送每个员工每天最多可发送500条,ISV方式最多可发送50条 *(5)企业/ISV发送消息时每分钟最多只能有5000人可以接收到消息 */public interface IDingDingService {
/** * 调用钉钉上传文件 * (1) 图片(image):1MB,支持JPG格式 * (2)语音(voice):2MB,播放长度不超过60s,AMR格式 * (3)普通文件(file):10MB * @param type 文件类型 image file (voice暂不支持) * @param file 文件 * @return 返回上传成功对象 OapiMediaUploadResponse */ OapiMediaUploadResponse uploadMedia(String type, MultipartFile file);
/** * 根据unionId获取userId * @param unionId 当前钉钉用户在当前企业下的唯一识别码 * @return */ OapiUserGetUseridByUnionidResponse getUserIdByUnionId(String unionId);
/** * 根据unionId获取userId * @param unionId 当前钉钉用户在当前企业下的唯一识别码 * @return */ OapiUserGetbyunionidResponse getUserIdByUnionIdV2(String unionId);
/** * 根据手机号获取userid * @param phone * @return */ OapiV2UserGetbymobileResponse getUserIdByPhone(String phone);
/** * 发送消息调用 * @param msgInfo 发送消息的内容对象 * @return AjaxResult */ int sendMessage(MsgInfo msgInfo);
/** * 获取部门列表 * @param accessToken * @param deptId * @return */ OapiV2DepartmentListsubResponse getDeptList(String accessToken, Long deptId) throws Exception;
/** * 获取部门下用户信息列表 * @param accessToken * @param deptId * @param cursor * @param size * @return * @throws Exception */ OapiV2UserListResponse getUserListByDeptId(String accessToken, Long deptId, Long cursor, Long size) throws Exception;
/** * 获取企业凭证 access_token * @return * @throws ApiException */ String getAccessToken() throws ApiException;
/** * 获取部门详情 * @param accessToken * @param deptId * @return * @throws Exception */ OapiV2DepartmentGetResponse getDeptDetail(String accessToken, Long deptId) throws Exception;}
复制代码

实现类 DingDingServiceImpl.java

package com.dongao.project.common.dingding;
import com.dingtalk.api.DefaultDingTalkClient;import com.dingtalk.api.DingTalkClient;import com.dingtalk.api.request.*;import com.dingtalk.api.response.*;import com.dongao.project.common.constants.Constants;import com.dongao.project.config.properties.DingDingProperties;import com.dongao.project.keymsghistory.domain.KeyMsgHistory;import com.dongao.project.keymsghistory.service.IKeyMsgHistoryService;import com.dongao.project.sysuser.service.ISysUserService;import com.ruoyi.common.utils.StringUtils;import com.ruoyi.common.utils.text.Convert;import com.taobao.api.ApiException;import com.taobao.api.FileItem;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.multipart.MultipartFile;
import java.util.Objects;
/** * Created by nao'nao on 2020/3/31. * @author dingding */@Servicepublic class DingDingServiceImpl implements IDingDingService {
@Autowired private DingDingProperties dingDingProperties;
@Autowired private ISysUserService sysUserService;
@Autowired private IKeyMsgHistoryService msgHistoryService;
/** * 调用钉钉发送工作通知消息 * @param useridList 员工在当前开发者企业账号范围内的userid * @param msgTemplet 消息模板 * @return 异步发送消息返回发送任务对象 OapiMessageCorpconversationAsyncsendV2Response */ private OapiMessageCorpconversationAsyncsendV2Response sendWorkMsg(String useridList, MsgTemplet msgTemplet) {
try { //给钉钉用户发送工作通知消息 OapiMessageCorpconversationAsyncsendV2Response rsp = send(useridList, msgTemplet); return rsp; } catch (Exception e) { e.printStackTrace(); } return null; }
/** * 给钉钉用户发送工作通知消息 * @param useridList 接收者的用户userid列表,最大用户列表长度:100 zhangsan,lisi * @param msgTemplet 消息内容 * @return OapiMessageCorpconversationAsyncsendV2Response */ private OapiMessageCorpconversationAsyncsendV2Response send(String useridList, MsgTemplet msgTemplet) { //获取企业认证 try { String accessToken = getAccessToken(); //给钉钉用户发送工作通知消息 DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"); OapiMessageCorpconversationAsyncsendV2Request req = new OapiMessageCorpconversationAsyncsendV2Request(); req.setAgentId(Long.parseLong(dingDingProperties.getAgentId())); req.setUseridList(useridList); //部门id串 ,分隔 ///req2.setDeptIdList("1"); //是否发送给企业全部用户 ///req2.setToAllUser(false); OapiMessageCorpconversationAsyncsendV2Request.Msg obj1 = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); if (Constants.MsgType.TEXT.getValue().equals(msgTemplet.getTempletType())) { //发送文本消息 obj1.setMsgtype(Constants.MsgType.TEXT.getValue()); OapiMessageCorpconversationAsyncsendV2Request.Text obj2 = new OapiMessageCorpconversationAsyncsendV2Request.Text(); obj2.setContent(msgTemplet.getContent()); obj1.setText(obj2); }else if (Constants.MsgType.IMAGE.getValue().equals(msgTemplet.getTempletType())) { //发送图片信息 content即为图片media_id obj1.setMsgtype(Constants.MsgType.IMAGE.getValue()); OapiMessageCorpconversationAsyncsendV2Request.Image obj2 = new OapiMessageCorpconversationAsyncsendV2Request.Image(); obj2.setMediaId(msgTemplet.getContent()); obj1.setImage(obj2); }else if (Constants.MsgType.FILE.getValue().equals(msgTemplet.getTempletType())) { //发送文件信息 content即为图片media_id obj1.setMsgtype(Constants.MsgType.FILE.getValue()); OapiMessageCorpconversationAsyncsendV2Request.File obj2 = new OapiMessageCorpconversationAsyncsendV2Request.File(); obj2.setMediaId(msgTemplet.getContent()); obj1.setFile(obj2); }else if (Constants.MsgType.LINK.getValue().equals(msgTemplet.getTempletType())) { obj1.setMsgtype(Constants.MsgType.LINK.getValue()); OapiMessageCorpconversationAsyncsendV2Request.Link obj2 = new OapiMessageCorpconversationAsyncsendV2Request.Link(); obj2.setPicUrl(msgTemplet.getPicUrl()); obj2.setMessageUrl(msgTemplet.getMessageUrl()); obj2.setText(msgTemplet.getContent()); obj2.setTitle(msgTemplet.getTitle()); obj1.setLink(obj2); }else if (Constants.MsgType.MARKDOWN.getValue().equals(msgTemplet.getTempletType())) { obj1.setMsgtype(Constants.MsgType.MARKDOWN.getValue()); OapiMessageCorpconversationAsyncsendV2Request.Markdown obj2 = new OapiMessageCorpconversationAsyncsendV2Request.Markdown(); obj2.setText(msgTemplet.getContent()); obj2.setTitle(msgTemplet.getTitle()); obj1.setMarkdown(obj2); } req.setMsg(obj1); OapiMessageCorpconversationAsyncsendV2Response rsp = client.execute(req, accessToken); return rsp; } catch (ApiException e) { e.printStackTrace(); }
return null;
}
/** * 获取企业凭证 access_token */ @Override public String getAccessToken() throws ApiException { //获取企业凭证 access_token 正常情况下access_token有效期为7200秒,有效期内重复获取返回相同结果,并自动续期。 DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken"); OapiGettokenRequest req = new OapiGettokenRequest(); req.setAppkey(dingDingProperties.getAppKey()); req.setAppsecret(dingDingProperties.getAppSecret()); req.setHttpMethod("GET"); OapiGettokenResponse rsp = client.execute(req); return rsp.getAccessToken(); }
/** * 调用钉钉上传文件 * (1) 图片(image):1MB,支持JPG格式 * (2)语音(voice):2MB,播放长度不超过60s,AMR格式 * (3)普通文件(file):10MB * @param type 文件类型 image file (voice暂不支持) * @param file 文件 * @return */ @Override public OapiMediaUploadResponse uploadMedia(String type, MultipartFile file) { try { //获取企业凭证 access_token String accessToken = getAccessToken(); DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/media/upload"); OapiMediaUploadRequest req = new OapiMediaUploadRequest(); req.setType(type); req.setMedia(new FileItem(file.getOriginalFilename(),file.getInputStream())); OapiMediaUploadResponse rsp = client.execute(req, accessToken); return rsp; } catch (Exception e) { e.printStackTrace(); } return null; }
/** * 根据unionId获取userId * @param unionId 当前钉钉用户在当前企业下的唯一识别码 * @return */ @Override public OapiUserGetUseridByUnionidResponse getUserIdByUnionId(String unionId) { try { String accessToken = getAccessToken(); //根据unionId获取userId DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/user/getUseridByUnionid"); OapiUserGetUseridByUnionidRequest req = new OapiUserGetUseridByUnionidRequest(); req.setUnionid(unionId); req.setHttpMethod("GET"); OapiUserGetUseridByUnionidResponse rsp = client.execute(req, accessToken); return rsp; } catch (ApiException e) { e.printStackTrace(); } return null; } /** * 根据unionId获取userId 2.0版本 * @param unionId 当前钉钉用户在当前企业下的唯一识别码 * @return */ @Override public OapiUserGetbyunionidResponse getUserIdByUnionIdV2(String unionId) { try { String accessToken = getAccessToken(); //根据unionId获取userId DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/getbyunionid"); OapiUserGetbyunionidRequest req = new OapiUserGetbyunionidRequest(); req.setUnionid(unionId); OapiUserGetbyunionidResponse rsp = client.execute(req, accessToken); return rsp; } catch (ApiException e) { e.printStackTrace(); } return null; }
/** * 根据手机号获取userid * @param phone * @return */ @Override public OapiV2UserGetbymobileResponse getUserIdByPhone(String phone){ try { String accessToken = getAccessToken(); DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/getbymobile"); OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest(); req.setMobile(phone); OapiV2UserGetbymobileResponse rsp = client.execute(req, accessToken); return rsp; } catch (ApiException e) { e.printStackTrace(); } return null; }
/** * 发送消息调用 * @param msgInfo 发送消息的内容对象 * @return AjaxResult */ @Override public int sendMessage(MsgInfo msgInfo) { String userIdsStr = msgInfo.getUserIds(); if (msgInfo != null && StringUtils.isNotEmpty(userIdsStr)) { //获取用户userId对应的钉钉平台用户userid String[] userIds = Convert.toStrArray(userIdsStr); String useridList = sysUserService.selectDingdingUseridList(userIds);
if (StringUtils.isNotEmpty(useridList)) { //获取消息模板 MsgTemplet msgTemplet = msgInfo.getMsgTemplet(); if (msgTemplet != null) {
OapiMessageCorpconversationAsyncsendV2Response rsp = sendWorkMsg(useridList, msgTemplet);
//插入消息发送记录表 KeyMsgHistory msgHistory = new KeyMsgHistory(); for (String userId:userIds) { msgHistory.setUserId(Long.parseLong(userId)); if (Objects.nonNull(rsp)){ msgHistory.setErrCode(rsp.getErrcode()); msgHistory.setErrMsg(rsp.getErrmsg()); msgHistory.setTaskId(rsp.getTaskId()); } msgHistory.setContent(msgTemplet.getContent()); msgHistory.setType(msgTemplet.getTempletType()); msgHistoryService.insertKeyMsgHistory(msgHistory); }
if (Objects.nonNull(rsp) && rsp.isSuccess()) { //success return 1; } } } } return 0; }
/** * 获取部门列表 * @throws Exception */ @Override public OapiV2DepartmentListsubResponse getDeptList(String accessToken, Long deptId) throws Exception { try { if (StringUtils.isEmpty(accessToken)) { accessToken = getAccessToken(); } DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub"); OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest(); if (deptId != null) { req.setDeptId(deptId); } OapiV2DepartmentListsubResponse rsp = client.execute(req, accessToken); return rsp; } catch (ApiException e) { e.printStackTrace(); return null; } }
/** * 获取部门下用户信息列表 * @throws Exception */ @Override public OapiV2UserListResponse getUserListByDeptId(String accessToken, Long deptId, Long cursor, Long size) throws Exception { try { if (StringUtils.isEmpty(accessToken)) { accessToken = getAccessToken(); } DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list"); OapiV2UserListRequest req = new OapiV2UserListRequest(); req.setDeptId(deptId); req.setCursor(cursor); req.setSize(size); OapiV2UserListResponse rsp = client.execute(req, accessToken); return rsp; } catch (ApiException e) { e.printStackTrace(); return null; } }
/** * 获取部门详情 * @param accessToken * @param deptId * @return * @throws Exception */ @Override public OapiV2DepartmentGetResponse getDeptDetail(String accessToken, Long deptId) throws Exception { try { if (StringUtils.isEmpty(accessToken)) { accessToken = getAccessToken(); } DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/get"); OapiV2DepartmentGetRequest req = new OapiV2DepartmentGetRequest(); req.setDeptId(deptId); OapiV2DepartmentGetResponse rsp = client.execute(req, accessToken); return rsp; } catch (ApiException e) { e.printStackTrace(); return null; } }}
复制代码

5.获取钉钉部门及人员并保存

获取钉钉部门及部门下人员 java 类主要方法如下

 /**   * 保存钉钉部门人员信息   * @param param   * @return   */  @Override  public AjaxResult saveDingDingDeptListV3(String param) {    //逐级获取部门信息列表并保存    AjaxResult ajaxResult = new AjaxResult();    ajaxResult.setMsg("成功!");    try {      String accessToken = dingDingService.getAccessToken();      if (StringUtils.isNotEmpty(param)) {        //获取多个部门的部门信息        String[] split = param.split(",");        for (String s : split) {          //获取叶子部门列表 and 获取部门下人员信息          saveDeptListV3(ajaxResult, accessToken, Long.parseLong(s));        }      }else {        //获取根部门列表 and 获取部门下人员信息        saveDeptListV3(ajaxResult, accessToken, null);      }    }catch (Exception e) {      e.printStackTrace();    }    return ajaxResult;  }      private void saveDeptListV3(AjaxResult ajaxResult, String accessToken, Long reqDeptId) throws Exception {    //保存当前部门下的人员信息    saveUserListV3(ajaxResult, accessToken, reqDeptId);    //获取部门列表    OapiV2DepartmentListsubResponse deptrsp = dingDingService.getDeptList(accessToken, reqDeptId);    if (deptrsp.isSuccess()) {            List<OapiV2DepartmentListsubResponse.DeptBaseResponse> result = deptrsp.getResult();            if (CollectionUtils.isNotEmpty(result)) {                SysDept sysDept = new SysDept();                for (OapiV2DepartmentListsubResponse.DeptBaseResponse dept : result) {          Long deptId = dept.getDeptId();          if (deptId > 0) {            //判定当前部门是否已存在,存在则不再新增            SysDept sysdept = sysDeptMapper.selectSysDeptByDeptId(deptId);            if (sysdept == null) {              sysDept.setDeptId(deptId);              sysDept.setDeptName(dept.getName());              sysDept.setParentId(dept.getParentId());              sysDept.setCreateBy("定时任务拉取");              sysDept.setCreateTime(new Date());              //保存部门信息              sysDeptMapper.insertSysDept(sysDept);            }          }                    //继续获取当前部门下的子级部门          saveDeptListV3(ajaxResult, accessToken, deptId);                }            }else {        ajaxResult.setMsg("当前部门已是叶子部门");      }        }else {            ajaxResult.setMsg("获取部门列表API调用失败");        }  }
private void saveUserListV3(AjaxResult ajaxResult, String accessToken, Long reqDeptId) throws Exception { //获取当前部门下的人员信息并保存 Boolean hasMore = false; OapiV2UserListResponse userrsp = dingDingService.getUserListByDeptId(accessToken, reqDeptId, 0L, 10L); if (userrsp.isSuccess()) { OapiV2UserListResponse.PageResult result = userrsp.getResult(); List<OapiV2UserListResponse.ListUserResponse> list = result.getList(); if (CollectionUtils.isNotEmpty(list)) { saveDingDingUserV3(list);
//继续 hasMore = result.getHasMore(); while (hasMore) { userrsp = dingDingService.getUserListByDeptId(accessToken, reqDeptId, result.getNextCursor(), 10L); if (userrsp.isSuccess()) { result = userrsp.getResult(); list = result.getList(); saveDingDingUserV3(list); hasMore = result.getHasMore(); } } }else { ajaxResult.setMsg("当前部门下无人员信息"); } }else { ajaxResult.setMsg("获取部门人员列表API调用失败"); } }
private void saveDingDingUserV3(List<OapiV2UserListResponse.ListUserResponse> list) { SysUser sysUser = new SysUser(); for (OapiV2UserListResponse.ListUserResponse user : list) { //判断是否已经插入过 String userid = user.getUserid(); int count = sysUserMapper.countSysUserByDingDingUserId(userid); if (count == 0) { sysUser.setDingdingUserid(user.getUserid()); sysUser.setAvatar(user.getAvatar()); sysUser.setUnionId(user.getUnionid()); String userName = user.getName(); sysUser.setUserName(userName); //中文转拼音作为loginName String loginName = PinYinUtils.getPingYin(userName); sysUser.setLoginName(loginName); List<Long> deptIdList = user.getDeptIdList(); if (CollectionUtils.isNotEmpty(deptIdList)) { for (Long deptid : deptIdList) { sysUser.setDeptId(deptid); sysUser.setCreateBy("定时任务拉取"); sysUser.setCreateTime(new Date()); sysUserMapper.insertSysUser(sysUser); } } } } }
复制代码

6.补充

在获取钉钉部门及人员信息时用到了汉字转拼音 jar,代码需要补充如下

pom.xml 引入 jar 包

<dependency>        <groupId>com.belerweb</groupId>        <artifactId>pinyin4j</artifactId>        <version>2.5.0</version></dependency>
复制代码

添加工具类 PinYinUtils.java

package com.dongao.project.utils;
import net.sourceforge.pinyin4j.PinyinHelper;import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
/** * @ClassName:PinYinUtils * @author:dongao * @date 2022/2/10 14:05 */public class PinYinUtils { /** * 中文转拼音 * @param inputStr * @return */ public static String getPingYin(String inputStr) { if (inputStr == null || "".equals(inputStr)) { return ""; }
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); //UPPERCASE 大写 LOWERCASE 小写 format.setCaseType(HanyuPinyinCaseType.LOWERCASE); //WITH_TONE_NUMBER 音标用数字 WITHOUT_TONE 无音标 WITH_TONE_MARK 直接用音标 format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); //WITH_U_AND_COLON 用u表示ü WITH_V 用v表示ü WITH_U_UNICODE 用ü表示ü format.setVCharType(HanyuPinyinVCharType.WITH_V);
StringBuilder pYStr = new StringBuilder(); char[] input = inputStr.trim().toCharArray(); try { for (int i = 0; i < input.length; i++) { if (Character.toString(input[i]).matches("[\\u4E00-\\u9FA5]+")) { pYStr.append(PinyinHelper.toHanyuPinyinStringArray(input[i], format)[0]); } else if (!(input[i] == ' ')) { //过滤空格 pYStr.append(input[i]); } } } catch (BadHanyuPinyinOutputFormatCombination e) { e.printStackTrace(); } return pYStr.toString(); }}
复制代码

总结:通过以上步骤即可以获取钉钉下部门及人员信息,sql 表语句此处没有列出是大家可以自行根据上面 set 字段进行创建表即可

发布于: 刚刚阅读数: 4
用户头像

让技术不再枯燥,让每一位技术人爱上技术 2022.07.22 加入

还未添加个人简介

评论

发布
暂无评论
开源一夏 |企业内部应用接入钉钉获取部门及人员信息_开源_六月的雨在infoQ_InfoQ写作社区