SpringBoot中企业微信的API调用

说明

企业微信官方提供的均为API接口,没有提供集成SDK。因此无需引入Maven依赖,直接以Https方式请求即可。

有些第三方提供了集成的Java SDK,可根据需求自行选用。

本文采用直接调用官方API的方式。

基础配置

企业微信注册后,可得到corpIdagentIdcorpSecret的信息。

而企业微信的所有接口均以https://qyapi.weixin.qq.com/cgi-bin开头。

综上,在yml中定义配置:

yml 复制代码
qywx:
  endpoint: https://qyapi.weixin.qq.com/cgi-bin
  corpId: wx00000000000000ba
  agentId: 1000000
  corpSecret: V0000000000_00000000000000000000000000000wc

然后定义一个配置类:

java 复制代码
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来进行请求。

首先引入依赖:

xml 复制代码
<!-- forest -->
<dependency>
    <groupId>com.dtflys.forest</groupId>
    <artifactId>forest-spring-boot-starter</artifactId>
    <version>1.5.32</version>
</dependency>

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

java 复制代码
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> {

    @Autowired
    private QywxConfig qywxConfig;

    @Override
    public void onInvokeMethod(ForestRequest req, ForestMethod method, Object[] args) {
        req.setBasePath(qywxConfig.getEndpoint());
    }
}

然后定义请求的接口类:

java 复制代码
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_token
    String 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

参数示例为:

js 复制代码
{
   "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
}

返回示例为:

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

现在根据文档的信息来添加接口。

首先定义一个MessageTextDto对象来承载发送时的参数。其中text属性又是一个对象。

java 复制代码
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对象:

java 复制代码
import lombok.Data;

@Data
public class MessageText {

    /**
     * 消息内容,最长不超过2048个字节,超过将截断(支持id转译)
     * 必填
     */
    private String content;
}

然后在QywxForestClient中添加接口:

java 复制代码
@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);
}

这样即可进行调用:

java 复制代码
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方法。

相关推荐
Asthenia04126 小时前
浏览器缓存机制深度解析:电商场景下的性能优化实践
后端
databook7 小时前
『Python底层原理』--Python对象系统探秘
后端·python
超爱吃士力架8 小时前
MySQL 中的回表是什么?
java·后端·面试
追逐时光者9 小时前
Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
后端·.net
典龙3309 小时前
如何使用springboot项目如何实现小程序里面商品的浏览记录功能案例
spring boot
苏三说技术10 小时前
10亿数据,如何迁移?
后端
bobz96510 小时前
openvpn 显示已经建立,但是 ping 不通
后端
customer0810 小时前
【开源免费】基于SpringBoot+Vue.JS个人博客系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
qq_4592384910 小时前
SpringBoot整合Redis和Redision锁
spring boot·redis·后端
灰色人生qwer11 小时前
SpringBoot 项目配置日志输出
java·spring boot·后端