接收微信用户发送的事件以及消息
进入第三方平台的管理中心,查看并保存以下信息
确认预设的
公众号消息与事件接收URL
把token和key保存在项目的静态类中或者数据库中,方便随时调用
微信公众平台技术文档
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140453
下面只讲接收普通文本消息
接收普通消息
当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。
请注意:
1、关于重试的消息排重,推荐使用msgid排重。
2、微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,
可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。详情请见“发送消息-被动回复消息”。
3、如果开发者需要对用户消息在5秒内立即做出回应,即使用“发送消息-被动回复消息”接口向用户被动回复消息时,可以在
公众平台官网的开发者中心处设置消息加密。开启加密后,用户发来的消息和开发者回复的消息都会被加密(但开发者通过客服
接口等API调用形式向用户发送消息,则不受影响)。关于消息加解密的详细说明,请见“发送消息-被动回复消息加解密说明”。
各消息类型的推送XML数据包结构如下:
文本消息
1348831860 1234567890123456
|
参数 |
描述 |
ToUserName |
开发者微信号 |
FromUserName |
发送方帐号(一个OpenID) |
CreateTime |
消息创建时间 (整型) |
MsgType |
text |
Content |
文本消息内容 |
MsgId |
消息id,64位整型 |
简单讲,就是微信用户在手机上给公众号发的普通文本消息会以上面的格式发到第三方平台的
公众号消息与事件接收URL
然后这个xml是加密过的,关于加解密前面第一篇讲过了,忘记的可以回去看
/**
* 接收公众号消息以及事件入口
* @return
*/
@ResponseBody
@RequestMapping(value = "/{appid}/callback")
public String callback(@RequestParam("timestamp")String timestamp, @RequestParam("nonce")String nonce,
@RequestParam("msg_signature")String msgSignature, @PathVariable String appid,@RequestBody String postData){
/**在日志中打印所有参数方便确认*/
logger.info("timestamp={},nonce={},msg_signature={}",timestamp,nonce,msgSignature);
try {
/**对xml进行解密*/
String resultData = thirdPartyService.decryptMsg(msgSignature, timestamp, nonce, postData);
logger.info("ThirdPartyController:callback:appid={},resultData={}",appid, resultData);
/**获取处理返回处理消息*/
String sendData = thirdPartyService.callback(resultData);
logger.info("ThirdPartyController:callback:sendData={}",sendData);
return thirdPartyService.encryptMsg( timestamp, nonce, sendData);
} catch (Exception e) {
/**如果加解密失败,打印失败信息*/
logger.info("ThirdPartyController:getComponentVerifyTicket:加解密失败");
e.printStackTrace();
return "success";
}
}
解密之后得到xml明文,将Xml转换成map,方便提取数据
之后根据消息类型进行分类处理
@Override
public String callback(String resultData) {
try {
/**将消息解析为map*/
Map dataMap = ThirdPartyUtil.xmlToMap(resultData);
/**下面这段是每次接收消息都记录下发送方和接收方的名称并保存到数据库,方便之后的业务处理*/
String userId = dataMap.get("FromUserName");
String platformId = dataMap.get("ToUserName");
/**拼装User*/
if(!userDBService.exists(userId)){
User user = new User(platformId, userId);
logger.info("将要插入数据库:user={}",user);
userDBService.set(user);
}
/**判断消息类型,调用对应的方法*/
switch (dataMap.get("MsgType")){
case "event":
return platformMessageService.replyEvent(dataMap);
case "text":
return platformMessageService.replyMsg(dataMap);
default:
return "success";
}
} catch (Exception e) {
e.printStackTrace();
return "callback发生了异常";
}
}
以全网发布需要的测试为例子
1、模拟粉丝触发专用测试公众号的事件,并推送事件消息到专用测试公众号,第三方平台方开发者需要提取推送XML信息中的event值,并在5秒内立即返回按照下述要求组装的文本消息给粉丝。
-
1)微信推送给第三方平台方: 事件XML内容(与普通公众号接收到的信息是一样的)
-
2)服务方开发者在5秒内回应文本消息并最终触达到粉丝:文本消息的XML中Content字段的内容必须组装为:event + “from_callback”(假定event为LOCATION,则Content为: LOCATIONfrom_callback)
@Override
public String replyMsg(Map dataMap) throws Exception {
String receivedContent = dataMap.get("Content");//获取消息内容
String platformId = dataMap.get("ToUserName");//获取公众号名称
String userId = dataMap.get("FromUserName");//获取微信用户名称
/**下面这个if也是全网发布需要的测试,通过客服消息接口给微信用户发消息*/
if(receivedContent.contains("QUERY_AUTH_CODE")){
int index = receivedContent.indexOf(":");
String authCode = receivedContent.substring(index+1);
String appId = thirdPartyService.queryAuth(authCode,"7200");
sendServiceMsg(appId,userId,receivedContent+"_from_api");
return "";
}
//拼装成指定格式
return WxMsgUtil.replyText(userId,platformId,"TESTCOMPONENT_MSG_TYPE_TEXT_callback");
}
replyText
public static String replyText(String toUserName, String fromUserName, String content) throws Exception {
Map replyMap = new HashMap();
replyMap.put("ToUserName",toUserName);
replyMap.put("FromUserName",fromUserName);
replyMap.put("CreateTime",ThirdPartyUtil.getCurrentTimestamp()+"");
replyMap.put("MsgType","text");
replyMap.put("Content",content);
return ThirdPartyUtil.mapToXml(replyMap);
}