> 技术文档 > 使用钉钉开源api发送钉钉工作消息

使用钉钉开源api发送钉钉工作消息

在工作管理系统场景中,上下级和不同部门之间常常有请假,餐补等流程操作,而这些操作通常需要人员手动进行,这里我们引入一个钉钉的api,可以基于钉钉来发送工作消息通知

1、导入钉钉sdk
 com.aliyun alibaba-dingtalk-service-sdk 2.0.0   com.aliyun dingtalk 2.2.26 
2、登录钉钉开发者后台,选择租户

3、点击右上角创建应用

4、申请开通工作消息API基础权限

5、获取企业AngentId并获取ClientID和ClientSecret,用于后续程序中获取token

6、配置clientId和clientSecret

7、进行api的调用和业务逻辑的开发(这里我封装了一个接口用于发送钉钉消息,方便前端调用)
@Tag(name = \"钉钉-发送工作消息\")@RestController@RequestMapping(\"/dingtalk\")@Validatedpublic class DingTalkController { @Resource private DingTalkService dingTalkService; @PostMapping(\"/sendSubmitMessage\") @Operation(summary = \"钉钉发送消息通知提交餐补证明\")/* @PreAuthorize(\"@ss.hasPermission(\'dingtalk:hr:sendsubmitmsg\')\")*/ public CommonResult sendSubmitMessage(@RequestBody List ids) { Boolean result = dingTalkService.sendSubmitMessageToUser(ids); return success(result); } @PostMapping(\"/sendReSubmitMessage\") @Operation(summary = \"钉钉发送消息通知重新提交餐补证明\") /*@PreAuthorize(\"@ss.hasPermission(\'dingtalk:hr:sendremsg\')\")*/ public CommonResult sendReSubmitMessage(@RequestParam Long poofId, @RequestParam String remark) { dingTalkService.sendReSubmitMessageToUser(poofId, remark); return success(true); }}
这里我们以发送上传餐补证明消息给指定用户接口为例
@Service@Slf4jpublic class DingTalkServiceImpl implements DingTalkService { // 注入钉钉应用的 AppKey 和 AppSecret @Value(\"${justauth.type.DINGTALK.client-id}\") private String clientId; @Value(\"${justauth.type.DINGTALK.client-secret}\") private String clientSecret; private static final String DINGTALK_API_BASE_URL = \"https://oapi.dingtalk.com\"; private static final String GET_TOKEN_URL = \"/gettoken\"; @Resource private AdminUserApi adminUserApi; @Resource private RestTemplate restTemplate; @Resource private MealAllowanceProofMapper mealAllowanceProofMapper; @Resource private MealAllowanceDataMapper mealAllowanceDataMapper; @Override public Boolean sendSubmitMessageToUser(List userIds) { /** * 发送钉钉消息 * @param */ //遍历用户id Boolean result = true; for (Long userId : userIds) { //通过用户id得到对应用户的钉钉id String userRemark = adminUserApi.getUserRemark(userId).replaceAll(\"\\\\D+\", \"\"); //通过用户id得到对应用户的餐补总金额 BigDecimal totalAmount = mealAllowanceDataMapper.selectByUserId(userId).getTotalAmount(); // 调用下方方法发送 result = sendSingleUserNotice(userRemark, totalAmount); if (!result) { throw exception(DING_TALK_SEND_MESSAGE_ERROR); } } return result; }
发送消息体封装逻辑和消息外观构造:
@SneakyThrows private Boolean sendSingleUserNotice(String dingUserId, BigDecimal amount){ //获取AccessToken String accessToken = getAccessToken(); //\"https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2\"为钉钉发送消息的接口请求地址 DingTalkClient client = new DefaultDingTalkClient(\"https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2\"); //构建消息请求体 OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request(); request.setAgentId(#自己企业的AngentId#); //设置发送给对应用户的钉钉id request.setUseridList(dingUserId); //不发给全体成员 request.setToAllUser(false); //构建PC端和移动端的url跳转路径地址,点击路径可以跳转到提交餐补信息的平台 String PcUrl = \"http://effi.fzxs.com.cn:8089/overtime/meal-allowance\"; String mobileUrl = \"dingtalk://dingtalkclient/page/link?url=\" + URLEncoder.encode(PcUrl, \"UTF-8\") + \"&pc_slide=false\"; // 使用ActionCard消息类型创建带按钮的消息 OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg(); msg.setMsgtype(\"action_card\"); // 创建ActionCard消息 OapiMessageCorpconversationAsyncsendV2Request.ActionCard actionCard = new OapiMessageCorpconversationAsyncsendV2Request.ActionCard(); // 设置消息标题 actionCard.setTitle(\"💰 加班餐补通知\"); // 构建精美的Markdown内容 StringBuilder content = new StringBuilder(); content.append(\"## 你有新的加班餐补啦 \\n\\n\"); content.append(\"### **💰餐补金额: ¥\").append(amount.toString()).append(\"**\\n\\n\"); content.append(\"**请及时上传:** 餐饮消费凭证截图,不要让hr小姐姐久等啦 \\n\\n\"); content.append(\"⚠️ **截止时间:** 2个工作日内,过期作废\"); actionCard.setMarkdown(content.toString()); // 设置按钮布局为竖直排列 actionCard.setBtnOrientation(\"0\"); // 创建按钮列表 List btnList = new ArrayList(); // 添加上传证明按钮 OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList uploadBtn = new OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList(); uploadBtn.setTitle(\"立即上传餐补证明\"); uploadBtn.setActionUrl(mobileUrl); btnList.add(uploadBtn); actionCard.setBtnJsonList(btnList); msg.setActionCard(actionCard); request.setMsg(msg); try { OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request, accessToken); if (response.getErrcode() == 0) { log.info(\"[sendSingleUserNotice][发送餐补通知成功] userId={}, amount={}, taskId={}\", dingUserId, amount, response.getTaskId()); return true; } else { log.error(\"[sendSingleUserNotice][发送餐补通知失败] userId={}, errcode={}, errmsg={}\", dingUserId, response.getErrcode(), response.getErrmsg()); return false; } } catch (ApiException e) { log.error(\"[sendSingleUserNotice][发送餐补通知异常] userId={}, error={}\", dingUserId, e.getMessage(), e); throw ServiceExceptionUtil.exception(DING_TALK_SEND_MESSAGE_ERROR); } } /** * 创建美观的钉钉卡片消息 * * @param title 卡片标题 * @param content 卡片内容 * @param pcUrl PC端链接 * @param mobileUrl 移动端链接 * @return ActionCard对象 */ private OapiMessageCorpconversationAsyncsendV2Request.ActionCard createBeautifulActionCard( String title, String content, String pcUrl, String mobileUrl) { OapiMessageCorpconversationAsyncsendV2Request.ActionCard actionCard = new OapiMessageCorpconversationAsyncsendV2Request.ActionCard(); actionCard.setTitle(title); actionCard.setMarkdown(content); actionCard.setBtnOrientation(\"1\"); // 添加操作按钮 List btnList = new ArrayList(); // 移动端按钮 OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList mobileBtn = new OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList(); mobileBtn.setTitle(\"📱 移动端处理\"); mobileBtn.setActionUrl(mobileUrl); btnList.add(mobileBtn); // PC端按钮 OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList pcBtn = new OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList(); pcBtn.setTitle(\"💻 电脑端处理\"); pcBtn.setActionUrl(pcUrl); btnList.add(pcBtn); actionCard.setBtnJsonList(btnList); return actionCard; }
获取accessToken方法封装:
/** * 获取钉钉访问令牌 * @return */ public String getAccessToken() { try { String url = UriComponentsBuilder.fromHttpUrl(DINGTALK_API_BASE_URL + GET_TOKEN_URL)  .queryParam(\"appkey\", clientId)  .queryParam(\"appsecret\", clientSecret)  .toUriString(); ResponseEntity response = restTemplate.getForEntity(url, String.class); JSONObject result = JSON.parseObject(response.getBody()); if (result.getInteger(\"errcode\") != 0) { log.error(\"获取钉钉访问令牌失败:{}\", result.getString(\"errmsg\")); throw exception(AUTH_ACCESS_TOKEN_ERROR); } return result.getString(\"access_token\"); } catch (Exception e) { log.error(\"获取钉钉访问令牌异常\",e); throw exception(AUTH_ACCESS_TOKEN_ERROR); } }