上一篇博文是介紹如何進行服務器端配置,配置的至關於爲微信的消息接口,微信向服務器端推送消息或者推送用戶發送的消息就會推送到該配置的URL中,配置好了事後,咱們就須要在服務器端接收用戶發送的一系列消息。html
服務器端接收用戶消息和接收微信推送消息是使用的同一個地址,可是有一個區別接收推送消息爲GET方法,接收用戶發送的消息爲POST方法。java
使用流接收POST消息轉爲String結果爲XML的消息體,若是是在微信後臺選擇的爲安全模式則須要解密,如果明文模式,那就直接解析XML就是了,此處爲加密模式需用到解密類,本博文使用的爲微信提供的解密類。連接爲:安全
微信加解密文檔:
http://mp.weixin.qq.com/wiki/11/2d2d1df945b75605e7fea9ea2573b667.html
加解密代碼:
http://mp.weixin.qq.com/wiki/static/assets/a5a22f38cb60228cb32ab61d9e4c414b.zip服務器
環境爲:SpringMvc4
栗子:微信
//微信接收消息接口 @ResponseBody @RequestMapping(value = "signature",method = RequestMethod.POST) public String signature(HttpServletRequest request) throws AesException{ try { //接收流 ServletInputStream sis = request.getInputStream(); StringBuilder xmlMsg = new StringBuilder(); byte[] b = new byte[4096]; for (int n; (n = sis.read(b)) != -1;) { xmlMsg.append(new String(b, 0, n, "UTF-8")); } System.out.println(xmlMsg); //接收加密的xml Object[] encrypt = XMLParse.extract(xmlMsg.toString()); //解密 WXBizMsgCrypt wxcpt = new WXBizMsgCrypt("token", "encodingAesKey", "appid"); //獲取解密後的XML String msg = wxcpt.decrypt(encrypt[1].toString()); //轉對象 WxMsgRequest wmr = this.convertWxMesgToObj(msg); System.out.println(wmr); if(wmr.getMsgType().equals(WxRequestMsgType.MSG_TEXT)){ WxTextMsgResponse wtmr = new WxTextMsgResponse(); wtmr.setContent("點點與麥兜的TEST"); Long createTime = System.currentTimeMillis() / 1000; wtmr.setCreateTime(createTime.toString()); wtmr.setFromUserName(wmr.getToUserName()); wtmr.setToUserName(wmr.getFromUserName()); wtmr.setMsgType(WxRequestMsgType.MSG_TEXT); String returnStr = this.convertObjToXml(wtmr); return returnStr; } } catch (Exception e) { e.printStackTrace(); } return null; } //微信驗證接口 @ResponseBody @RequestMapping(value = "signature",method=RequestMethod.GET) public String signature(String signature, String timestamp, String nonce, String echostr){ try { String shaPw = SHA1.getSHA1("xiaofli007", timestamp, nonce); if(signature.equals(shaPw)) return echostr; else return null; } catch (Exception e) { e.printStackTrace(); } return null; } //將xml數據解析爲對象 private WxMsgRequest convertWxMesgToObj(String msg) throws JAXBException{ JAXBContext context = JAXBContext.newInstance(WxMsgRequest.class); Unmarshaller unmarshaller = context.createUnmarshaller(); return (WxMsgRequest)unmarshaller.unmarshal(new StringReader(msg)); } //將對象轉爲xml字符串 public String convertObjToXml(Object obj) throws JAXBException{ JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); StringWriter writer = new StringWriter(); marshaller.marshal(obj, writer); String temp = writer.toString(); return temp; }
解密前消息: 微信開發
<xml> <ToUserName><![CDATA[gh_e1c44a3a9f81]]></ToUserName> <Encrypt><![CDATA[HusAtbuEO8XmYaH4tzuZHcdi7Kg2e6szJfZrzdQLnpEs6D0jrNWKLFYftafLyKLFy7sOPbQUYI8DaVPPV/0npFSRym2oskoN0ip3q93XXtunbz5OBmWlYsvKnJuYK/UlIttgrJbrRFJlz4AKiHYUnJx7vaSAFvErAlhudPA1rhPEa64sARRGRQhrP1m/zffbSRl6uI7Wz1jsIsfiZAPg0nxqfxdDXh9Gklcp6DNHhf3phAx9pt8kyZKh4n8yhHV1+R+WU0c86YEgwQ7NHgA0CaryQPemkNRF06YrWEvE0meToeT08sm2A0bZJUiGGmj8dD9/b6KsESaQmfsF2JzdRvSq79gLO+Mn0swQS4wjOnbrgw7otvlYCZnDu4+xcfv+lGgMIc0YfG/jtT4VH6pboBtm1xCRs01N14SHB8pGryA=]]></Encrypt> </xml>
解密後的消息:app
<xml> <ToUserName><![CDATA[gh_e1c44a3a9f81]]></ToUserName> <FromUserName><![CDATA[oMffXwBl4N4F29vbH3UAbrdhMq4Y]]></FromUserName> <CreateTime>1475129963</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[11]]></Content> <MsgId>6335634948877288984</MsgId> </xml>
文本消息(text)
圖片消息(image)
語音消息(voice)
視頻消息(video)
小視頻消息 (shortvideo)
地理位置消息(location)
連接消息(link)curl
建立一個實體類,用於接受消息(爲了方便我是所有字段寫到一個類中,也能夠先判斷類型:再指定接受的類型):ide
@XmlRootElement(name = "xml") public class WxMsgRequest { /*** 開發者微信號 */ private String ToUserName; /*** 發送方賬號(一個OpenID)*/ private String FromUserName; /*** 消息建立時間 (整型)*/ private String CreateTime; /*** 消息類型有:text ; event ; 語音爲voice*/ private String MsgType; /*** 消息id*/ private String MsgId; /*** 語音消息媒體id,能夠調用多媒體文件下載接口拉取數據。*/ private String MediaId; /*** 語音格式,如amr,speex等*/ private String Format; /*** 視頻消息縮略圖的媒體id,能夠調用多媒體文件下載接口拉取數據。*/ private String ThumbMediaId; /*** 文本消息內容*/ private String Content; /*** 圖片消息URL*/ private String picUrl; /*** 地理位置消息 地理位置緯度*/ private String gpsX; /*** 地理位置消息 地理位置經度*/ private String gpsY; /*** 地理位置消息 地圖縮放大小*/ private String scale; /*** 地理位置消息 地理位置信息*/ private String label; /*** 連接消息 消息標題*/ private String title; /*** 連接消息 消息描述*/ private String description; /*** 連接消息 消息連接*/ private String url; /** * 事件類型,subscribe(訂閱)、unsubscribe(取消訂閱)、CLICK(自定義菜單點擊事件) * WeixinRequestMsgType#SUBSCRIBE_EVENT */ private String Event; /*** 事件KEY值,與自定義菜單接口中KEY值對應*/ private String EventKey; /** 二維碼的ticket,可用來換取二維碼圖片 **/ private String Ticket; @XmlElement(name = "Ticket") public String getTicket() { return Ticket; } public void setTicket(String ticket) { Ticket = ticket; } //因爲文章篇幅問題,下面的參數set方法和get方法就不展現了。。每一個get方法加@XmlElement(name="參數名") }
將xml解析成對象:ui
private WxMsgRequest convertWxMesgToObj(String msg) throws JAXBException{ JAXBContext context = JAXBContext.newInstance(WxMsgRequest.class); Unmarshaller unmarshaller = context.createUnmarshaller(); return (WxMsgRequest)unmarshaller.unmarshal(new StringReader(msg)); }
文本消息(text)
圖片消息 ( image )
語音消息 ( voice )
視頻消息 ( video )
音樂消息 ( music )
圖文消息 ( picurl )
此處栗子爲文本消息回覆。
建立一個微信消息類型實體,用於判斷消息類型:
public class WxRequestMsgType { /*** 請求的,應答的,文本推送消息 */ public static final String MSG_TEXT = "text"; /**** 請求的, 圖片推送消息*/ public static final String MSG_IMAGE = "image"; /*** 請求的, 地理位置信息*/ public static final String MSG_LOCATION = "location"; /*** 請求的, 連接信息*/ public static final String MSG_LINK = "link"; /*** 請求的,事件推送消息*/ public static final String MSG_EVENT = "event"; /*** 應答的,圖文消息體*/ public static final String MSG_NEW = "news"; /*** 請求的,語音推送消息*/ public static final String MSG_VOICE = "voice"; /*** 事件類型訂閱*/ public static final String EVENT_SUBSCRIBE = "subscribe"; /*** 事件取消訂閱*/ public static final String EVENT_UNSUBSCRIBE = "unsubscribe"; /*** 自定義菜單的點擊事件*/ public static final String EVENT_CLICK = "CLICK"; public static final String EVENT_SCAN = "SCAN"; /** * 若是公衆號處於開發模式,須要在接收到用戶發送的消息時, 返回一個MsgType爲transfer_customer_service的消息, * 微信服務器在收到這條消息時,會把此次發送的消息轉到多客服系統。 用戶被客服接入之後,客服關閉會話之前,處於會話過程當中, * 用戶發送的消息均會被直接轉發至客服系統 */ public static final String TRANSFER_CUSTOMER_SERVICE_MSG = "transfer_customer_service"; }
建立文本回復實體:
@XmlRootElement(name = "xml") public class WxTextMsgResponse{ /*** 開發者微信號*/ private String ToUserName; /*** 發送方賬號(一個OpenID)*/ private String FromUserName; /*** 消息建立時間 (整型)*/ private String CreateTime; /*** 應答消息類型有: news ;text;*/ private String MsgType; /*** 文本消息內容*/ private String Content; /** * 位0x0001被標誌時,星標剛收到的消息。 */ private String FuncFlag; @XmlElement(name = "Content") public String getContent() { return Content; } public void setContent(String content) { Content = content; } //省略其餘get、set方法 }
JAXB2對象轉爲XML字符串:
public String convertObjToXml(Object obj) throws JAXBException{ JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); StringWriter writer = new StringWriter(); marshaller.marshal(obj, writer); String temp = writer.toString(); return temp; }
在signature、POST方法中加入文本消息的判斷進行回覆:
if(wmr.getMsgType().equals(WxRequestMsgType.MSG_TEXT)){ WxTextMsgResponse wtmr = new WxTextMsgResponse(); wtmr.setContent("點點與麥兜的TEST"); Long createTime = System.currentTimeMillis() / 1000; wtmr.setCreateTime(createTime.toString()); wtmr.setFromUserName(wmr.getToUserName()); wtmr.setToUserName(wmr.getFromUserName()); wtmr.setMsgType(WxRequestMsgType.MSG_TEXT); String returnStr = this.convertObjToXml(wtmr); return returnStr; }
此處只舉例了消息接受和文本消息的回覆,後面還有主動推送消息、還有其餘事件,好比關注事件,取消關注事件等、這裏就不一一舉例了,其餘事件接受和回覆請查看微信開發文檔(實際上是大同小異)
1,這個回覆其實能夠作一個後臺自動回覆管理。好比後臺設置關鍵字回覆、被添加回復、自動回覆,發送過來的消息進行內容識別,是否爲關鍵字,或者自動回覆等。