1. 程式人生 > >springboot框架開發微信公眾號(二)之訊息的接受與響應

springboot框架開發微信公眾號(二)之訊息的接受與響應

在開發之前我們要先知道使用者傳送的資訊是先傳送到微信伺服器,微信伺服器在以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 + "]";
	}
}

文中涉及到的圖文訊息等回覆的訊息將在下節中介紹