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

企业微信、飞书、钉钉机器人消息发送工具类

1、实例化WebClient对象

其实你也可以使用RestTemplate,我这里主要是用到了webflux框架,所以需要实例化客户端请求对象

@Bean
public WebClient webClient(){HttpClient httpClient = getHttpClient();return WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build();
}private HttpClient getHttpClient() {ConnectionProvider provider = ConnectionProvider.builder("你爱咋咋的,一般用你项目名即可").maxConnections(500).maxIdleTime(Duration.ofSeconds(10)).maxLifeTime(Duration.ofSeconds(20)).pendingAcquireTimeout(Duration.ofSeconds(30)).pendingAcquireTimer((r, d) -> {Timeout t = wheel.newTimeout(timeout -> r.run(), d.toMillis(), TimeUnit.MILLISECONDS);return () -> t.cancel();}).fifo().build();HttpClient httpClient = HttpClient.create(provider);return httpClient;
}

2、发送及有效性测试工具类


import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;import static com.paratera.console.notice.utils.Constants.*;/*** 机器人发送工具类(微信,飞书,钉钉)** @author huxiang*/
@Component
@Slf4j
public class RobotUtil {@Autowiredprivate WebClient webClient;/*** 机器人发送消息(markdown格式)** @param robotUrl   机器人地址* @param type       类型:1微信,2飞书,3钉钉* @param context    markdown文本内容* @param signSecret 签名校验(飞书,钉钉使用,可为空,具体要根据用户是否启用签名)*/public void sendMsg(String robotUrl, Integer type, String context, String signSecret) {JSONObject msgObj = JSONUtil.createObj();JSONObject mdObj = JSONUtil.createObj();switch (type) {case ROBOT_TYPE_WX:msgObj.set("msgtype", "markdown");mdObj.set("content", context);msgObj.set("markdown", mdObj);break;case ROBOT_TYPE_FS:if (StringUtils.isNotEmpty(signSecret)) {msgObj = getFsSignObj(signSecret);}msgObj.set("msg_type", "interactive");mdObj.set("tag", "lark_md");mdObj.set("content", context);JSONArray elements = JSONUtil.createArray();JSONObject wrapObj = JSONUtil.createObj();wrapObj.set("tag", "div");wrapObj.set("text", mdObj);elements.put(wrapObj);JSONObject cardObj = JSONUtil.createObj();cardObj.set("elements", elements);msgObj.set("card", cardObj);break;case ROBOT_TYPE_DD:if (StringUtils.isNotEmpty(signSecret)) {robotUrl = getDdRobotURL(robotUrl, signSecret);}msgObj.set("msgtype", "markdown");mdObj.set("title", "通知");mdObj.set("text", context);msgObj.set("markdown", mdObj);break;}webClient.post().uri(robotUrl).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(msgObj)).retrieve().bodyToMono(String.class).subscribe(result -> {log.info("机器人通知发送结果:" + result);});}/*** 机器人有效性测试 0表示成功,其他表示失败** @param robotUrl   机器人地址* @param type       类型:1微信,2飞书,3钉钉* @param signSecret 签名校验(飞书,钉钉使用,可为空,具体要根据用户是否启用签名)* @return*/public Integer sendTestMsg(String robotUrl, Integer type, String signSecret) {JSONObject msgObj = JSONUtil.createObj();JSONObject mdObj = JSONUtil.createObj();ObjectMapper mapper = new ObjectMapper();switch (type) {case ROBOT_TYPE_WX:msgObj.set("msgtype", "markdown");mdObj.set("content", "机器人有效性测试!");msgObj.set("markdown", mdObj);break;case ROBOT_TYPE_FS:if (StringUtils.isNotEmpty(signSecret)) {msgObj = getFsSignObj(signSecret);}msgObj.set("msg_type", "interactive");mdObj.set("tag", "lark_md");mdObj.set("content", "机器人有效性测试!");JSONArray elements = JSONUtil.createArray();JSONObject wrapObj = JSONUtil.createObj();wrapObj.set("tag", "div");wrapObj.set("text", mdObj);elements.put(wrapObj);JSONObject cardObj = JSONUtil.createObj();cardObj.set("elements", elements);msgObj.set("card", cardObj);break;case ROBOT_TYPE_DD:if (StringUtils.isNotEmpty(signSecret)) {robotUrl = getDdRobotURL(robotUrl, signSecret);}msgObj.set("msgtype", "markdown");mdObj.set("title", "通知");mdObj.set("text", "机器人有效性测试!");msgObj.set("markdown", mdObj);break;}Mono<String> mono = webClient.post().uri(robotUrl).contentType(MediaType.APPLICATION_JSON).body(BodyInserters.fromValue(msgObj)).retrieve().bodyToMono(String.class);String result = mono.block();try {Map res = mapper.readValue(result, Map.class);return (Integer) (res.containsKey("errcode") ? res.get("errcode") : res.get("code"));} catch (JsonProcessingException e) {log.error("类型转换异常-RobotUtil.sendTestMsg:" + e);}return -1;}/*** 飞书获取带签名的消息体** @return*/public JSONObject getFsSignObj(String signSecret) {JSONObject signObj = JSONUtil.createObj();Long timestamp = DateUtil.currentSeconds();String sign = null;try {//把timestamp+"\n"+密钥当做签名字符串String stringToSign = timestamp + "\n" + signSecret;//使用HmacSHA256算法计算签名Mac mac = Mac.getInstance("HmacSHA256");mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));byte[] signData = mac.doFinal(new byte[]{});sign = Base64.encodeBase64String(signData);} catch (Exception e) {log.error("飞书获取签名失败:" + e);}if (StringUtils.isEmpty(sign)) {return null;}signObj.set("timestamp", timestamp);signObj.set("sign", sign);return signObj;}/*** 钉钉获取带签名的机器人推送URL** @return*/public String getDdRobotURL(String robotUrl, String signSecret) {Long timestamp = System.currentTimeMillis();String stringToSign = timestamp + "\n" + signSecret;String sign = null;try {Mac mac = Mac.getInstance("HmacSHA256");mac.init(new SecretKeySpec(signSecret.getBytes("UTF-8"), "HmacSHA256"));byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));sign = URLEncoder.encode(Base64.encodeBase64String(signData), "UTF-8");} catch (Exception e) {log.error("钉钉获取签名失败:" + e);}if (StringUtils.isEmpty(sign)) {return null;}return robotUrl + "&timestamp=" + timestamp + "&sign=" + sign;}
}

相关文章:

企业微信、飞书、钉钉机器人消息发送工具类

1、实例化WebClient对象 其实你也可以使用RestTemplate&#xff0c;我这里主要是用到了webflux框架&#xff0c;所以需要实例化客户端请求对象 Bean public WebClient webClient(){HttpClient httpClient getHttpClient();return WebClient.builder().clientConnector(new R…...

手撕 视觉slam14讲 ch7 / pose_estimation_3d2d.cpp (1)

首先理清我们需要实现什么功能&#xff0c;怎么实现&#xff0c;提供一份整体逻辑&#xff1a;包括主函数和功能函数 主函数逻辑&#xff1a; 1. 读图,两张rgb&#xff08;cv::imread&#xff09; 2. 找到两张rgb图中的特征点匹配对 2.1定义所需要的参数&#xff1a;keypoints…...

Mac安装Dart时,Homebrew报错 Error: Failure while executing

前言&#xff1a; 最近准备开发Flutter项目时&#xff0c;在安装环境时&#xff0c;安装Homebew时遇到了以下报错信息&#xff0c;在这里分享一下。 报错信息&#xff1a; ~ % brew tap dart-lang/dart > Tapping dart-lang/dart Cloning into /opt/homebrew/Library/Tap…...

SSM整合~

构建并配置项目&#xff1a; 第一步&#xff1a;创建maven项目 第二步&#xff1a;配置pom.xml文件 设置打包方式&#xff1a; 为了方便部署&#xff0c;我们通常情况下&#xff0c;将项目打包为WAR&#xff0c;因为WAR文件是一种可执行的压缩文件&#xff0c;它可以将项目…...

Self-supervised 3D Human Pose Estimation from a Single Image

基于单幅图像的自监督三维人体姿态估计 主页&#xff1a; https://josesosajs.github.io/ imagepose/ 源码&#xff1a;未开源 摘要 我们提出了一种新的自我监督的方法预测三维人体姿势从一个单一的图像。预测网络是从描绘处于典型姿势的人的未标记图像的数据集和一组未配对…...

ubuntu下cups部分场景

第一章&#xff1a;部分操作指令 在计算机领域中&#xff0c;cups 是“通用UNIX打印系统”&#xff08;Common UNIX Printing System&#xff09;的缩写&#xff0c;它是一种用于在UNIX-like操作系统上管理打印任务的开源打印系统。cups 提供了一个框架&#xff0c;允许用户和…...

通过geoserver imageMosic发布多张tif数据

通过geoserver imageMosic发布多张tif数据 reference: https://zhuanlan.zhihu.com/p/132388558 https://zhuanlan.zhihu.com/p/103674876 https://docs.geoserver.org/latest/en/user/tutorials/imagemosaic_timeseries/imagemosaic_timeseries.html 步骤 下载数据 http…...

输出图元(四)8-2 OpenGL画点函数、OpenGL画线函数

4.3 OpenGL画点函数 要描述一个点的几何要素&#xff0c;我们只需在世界坐标系中指定一个位置。然后该坐标位置和场景中已有的其他几何描述一起被传递给观察子程序。除非指定其他属性值&#xff0c;OpenGL 图元按默认的大小和颜色来显示。默认的图元颜色是白色&#x…...

java八股文

6. 如何保证消息的可靠性&#xff1f; 在RabbitMq的整个消息投递过程中&#xff0c;有三种情况下&#xff0c;会存在消息丢失的问题&#xff1a; 6. RabbitMq如何保证消息的可靠性&#xff1f; 所以从这三个维度保证消息的可靠性去可靠性传递就可以了&#xff0c;从生产者发送…...

算法通关村——解析堆的应用

在数组中找第K大的元素 LeetCode21 Medium 我们要找第 K 大的元素&#xff0c;如果我们找使用大堆的话那么就会造成这个堆到底需要多大的&#xff0c;而且哪一个是第 K 的的元素我们不知道是哪一个索引&#xff0c;我们更想要的结果就是根节点就是我们要找的值&#xff0c;所以…...

爬虫源码---爬取小猫猫交易网站

前言&#xff1a; 本片文章主要对爬虫爬取网页数据来进行一个简单的解答&#xff0c;对与其中的数据来进行一个爬取。 一&#xff1a;环境配置 Python版本&#xff1a;3.7.3 IDE:PyCharm 所需库&#xff1a;requests &#xff0c;parsel 二&#xff1a;网站页面 我们需要…...

Python的由来和基础语法(一)

目录 一、Python 背景知识 1.1Python 是咋来的? 1.2Python 都能干啥? 1.3Python 的优缺点 二、基础语法 2.1常量和表达式 2.2变量和类型 变量的语法 (1) 定义变量 (2) 使用变量 变量的类型 (1) 整数 (2) 浮点数(小数) (3) 字符串 (4) 布尔 (5) 其他 动态类型…...

使用maven创建springboot项目

创建maven快速启动项目 命令行或者idea、eclipse快捷创建也可以 pom.xml下project项目下导入springboot 父工程 <!--导入springboot 父工程--> <parent><artifactId>spring-boot-starter-parent</artifactId><groupId>org.springframework.bo…...

MySQL 基本操作1

目录 Create insert 插入跟新 1 插入跟新 2 Retrive select where 子句查询 1.查找数学成绩小于 80 的同学。 2.查询数学成绩等于90分的同学。 3.查询总分大于240 的学生 4.查询空值或者非空值 5.查询语文成绩在70~80之间的同学 6.查询英语成绩是99 和 93 和 19 和…...

linux内网yum源服务器搭建

1.nginx: location / {root /usr/local/Kylin-Server-V10-SP3-General-Release-2303-X86_64;autoindex on;autoindex_localtime on;autoindex_exact_size off; } 注:指定到镜像的包名 2.修改yum源地址 cd /etc/yum.repos.d/vim kylin_x86_64.repo 注: --enabled设置为1 3.重…...

机器学习与数据分析

【数据清洗】 异常检测 孤立森林&#xff08;Isolation Forest&#xff09;从原理到实践 效果评估&#xff1a;F-score 【1】 保护隐私的时间序列异常检测架构 概率后缀树 PST – &#xff08;异常检测&#xff09; 【1】 UEBA架构设计之路5&#xff1a; 概率后缀树模型 【…...

项目总结知识点记录-文件上传下载(三)

&#xff08;1&#xff09;文件上传 代码&#xff1a; RequestMapping(value "doUpload", method RequestMethod.POST)public String doUpload(ModelAttribute BookHelper bookHelper, Model model, HttpSession session) throws IllegalStateException, IOExcepti…...

基于LinuxC语言实现的TCP多线程/进程服务器

多进程并发服务器 设计流程 框架一&#xff08;使用信号回收僵尸进程&#xff09; void handler(int sig) {while(waitpid(-1, NULL, WNOHANG) > 0); }int main() {//回收僵尸进程siganl(17, handler);//创建服务器监听套接字 serverserver socket();//给服务器地址信息…...

浅谈JVM垃圾回收机制

一、HotSpot VM中的GC分为两大类 1.部分收集(Partial GC): 新生代收集(Minor GC/Young GC):只对新生代进行垃圾收集老年代收集(Major GC/Old GC):只队老年代进行垃圾收集混合收集(Mixed GC):对整个新生代和老年代进行垃圾收集 2.整堆收集(Full GC) 收集整个Java堆和方法区 …...

【80天学习完《深入理解计算机系统》】第十二天3.6数组和结构体

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

docker详细操作--未完待续

docker介绍 docker官网: Docker&#xff1a;加速容器应用程序开发 harbor官网&#xff1a;Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台&#xff0c;用于将应用程序及其依赖项&#xff08;如库、运行时环…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

React hook之useRef

React useRef 详解 useRef 是 React 提供的一个 Hook&#xff0c;用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途&#xff0c;下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

2025盘古石杯决赛【手机取证】

前言 第三届盘古石杯国际电子数据取证大赛决赛 最后一题没有解出来&#xff0c;实在找不到&#xff0c;希望有大佬教一下我。 还有就会议时间&#xff0c;我感觉不是图片时间&#xff0c;因为在电脑看到是其他时间用老会议系统开的会。 手机取证 1、分析鸿蒙手机检材&#x…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

rnn判断string中第一次出现a的下标

# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...