在工作管理系统场景中,上下级和不同部门之间常常有请假,餐补等流程操作,而这些操作通常需要人员手动进行,这里我们引入一个钉钉的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.pswp.cn/news/916303.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/916303.shtml
英文地址,请注明出处:http://en.pswp.cn/news/916303.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

拒绝SQL恐惧:用Python+pyqt打造任意Excel数据库查询系统

一、引言 在数字化转型浪潮中&#xff0c;超过76%的基层业务人员仍被困在"SQL恐惧症"的泥潭里——他们精通业务逻辑却受限于技术门槛&#xff0c;面对海量数据时只能反复请求IT部门协助。本项目通过PythonPyQt来构建基于Excel风格的查询系统&#xff0c;从而打破这种…

KubeKey安装KubeSphere、部署应用实践问题总结

使用KubeSphere的KubeKey 安装K8s 集群过程中&#xff0c;碰到了一些问题&#xff0c;现在都一一解决了&#xff0c;以此记录一下。 kubekey 安装k8s 集群报错 execute task timeout, Timeout1m error: Pipeline[CreateClusterPipeline] execute failed: Module[GreetingsModul…

基于粒子群优化的PID控制在药液流量控制系统中的应用

基于粒子群优化的PID控制在药液流量控制系统中的应用 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家,觉得好请收藏。点击跳转到网站。 1. 引言 在现代工业控制系统中,精确的流量控制是许多生产过程的关键环节。本文针对药液流量控制…

不用电脑要不要关机?

1. 短时间不用&#xff08;午休、临时外出&#xff09;&#xff1a;建议「睡眠」或「休眠」睡眠&#xff1a;电脑暂停工作&#xff0c;唤醒速度快&#xff0c;耗电较少适合需要快速恢复工作的场景休眠&#xff1a;整机断电&#xff0c;唤醒速度比睡眠慢&#xff0c;但完全不耗电…

【Spring AI】SiliconFlow-硅基流动

硅基流动 https://docs.siliconflow.cn/cn/userguide/introduction

swagger基本注解@Tag、@Operation、@Parameters、@Parameter、@ApiResponse、@Schema

swagger基本注解 Tag 介绍&#xff1a;用于给接口分组&#xff0c;用途类似于为接口文档添加标签。用于&#xff1a;方法、类、接口。常用属性&#xff1a; name&#xff1a;分组的名称 RestController RequestMapping("/sysUser") Tag(name "管理员接口&quo…

Unity 实现帧率(FPS)显示功能

一、功能介绍本教程实现一个 FPS 显示脚本&#xff0c;支持 TextMeshProUGUI 组件。脚本会每秒更新一次帧率&#xff0c;并显示在 UI 上&#xff0c;便于开发和调试时观察性能变化。二、完整代码将以下代码保存为 FPS.cs 脚本&#xff1a;using UnityEngine; using TMPro;[Requ…

【星野AI】minimax非活动时间充值优惠漏洞

点开发现有活动即将开启。把手机时间修改为20250729&#xff0c;或者其它活动内时间。发现活动的充值接口未进行时间校验。叠加新人首充优惠&#xff0c;充值六元&#xff0c;获得1800钻。在非活动时间获取了优惠。

Python 程序设计讲义(22):循环结构——for 循环

Python 程序设计讲义&#xff08;22&#xff09;&#xff1a;循环结构——for 循环 目录Python 程序设计讲义&#xff08;22&#xff09;&#xff1a;循环结构——for 循环一、for 循环的语法二、for 循环执行的流程三、for 循环应用举例while 循环的循环次数往往是不确定的&am…

自动驾驶---视觉语言模型(VLM)引导的模型预测控制器(MPC)

1 背景之前大家普遍认为的端到端就是传感器输入&#xff0c;控制输出&#xff0c;这也确实是真正的端到端&#xff0c;但目前车企走的更多的是轨迹生成。自动驾驶端到端控制瓶颈主要有以下两点&#xff1a;可解释性缺失&#xff1a;传统端到端模型&#xff08;如纯VLM控制器&am…

最优估计准则与方法(5)加权最小二乘估计(WLS)_学习笔记

前言 最优估计理论中研究的最小二乘估计&#xff08;LS&#xff09;为线性最小二乘估计&#xff08;LLS&#xff09;&#xff0c;包括古典最小二乘估计&#xff08;CLS&#xff09;[1]、加权最小二乘估计&#xff08;WLS&#xff09;和递推最小二乘估计&#xff08;RLS&#x…

Linux——线程互斥

文章目录一、有关概念原子性错误认知澄清加锁二、锁的相关函数全局锁局部锁初始化销毁加锁解锁三、锁相关如何看待锁一个线程在执行临界区的代码时&#xff0c;可以被切换吗&#xff1f;锁是本身也是临界资源&#xff0c;它如何做到保护自己&#xff1f;&#xff08;锁的实现&a…

扣子(Coze)宣布开源两大核心项目——Coze Studio(扣子开发平台)和Coze Loop(扣子罗盘),附安装步骤

2025年7月26日,字节跳动旗下AI开发平台“扣子(Coze)”宣布开源两大核心项目——Coze Studio(扣子开发平台)和Coze Loop(扣子罗盘),采用Apache 2.0协议,支持免费商用及本地化部署。 开源内容 Coze Studio:提供可视化AI智能体开发工具,支持零代码/低代码拖拽式工作流编…

InfluxDB Flux 查询协议实战应用(二)

四、实战案例解析4.1 服务器性能监控数据查询在服务器性能监控场景中&#xff0c;InfluxDB 和 Flux 查询协议能够发挥重要作用&#xff0c;帮助运维人员实时了解服务器的运行状态&#xff0c;及时发现性能问题。假设我们的服务器性能监控数据存储在名为server-monitoring的存储…

二层隧道协议(PPP、PPTP、L2TP)

PPP —— 点对点链路上的“链路层会话层”协议&#xff0c;解决拨号认证、IP 分配和多协议封装。PPTP —— 在 IP 网络里开一条“PPP-over-GRE”隧道&#xff0c;把 PPP 封装进公共网络&#xff0c;速度快但已不安全。L2TP —— 在 IP/UDP 里再开一条“PPP-over-UDP”隧道&…

openmv特征点检测

AGAST 角点检测器和 FAST 角点检测器&#xff1a; 两者都是计算机视觉中快速检测图像角点的算法&#xff0c;核心目的是高效找到图像中 "有辨识度的点"&#xff0c;但细节略有不同&#xff1a; &#xff08;1&#xff09;FAST 角点检测器 • 特点&#xff1a;速度极快…

基于深度学习的CT图像3D重建技术研究

基于深度学习的CT图像3D重建技术研究 摘要 本文详细探讨了使用深度学习技术进行CT(计算机断层扫描)图像3D重建的全过程。我们从CT成像基本原理出发,系统介绍了数据预处理、深度学习模型构建、训练优化以及三维可视化等关键技术环节。研究采用了先进的深度学习架构如3D U-Net…

JVM相关面试八股

什么是双亲委派模型&#xff1f; 如果一个类加载器在接到加载类的请求时&#xff0c;它首先不会自己尝试去加载这个类&#xff0c;而是把这个请求任务委托给父类加载器去完成&#xff0c;依次递归&#xff0c;如果父类加载器可以完成类加载任务&#xff0c;就返回成功&#xff…

Javaweb————HTTP消息体拆分讲解

❤️❤️❤️一.HTTP请求消息结构 &#xff08;1&#xff09;请求行 &#x1f499; 请求方法 &#x1f499;URL地址 &#x1f499;协议名 &#xff08;2&#xff09;请求头 报文头包含若千个属性格式为“属性名:属性值”, 服务端据此获取客户端的基本信息 &#xff08;3&…

GitHub的免费账户的存储空间有多少?

GitHub的免费账户在存储空间方面的具体限制如下: 一、普通仓库(非LFS)存储限制 公共仓库 总存储:无明确总容量限制,但建议单个仓库不超过1GB以确保性能。若仓库过大(如超过5GB),可能会收到GitHub的优化提示邮件。 文件大小:单个文件最大100MB,超过100MB的文件会被直…