关注作者,更多动态实时掌握
上一篇我们经过接口验证,已经可以与微信的服务器进行通信,错过的可以通过下面链接来进行回顾,这一篇就来实现一个基本的消息接收与响应。
SpringBoot搭建微信公众号后台(零):服务搭建与接口验证
所谓的消息接收就是当用户与你的公众号有交互时,比如新增关注,发送消息,点击菜单等,微信就会通过接口调用的形式通知我们进行回应,而且这个接口地址就是上一篇中我们配置的用来验证服务的地址,只是请求方式由GET改成POST,因此我们上篇中的@RequestMAPPing("/wechat")就要改成@GetMapping("/wechat"),并且还要新增一个同路径的POST请求的处理接口。
微信发送的报文是xml格式的:
<xml><ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[this is a test]]></Content>
<MsgId>1234567890123456</MsgId>
<MsgDataId>xxxx</MsgDataId>
<Idx>xxxx</Idx>
</xml>
我们需要回复的格式也是xml:
<xml><ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[你好]]></Content>
</xml>
需要注意的是,微信对接口的响应要求比较严格,五秒之内必须进行响应,如果你的业务执行时间超过五秒,请直接回复“success”或空字符串“”,否则会在公众号消息页面提示服务异常。

服务异常
假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。详见下面说明:1、直接回复success(推荐方式) 2、直接回复空串(指字节长度为0的空字符串,而不是 XML 结构体中 content 字段的内容为空) 一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示“该公众号暂时无法提供服务,请稍后再试”:1、开发者在5秒内未回复任何内容 2、开发者回复了异常数据,比如 JSON 数据等微信公众号开发文档
通过使用@RequestBody,并且在消息实体类上添加@XmlRootElement,我们就可以直接接收xml类型的请求,不需要额外的代码去做Java对象与xml的转换(这样写有一个缺点,后面说)。在返回请求时,如果成功则返回消息对象,出现异常就返回字符串“success”(这个设定是真的奇葩,好歹返回格式保持一致啊),所以我们就用Object作为返回类型。在@PostMapping注解参数中添加produces = MediaType.APPLICATION_XML_VALUE即可实现返回xml格式响应,也无需额外转换。
相关影片资源迅雷下载推荐
北京软件系统开发公司排行榜
推荐企业:北京锐智互动 400-1050-360推荐指数:推荐理由:做软件15年了,经验多。系统,APP,小程序都可以开发,售后也做得很好 北京近年来软件外包行业是发展的越来越好,处于首都这样优越的地理位 ...
软件开发,北京软件系统开发公司排行榜
参数 | 描述 |
---|---|
ToUserName | 开发者微信号 |
FromUserName | 发送方帐号(一个OpenID) |
CreateTime | 消息创建时间 (整型) |
MsgType | 消息类型,文本为text |
Content | 文本消息内容 |
MsgId | 消息id,64位整型 |
MsgDataId | 消息的数据ID(消息如果来自文章时才有) |
Idx | 多图文时第几篇文章,从1开始(消息如果来自文章时才有) |
我们先做一个最简单的“复读机”,收到什么就回复什么。下面是示例代码,有详细注释。(大家有什么建议可以关注微信公众号进行留言反馈,也可以按照提示方式进群,方便交流。)

示例代码
请求处理类:
package com.prince.wechat;import com.prince.wechat.common.WechatUtils;
import com.prince.wechat.dto.Message;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
@SpringBootApplication
@RestController
public class WechatApplication {
public static void main(String[] args) {
SpringApplication.run(WechatApplication.class, args);
}
/**
* 微信接口验证
* @param request 请求参数
* @return String
*/
//改成GetMapping
@GetMapping("/wechat")
public String check(HttpServletRequest request){
System.out.println("get方法");
String signature = request.getParameter("signature");
String timestamp = request.getParameter("timestamp");
String nonce = request.getParameter("nonce");
String echostr = request.getParameter("echostr");
if (WechatUtils.checkSignature(signature, timestamp, nonce)) {
System.out.println("检验通过");
return echostr;
}
System.out.println("检验不通过");
return "校验不通过";
}
/**
* 消息处理
* @param requestMessage 请求消息
* @return 响应消息或者“success”
*/
//改成PostMapping用来接收POST请求,produces指定响应的类型为xml,RequestBody和实体类Message的Xml注解一起实现直接接收xml请求
@PostMapping(value="/wechat",produces = MediaType.APPLICATION_XML_VALUE)
public Object message(@RequestBody Message requestMessage){
System.out.println("post方法入参:"+requestMessage);
String fromUserName = requestMessage.getFromUserName();
String toUserName = requestMessage.getToUserName();
//新建一个响应对象
Message responseMessage = new Message();
//消息来自谁
responseMessage.setFromUserName(toUserName);
//消息发送给谁
responseMessage.setToUserName(fromUserName);
//消息类型,返回的是文本
responseMessage.setMsgType("text");
//消息创建时间,当前时间就可以
responseMessage.setCreateTime(System.currentTimeMillis());
//这个是响应消息内容,直接复制收到的内容做演示,甚至整个响应对象都可以直接使用原请求参数对象,只需要换下from和to就可以了哈哈哈
responseMessage.setContent(requestMessage.getContent());
return responseMessage;
}
}
消息实体类:
package com.prince.wechat.dto;import lombok.Data;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@Data
//指定xml的根节点
@XmlRootElement(name = "xml")
//指定Xml映射的生效范围
@XmlAccessorType(XmlAccessType.FIELD)
public class Message {
/**
* 开发者微信号
*/
//指定Xml映射节点名
@XmlElement(name = "ToUserName")
protected String toUserName;
/**
* 发送方账号(一个OpenID)
*/
@XmlElement(name = "FromUserName")
protected String fromUserName;
/**
* 消息类型,文本为text
*/
@XmlElement(name = "MsgType")
protected String msgType;
/**
* 消息id,64位整型
*/
@XmlElement(name = "MsgId")
protected String msgId;
/**
* 消息的数据ID(消息如果来自文章时才有)
*/
@XmlElement(name = "MsgDataId")
protected String msgDataId;
/**
* 多图文时第几篇文章,从1开始(消息如果来自文章时才有)
*/
@XmlElement(name = "Idx")
protected String idx;
/**
* 消息创建时间 (整型)
*/
@XmlElement(name = "CreateTime")
protected long createTime;
/**
* 文本消息内容
*/
@XmlElement(name = "Content")
private String content;
}
测试结果:

测试结果
到这里我们的“复读机”就算完成了,微信消息类型有文本消息text,图片消息,语音消息,视频消息,地理位置消息,链接消息以及事件消息等,其他消息与文本消息类型类似,只是入参和出参稍有不同,以图片消息为例,入参:
<xml><ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>1348831860</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<PicUrl><![CDATA[this is a url]]></PicUrl>
<MediaId><![CDATA[media_id]]></MediaId>
<MsgId>1234567890123456</MsgId>
<MsgDataId>xxxx</MsgDataId>
<Idx>xxxx</Idx>
</xml>
出参:
<xml><ToUserName><![CDATA[toUser]]></ToUserName>
<FromUserName><![CDATA[fromUser]]></FromUserName>
<CreateTime>12345678</CreateTime>
<MsgType><![CDATA[image]]></MsgType>
<Image>
<MediaId><![CDATA[media_id]]></MediaId>
</Image>
</xml>
可以看出入参多了PicUrl和MediaId,出参则多出来一级标签<Image>。这里就涉及到我前面的提到的弊端,不同消息参数不同的情况下,消息实体类只能全部往里塞,显得略微臃肿,不如写个转换类按需转换来的灵活(谁有好的解决办法可以告知一下,谢谢),出参也是一样。代码稍作改造:

改造
可以看到如果对每一种消息都单独处理的话需要大量的if-else,维护起来不方便而且代码也不优雅,有没有办法可以简化掉这么多的分支判断呢,下一篇我们就试试使用策略模式+工厂模式,减少分支判断。感兴趣的记得点个关注(微信公众号:隔壁的程序员),我们下一篇再见。

企业网站建设与开发最低只要299元起,包含域名服务器,需要的联系QQ345424724,电话15516990022,18530226930相关影片资源迅雷下载推荐
04传统游戏进军区块链Gamefi探索之路?有什么可借鉴的
传统游戏进军Gamefi链游的区块链经济模型制定参考系MMORPG 型(端游)1 概述MMORPG在传统游戏里最常见的游戏类型之一,在区块链上由于游戏开发成本高、开发团队组成等原因,目前市面上较少看到该类型。值得关注的同 ...
游戏开发,04传统游戏进军区块链Gamefi探索之路?有什么可借鉴的
标签: 公众号开发 SpringBoot搭建微信公众号后台(一):消息接收与响应