说明
企业微信官方提供的均为API接口,没有提供集成SDK。因此无需引入Maven依赖,直接以Https
方式请求即可。
有些第三方提供了集成的Java SDK,可根据需求自行选用。
本文采用直接调用官方API的方式。
基础配置
企业微信注册后,可得到corpId
、agentId
、corpSecret
的信息。
而企业微信的所有接口均以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);
}
当调用时,引入QywxConfig
和QywxForestClient
:
@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
的官方文档地址:
里面明确提到了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
方法。