项目实践-SpringBoot项目对接钉钉发送工作通知
**书山有路勤为径,学海无涯苦作舟**
记录程序员生活点点滴滴,希望记录的内容能帮助到努力爬山的各位伙伴!
标签:Java/钉钉/工作通知
前言
- 业务场景:目前很多企业在日常运行中的消息会议,工作通知,任务安排等信息一般都通过企业微信/邮件等通讯软件来进行交流和消息分发,避免了口头传达的不及时性和传递错误性。在笔者的项目研发中,业务中到审批流的消息分发,在支持企业微信/邮件等形式的基础上,开发支持钉钉发送工作通知消息的方式,毕竟支持通知的方式越多,说明系统的功能越完备嘛!
- 开发步骤:(这里以笔者自建的钉钉组织架构为例)
– 创建属于自己的企业管理平台(钉钉开放平台)
– 应用开发-企业内部应用-钉钉用用-H5微应用
– 参照开发者文档,设置微应用的权限/IP等信息(开发者文档-消息通知)
– 代码开发(下面会逐步介绍)
一、钉钉应用申请?
1.钉钉应用创建,若开发人员的钉钉账号已经是既有组织的平台管理账号,可以直接登录钉钉管理后台,若没有管理权限则可以通过管理员授权或者自己创建组织的形式来完成开发工作。
2.工作通知创建的应用类别为:企业内部应用–H5微应用,这里需要注意的是,应用创建完成后需要完成IP设置和权限设置
二、SpringBoot实现钉钉工作通知
1.引入钉钉SDK工具包pom依赖
<!--钉钉工具包-->
<dependency>
<groupId>com.dingtalk.api</groupId>
<artifactId>top-api-sdk</artifactId>
<version>2.0.0-RELEASE</version>
</dependency>
这里在引入SDK工具包的时候需要注意,多数环境的私服中不存在SDK的工具包,需要手动下载然后挂载到maven仓库中
- 挂载的过程
从官方或者笔者的资源中下载SDK工具包(可以私信我免费获取)
在项目控制台中通过命令将jar包挂载到仓库中
mvn install:install-file -DgroupId=com.dingtalk.api -DartifactId=top-api-sdk-dev -Dversion=ding-open-mc-SNAPSHOT -Dfile=lib/taobao-sdk-java-auto_1479188381469-20210630.jar -Dpackaging=jar -DgeneratePom=true
2.Nacos配置
dingding:
agentId: ********(按应用填写)
appKey: dingsg*********ceyk(按应用填写)
appSecret: pghvjQeW********vObLlkLlIh88ng0Elm42M***m8JhPa7CSciPntRjarjo(按应用填写)
# 获取Access_token
getTokenUrl: https://oapi.dingtalk.com/gettoken
# 根据电话号码获取urid
getByMobileUrl: https://oapi.dingtalk.com/user/get_by_mobile
# 发送消息通知
asyncMessageUrl: https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2
# 根据电话号码获取用户信息
userByMobileUrl: https://oapi.dingtalk.com/topapi/v2/user/getbymobile
# 更新通讯录用户
userUpdateUrl: https://oapi.dingtalk.com/topapi/v2/user/update
# 新增通讯录用户
userAddUrl: https://oapi.dingtalk.com/topapi/v2/user/create
备注:
笔者此处将应用的参数和涉及的开放Api配置到nacos中,避免在服务运行过程中因应用调整或Api升级需要重新调整项目代码。
3.实现钉钉工作通知
整体思路
- 同步系统平台人员到钉钉通讯录(根据项目需要进行同步,也可以选择不同步)
- 获取钉钉Access_Token
- 根据钉钉通知类别组装消息体
- 钉钉通知发送
A.获取Access_Token
/**
- @author Miracle
- @title: DingdingServiceImpl
- @projectName proxy
- @description: 【钉钉服务接口】Access_Token
- @date 2021/7/614:52
*/
@Service
@Slf4j
public class DingdingServiceImpl implements DingdingService {
@Value("${mare.loginUrl}")
private String loginUrl;
@Value("${dingding.agentId}")
private Long AgentId;
@Value("${dingding.appKey}")
private String APP_KEY;
@Value("${dingding.appSecret}")
private String APP_SECRET;
@Value("${dingding.getTokenUrl}")
private String getTokenUrl;
@Value("${dingding.getByMobileUrl}")
private String getByMobileUrl;
@Value("${dingding.asyncMessageUrl}")
private String asyncMessageUrl;
@Value("${dingding.userByMobileUrl}")
private String userByMobileUrl;
@Value("${dingding.userUpdateUrl}")
private String userUpdateUrl;
@Value("${dingding.userAddUrl}")
private String userAddUrl;
/**
* 获取AccessToken
* @return
*/
public String getAccessToken() throws ApiException {
DefaultDingTalkClient client =
new DefaultDingTalkClient(getTokenUrl);
OapiGettokenRequest request = new OapiGettokenRequest();
//Appkey
request.setAppkey(APP_KEY);
//Appsecret
request.setAppsecret(APP_SECRET);
/*请求方式*/
request.setHttpMethod("GET");
OapiGettokenResponse response = client.execute(request);
return response.getAccessToken();
}
}
B.同步平台人员到钉钉通讯录
/**
* 同步钉钉通讯录
*/
@Override
public void syncUsers() {
try {
// 获取钉钉AccessToken信息
String accessToken = this.getAccessToken();
log.info("获取钉钉AccessToken信息完成");
// 获取平台全量人员信息
Map<String, StaffObject> staffMap = getPlatformStaffs();
log.info("获取平台全量人员信息完成");
if(staffMap != null && staffMap.size() > 0){
for (Map.Entry<String, StaffObject> entry : staffMap.entrySet()){
StaffObject staff = entry.getValue();
// 根据平台人员手机账号判断是否存在
DingTalkClient client = new DefaultDingTalkClient(userByMobileUrl);
OapiV2UserGetbymobileRequest req = new OapiV2UserGetbymobileRequest();
req.setMobile(staff.getPhoneNum());
OapiV2UserGetbymobileResponse user = client.execute(req, accessToken);
// 返回码
String errcode = user.getErrorCode();
// 通讯录中存在该用户
if("0".equals(errcode) || errcode == "0"){
OapiV2UserGetbymobileResponse.UserGetByMobileResponse json = user.getResult();
String userId = json.getUserid();
DingTalkClient updateClient = new DefaultDingTalkClient(userUpdateUrl);
OapiV2UserUpdateRequest updateReq = new OapiV2UserUpdateRequest();
updateReq.setUserid(userId);
updateReq.setName(staff.getName());
// 用户信息更新
OapiV2UserUpdateResponse updateRst = updateClient.execute(updateReq, accessToken);
log.info("【钉钉通讯录更新】电话号码:" + staff.getPhoneNum() + ",更新结果:" + updateRst.getErrcode() + "/" + updateRst.getErrmsg());
}else {
// 新增用户
DingTalkClient addClient = new DefaultDingTalkClient(userAddUrl);
OapiV2UserCreateRequest addReq = new OapiV2UserCreateRequest();
addReq.setName(staff.getName());
addReq.setMobile(staff.getPhoneNum());
addReq.setDeptIdList("1");
OapiV2UserCreateResponse addRst = addClient.execute(addReq, accessToken);
log.info("【钉钉通讯录新增】电话号码:" + staff.getPhoneNum() + ",更新结果:" + addRst.getResult());
}
}
}
} catch (ApiException e) {
e.printStackTrace();
}
}
C.发送工作通知(以Text类型为例,其他类型可以参考开发者文档)
/**
* 发送钉钉消息
* @return
* @throws ApiException
*/
@Override
public boolean sendDingMsg(DingEntity dingEntity) throws ApiException {
Boolean sendResult = false;
// 开始获取钉钉Access_Token,开启消息通知
String accessToken = this.getAccessToken();
// 通知接收人电话号码
// String mobile = "15686457316,15712366325";
if(StringUtils.isBlank(mobile)){
return false;
}
String userIdList = "";
// 循环处理拼接用户列表
String[] split = mobile.split(",");
for(String cell : split){
DingTalkClient client2 = new DefaultDingTalkClient(getByMobileUrl);
OapiUserGetByMobileRequest req = new OapiUserGetByMobileRequest();
req.setMobile(cell);
req.setHttpMethod("GET");
OapiUserGetByMobileResponse rsp = client2.execute(req, accessToken);
// 获取的urid即为发送的目标人员的ID
String urid = rsp.getUserid();
// 将接受人员的urid按照(user123,user456)的形式拼接
userIdList = userIdList + urid + ",";
}
DingTalkClient client = new DefaultDingTalkClient(asyncMessageUrl);
OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
request.setUseridList(userIdList);
request.setAgentId(AgentId);
request.setToAllUser(false);
OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
// 消息类别时文本消息
msg.setMsgtype("text");
msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
// msg.getText().setContent("工作通知:你存在未处理的待办任务,请及时处理待办事项!");
request.setMsg(msg);
// 消息发送
OapiMessageCorpconversationAsyncsendV2Response dingResult = client.execute(request, accessToken);
JSONObject json = JSONObject.fromObject(dingResult);
return json.get("errcode").equals("0");
}
备注:
- 因为钉钉暂时不支持获取全量的通讯录信息,因此笔者采用通过号码校验的方式来判断通讯录人员是否存在,此处会存在资源浪费和效率地下的情况,大家可以考虑采用更优的方案解决。
- 钉钉消息通知的次数存在上限,具体信息参考官方开发者文档。
总结
登山路上的慕码人,理解不透的地方还请各位指点!
欢迎大家多多指正交流!