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方法。

相关推荐
码上一元3 小时前
SpringBoot自动装配原理解析
java·spring boot·后端
计算机-秋大田3 小时前
基于微信小程序的养老院管理系统的设计与实现,LW+源码+讲解
java·spring boot·微信小程序·小程序·vue
魔道不误砍柴功5 小时前
简单叙述 Spring Boot 启动过程
java·数据库·spring boot
枫叶_v5 小时前
【SpringBoot】22 Txt、Csv文件的读取和写入
java·spring boot·后端
路在脚下@5 小时前
Springboot 的Servlet Web 应用、响应式 Web 应用(Reactive)以及非 Web 应用(None)的特点和适用场景
java·spring boot·servlet
杜杜的man5 小时前
【go从零单排】Closing Channels通道关闭、Range over Channels
开发语言·后端·golang
java小吕布6 小时前
Java中Properties的使用详解
java·开发语言·后端
尘浮生6 小时前
Java项目实战II基于微信小程序的移动学习平台的设计与实现(开发文档+数据库+源码)
java·开发语言·数据库·spring boot·学习·微信小程序·小程序
2401_857610037 小时前
Spring Boot框架:电商系统的技术优势
java·spring boot·后端
java—大象8 小时前
基于java+springboot+layui的流浪动物交流信息平台设计实现
java·开发语言·spring boot·layui·课程设计