当前位置: 首页 > news >正文

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

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

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

3、点击右上角创建应用

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

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

6、配置clientId和clientSecret

7、进行api的调用和业务逻辑的开发(这里我封装了一个接口用于发送钉钉消息,方便前端调用)
@Tag(name = "钉钉-发送工作消息")
@RestController
@RequestMapping("/dingtalk")
@Validated
public class DingTalkController {@Resourceprivate DingTalkService dingTalkService;@PostMapping("/sendSubmitMessage")@Operation(summary = "钉钉发送消息通知提交餐补证明")
/*    @PreAuthorize("@ss.hasPermission('dingtalk:hr:sendsubmitmsg')")*/public CommonResult<Boolean> sendSubmitMessage(@RequestBody List<Long> ids) {Boolean result = dingTalkService.sendSubmitMessageToUser(ids);return success(result);}@PostMapping("/sendReSubmitMessage")@Operation(summary = "钉钉发送消息通知重新提交餐补证明")/*@PreAuthorize("@ss.hasPermission('dingtalk:hr:sendremsg')")*/public CommonResult<Boolean> sendReSubmitMessage(@RequestParam Long poofId, @RequestParam String remark) {dingTalkService.sendReSubmitMessageToUser(poofId, remark);return success(true);}
}
这里我们以发送上传餐补证明消息给指定用户接口为例
@Service
@Slf4j
public 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";@Resourceprivate AdminUserApi adminUserApi;@Resourceprivate RestTemplate restTemplate;@Resourceprivate MealAllowanceProofMapper mealAllowanceProofMapper;@Resourceprivate MealAllowanceDataMapper mealAllowanceDataMapper;@Overridepublic Boolean sendSubmitMessageToUser(List<Long> userIds) {/*** 发送钉钉消息* @param*///遍历用户idBoolean result = true;for (Long userId : userIds) {//通过用户id得到对应用户的钉钉idString 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;}
发送消息体封装逻辑和消息外观构造:
@SneakyThrowsprivate Boolean sendSingleUserNotice(String dingUserId, BigDecimal amount){//获取AccessTokenString 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#);//设置发送给对应用户的钉钉idrequest.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<OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList> 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<OapiMessageCorpconversationAsyncsendV2Request.BtnJsonList> 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<String> 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);}}

http://www.lryc.cn/news/598720.html

相关文章:

  • kafka的shell操作
  • kafka消费者组消费进度(Lag)深入理解
  • 【阿里云-ACP-1】疑难题解析
  • 力扣189:轮转数组
  • Linux基础服务(autofs和Samba)
  • 深圳三维扫描铸件形位公差尺寸测量3d偏差检测-中科米堆CASAIM
  • LeetCode 2322:从树中删除边的最小分数
  • Elasticsearch 的聚合(Aggregations)操作详解
  • multiprocessing 模块及其底层机制 spawn_main 在大模型应用中的场景
  • STM32-FSMC
  • multiprocessing模块使用方法(一)
  • S7-1500 与 ET200MP 的组态控制通信(Configuration Control)功能实现详解(上)
  • 设备虚拟化技术IRF
  • 力扣刷题(第九十七天)
  • 智慧驾驶疲劳检测算法的实时性优化
  • 「Linux命令基础」用户和用户组实训
  • 雷达使用的MSOP端口和DIFOP端口是什么意思
  • Spring-狂神说
  • Claude4、GPT4、Kimi K2、Gemini2.5、DeepSeek R1、Code Llama等2025主流AI编程大模型多维度对比分析报告
  • 【PZ-ZU7EV-KFB】——ZYNQ UltraScale + ZU7EV开发板ARM/FPGA异构计算开发平台,赋能多域智能硬件创新
  • python学习xlsx表格导入mysql脚本 + leetcode19删除链表倒N + python与本地mysql连接不上排错
  • 游戏开发Unity/ ShaderLab学习路径
  • rust-数据结构
  • 20250724-day21
  • Qt 调用ocx的详细步骤
  • 解决 SQL 错误 [1055]:深入理解 only_full_group_by 模式下的查询规范
  • R study notes[1]
  • 完成多项问题修复,MaxKB开源企业级智能体平台v1.10.9 LTS版本发布
  • C++图论全面解析:从基础概念到算法实践
  • 学习游戏制作记录(技能系统)7.24