工具:idea2018,jdk1.8,框架:springboot+thymeleaf
基础搭建
说明,本项目着力于快速开发,前端页面只做最基本的页面跳转和参数校验。若是需要前后端分离,可参考一些开源的项目,如givebest/node.js-wechat-js-sdk
准备
一、测试/正式账号公众平台测试账号,根据上一篇注册即可
二、web开发者工具,拖至文末,选择适配版本下载即可。(因为微信部分URL需要权限的校验,只能在微信浏览器内打开,而类似postman的第三方工具无法使用)
三、公网可访问地址,如阿里云,或内网穿透工具,可参考上一篇中【接口配置信息修改】。(我的是http://chety.mynatapp.cc -> 127.0.0.1:8080,已打开状态)
四、订阅测试号,扫描二维码即可
开始开发——被动回复
描述
向公众号发送消息,公众号原样返回我们的内容,如发送【你好】,公众号回复【你好】
实现思路
一、参考微信公众平台技术文档,选择【消息管理】模块中的【接收普通消息】。
二、根据接收普通消息的介绍,可知:
- 消息类型分为:文本消息,图片消息,语音消息,视频消息等
- 消息的数据包请求格式为xml,请求方式为post
- 消息请求有重试和加密机制
- 接收消息的URL与接入验证的路径一致,用请求方式来区分
三、参数介绍
如文本消息,有消息的发送的接收方,消息类型和内容等。可使用bean对象来封装该消息格式
ToUserName
:开发者微信号,即目前我正在使用的测试公众号FromUserName
:发送方账号,描述为一个openid
,即一个手机微信用户在一公众号下的唯一标识,无论何种客户端设备访问,该id都是统一且唯一的。
注意:消息的收发方是相对的,客户端与服务端相反
代码开发
一、新建springboot项目,需要的核心依赖如下:
<dependencies>
<!-- web项目 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>
<!-- 引入thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- alibaba druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- lombok JavaBean工具 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.11</version>
</dependency>
<!-- http客户端工具 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.9</version>
</dependency>
<!-- json转换工具 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<!-- 数据库可选,如项目需要本地存储支付交易流水 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.26</version>
<scope>runtime</scope>
</dependency>
</dependencies>
复制代码
二、我这里都使用默认配置,因此暂时不配置application.yml,各位根据自己的需要配置
发送消息
三、根据输入消息的字段,封装为bean对象
注意,xml中参数的键都是大写,因此定义java参数时,需要使用注解或直接大写命名
@Data // lombok,包含setter,getter,tostring
@XmlRootElement(name = "xml") // 根节点
@XmlAccessorType(XmlAccessType.FIELD) // 映射类中的所有字段到XML
public class MsgSendEntity {
/**
* 公有部分
*/
// 开发者微信号
@XmlElement(name = "ToUserName") // 指定名称映射
private String toUserName;
// 发送方帐号(一个OpenID)
@XmlElement(name = "FromUserName")
private String fromUserName;
// 消息创建时间 (整型)
@XmlElement(name = "CreateTime")
private Long createTime;
// 消息类型
@XmlElement(name = "MsgType")
private String msgType;
// 消息id,64位整型
@XmlElement(name = "MsgId")
private Long msgId;
// 文本消息内容
@XmlElement(name = "Content")
private String content;
}
复制代码
四、URL接入校验接口,需公网可见或打开内网穿透工具。详细内容参考上一篇文章
@Controller
@RequestMapping("/api/v1/wechat1")
public class WeChatController {
/**
* url接入校验
* @param signature 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。
* @param timestamp 时间戳
* @param nonce 随机数
* @param echostr 随机字符串
* @return 若校验成功,原样返回echostr参数内容
*/
@GetMapping("/gzh")
@ResponseBody
public String validate(String signature,String timestamp,String nonce,String echostr){
if (!WeChatUtil.checkSignature(signature, timestamp, nonce)) {
WeChatUtil.getLogger().info("WeChatController.validate -- 公众号接入失败");
return null;
}
WeChatUtil.getLogger().info("WeChatController.validate -- 公众号接入成功,echostr:{}"+echostr);
return echostr;
}
}
复制代码
测试号管理配置如图:
五、接收消息接口(路径与接入验证URL的一致)
/**
* 公众号消息处理
* @param inMsg 客户端输入的消息信息
* @return 服务端返回信息
*/
@PostMapping("gzh")
@ResponseBody
public Object handleMessage(@RequestBody InMsgEntity inMsg) {
return null;
}
复制代码
六、断点调试
微信在测试公众号(已订阅)发送文本消息
查看断点信息,可以看到接收到文本消息的字段信息
放行断点,可以看到接收消息时的重试机制
接收消息
参考技术文档,这里选择【被动回复消息】
七、封装【回复文本消息】的实体类
@Data
@XmlRootElement(name="xml")
@XmlAccessorType(XmlAccessType.FIELD)
public class MsgReplyEntity {
// 用户的OpenID
private String ToUserName;
// 测试号的微信号
private String FromUserName;
// 消息创建时间 (整型)
private Long CreateTime;
// 消息类型
private String MsgType;
// 文本消息内容
private String Content;
}
复制代码
八、完善消息处理接口的方法
@PostMapping("gzh")
@ResponseBody
public Object handleMessage(@RequestBody MsgSendEntity msgSend) {
// 服务端消息回复的实体类
MsgReplyEntity msgReply = new MsgReplyEntity();
// 根据接收的信息回复,接收和发送方相反
msgReply.setFromUserName(msgSend.getToUserName());
msgReply.setToUserName(msgSend.getFromUserName());
msgReply.setCreateTime(new Date().getTime());
msgReply.setMsgType(msgSend.getMsgType());
// 消息内容原样返回
msgReply.setContent(msgSend.getContent());
return msgReply;
}
复制代码
测试样例
一、客户端发送消息测试
ok,公众号的简单被动文本消息回复就完成了。当然,其他的消息类型也类似处理,只需简单的判断即可。