钉钉发送消息(非群机器人)
保姆式记录,亲测
一、钉钉的准备工作
首先进入钉钉的开发者后台 https://open.dingtalk.com/
应用开发—> 企业应用开发
进入之后选择创建应用
小程序和h5微应用都可以。这里只是把他们作为一个载体,只需要他们的一些对应信息就可以了,不需要前端进行开发对应的应用,如果前端想开发那也可以。
接下来就是点击自己创建的应用
最重要的就是下面的三个参数
AgentId
AppKey
AppSecret
这里的服务器出口ip地址,就是你本地服务器的公网地址,如果是本地测试不知道的话,后面调用钉钉接口,获得access_token 时候,会报错(某某地址不是白名单ip,这是你把他提示的地址放在下面就好了)
然后就是下面的权限管理
一般是全部员工,然后,你想调用那个接口就申请那个权限。如果你不知道申请那个权限可以再他的官方文档里找,那里有提示。
(建议不管是新旧API,找到符合你需求的即可)
因为这里是做的发送消息通知,那么就需要通讯录的权限,找到通讯录,把需要的都选了。
二、开发的准备工作
-
pom的导入
<!-- 钉钉 --> <dependency> <groupId>com.aliyun</groupId> <artifactId>dingtalk</artifactId> <version>1.2.15</version> </dependency> <dependency> <groupId>com.aliyun</groupId> <artifactId>alibaba-dingtalk-service-sdk</artifactId> <version>2.0.0</version> </dependency>
-
配置文件(yml配置文件)
dingtalk: #钉钉--消息通知 agentId: 146xxxcs appKey: dingwxsssdcs appSecret: jHsdsBvsdsdsdccccsss
这里需要的参数,在前面已经说了再那里找
-
配置类
@Data @Configuration @ConfigurationProperties(prefix="dingtalk") public class DingTalkProperties { /** * AgentId */ private String agentId; /** * AppKey */ private String appKey; /** * AppSecret */ private String appSecret; }
-
工具类
-
首先获得对应的access_token
/** * @date 2022/2/15 10:31 * 钉钉发送消息工具类 */ @Slf4j @Component @AllArgsConstructor public class DingTalkUtil { private final DingTalkProperties dingTalkProperties; /** * 使用钉钉自带的方法去获取通行证 * 获取钉钉的token * * @return access_token */ public String getAccessToken() { try { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken"); OapiGettokenRequest request = new OapiGettokenRequest(); request.setAppkey(dingTalkProperties.getAppKey()); request.setAppsecret(dingTalkProperties.getAppSecret()); request.setHttpMethod("GET"); OapiGettokenResponse response = client.execute(request); return response.getAccessToken(); } catch (ApiException e) { log.error("请求获取钉钉的access_token失败:{}", e.getErrMsg()); } return null; }
-
根据这个access_token就是获得了对应的接口凭证,现在根据api
根据用户电话获得钉钉的userId
/** * 使用钉钉自带的方法,获取钉钉的用户的userid * * @param phone 用户电话 * @return 钉钉用户内部userId */ public String getDingTalkUserId(String phone) { String accessToken = this.getAccessToken(); if (accessToken == null) { throw new CiErrorException(63001, "钉钉出现异常,没有获取到对应的access_token,请联系管理员进行检查!"); } try { 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); //把userId存入数据库,这里的userId是不变的,可以存入数据库 String userId = rsp.getResult().getUserid(); return userId; } catch (ApiException e) { log.error("请求获取钉钉用户的userid失败:{}", e.getErrMsg()); } return null; }
-
根据userId可以发送消息
这里采用的是工作消息(消息类型是oa)
/** * 多条发送消息 * 钉钉发送工作通知(oa) * 注意请求接口的时候的参数配置,这里采用的是发送oa消息 * 钉钉接口文档地址:https://open.dingtalk.com/document/orgapp-server/asynchronous-sending-of-enterprise-session-messages * * @param userIdList 钉钉内部用户id列表,多个用户id用 ' ,' 分割 * @param msgVO 内容(类型不同内容不同) */ public void sendDingTalkMsg(String userIdList, MsgVO msgVO) { String accessToken = this.getAccessToken(); if (accessToken == null) { throw new CiErrorException(63001, "钉钉出现异常,没有获取到对应的access_token,请联系管理员进行检查!"); } try { DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2"); OapiMessageCorpconversationAsyncsendV2Request req = new OapiMessageCorpconversationAsyncsendV2Request(); req.setAgentId(Long.parseLong(dingTalkProperties.getAgentId())); req.setUseridList(userIdList); //设置消息发送类型 OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); msg.setMsgtype("oa"); //设置跳转链接 OapiMessageCorpconversationAsyncsendV2Request.OA oa = new OapiMessageCorpconversationAsyncsendV2Request.OA(); oa.setPcMessageUrl(msgVO.getPcMessageUrl()); oa.setMessageUrl(msgVO.getMessageUrl()); //设置消息主题 OapiMessageCorpconversationAsyncsendV2Request.Body body = new OapiMessageCorpconversationAsyncsendV2Request.Body(); //设置作者 body.setAuthor("xxxx"); //设置通知消息标题 body.setTitle(msgVO.getTitle()); //设置表单内容 body.setForm(this.setMsgForm(msgVO.getFormVOList())); oa.setBody(body); //设置状态提示栏 OapiMessageCorpconversationAsyncsendV2Request.StatusBar statusBar = new OapiMessageCorpconversationAsyncsendV2Request.StatusBar(); //设置状态提示颜色 statusBar.setStatusBg("0xFFF65E5E"); //设置状态提示内容 statusBar.setStatusValue(msgVO.getStatusContent()); oa.setStatusBar(statusBar); //设置头部内容 OapiMessageCorpconversationAsyncsendV2Request.Head head = new OapiMessageCorpconversationAsyncsendV2Request.Head(); head.setBgcolor("0xFFF65E5E"); oa.setHead(head); msg.setOa(oa); req.setMsg(msg); OapiMessageCorpconversationAsyncsendV2Response rsp = client.execute(req, accessToken); } catch (ApiException e) { log.error("发送钉钉消息失败:{}", e.getErrMsg()); } } /** * 设置发送消息的表单 * * @param list 消息表单 * @return 处理表单 */ private List<OapiMessageCorpconversationAsyncsendV2Request.Form> setMsgForm(List<FormVO> list) { List<OapiMessageCorpconversationAsyncsendV2Request.Form> formList = new ArrayList<>(7); for (FormVO formVO : list) { OapiMessageCorpconversationAsyncsendV2Request.Form form = new OapiMessageCorpconversationAsyncsendV2Request.Form(); form.setKey(formVO.getKey()); form.setValue(formVO.getValue()); formList.add(form); } return formList; }
这里对应的vo
import lombok.Data; /** * @author zwh * @date 2022/2/15 20:21 * 钉钉发送消息表单实体类 * * 钉钉最多展示是6个,多的就会折叠不显示 */ @Data public class FormVO { /** * 键 */ private String key; /** * 值 */ private String value; }
import lombok.Data; import java.util.List; /** * @date 2022/2/15 20:35 * 钉钉发送消息实体类 */ @Data public class MsgVO { /** * 移动端跳转url */ private String messageUrl; /** * PC端跳转url */ private String pcMessageUrl; /** * body参数中的正文标题 */ private String title; /** * body参数中的表单数据 */ private List<FormVO> formVOList; /** * 状态提示消息 */ private String statusContent; }
-
-
然后只要调用这里面的发送消息的方法就可以了,但是必须满足对应的参数。
当前也可以使用其他方式的消息类型,我这边使用了最复杂的一个,因为业务需要。
三、总结
这里的所有方法都是从钉钉的调试里面进行修改的,可以直接现在钉钉的调试中进行调试,然后再把代码借鉴过来,然后进行修改,符合自己的需求就可以了。
(1)、获取企业内部的access_token https://open.dingtalk.com/document/orgapp-server/obtain-orgapp-token
(2)、根据用户phone获得userId https://open.dingtalk.com/document/orgapp-server/query-users-by-phone-number
(3)、发送工作通知 https://open.dingtalk.com/document/orgapp-server/asynchronous-sending-of-enterprise-session-messages
消息类型 https://open.dingtalk.com/document/orgapp-server/message-types-and-data-format
一定要好好的阅读钉钉的接口文档,并且使用他们的原生方法,节省时间(自己能力不足,所以直接那人家的方法用)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ItIm7NeO-1645434398518)(C:\Users\Yuki\AppData\Roaming\Typora\typora-user-images\image-20220221170307997.png)]
ment/orgapp-server/query-users-by-phone-number>
(3)、发送工作通知 https://open.dingtalk.com/document/orgapp-server/asynchronous-sending-of-enterprise-session-messages
消息类型 https://open.dingtalk.com/document/orgapp-server/message-types-and-data-format
一定要好好的阅读钉钉的接口文档,并且使用他们的原生方法,节省时间(自己能力不足,所以直接那人家的方法用)
注意: 这里的消息不会发送重复消息,比如你把一条消息发给三个人,但是你在把这样的消息发给其他的四个人,那么这后面的四个人是收不到消息的,因为钉钉任务你在发送重复消息。