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

SpringBoot中企业微信的API调用

说明

企业微信官方提供的均为API接口,没有提供集成SDK。因此无需引入Maven依赖,直接以Https方式请求即可。
有些第三方提供了集成的Java SDK,可根据需求自行选用。
本文采用直接调用官方API的方式。

基础配置

企业微信注册后,可得到corpIdagentIdcorpSecret的信息。
而企业微信的所有接口均以https://qyapi.weixin.qq.com/cgi-bin开头。
综上,在yml中定义配置:

qywx:endpoint: https://qyapi.weixin.qq.com/cgi-bincorpId: wx00000000000000baagentId: 1000000corpSecret: V0000000000_00000000000000000000000000000wc

然后定义一个配置类:

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;@Component
@Configuration
@ConfigurationProperties(prefix = QywxConfig.prefix)
@Data
public class QywxConfig {public final static String prefix = "qywx";/*** 企业微信请求地址*/private String endpoint;/*** 企业id*/private String corpId;private String agentId;private String corpSecret;
}

这样即可在容器类中引用配置。

发送请求

服务端需要向企业微信发送请求。这里使用Forest来进行请求。
首先引入依赖:

<!-- forest -->
<dependency><groupId>com.dtflys.forest</groupId><artifactId>forest-spring-boot-starter</artifactId><version>1.5.32</version>
</dependency>

考虑到所有的请求都需拼接共同的企业微信请求地址,因此为Forest添加拦截器来统一处理:

import com.dtflys.forest.http.ForestRequest;
import com.dtflys.forest.interceptor.Interceptor;
import com.dtflys.forest.reflection.ForestMethod;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;@Component
public class QywxForestInterceptor implements Interceptor<String> {@Autowiredprivate QywxConfig qywxConfig;@Overridepublic void onInvokeMethod(ForestRequest req, ForestMethod method, Object[] args) {req.setBasePath(qywxConfig.getEndpoint());}
}

然后定义请求的接口类:

import com.cosmoplat.hyida.core.result.Result;
import com.cosmoplat.qingyin.safety.qywx.controller.model.dto.MessageTextDto;
import com.cosmoplat.qingyin.safety.qywx.controller.model.dto.QyWxUserDetailDto;
import com.cosmoplat.qingyin.safety.qywx.inteceptor.SafetyForestInterceptor;
import com.dtflys.forest.annotation.*;import java.util.Map;@BaseRequest(interceptor = QywxForestInterceptor.class, headers = {"Accept: */*", "Content-Type: application/json"})
public interface QywxForestClient {/*** 获取access_token* @param corpId* @param corpSecret* @return*/@Get(url = "/gettoken?corpid={corpId}&corpsecret={corpSecret}")Map<String,Object> getToken(@Var("corpId") String corpId, @Var("corpSecret") String corpSecret);}

当调用时,引入QywxConfigQywxForestClient

@Resource
private QywxConfig qywxConfig;@Resource
private QywxForestClient qywxForestClient;private String getAccessToken() {// 根据corpId和corpSecret获取 access_tokenString corpId = qywxConfig.getCorpId();String corpSecret = qywxConfig.getCorpSecret();Map<String, Object> tokenResult = qywxForestClient.getToken(corpId, corpSecret);if (!result.get("errcode").equals(0) || StringUtils.isEmpty(result.get("access_token"))) {System.out.println("获取企业微信access_token失败!" + result.get("errmsg"));            }return String.valueOf(result.get("access_token"));
}

关于access_token

access_token的官方文档地址:

https://developer.work.weixin.qq.com/document/path/91039

里面明确提到了3个注意事项:

  • 为了安全考虑,开发者 请勿 将 access_token 返回给前端,需要开发者保存在后台,所有访问企业微信api的请求由后台发起。
  • 开发者需要缓存access_token,用于后续接口的调用(注意:不能频繁调用gettoken接口,否则会受到频率拦截)。当access_token失效或过期时,需要重新获取。
  • access_token的有效期通过返回的expires_in来传达,正常情况下为7200秒(2小时),有效期内重复获取返回相同结果,过期后获取会返回新的access_token。

因此,最佳实践应使用Redis缓存access_token。当获取access_token时先从Redis中取。若取不到,则向企业微信发起请求获取,并写入到Redis中。

携带参数

以发送应用消息为例,现在要发送一个文本消息。
参考官方文档:
请求方式:POST(HTTPS)
请求地址: https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=ACCESS_TOKEN
参数示例为:

{"touser" : "UserID1|UserID2|UserID3","toparty" : "PartyID1|PartyID2","totag" : "TagID1 | TagID2","msgtype" : "text","agentid" : 1,"text" : {"content" : "你的快递已到,请携带工卡前往邮件中心领取。\n出发前可查看<a href=\"http://work.weixin.qq.com\">邮件中心视频实况</a>,聪明避开排队。"},"safe":0,"enable_id_trans": 0,"enable_duplicate_check": 0,"duplicate_check_interval": 1800
}

返回示例为:

{"errcode" : 0,"errmsg" : "ok","invaliduser" : "userid1|userid2","invalidparty" : "partyid1|partyid2","invalidtag": "tagid1|tagid2","unlicenseduser" : "userid3|userid4","msgid": "xxxx","response_code": "xyzxyz"
}

现在根据文档的信息来添加接口。
首先定义一个MessageTextDto对象来承载发送时的参数。其中text属性又是一个对象。

import io.swagger.annotations.ApiModel;
import lombok.Data;@Data
public class MessageTextDto {/*** 指定接收消息的成员,成员ID列表(多个接收者用‘|’分隔,最多支持1000个)。* 特殊情况:指定为"@all",则向该企业应用的全部成员发送*/private String touser;/*** 指定接收消息的部门,部门ID列表,多个接收者用‘|’分隔,最多支持100个。* 当touser为"@all"时忽略本参数*/private String toparty;/*** 指定接收消息的标签,标签ID列表,多个接收者用‘|’分隔,最多支持100个。* 当touser为"@all"时忽略本参数*/private String totag;/*** 消息类型,此时固定为:text* 必填*/private String msgtype = "text";/*** 企业应用的id,整型。企业内部开发,可在应用的设置页面查看;第三方服务商,可通过接口 获取企业授权信息 获取该参数值* 必填*/private String agentid;/*** 消息内容,最长不超过2048个字节,超过将截断(支持id转译)* 必填*/private MessageText text = new MessageText();/*** 表示是否是保密消息,0表示可对外分享,1表示不能分享且内容显示水印,默认为0*/private String safe;/*** 表示是否开启id转译,0表示否,1表示是,默认0。仅第三方应用需要用到,企业自建应用可以忽略。*/private String enable_id_trans;/*** 	表示是否开启重复消息检查,0表示否,1表示是,默认0*/private String enable_duplicate_check;/*** 表示是否重复消息检查的时间间隔,默认1800s,最大不超过4小时*/private String duplicate_check_interval;
}

MessageText对象:

import lombok.Data;@Data
public class MessageText {/*** 消息内容,最长不超过2048个字节,超过将截断(支持id转译)* 必填*/private String content;
}

然后在QywxForestClient中添加接口:

@BaseRequest(interceptor = QywxForestInterceptor.class, headers = {"Accept: */*", "Content-Type: application/json"})
public interface QywxForestClient {/*** 获取访问用户敏感信息* @param messageTextDto* @param accessToken* @return*/@Post(url = "/message/send?access_token={accessToken}")Map<String, Object> messageSend(@Body MessageTextDto messageTextDto, @Var("accessToken") String accessToken);
}

这样即可进行调用:

private Map<String, Object> sendMessage(String touser, String content) {if (StrUtil.isEmpty(touser)) {// 消息接收者为空return Maps.newHashMap();}MessageTextDto messageTextDto = new MessageTextDto();messageTextDto.setAgentid(safetyConfig.getAgentId());messageTextDto.setTouser(touser);messageTextDto.getText().setContent(content);String accessToken = getAccessToken();Map<String, Object> result = qywxForestClient.messageSend(messageTextDto, accessToken);return result;
}

其中getAccessToken()调用了前面封装的getAccessToken方法。

相关文章:

SpringBoot中企业微信的API调用

说明 企业微信官方提供的均为API接口&#xff0c;没有提供集成SDK。因此无需引入Maven依赖&#xff0c;直接以Https方式请求即可。 有些第三方提供了集成的Java SDK&#xff0c;可根据需求自行选用。 本文采用直接调用官方API的方式。 基础配置 企业微信注册后&#xff0c;可…...

[前端] V8引擎编译原理

文章目录 1.什么是V81.1 扫描器Scanner1.2 解析器parser1.3 预解析PreParser1.4 解释器Ignition1.5 编译器TurboFan 1.什么是V8 V8是谷歌的开源高性能JavaScript和WebAssembly引擎&#xff0c;用C编写。它被用于Chrome和Node.js等。它实现ECMAScript和WebAssembly&#xff0c;…...

使用Pytorch实现linear_regression

使用Pytorch实现线性回归 # import necessary packages import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt# Set necessary Hyper-parameters. input_size 1 output_size 1 num_epochs 60 learning_rate 0.001# Define a Toy datas…...

网络安全等级保护收费标准?

不同省份价格会略有不同&#xff0c;二级等保一般不低于5万元;三级等保不低于9万元&#xff0c;个别省份也可能7万也能办理&#xff0c;根据企业实际情况和省市选定的代理机构确定。 等级保护二级? 第二级等保是指信息系统受到破坏后&#xff0c;会对公民、法人和其他组织的合…...

16 Go的反射

概述 在上一节的内容中&#xff0c;我们介绍了Go的并发&#xff0c;包括&#xff1a;Goroutines、Channels、WaitGroups、Mutex、Select等。在本节中&#xff0c;我们将介绍Go的反射。Go语言中的反射是一种在运行时检查类型信息并操作对象的能力&#xff0c;通过反射&#xff0…...

SQL Server 百万数据查询优化技巧三十则

点击上方蓝字关注我 互联网时代的进程越走越深&#xff0c;使用MySQL的人也越来越多&#xff0c;关于MySQL的数据库优化指南很多&#xff0c;而关于SQL SERVER的T-SQL优化指南看上去比较少&#xff0c;近期有学习SQLSERVER的同学问到SQL SERVER数据库有哪些优化建议&#xff1f…...

list转map(根据某个或多个属性分组)

需要将对应的list换成本地list&#xff0c;和对象换成本地对象 1、List转Map<String,List> // 根据一个字段分组 Map<String, List<String>> map objectLists.stream().collect(Collectors.groupingBy(Object::getName,Collectors.mapping(Object::getId, …...

常见树种(贵州省):012茶、花椒、八角、肉桂、杜仲、厚朴、枸杞、忍冬

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、茶 灌…...

千云物流 - 使用k8s负载均衡openelb

openelb的介绍 具体根据官方文档进行安装官方文档,这里作为测试环境的安装使用. OpenELB 是一个开源的云原生负载均衡器实现,可以在基于裸金属服务器、边缘以及虚拟化的 Kubernetes 环境中使用 LoadBalancer 类型的 Service 对外暴露服务。OpenELB 项目最初由 KubeSphere 社区…...

C语言之字符串函数

C语言之字符串函数 文章目录 C语言之字符串函数1. strlen的使用和模拟实现1.1 strlen的使用1.2 strlen的模拟实现 2. strcpy的使用和模拟实现2.1 strcpy的使用2.2 strncpy的使用2.3 strcpy的模拟实现 3. strcat的使用和模拟实现3.1 strcat的使用3.2 strncat3.3 strcat的模拟实现…...

python中一个文件(A.py)怎么调用另一个文件(B.py)中定义的类AA详解和示例

本文主要讲解python文件中怎么调用另外一个py文件中定义的类&#xff0c;将通过代码和示例解读&#xff0c;帮助大家理解和使用。 目录 代码B.pyA.py 调用过程 代码 B.py 如在文件B.py,定义了类别Bottleneck&#xff0c;其包含卷积层、正则化和激活函数层&#xff0c;主要对…...

spark shuffle 剖析

ShuffleExchangeExec private lazy val writeMetrics SQLShuffleWriteMetricsReporter.createShuffleWriteMetrics(sparkContext)private[sql] lazy val readMetrics SQLShuffleReadMetricsReporter.createShuffleReadMetrics(sparkContext)用在了两个地方&#xff0c;承接的是…...

C语言之认识柔性数组(flexible array)

在学习之前&#xff0c;我们首先要了解柔性数组是放在结构体当中的&#xff0c;知道这一点&#xff0c;我们就开始今天的学习吧&#xff01; 1.柔性数组的声明 在C99中&#xff0c;结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫做柔性数组成员 这里的结构是结构…...

【MATLAB基础绘图第17棒】绘制玫瑰图

MATLAB绘制玫瑰图 玫瑰图&#xff08;Nightingale Rose Chart&#xff09;风玫瑰图&#xff08;WindRose&#xff09;准备工作&#xff1a;WindRose工具包下载案例案例1&#xff1a;基础绘图 参考 玫瑰图&#xff08;Nightingale Rose Chart&#xff09; 玫瑰图&#xff08;Ni…...

Qt 基于海康相机的视频绘图

需求 在视频窗口上进行绘图&#xff0c;包括圆&#xff0c;矩形&#xff0c;扇形等 效果&#xff1a; 思路&#xff1a; 自己取图然后转成QImage &#xff0c;再向QWidget 进行渲染&#xff0c;根据以往的经验&#xff0c;无法达到很高的帧率。因此决定使用相机SDK自带的渲染…...

FlinkCDC实现主数据与各业务系统数据的一致性(瀚高、TIDB)

文章末尾附有flinkcdc对应瀚高数据库flink-cdc-connector代码下载地址 1、业务需求 目前项目有主数据系统和N个业务系统,为保障“一数一源”,各业务系统表涉及到主数据系统的字段都需用主数据系统表中的字段进行实时覆盖,这里以某个业务系统的一张表举例说明:业务系统表Ta…...

JSP:Servlet

Servlet处理请求过程 B/S请求响应模型 Servlet介绍 JSP是Servlet的一个成功应用&#xff0c;其子集。 JSP页面负责前台用户界面&#xff0c;JavaBean负责后台数据处理&#xff0c;一般的Web应用采用JSPJavaBean就可以设计得很好了。 JSPServletJavaBean是MVC Servlet的核心…...

react中的state

没想到hooks中也有state这一说法 看下面的两个案例 1、无state变化不会执行父子函数 2、有state更改执行父子函数...

VR全景航拍要注意什么,航拍图片如何处理

引言: VR全景航拍技术是当前摄影和航拍领域的新潮流。它采用虚拟现实技术&#xff0c;通过360度全景镜头捕捉画面&#xff0c;可以为观众提供身临其境的视觉体验。在宣传展示中&#xff0c;利用VR全景航拍技术可以为品牌宣传带来更加生动、震撼的视觉效果。 一、航拍注意事项 …...

Spark---集群搭建

Standalone集群搭建与Spark on Yarn配置 1、Standalone Standalone集群是Spark自带的资源调度框架&#xff0c;支持分布式搭建&#xff0c;这里建议搭建Standalone节点数为3台&#xff0c;1台master节点&#xff0c;2台worker节点&#xff0c;这虚拟机中每台节点的内存至少给…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

C++.OpenGL (10/64)基础光照(Basic Lighting)

基础光照(Basic Lighting) 冯氏光照模型(Phong Lighting Model) #mermaid-svg-GLdskXwWINxNGHso {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-GLdskXwWINxNGHso .error-icon{fill:#552222;}#mermaid-svg-GLd…...

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

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

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

OPENCV形态学基础之二腐蚀

一.腐蚀的原理 (图1) 数学表达式&#xff1a;dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一&#xff0c;腐蚀跟膨胀属于反向操作&#xff0c;膨胀是把图像图像变大&#xff0c;而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

Java求职者面试指南:计算机基础与源码原理深度解析

Java求职者面试指南&#xff1a;计算机基础与源码原理深度解析 第一轮提问&#xff1a;基础概念问题 1. 请解释什么是进程和线程的区别&#xff1f; 面试官&#xff1a;进程是程序的一次执行过程&#xff0c;是系统进行资源分配和调度的基本单位&#xff1b;而线程是进程中的…...