一、接收用户消息
(1) 介绍
接收消息的官方文档:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html
接收用户给公众号发送的消息(如:愿你万事顺心)
当普通微信用户向公众账号发消息时,微信服务器将 POST 消息的 XML 数据包发送到开发者填写的 URL 上。
- 关于重试的消息排重,推荐使用 msgid(XML 数据包中的内容) 排重
- 微信服务器在五秒内收不到响应会断掉连接,并重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对空串作任何处理,并且不会发起重试
公众号支持用户发送文本、图片、视频、语音、小视频、地理位置、链接消息等格式的数据。
(2) 接收用户在微信公众号发送的消息(Java 代码)
微信服务器发送的数据包是 XML 格式的,在 Java 代码中需要把 XML 格式的数据转换为 Map 格式。其中可使用 dom4 进行 XML 文件的读写。
dom4j 是一个 Java 的 XML API,是 jdom 的升级品,用于读写 XML 文件的。dom4j 是一个十分优秀的 Java XML API,具有性能优异、功能强大和简单易用的特点。它的性能超过 sun 公司官方的 dom 技术,同时它也是一个开放源代码的软件。
<!-- XML 文件读写 -->
<dependency>
<groupId>org.dom4j</groupId>
<artifactId>dom4j</artifactId>
<version>2.0.0</version>
</dependency>
@RestController
@RequestMapping("/wechats")
public class WechatController {
@Autowired
private WechatService service;
/**
* 向公众号发送的消息会被转发到这里
*/
@RequestMapping("/postAndGet")
public String checkValid(String signature, String timestamp,
String nonce, String echostr, HttpServletRequest req) {
String requestMethod = req.getMethod();
if (requestMethod.equals("POST")) { // 处理 POST 请求
Map<String, String> msgMap = service.parseXmlData2Map(req);
System.out.println(msgMap);
return "OK";
} else if (requestMethod.equals("GET")) { // 处理 GET 请求
return service.checkSignature(timestamp, nonce, signature) ? echostr
: "校验失败";
} else {
return "不是 GET 和 POST";
}
}
}
@Service
public class WechatServiceImpl implements WechatService {
// checkSignature 方法的实现省略
/**
* 用户在微信公众号发送消息后, 微信服务器会发送一个 POST 请求过来
* POST 请求中携带者用户发送的数据(XML 格式)
*
* @param req 可通过该参数获得 XML 数据包的输入流
* @return 数据的 Map 格式
*/
@Override
public Map<String, String> parseXmlData2Map(HttpServletRequest req) {
HashMap<String, String> msgMap = new HashMap<>();
try {
ServletInputStream inputStream = req.getInputStream();
// dom4j 用于读取 XML 文件输入流的类
SAXReader saxReader = new SAXReader();
// 读取 XML 文件输入流, XML 文档对象
Document document = saxReader.read(inputStream);
// XML 文件的根节点
Element root = document.getRootElement();
// 所有的子节点
List<Element> childrenElement = root.elements();
for (Element element : childrenElement) {
msgMap.put(element.getName(), element.getStringValue());
}
} catch (Exception e) {
e.printStackTrace();
}
return msgMap;
}
}
发送上图所示的消息后,Java 后台可以获取到如下所示的数据(转换为 Map 后)
{
Content = 愿你万事顺心, CreateTime = 1658903941, ToUserName = gh_29705b432aef, FromUserName = oUE315qFa2F6dRMPbLLe6Ni_nx08, MsgType = text, MsgId = 23749791147819923
},
{
Content = [Doge],
CreateTime = 1658904124,
ToUserName = gh_29705b432aef,
FromUserName = oUE315qFa2F6dRMPbLLe6Ni_nx08,
MsgType = text,
MsgId = 23749795504918624
},
{
MediaId = daG_YW6LhR7SRXIuWy4Ta9VaiUBDv85kqbwWc7qhnqVB2Paq8N3myGIbnFl51563,
CreateTime = 1658904571,
ToUserName = gh_29705b432aef,
FromUserName = oUE315qFa2F6dRMPbLLe6Ni_nx08,
MsgType = image,
PicUrl = http: //mmbiz.qpic.cn/mmbiz_jpg/FH7OzIia0uFlkbrB1Tj5oicgt2a3LYjquCAIibOEia3SAibLibgjBib7UJvnicPLbfb8icj9KALOlMHSTnpicrcGO0mKQvFQ/0, MsgId=23749799177282167
},
{
MediaId = daG_YW6LhR7SRXIuWy4Ta6JinoCv9rpXxQHAH_bCU08Ina4HlijE69j - YkT1OwA8opFxjBZcxZ5RN1P8kjFZZQ,
CreateTime = 1658904585,
ToUserName = gh_29705b432aef,
FromUserName = oUE315qFa2F6dRMPbLLe6Ni_nx08,
MsgType = video,
ThumbMediaId = daG_YW6LhR7SRXIuWy4TaytQBIglivXbQIVmUxFAQ__MNUnc0MAJgcdkD6PmDgcH,
MsgId = 23749801832652057
},
{
Location_X = 26.569666,
CreateTime = 1658904619,
Location_Y = 106.691162,
Label = 贵州省贵阳市南明区花果园彭家湾花果园项目F区第2栋1单元5层8号房(花果园社区),
Scale = 15,
ToUserName = gh_29705b432aef,
FromUserName = oUE315qFa2F6dRMPbLLe6Ni_nx08,
MsgType = location,
MsgId = 23749805760942682
}
二、回复用户消息
(1) 介绍
官方文档:
https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Passive_user_reply_message.html
用户发送消息给公众号后(或某些特定的用户操作引发的事件推送时),会产生一个 POST 请求,开发者可以在响应包(Get)中返回特定 XML 结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。
严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来的消息的一次回复。
微信服务器在将用户的消息发给公众号的开发者服务器地址(开发者中心处配置)后,若微信服务器在五秒内收不到响应,则会断掉连接,并且重新发起请求,总共重试三次。
如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。关于重试的消息排重,有 msgid 的消息,推荐使用 msgid 排重。事件类型消息,推荐使用 FromUserName + CreateTime 排重。
假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试,否则,将出现严重的错误提示(该公众号暂时无法提供服务,请稍后再试)
- 直接回复 success(推荐方式)
- 直接回复空串(指字节长度为0的空字符串,而不是 XML 结构体中 content 字段的内容为空)
一旦遇到以下情况,微信都会在公众号会话中,向用户下发系统提示【该公众号暂时无法提供服务,请稍后再试】
1、开发者在5秒内未回复任何内容
2、开发者回复了异常数据,比如 JSON 数据等3
3、回复图片(不支持 gif 动图)等多媒体消息时需要预先通过素材管理接口上传临时素材到微信服务器(可以使用素材管理中的临时素材,也可以使用永久素材)
可以回复的消息有6种:
- 文本消息
- 图片消息
- 语音消息
- 视频消息
- 音乐消息
- 图文消息
(2) 基本使用
<!-- 把 Java 对象转换为 XML 字符串 -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>
接收到用户在微信公众号发送的消息后,返回类似上图所示的 XML 字符串就可以对用户的消息进行回复。