Java微信公眾平臺之消息管理
Java微信公眾平臺開發(fā)之消息管理,一定要先看下官方文檔
微信消息管理分為接收普通消息、接收事件推送、發(fā)送消息(被動回復(fù))、客服消息、群發(fā)消息、模板消息這幾部分
一、接收普通消息
當(dāng)普通微信用戶向公眾賬號發(fā)消息時,微信服務(wù)器將POST消息的XML數(shù)據(jù)包到開發(fā)者填寫的URL上。
關(guān)于MsgId,官方給出解釋,相當(dāng)于每個消息ID,關(guān)于重試的消息排重,推薦使用msgid排重。微信服務(wù)器在五秒內(nèi)收不到響應(yīng)會斷掉連接,并且重新發(fā)起請求,總共重試三次。
比如文本消息的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> </xml>
其他的消息去官方文檔查看,簡單封裝如下
消息抽象基類AbstractMsg.java
package com.phil.wechat.msg.model.req;
import java.io.Serializable;
/**
* 基礎(chǔ)消息類
*
* @author phil
*
*/
public abstract class AbstractMsg implements Serializable {
private static final long serialVersionUID = -6244277633057415731L;
private String ToUserName; // 開發(fā)者微信號
private String FromUserName; // 發(fā)送方帳號(一個OpenID)
private String MsgType = SetMsgType(); // 消息類型 例如 /text/image
private long CreateTime; // 消息創(chuàng)建時間 (整型)
private long MsgId; // 消息id,64位整型
/**
* 消息類型
*
* @return
*/
public abstract String SetMsgType();
}
文本消息TextMsg.java
package com.phil.wechat.msg.model.req;
/**
* 文本消息
* @author phil
* @date 2017年6月30日
*
*/
public class TextMsg extends AbstractMsg {
private static final long serialVersionUID = -1764016801417503409L;
private String Content; // 文本消息
@Override
public String SetMsgType() {
return "text";
}
}
其他的依樣畫葫蘆......
二、被動回復(fù)用戶消息
微信服務(wù)器在將用戶的消息發(fā)給公眾號的開發(fā)者服務(wù)器地址(開發(fā)者中心處配置)后,微信服務(wù)器在五秒內(nèi)收不到響應(yīng)會斷掉連接,并且重新發(fā)起請求,總共重試三次,如果在調(diào)試中,發(fā)現(xiàn)用戶無法收到響應(yīng)的消息,可以檢查是否消息處理超時。假如服務(wù)器無法保證在五秒內(nèi)處理并回復(fù),可以直接回復(fù)空串,微信服務(wù)器不會對此作任何處理,并且不會發(fā)起重試。
如果出現(xiàn)“該公眾號暫時無法提供服務(wù),請稍后再試”,原因有兩個
- 開發(fā)者在5秒內(nèi)未回復(fù)任何內(nèi)容
- 開發(fā)者回復(fù)了異常數(shù)據(jù)
比如回復(fù)的文本消息Xml示例
<xml> <ToUserName><![CDATA[toUser]]></ToUserName> <FromUserName><![CDATA[fromUser]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你好]]></Content> </xml>
簡單封裝下
回復(fù)消息抽象基類RespAbstractMsg.java
package com.phil.wechat.msg.model.resp;
import java.io.Serializable;
/**
* 消息基類(公眾帳號 -> 普通用戶)
*
* @author phil
*
*/
public abstract class RespAbstractMsg{
// 接收方帳號(收到的OpenID)
private String ToUserName;
// 開發(fā)者微信號
private String FromUserName;
// 消息創(chuàng)建時間 (整型)
private long CreateTime;
// 消息類型(text/music/news)
private String MsgType = setMsgType(); // 消息類型
public abstract String setMsgType();
}
回復(fù)文本消息RespTextMsg.java
package com.phil.wechat.msg.model.resp;
/**
* 回復(fù)圖片消息
*
* @author phil
* @data 2017年3月26日
*
*/
public class RespImageMsg extends RespAbstractMsg {
private Image Image;
@Override
public String setMsgType() {
return "image";
}
/**
*
* @author phil
* @date 2017年7月19日
*
*/
public class Image {
// 通過素材管理中的接口上傳多媒體文件,得到的id。
private String MediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
}
}
其他消息類型依樣畫葫蘆......
三、消息的處理
掌握xml解析
package com.phil.wechat.msg.controller;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
import org.dom4j.DocumentException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.phil.modules.config.WechatConfig;
import com.phil.modules.util.MsgUtil;
import com.phil.modules.util.SignatureUtil;
import com.phil.modules.util.XmlUtil;
import com.phil.wechat.base.controller.BaseController;
import com.phil.wechat.base.result.WechatResult;
import com.phil.wechat.msg.model.req.BasicMsg;
import com.phil.wechat.msg.model.resp.RespAbstractMsg;
import com.phil.wechat.msg.model.resp.RespNewsMsg;
import com.phil.wechat.msg.service.WechatMsgService;
/**
* @author phil
* @date 2017年9月19日
*
*/
@Controller
@RequestMapping("/wechat")
public class WechatMsgController extends BaseController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private WechatMsgService wechatMsgService;
/**
* 校驗信息是否是從微信服務(wù)器發(fā)出,處理消息
* @param out
* @throws IOException
*/
@RequestMapping(value = "/handler", method = { RequestMethod.GET, RequestMethod.POST })
public void processPost() throws Exception {
this.getRequest().setCharacterEncoding("UTF-8");
this.getResponse().setCharacterEncoding("UTF-8");
boolean ispost = Objects.equals("POST", this.getRequest().getMethod().toUpperCase());
if (ispost) {
logger.debug("接入成功,正在處理邏輯");
String respXml = defaultMsgDisPose(this.getRequest().getInputStream());//processRequest(request, response);
if (StringUtils.isNotBlank(respXml)) {
this.getResponse().getWriter().write(respXml);
}
} else {
String signature = this.getRequest().getParameter("signature");
// 時間戳
String timestamp = this.getRequest().getParameter("timestamp");
// 隨機(jī)數(shù)
String nonce = this.getRequest().getParameter("nonce");
// 通過檢驗signature對請求進(jìn)行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗
if (SignatureUtil.checkSignature(signature, timestamp, nonce)) {
// 隨機(jī)字符串
String echostr = this.getRequest().getParameter("echostr");
logger.debug("接入成功,echostr {}", echostr);
this.getResponse().getWriter().write(echostr);
}
}
}
/**
* 默認(rèn)處理方法
* @param input
* @return
* @throws Exception
* @throws DocumentException
*/
private String defaultMsgDisPose(InputStream inputStream) throws Exception {
String result = null;
if (inputStream != null) {
Map<String, String> params = XmlUtil.parseStreamToMap(inputStream);
if (params != null && params.size() > 0) {
BasicMsg msgInfo = new BasicMsg();
String createTime = params.get("CreateTime");
String msgId = params.get("MsgId");
msgInfo.setCreateTime((createTime != null && !"".equals(createTime)) ? Integer.parseInt(createTime) : 0);
msgInfo.setFromUserName(params.get("FromUserName"));
msgInfo.setMsgId((msgId != null && !"".equals(msgId)) ? Long.parseLong(msgId) : 0);
msgInfo.setToUserName(params.get("ToUserName"));
WechatResult resultObj = coreHandler(msgInfo, params);
if(resultObj == null){ //
return null;
}
boolean success = resultObj.isSuccess(); //如果 為true,則表示返回xml文件, 直接轉(zhuǎn)換即可,否則按類型
if (success) {
result = resultObj.getObject().toString();
} else {
int type = resultObj.getType(); // 這里規(guī)定 1 圖文消息 否則直接轉(zhuǎn)換
if (type == WechatResult.NEWSMSG) {
RespNewsMsg newsMsg = (RespNewsMsg) resultObj.getObject();
result = MsgUtil.newsMsgToXml(newsMsg);
} else {
RespAbstractMsg basicMsg = (RespAbstractMsg) resultObj.getObject();
result = MsgUtil.msgToXml(basicMsg);
}
}
} else {
result = "msg is wrong";
}
}
return result;
}
/**
* 核心處理
*
* @param msg
* 消息基類
* @param params
* xml 解析出來的 數(shù)據(jù)
* @return
*/
private WechatResult coreHandler(BasicMsg msg, Map<String, String> params) {
WechatResult result = null;
String msgType = params.get("MsgType");
if (StringUtils.isEmpty(msgType)) {
switch (msgType) {
case WechatConfig.REQ_MESSAGE_TYPE_TEXT: // 文本消息
result = wechatMsgService.textMsg(msg, params);
break;
case WechatConfig.REQ_MESSAGE_TYPE_IMAGE: // 圖片消息
result = wechatMsgService.imageMsg(msg, params);
break;
case WechatConfig.REQ_MESSAGE_TYPE_LINK: // 鏈接消息
result = wechatMsgService.linkMsg(msg, params);
break;
case WechatConfig.REQ_MESSAGE_TYPE_LOCATION: // 地理位置
result = wechatMsgService.locationMsg(msg, params);
break;
case WechatConfig.REQ_MESSAGE_TYPE_VOICE: // 音頻消息
result = wechatMsgService.voiceMsg(msg, params);
break;
case WechatConfig.REQ_MESSAGE_TYPE_SHORTVIDEO: // 短視頻消息
result = wechatMsgService.shortvideo(msg, params);
break;
case WechatConfig.REQ_MESSAGE_TYPE_VIDEO: // 視頻消息
result = wechatMsgService.videoMsg(msg, params);
break;
case WechatConfig.REQ_MESSAGE_TYPE_EVENT: // 事件消息
String eventType = params.get("Event"); //
if (eventType != null && !"".equals(eventType)) {
switch (eventType) {
case WechatConfig.EVENT_TYPE_SUBSCRIBE:
result = wechatMsgService.subscribe(msg, params);
break;
case WechatConfig.EVENT_TYPE_UNSUBSCRIBE:
result = wechatMsgService.unsubscribe(msg, params);
break;
case WechatConfig.EVENT_TYPE_SCAN:
result = wechatMsgService.scan(msg, params);
break;
case WechatConfig.EVENT_TYPE_LOCATION:
result = wechatMsgService.eventLocation(msg, params);
break;
case WechatConfig.EVENT_TYPE_CLICK:
result = wechatMsgService.eventClick(msg, params);
break;
case WechatConfig.EVENT_TYPE_VIEW:
result = wechatMsgService.eventView(msg, params);
break;
case WechatConfig.KF_CREATE_SESSION:
result = wechatMsgService.kfCreateSession(msg, params);
break;
case WechatConfig.KF_CLOSE_SESSION:
result = wechatMsgService.kfCloseSession(msg, params);
break;
case WechatConfig.KF_SWITCH_SESSION:
result = wechatMsgService.kfSwitchSession(msg, params);
break;
default:
wechatMsgService.eventDefaultReply(msg, params);
break;
}
}
break;
default:
wechatMsgService.defaultMsg(msg, params);
}
}
return result;
}
}
只是提供個思路,如若參考代碼請移步
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
詳解Spring Boot應(yīng)用的啟動和停止(start啟動)
這篇文章主要介紹了詳解Spring Boot應(yīng)用的啟動和停止(start啟動),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-12-12
對SpringBoot項目Jar包進(jìn)行加密防止反編譯
最近項目要求部署到其他公司的服務(wù)器上,但是又不想將源碼泄露出去,要求對正式環(huán)境的啟動包進(jìn)行安全性處理,防止客戶直接通過反編譯工具將代碼反編譯出來,本文介紹了如何對SpringBoot項目Jar包進(jìn)行加密防止反編譯,需要的朋友可以參考下2023-10-10
淺談MyBatis3 DynamicSql風(fēng)格語法使用指南
這篇文章主要介紹了淺談MyBatis3 DynamicSql風(fēng)格語法使用指南,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03
Redis使用RedisTemplate模板類的常用操作方式
這篇文章主要介紹了Redis使用RedisTemplate模板類的常用操作方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Java inputstream和outputstream使用詳解
這篇文章主要介紹了Java inputstream和outputstream使用詳解,本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
springboot實現(xiàn)異步調(diào)用@Async的示例
這篇文章主要介紹了springboot實現(xiàn)異步調(diào)用@Async的示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12

