【需求】将外部事件消息发送至企业微信,使用SpringBoot完成该功能的API开发,并且整合Swagger2,在web端进行调试。
【实现流程】管理员在企业微信中自建小程序,将小程序的ID和微信的access_token作为接入连接的凭证,实现外部消息内容与企业微信自建应用聊天框的对接,使用所需要的HTTP注解和Swagger2的相关注解完成接口的开发。
目录总览
1 创建Spring-Boot项目,并引入相关依赖。
(1)所需版本配置。
<properties>
<java.version>11</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.0.RELEASE</spring-boot.version>
</properties>
(2)所需依赖如下。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.3.4.Final</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
2 封装各种Bean对象,便于后端参数的储存和传递。
(1)对access_token响应内容的封装。
public class AccessToken {
/**
* access_token:获取到的access_token字符串
*/
private String accessToken;
/**
* expires_in:有效时间(2h,7200s)
*/
private int expiresIn;
public AccessToken() {}
public AccessToken(AccessToken accessTokenMore) {
accessToken = accessTokenMore.getAccessToken();
expiresIn = accessTokenMore.getExpiresIn();
}
public String getAccessToken() {
return accessToken;
}
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpiresIn() {
return expiresIn;
}
public void setExpiresIn(int validTime) {
this.expiresIn = validTime;
}
@Override
public String toString() {
return "AccessToken{" +
"accessToken='" + accessToken + '\'' +
", expiresIn=" + expiresIn +
'}';
}
}
(2)对access_token请求体内容的封装。
public class AccessTokenRequest {
/**
* corpid:企业微信号,可从企业管理界面获得
*/
private String corpid = "wwb57d1d1f91303d52";
/**
* corpsecret:企业应用密钥,可从企业应用管理界面获得
*/
private String corpsecret = "r49wz8vesxBZdzIy0J8FzvGlflhOg1o9s32uiB3RVs0";
public AccessTokenRequest() {}
public AccessTokenRequest(AccessTokenRequest accessTokenRequestMore) {
corpid = accessTokenRequestMore.getCorpid();
corpsecret = accessTokenRequestMore.getCorpsecret();
}
public String getCorpid() {
return corpid;
}
public void setCorpid(String corpid) {
this.corpid = corpid;
}
public String getCorpsecret() {
return corpsecret;
}
public void setCorpsecret(String corpsecret) {
this.corpsecret = corpsecret;
}
/**
* 将变量转换为JSON格式的字符串
*/
public String toWXJsonFormStr() {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("{");
stringBuffer.append("\"corpid\":" + "\"" + corpid + "\",");
stringBuffer.append("\"corpsecret\":" + "\"" + corpsecret + "\"");
stringBuffer.append("}");
String jsonFormStr = stringBuffer.toString();
System.out.println("请求内容为:" + jsonFormStr);
return jsonFormStr;
}
@Override
public String toString() {
return "AccessTokenRequest{" +
"corpid='" + corpid + '\'' +
", corpsecret='" + corpsecret + '\'' +
'}';
}
}
(3)对发送文本信息的对象进行封装。
JSON中为嵌套对象,故使用类变量完成数据封装的嵌套;为节省篇幅,有些此处暂时用不到的构造函数未给出;未给出getter&setter&toString函数,需自行补充。
public class TextMessage {
/**
* touser:非必需,成员ID列表,多个接收用'|'分隔,为@all时发送该企业应用全部成员
*/
private String toUser;
/**
* toparty:非必需,部门ID列表,多个接收用'|'分隔,toUser为@all时忽略该参数
*/
private String toParty;
/**
* totag:非必需,标签ID列表,多个接收用'|'分隔,toUser为@all时忽略该参数
*/
private String toTag;
/**
* msgtype:必需,消息类型,此处固定为"text"
*/
private final static String msgtype = "text";
/**
* agentid:必需,企业应用的id,整型,可在应用的设置页面查看
*/
private int agentId;
/**
* content:必需,消息内容,为"text"的内置对象
*/
private Text text = new Text();
/**
* safe:非必需,是否保密,0否1是默认0
*/
private int safe = 0;
/**
* enable_id_trans:非必需,是否开启id转译,0否1是默认0
*/
private int enableIdTrans = 0;
/**
* enable_duplicate_check:非必需,是否开启重复消息检查,0否1是默认0
*/
private int enableDuplicateCheck = 0;
/**
* duplicate_check_interval:非必需,消息重检的间隔,默认1800s,最大不超过4小时
*/
private int duplicateCheckInterval = 0;
/**
* Debug日记:
* 涉及到POST请求参数时,需要有默认的构造函数
* 否则会报500错误
*/
public TextMessage() {
}
public TextMessage(String toUser, String toParty, String toTag, int agentId, String content) {
this.toUser = toUser;
this.toParty = toParty;
this.toTag = toTag;
this.agentId = agentId;
text.setContext(content);
}
public TextMessage(TextMessage message) {
toUser = message.getToUser();
toParty = message.getToParty();
toTag = message.getToTag();
agentId = message.getAgentId();
text = message.getText();
safe = message.getSafe();
enableIdTrans = message.getEnableIdTrans();
enableDuplicateCheck = message.getEnableDuplicateCheck();
duplicateCheckInterval = message.getDuplicateCheckInterval();
}
/**
* 将变量转换为JSON格式的字符串
*/
public String toWXJsonFormStr() {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("{");
stringBuffer.append("\"touser\":" + "\"" + toUser + "\",");
stringBuffer.append("\"toparty\":" + "\"" + toParty + "\",");
stringBuffer.append("\"totag\":" + "\"" + toTag + "\",");
stringBuffer.append("\"msgtype\":" + "\"" + msgtype + "\",");
stringBuffer.append("\"agentid\":" + "\"" + agentId + "\",");
stringBuffer.append("\"text\":" + "{");
stringBuffer.append("\"content\":" + "\"" + text.getContext() + "\"");
stringBuffer.append("}");
stringBuffer.append(",\"safe\":" + "\"" + safe + "\",");
stringBuffer.append("\"enable_id_trans\":" + "\"" + enableIdTrans + "\",");
stringBuffer.append("\"enable_duplicate_check\":" + "\"" + enableDuplicateCheck + "\",");
stringBuffer.append("\"duplicate_check_interval\":" + "\"" + duplicateCheckInterval + "\"");
stringBuffer.append("}");
String jsonFormStr = stringBuffer.toString();
System.out.println("请求内容为:" + jsonFormStr);
return jsonFormStr;
}
/**
* 有些暂时用不到的构造函数未给出;未给出getter&setter&toString函数,需自行补充
*/
}
/**
* 用于text对象,其参数为content
* 只有再创类,在Swagger2上显示的JSON模板才是嵌套格式
*/
class Text {
private String context;
public String getContext() {
return context;
}
public void setContext(String context) {
this.context = context;
}
@Override
public String toString() {
return "Text{" +
"context='" + context + '\'' +
'}';
}
}
3 创建package,名为method,用于处理过程的封装。
(1)获取access_token。
public class GetAccessToken {
/**
* 使用后端设定值获取access_token
*/
public AccessToken getAccessToken() {
/**
* ACCESS_TOKEN_URL:ACCESS_TOKEN访问权限码URL
*/
String ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={corpid}&corpsecret={corpsecret}";
AccessTokenRequest accessTokenRequest = new AccessTokenRequest();
AccessToken accessToken = new AccessToken();
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
/**
* 设置传参
*/
Map<String,String> param = new HashMap<>();
param.put("corpid",accessTokenRequest.getCorpid());
param.put("corpsecret",accessTokenRequest.getCorpsecret());
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
String body = restTemplate.getForEntity(ACCESS_TOKEN_URL,String.class,param).getBody();
/**
* 将返回体转换为json格式,然后提取value
*/
JSONObject jsonObject = JSONObject.parseObject(body);
accessToken.setAccessToken(jsonObject.getString("access_token"));
accessToken.setExpiresIn(jsonObject.getInteger("expires_in"));
return accessToken;
}
/**
* 主动填写参数值来获取access_token
*/
public AccessToken getAccessToken(AccessTokenRequest accessTokenRequest) {
AccessToken accessToken = new AccessToken();
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
/**
* 将请求体转换为json格式
*/
String ACCESS_TOKEN_URL = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
String str = accessTokenRequest.toWXJsonFormStr();
/**
* 开始post请求
*/
HttpEntity<String> formEntity = new HttpEntity<>(str,httpHeaders);
String result = restTemplate.postForObject(ACCESS_TOKEN_URL,formEntity,String.class);
System.out.println("请求返回结果:" + result);
/**
* 将返回体转换为json格式,然后提取value
*/
JSONObject jsonObject = JSONObject.parseObject(result);
accessToken.setAccessToken(jsonObject.getString("access_token"));
accessToken.setExpiresIn(jsonObject.getInteger("expires_in"));
return accessToken;
}
}
(2)发送文本信息。
public class SendMessage {
/**
* @param CREATE_SESSION_URL post请求URL,https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={corpsecret}
*/
private final static String CREATE_SESSION_URL = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";
/**
* 用于文本消息发送
*/
public String sendTextMessage(TextMessage message) {
AccessTokenRequest accessTokenRequest = new AccessTokenRequest();
GetAccessToken getAccessToken = new GetAccessToken();
RestTemplate restTemplate = new RestTemplate();
HttpHeaders httpHeaders = new HttpHeaders();
/**
* 设置传参为JSON格式
*/
MediaType type = MediaType.parseMediaType("application/json;charset=UTF-8");
httpHeaders.setContentType(type);
httpHeaders.add("Accept",MediaType.APPLICATION_JSON.toString());
/**
* 获取access_token
*/
AccessToken accessToken = getAccessToken.getAccessToken(accessTokenRequest);
String ACCESS_TOKEN = accessToken.getAccessToken();
String url = CREATE_SESSION_URL + ACCESS_TOKEN;
/**
* 封装发送消息请求JSON
*/
TextMessage textMessage = new TextMessage(message);
String str = textMessage.toWXJsonFormStr();
/**
* 开始post请求
*/
HttpEntity<String> formEntity = new HttpEntity<>(str,httpHeaders);
String result = restTemplate.postForObject(url,formEntity,String.class);
System.out.println("请求返回结果:" + result);
return result;
}
}
4 创建API测试接口,将其放在controller下。
接口的功能分为两部分:对access_token进行获取测试;对文本信息的推送进行测试。
(1)后端获取access_token。
根据个人企业微信账号的各种初始数据,将其设定为后端测试的初始值,通过该值进行access_token的获取。
功能:后端设定值下的企业微信凭证获取
方法:GET
路径:http://localhost:8080/get_access_token/access_token
@Api(tags = "企业微信凭证获取")
@RestController
@RequestMapping(value = "/get_access_token")
public class AcessTokenController {
@ApiOperation(value = "后台指定access_token获取")
@GetMapping(value = "/access_token")
public String getAccessTokenController() {
GetAccessToken getAccessToken = new GetAccessToken();
AccessToken accessToken = getAccessToken.getAccessToken();
return accessToken.toString();
}
(2)手动输入参数进行access_token的获取。
功能:主动设定值下的企业微信凭证获取
方法:POST
路径:http://localhost:8080/get_access_token/access_token_more
请求格式:{ “corpid”: “string”,“corpsecret”: “string”}
@ApiOperation(value = "主动指定access_token获取")
@PostMapping(value = "/access_token_more")
/**
* Debug日记:
* 带参数时需要使用POST方法
* 否则使用Swagger2时会出现400错误
*/
public String getAccessTokenControllerMore(@RequestBody AccessTokenRequest accessTokenRequest) {
GetAccessToken getAccessToken = new GetAccessToken();
AccessToken accessToken = getAccessToken.getAccessToken(accessTokenRequest);
return accessToken.toString();
}
}
(3)后端发送文本消息。
根据个人企业微信账号的各种初始数据,将其设定为后端测试的初始值,以初始参数直接进行文本消息发送。
功能:后端设定值下的文本信息发送
方法:POST
路径:http://localhost:8080/send_message/text
@Api(tags = "企业微信消息发送")
@RestController
@RequestMapping("/send_message")
public class SendMessageController {
@ApiOperation(value = "后台文本消息发送")
@RequestMapping(value = "/text",method = RequestMethod.POST)
public String sendTextMessageController() {
SendMessage workWeChat = new SendMessage();
TextMessage textMessage = new TextMessage("WangXingWen","1","",1000002,"水漫金山。");
String str = workWeChat.sendTextMessage(textMessage);
return str;
}
(4)手动输入参数来请求文本消息的发送。
功能:主动设定值下的文本信息发送
方法:POST
路径:http://localhost:8080/send_message/text_more
请求格式:请参考企业微信的内部开发官方文档
文档链接:https://open.work.weixin.qq.com/api/doc/90000/90135/90236
@ApiOperation(value = "主动文本消息发送")
@PostMapping(value = "/text_more")
public String sendTextMessageControllerMore(@RequestBody TextMessage textMessage) {
SendMessage workWeChat = new SendMessage();
String str = workWeChat.sendTextMessage(textMessage);
return str;
}
}
5 配置Swagger2文件。
/**
* Swagger2 web端访问地址 http://localhost:8080/swagger-ui.html
*/
@Configuration
@EnableSwagger2
public class Swagger2 {
@Bean
public Docket wxSendTextMsgApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("企业微信API")
.termsOfServiceUrl("http://localhost:8080/swagger-ui.html")
.contact("Akazia")
.version("1.0")
.description("用于企业微信的各种API接口调试")
.build();
}
}
6 进行测试。
(1)后端获取access_token。
启动项目,打开Swagger2页面,根据后端值直接获取access_token。
(2)输入参数获取access_token。
在接口处可以在右侧看到请求体模板,根据模板在一侧输入对应参数来获取access_token。
(3)后端值作为请求的参数,直接进行信息发送。
(4)输入参数发送信息。
在接口处可以在右侧看到请求体模板,根据模板在一侧输入对应参数来发送文本消息。
详细信息可参考企业微信的内部开发官方文档。此处为了测试,先发送初始0值,表明无id等内容,用于调试接口是否能正常运行;之后再进行正常的参数赋值,如果响应体内容正常,则浏览app界面,会看到文本消息已被成功发送。
源码资源地址:https://download.csdn.net/download/weixin_43148731/12670210
PS:如果对代码还有优化的欢迎留言,尤其是bean里转json格式的那一堆……笔者自己看着也难受,希望有这方面的大佬指教一下小白。