springboot框架開發微信公眾號(二)之訊息的接受與響應
阿新 • • 發佈:2018-11-30
在開發之前我們要先知道使用者傳送的資訊是先傳送到微信伺服器,微信伺服器在以xml的格式傳送給進行公眾號
開發流程圖
程式碼實現
控制層程式碼
/** * 微信核心控制器(驗證服務號是否合法,以及訊息轉發都需要通過此controller) */ package com.b505.web; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import com.b505.tool.DataProcess; import com.b505.trycatch.TryCatchWeixinCoreService; import com.b505.weixin.util.WeixinSignUtil; import com.b505.weixin.util.WeixinVerification; /** * <p>Company: B505資訊科技研究所 </p> * @Description: 微信核心controller,接入微信服務層 * @Create Date: 2017年10月9日下午7:31:29 * @Version: V1.00 * @Author: 來日可期 */ @RestController @RequestMapping(value = "/wechat") public class WeixinCoreController { private static Logger logger = LoggerFactory.getLogger(WeixinCoreController.class); @Autowired private WeixinSignUtil weixinSignUtil; @Autowired private DataProcess dataProcess; @Autowired private WeixinCoreService weixinCoreService; @RequestMapping(value="/access", method=RequestMethod.POST) public String getWeiXinMessage(HttpServletRequest request, HttpServletResponse response)throws Exception{ logger.info("----------------開始處理微信發過來的訊息------------------"); // 微信伺服器POST訊息時用的是UTF-8編碼,在接收時也要用同樣的編碼,否則中文會亂碼; request.setCharacterEncoding("UTF-8"); // 在響應訊息(回覆訊息給使用者)時,也將編碼方式設定為UTF-8,原理同上; response.setCharacterEncoding("UTF-8"); String respXml = weixinCoreService.weixinMessageHandelCoreService(request, response); if (dataProcess.dataIsNull(respXml)){ logger.error("-------------處理微信訊息失敗-----------------------"); return null; }else { logger.info("----------返回微信訊息處理結果-----------------------:"+respXml); return respXml; } } }
private WeixinCoreService weixinCoreService; @RequestMapping(value="/access", method=RequestMethod.POST) public String getWeiXinMessage(HttpServletRequest request, HttpServletResponse response)throws Exception{ logger.info("----------------開始處理微信發過來的訊息------------------"); // 微信伺服器POST訊息時用的是UTF-8編碼,在接收時也要用同樣的編碼,否則中文會亂碼; request.setCharacterEncoding("UTF-8"); // 在響應訊息(回覆訊息給使用者)時,也將編碼方式設定為UTF-8,原理同上; response.setCharacterEncoding("UTF-8"); String respXml = weixinCoreService.weixinMessageHandelCoreService(request, response); if (dataProcess.dataIsNull(respXml)){ logger.error("-------------處理微信訊息失敗-----------------------"); return null; }else { logger.info("----------返回微信訊息處理結果-----------------------:"+respXml); return respXml; } } }
service層程式碼
/** * 微信訊息處理核心service實現類 */ package com.b505.service.impl; import java.util.Date; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.b505.dao.UserDao; import com.b505.service.WeixinCoreService; import com.b505.tool.DataProcess; import com.b505.weixin.message.resp.TextMessage; import com.b505.weixin.pojo.WeixinMessageInfo; import com.b505.weixin.util.WeixinMessageModelUtil; import com.b505.weixin.util.WeixinMessageUtil; /** * <p>Company: B505資訊科技研究所 </p> * @Description: 微信訊息處理核心service實現類 * @Create Date: 2017年10月10日下午3:33:16 * @Version: V1.00 * @Author: 來日可期 */ @Service("weixinCoreService") public class WeixinCoreServiceImpl implements WeixinCoreService { private static Logger logger = LoggerFactory.getLogger(WeixinCoreServiceImpl.class); @Autowired private WeixinMessageUtil weixinMessageUtil; @Autowired private WeixinMessageInfo weixinMessageInfo; @Autowired private WeixinMessageModelUtil weixinMessageModelUtil; @Autowired private UserDao userDao; @Autowired private DataProcess dataProcess; @Override public String weixinMessageHandelCoreService(HttpServletRequest request, HttpServletResponse response) { logger.info("------------微信訊息開始處理-------------"); // 返回給微信伺服器的訊息,預設為null String respMessage = null; try { // 預設返回的文字訊息內容 String respContent = null; // xml分析 // 呼叫訊息工具類MessageUtil解析微信發來的xml格式的訊息,解析的結果放在HashMap裡; Map<String, String> map = weixinMessageUtil.parseXml(request); // 傳送方賬號 String fromUserName = map.get("FromUserName"); weixinMessageInfo.setFromUserName(fromUserName); System.out.println("fromUserName--->"+fromUserName); // 接受方賬號(公眾號) String toUserName = map.get("ToUserName"); weixinMessageInfo.setToUserName(toUserName); System.out.println("toUserName----->"+toUserName); // 訊息型別 String msgType = map.get("MsgType"); weixinMessageInfo.setMessageType(msgType); logger.info("fromUserName is:" +fromUserName+" toUserName is:" +toUserName+" msgType is:" +msgType); // 預設回覆文字訊息 TextMessage textMessage = new TextMessage(); textMessage.setToUserName(fromUserName); textMessage.setFromUserName(toUserName); textMessage.setCreateTime(new Date().getTime()); textMessage.setMsgType(weixinMessageUtil.RESP_MESSAGE_TYPE_TEXT); textMessage.setFuncFlag(0); // 分析使用者傳送的訊息型別,並作出相應的處理 // 文字訊息 if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_TEXT)){ respContent = "親,這是文字訊息!"; textMessage.setContent(respContent); respMessage = weixinMessageUtil.textMessageToXml(textMessage); } // 圖片訊息 else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_IMAGE)) { respContent = "您傳送的是圖片訊息!"; textMessage.setContent(respContent); respMessage = weixinMessageUtil.textMessageToXml(textMessage); } // 語音訊息 else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_VOICE)) { respContent = "您傳送的是語音訊息!"; textMessage.setContent(respContent); respMessage = weixinMessageUtil.textMessageToXml(textMessage); } // 視訊訊息 else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_VIDEO)) { respContent = "您傳送的是視訊訊息!"; textMessage.setContent(respContent); respMessage = weixinMessageUtil.textMessageToXml(textMessage); } // 地理位置訊息 else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_LOCATION)) { respContent = "您傳送的是地理位置訊息!"; textMessage.setContent(respContent); respMessage = weixinMessageUtil.textMessageToXml(textMessage); } // 連結訊息 else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_LINK)) { respContent = "您傳送的是連結訊息!"; textMessage.setContent(respContent); respMessage = weixinMessageUtil.textMessageToXml(textMessage); } // 事件推送(當用戶主動點選選單,或者掃面二維碼等事件) else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_EVENT)) { // 事件型別 String eventType =map.get("Event"); System.out.println("eventType------>"+eventType); // 關注 if (eventType.equals(weixinMessageUtil.EVENT_TYPE_SUBSCRIBE)){ respMessage = weixinMessageModelUtil.followResponseMessageModel(weixinMessageInfo); } // 取消關注 else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_UNSUBSCRIBE)) { weixinMessageModelUtil.cancelAttention(fromUserName); } // 掃描帶引數二維碼 else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_SCAN)) { System.out.println("掃描帶引數二維碼"); } // 上報地理位置 else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_LOCATION)) { System.out.println("上報地理位置"); } // 自定義選單(點選選單拉取訊息) else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_CLICK)) { // 事件KEY值,與建立自定義選單時指定的KEY值對應 String eventKey=map.get("EventKey"); System.out.println("eventKey------->"+eventKey); } // 自定義選單((自定義選單URl檢視)) else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_VIEW)) { System.out.println("處理自定義選單URI檢視"); } } } catch (Exception e) { e.printStackTrace(); logger.error("系統出錯"); System.err.println("系統出錯"); respMessage = null; } finally{ if (null == respMessage) { respMessage = weixinMessageModelUtil.systemErrorResponseMessageModel(weixinMessageInfo); } } return respMessage; } }
工具類
/**
* 封裝微信訊息型別,有一個解析微信發過的xml訊息的工具
*/
package com.b505.weixin.util;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.stereotype.Component;
import com.b505.Message.model.Article;
import com.b505.weixin.message.resp.ImageMessage;
import com.b505.weixin.message.resp.MusicMessage;
import com.b505.weixin.message.resp.NewsMessage;
import com.b505.weixin.message.resp.TextMessage;
import com.b505.weixin.message.resp.VideoMessage;
import com.b505.weixin.message.resp.VoiceMessage;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
/**
* <p>Company: B505資訊科技研究所 </p>
* @Description: 封裝微信訊息型別,有一個解析xml格式的工具
* @Create Date: 2017年10月11日上午11:28:48
* @Version: V1.00
* @Author: 來日可期
*/
@Component
public class WeixinMessageUtil {
/**
* 請求訊息型別:文字
*/
public final String REQ_MESSAGE_TYPE_TEXT = "text";
/**
* 請求訊息型別:圖片
*/
public final String REQ_MESSAGE_TYPE_IMAGE="image";
/**
* 請求訊息型別:語音
*/
public final String REQ_MESSAGE_TYPE_VOICE="voice";
/**
* 請求訊息型別:視訊
*/
public final String REQ_MESSAGE_TYPE_VIDEO="video";
/**
* 請求訊息型別:連結
*/
public final String REQ_MESSAGE_TYPE_LINK = "link";
/**
* 請求訊息型別:地理位置
*/
public final String REQ_MESSAGE_TYPE_LOCATION="location";
/**
* 請求訊息型別:小視訊
*/
public final String REQ_MESSAGE_TYPE_SHORTVIDEO="shortvideo";
/**
*請求訊息型別:事件推送
*/
public final String REQ_MESSAGE_TYPE_EVENT = "event";
/**
* 返回訊息型別:文字
*/
public final String RESP_MESSAGE_TYPE_TEXT = "text";
/**
* 訊息返回型別:圖片
*/
public final String RESP_MESSAGE_TYPE_IMAGE="image";
/**
* 訊息返回型別:語音
*/
public final String RESP_MESSAGE_TYPE_VOICE = "voice";
/**
* 訊息返回型別:音樂
*/
public final String RESP_MESSAGE_TYPE_MUSIC = "music";
/**
* 訊息返回型別:圖文
*/
public final String RESP_MESSAGE_TYPE_NEWS = "news";
/**
* 訊息返回型別:視訊
*/
public final String RESP_MESSAGE_TYPE_VIDEO="video";
/**
* 事件型別:訂閱
*/
public final String EVENT_TYPE_SUBSCRIBE = "subscribe";
/**
* 事件型別:取消訂閱
*/
public final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
/**
* 事件型別:scan(關注使用者掃描帶參二維碼)
*/
public final String EVENT_TYPE_SCAN = "scan";
/**
* 事件型別:location(上報地理位置)
*/
public final String EVENT_TYPE_LOCATION = "location";
/**
* 事件型別:CLICK(點選選單拉取訊息)
*/
public final String EVENT_TYPE_CLICK ="CLICK";
/**
* 事件型別:VIEW(自定義選單URl檢視)
*/
public final String EVENT_TYPE_VIEW ="VIEW";
/**
* 事件型別:TEMPLATESENDJOBFINISH(模板訊息送達情況提醒)
*/
public final String EVENT_TYPE_TEMPLATESENDJOBFINISH="TEMPLATESENDJOBFINISH";
/**
* @Description: 解析微信伺服器發過來的xml格式的訊息將其轉換為map
* @Parameters: WeixinMessageUtil
* @Return: Map<String, String>
* @Create Date: 2017年10月11日上午11:41:23
* @Version: V1.00
* @author:來日可期
*/
public Map<String, String> parseXml(HttpServletRequest request)throws Exception{
// 將解析結果儲存在HashMap中
Map<String, String>map =new HashMap<String, String>();
// 從request中得到輸入流
InputStream inputStream=request.getInputStream();
// 讀取輸入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到XML的根元素
Element root = document.getRootElement();
// 得到根元素的所有子節點
@SuppressWarnings("unchecked")
List<Element> elementList = root.elements();
// 判斷又沒有子元素列表
if (elementList.size()==0){
map.put(root.getName(), root.getText());
}else {
for (Element e : elementList)
map.put(e.getName(), e.getText());
}
// 釋放資源
inputStream.close();
inputStream = null;
System.out.println("---------xml轉換為map-----:"+map);
return map;
}
/**
* @Description: 文字訊息物件轉換成xml
* @param textMessage
* @date 2016-12-01
* @return xml
*/
public String textMessageToXml(TextMessage textMessage) {
xstream.alias("xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
/**
* @Description: 圖文訊息物件轉換成xml
* @param newsMessage
* @date 2016-12-01
* @return xml
*/
public String newsMessageToXml(NewsMessage newsMessage) {
xstream.alias("xml", newsMessage.getClass());
xstream.alias("item", new Article().getClass());
return xstream.toXML(newsMessage);
}
/**
* @Description: 圖片訊息物件轉換成xml
* @param imageMessage
* @date 2016-12-01
* @return xml
*/
public String imageMessageToXml(ImageMessage imageMessage) {
xstream.alias("xml", imageMessage.getClass());
return xstream.toXML(imageMessage);
}
/**
* @Description: 語音訊息物件轉換成xml
* @param voiceMessage
* @date 2016-12-01
* @return xml
*/
public String voiceMessageToXml(VoiceMessage voiceMessage) {
xstream.alias("xml", voiceMessage.getClass());
return xstream.toXML(voiceMessage);
}
/**
* @Description: 視訊訊息物件轉換成xml
* @param videoMessage
* @date 2016-12-01
* @return xml
*/
public String videoMessageToXml(VideoMessage videoMessage) {
xstream.alias("xml", videoMessage.getClass());
return xstream.toXML(videoMessage);
}
/**
* @Description: 音樂訊息物件轉換成xml
* @param MusicMessage
* @date 2016-12-01
* @return xml
*/
public String musicMessageToXml(MusicMessage musicMessage) {
xstream.alias("xml", musicMessage.getClass());
return xstream.toXML(musicMessage);
}
/**
* 物件到xml的處理
* 擴充套件xstream,使其支援CDATA塊
*/
private XStream xstream = new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 對所有xml節點的轉換都增加CDATA標記
boolean cdata = true;
@Override
@SuppressWarnings("rawtypes")
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
}
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
封裝的WeixinMessageInfo類
/**
* 將傳送方,接收方,微信使用者名稱等封裝成類
*/
package com.b505.weixin.pojo;
import java.io.Serializable;
import org.springframework.stereotype.Component;
/**
* <p>Company: B505資訊科技研究所 </p>
* @Description: 將傳送方,接收方,微信使用者名稱封裝
* @Create Date: 2017年10月23日上午11:45:44
* @Version: V1.00
* @Author: 來日可期
*/
@Component
public class WeixinMessageInfo implements Serializable{
private static final long serialVersionUID = 1L;
private String fromUserName; // 傳送發微信賬號
private String toUserName; // 接收方微信賬號
private String weixinUserName; // 微信使用者名稱
private String messageType; // 訊息型別
/**
* @return the fromUserName
*/
public String getFromUserName() {
return fromUserName;
}
/**
* @param fromUserName the fromUserName to set
*/
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
/**
* @return the toUserName
*/
public String getToUserName() {
return toUserName;
}
/**
* @param toUserName the toUserName to set
*/
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
/**
* @return the weixinUserName
*/
public String getWeixinUserName() {
return weixinUserName;
}
/**
* @param weixinUserName the weixinUserName to set
*/
public void setWeixinUserName(String weixinUserName) {
this.weixinUserName = weixinUserName;
}
/**
* @return the messageType
*/
public String getMessageType() {
return messageType;
}
/**
* @param messageType the messageType to set
*/
public void setMessageType(String messageType) {
this.messageType = messageType;
}
@Override
public String toString() {
return "WeixinMessageInfo [fromUserName=" + fromUserName
+ ", toUserName=" + toUserName + ", weixinUserName="
+ weixinUserName + ", messageType=" + messageType + "]";
}
}
文中涉及到的圖文訊息等回覆的訊息將在下節中介紹