前言:java
1,消息推送—— 當普通用戶向公衆賬號發消息時,微信服務器將POST該消息到填寫的URL上(發消息=操做,包括掃描二維碼,點擊菜單等;URL:coreServlet)json
2,消息回覆——對每個POST請求,開發者能夠在響應包中返回特定XML結構,來對該消息進行響應(現支持回覆文本、圖片、圖文、語音、視頻、音樂)服務器
3,消息回覆——假如服務器沒法保證在五秒內處理回覆,則必須回覆「success」或者「」(空串),不然微信後臺會發起三次重試。微信
4,主動發送消息——模板消息(該章節並未說起)app
正文:dom
1,接收消息的封裝(message.req)post
接收消息之基類ui
public class BaseMessage { private String ToUserName; // 開發者微信號 private String FromUserName; // 發送方賬號(一個OpenID) private long CreateTime; // 消息建立時間 (整型) private String MsgType; // 消息類型(text/image/location/link) private long MsgId; // 消息id,64位整型 public String getToUserName() { return ToUserName; } public void setToUserName(String toUserName) { ToUserName = toUserName; } public String getFromUserName() { return FromUserName; } public void setFromUserName(String fromUserName) { FromUserName = fromUserName; } public long getCreateTime() { return CreateTime; } public void setCreateTime(long createTime) { CreateTime = createTime; } public String getMsgType() { return MsgType; } public void setMsgType(String msgType) { MsgType = msgType; } public long getMsgId() { return MsgId; } public void setMsgId(long msgId) { MsgId = msgId; } }
接收消息之文本消息編碼
public class TextMessage extends BaseMessage { // 消息內容 private String Content; public String getContent() { return Content; } public void setContent(String content) { Content = content; } }
接收消息之圖片消息url
public class ImageMessage extends BaseMessage { // 圖片連接 private String PicUrl; public String getPicUrl() { return PicUrl; } public void setPicUrl(String picUrl) { PicUrl = picUrl; } }
接收消息之地理位置消息
public class LocationMessage extends BaseMessage { // 地理位置維度 private String Location_X; // 地理位置經度 private String Location_Y; // 地圖縮放大小 private String Scale; // 地理位置信息 private String Label; public String getLocation_X() { return Location_X; } public void setLocation_X(String location_X) { Location_X = location_X; } public String getLocation_Y() { return Location_Y; } public void setLocation_Y(String location_Y) { Location_Y = location_Y; } public String getScale() { return Scale; } public void setScale(String scale) { Scale = scale; } public String getLabel() { return Label; } public void setLabel(String label) { Label = label; } }
接收消息之連接消息
public class LinkMessage extends BaseMessage { // 消息標題 private String Title; // 消息描述 private String Description; // 消息連接 private String Url; public String getTitle() { return Title; } public void setTitle(String title) { Title = title; } public String getDescription() { return Description; } public void setDescription(String description) { Description = description; } public String getUrl() { return Url; } public void setUrl(String url) { Url = url; } }
接收消息之語音消息
public class VoiceMessage extends BaseMessage { // 媒體ID private String MediaId; // 語音格式 private String Format; public String getMediaId() { return MediaId; } public void setMediaId(String mediaId) { MediaId = mediaId; } public String getFormat() { return Format; } public void setFormat(String format) { Format = format; } }
2,響應消息的封裝(message.resp)
響應消息之基類
public class BaseMessage { private String ToUserName; // 接收方賬號(收到的OpenID) private String FromUserName; // 開發者微信號 private long CreateTime; // 消息建立時間 (整型) private String MsgType; // 消息類型(text/music/news) private int FuncFlag; // 位0x0001被標誌時,星標剛收到的消息 public String getToUserName() { return ToUserName; } public void setToUserName(String toUserName) { ToUserName = toUserName; } public String getFromUserName() { return FromUserName; } public void setFromUserName(String fromUserName) { FromUserName = fromUserName; } public long getCreateTime() { return CreateTime; } public void setCreateTime(long createTime) { CreateTime = createTime; } public String getMsgType() { return MsgType; } public void setMsgType(String msgType) { MsgType = msgType; } public int getFuncFlag() { return FuncFlag; } public void setFuncFlag(int funcFlag) { FuncFlag = funcFlag; } }
響應消息之文本消息
public class TextMessage extends BaseMessage { // 回覆的消息內容 private String Content; public String getContent() { return Content; } public void setContent(String content) { Content = content; } }
響應消息之音樂消息
public class MusicMessage extends BaseMessage { // 音樂 private Music Music; public Music getMusic() { return Music; } public void setMusic(Music music) { Music = music; } }
音樂消息中Music類的定義
public class Music { // 音樂名稱 private String Title; // 音樂描述 private String Description; // 音樂連接 private String MusicUrl; // 高質量音樂連接,WIFI環境優先使用該連接播放音樂 private String HQMusicUrl; public String getTitle() { return Title; } public void setTitle(String title) { Title = title; } public String getDescription() { return Description; } public void setDescription(String description) { Description = description; } public String getMusicUrl() { return MusicUrl; } public void setMusicUrl(String musicUrl) { MusicUrl = musicUrl; } public String getHQMusicUrl() { return HQMusicUrl; } public void setHQMusicUrl(String musicUrl) { HQMusicUrl = musicUrl; } }
響應消息之圖文消息
public class NewsMessage extends BaseMessage { // 圖文消息個數,限制爲10條之內 private int ArticleCount; // 多條圖文消息信息,默認第一個item爲大圖 private List<Article> Articles; public int getArticleCount() { return ArticleCount; } public void setArticleCount(int articleCount) { ArticleCount = articleCount; } public List<Article> getArticles() { return Articles; } public void setArticles(List<Article> articles) { Articles = articles; } }
圖文消息中Article類的定義
public class Article { // 圖文消息名稱 private String Title; // 圖文消息描述 private String Description; // 圖片連接,支持JPG、PNG格式,較好的效果爲大圖640*320,小圖80*80,限制圖片連接的域名須要與開發者填寫的基本資料中的Url一致 private String PicUrl; // 點擊圖文消息跳轉連接 private String Url; public String getTitle() { return Title; } public void setTitle(String title) { Title = title; } public String getDescription() { return null == Description ? "" : Description; } public void setDescription(String description) { Description = description; } public String getPicUrl() { return null == PicUrl ? "" : PicUrl; } public void setPicUrl(String picUrl) { PicUrl = picUrl; } public String getUrl() { return null == Url ? "" : Url; } public void setUrl(String url) { Url = url; } }
3,解析接收到的消息及將響應消息轉換成xml返回
前言中說的URL
@ResponseBody @RequestMapping(value = "coreServlet", method = RequestMethod.POST) public void coreServletPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //獲取微信POST過來的內容。消息爲xml格式 // 將請求、響應的編碼均設置爲UTF-8(防止中文亂碼) request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); //從請求中讀取整個post數據 InputStream inputStream = request.getInputStream(); String postData = IOUtils.toString(inputStream, "UTF-8"); logger.info("postData = " + postData); // 調用核心業務類接收消息、處理消息 Message message = CoreService.processRequest(postData); String respMessage = message.getRespMessage(); // 響應消息 PrintWriter out = response.getWriter(); out.print(respMessage); out.close(); }
調用核心業務類接收消息、處理消息 CoreService.processRequest
private static String UPDATE_MENU = "menu";//更新自定義菜單的口令 public static Message processRequest(String msg) { Message message = new Message(); String param1 = "";//二維碼帶的參數 try { Map<String, String> requestMap = MessageUtil.parseXml(msg); // xml請求解析 String fromUserName = requestMap.get("FromUserName"); // 發送方賬號 String toUserName = requestMap.get("ToUserName"); // 接收方賬號 String msgType = requestMap.get("MsgType"); // 消息類型 String eventKey = requestMap.get("EventKey"); // 事件KEY值,與建立自定義菜單時指定的KEY值對應 String respContent = "請求處理中..."; // 默認返回的文本消息內容 // 回覆文本消息 TextMessage textMessage = new TextMessage(); textMessage.setToUserName(fromUserName); textMessage.setFromUserName(toUserName); textMessage.setCreateTime(new Date().getTime()); textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT); textMessage.setFuncFlag(0); // 建立圖文消息 NewsMessage newsMessage = new NewsMessage(); newsMessage.setToUserName(fromUserName); newsMessage.setFromUserName(toUserName); newsMessage.setCreateTime(new Date().getTime()); newsMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS); newsMessage.setFuncFlag(0); // 文本消息 if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) { respContent = "您發送的是文本消息!"; if((UPDATE_MENU).equals(requestMap.get("Content"))){ respContent = MenuManager.menuManager();//更新自定義菜單 } // 回覆包含「定位跑」 else if ( requestMap.get("Content").contains("定位跑")) { respContent = "您的願望咱們已經收到,請關注8月8日將發佈的中獎名單信息"; } } // 圖片消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) { respContent = "您發送的是圖片消息!"; } // 地理位置消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) { respContent = "您發送的是地理位置消息!"; } // 連接消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) { respContent = "您發送的是連接消息!"; } // 音頻消息 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) { } // 事件推送 else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) { // 事件類型 String eventType = requestMap.get("Event"); // 訂閱 if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) { respContent = "歡迎關注愛關節網"; if(!StringUtils.isEmpty(eventKey)){ param1 = eventKey.substring(eventKey.indexOf("_")+1); } } // 掃描 if (eventType.equals(MessageUtil.EVENT_TYPE_SCAN)) { respContent = ""; if(!StringUtils.isEmpty(eventKey)){ param1 = eventKey; } } // 取消訂閱 else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) { // TODO 取消訂閱後用戶再收不到公衆號發送的消息,所以不須要回復消息 } // 自定義菜單點擊事件 else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) { List<Article> articleList = new ArrayList<Article>(); if (eventKey.equals("13")) { respContent = "內容建設中,敬請期待"; } else if (eventKey.equals("14")) { //單圖文消息 Article article = new Article(); article.setTitle("靈動中國|愛關節·不等待 廣場舞公益活動川渝開賽"); article.setDescription("靈動中國|愛關節·不等待 廣場舞公益活動川渝開賽"); article.setPicUrl(Config.domain() + "/UCenter/wx_marathon/img/zuimeiguangchangwu.png"); article.setUrl("http://mp.weixin.qq.com/s/6_-hwdJ6fFV58UD8SLAtcg"); articleList.add(article); // 設置圖文消息個數 newsMessage.setArticleCount(articleList.size()); // 設置圖文消息包含的圖文集合 newsMessage.setArticles(articleList); // 將圖文消息對象轉換成xml字符串 respMessage = MessageUtil.newsMessageToXml(newsMessage); message.setParam1(""); message.setRespMessage(respMessage); message.setFromUserName(fromUserName); message.setToUserName(toUserName); return message; } } } textMessage.setContent(respContent); respMessage = MessageUtil.textMessageToXml(textMessage); message.setParam1(param1); message.setRespMessage(respMessage); message.setFromUserName(fromUserName); message.setToUserName(toUserName); } catch (Exception e) { e.printStackTrace(); } return message; }
MessageUtil
public class MessageUtil { public static final String RESP_MESSAGE_TYPE_TEXT = "text"; //返回消息類型:文本 public static final String RESP_MESSAGE_TYPE_MUSIC = "music"; //返回消息類型:音樂 public static final String RESP_MESSAGE_TYPE_NEWS = "news"; //返回消息類型:圖文 public static final String REQ_MESSAGE_TYPE_TEXT = "text"; //請求消息類型:文本 public static final String REQ_MESSAGE_TYPE_IMAGE = "image"; //請求消息類型:圖片 public static final String REQ_MESSAGE_TYPE_LINK = "link"; //請求消息類型:連接 public static final String REQ_MESSAGE_TYPE_LOCATION = "location"; //請求消息類型:地理位置 public static final String REQ_MESSAGE_TYPE_VOICE = "voice"; //請求消息類型:音頻 public static final String REQ_MESSAGE_TYPE_EVENT = "event"; //請求消息類型:推送 public static final String EVENT_TYPE_SUBSCRIBE = "subscribe"; //事件類型:subscribe(訂閱) public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe"; //事件類型:unsubscribe(取消訂閱) public static final String EVENT_TYPE_CLICK = "CLICK"; //事件類型:CLICK(自定義菜單點擊事件) public static final String EVENT_TYPE_SCAN = "SCAN"; //事件類型:SCAN(掃描) //解析微信發來的請求(XML) @SuppressWarnings("unchecked") public static Map<String, String> parseXml(String msg) throws IOException { // 將解析結果存儲在HashMap中 Map<String, String> map = new HashMap<String, String>(); //讀取輸入流 SAXReader reader = new SAXReader(); try { InputStream inputStream = new ByteArrayInputStream(msg.getBytes("UTF-8")); Document document = reader.read(inputStream); Element root = document.getRootElement(); // 獲得xml根元素 List<Element> elementList = root.elements(); // 獲得根元素的全部子節點 for (Element e : elementList) map.put(e.getName(), e.getText()); inputStream.close(); inputStream = null; } catch (DocumentException e) { logger.error("解析失敗",e); } return map; } //文本消息對象轉換成xml public static String textMessageToXml(TextMessage textMessage) { xstream.alias("xml", textMessage.getClass()); return xstream.toXML(textMessage); } //音樂消息對象轉換成xml public static String musicMessageToXml(MusicMessage musicMessage) { xstream.alias("xml", musicMessage.getClass()); return xstream.toXML(musicMessage); } //圖文消息對象轉換成xml public static String newsMessageToXml(NewsMessage newsMessage) { xstream.alias("xml", newsMessage.getClass()); xstream.alias("item", new Article().getClass()); return xstream.toXML(newsMessage); } //擴展xstream,使其支持CDATA塊 private static XStream xstream = new XStream(new XppDriver() { public HierarchicalStreamWriter createWriter(Writer out) { return new PrettyPrintWriter(out) { // 對全部xml節點的轉換都增長CDATA標記 boolean cdata = true; @SuppressWarnings("unchecked") public void startNode(String name, Class clazz) { super.startNode(name, clazz); } protected void writeText(QuickWriter writer, String text) { if (cdata) { writer.write("<![CDATA["); writer.write(text); writer.write("]]>"); } else { writer.write(text); } } }; } }); //將java對象轉換爲json對象 public static String Object2Json(Object obj){ JSONObject json = JSONObject.fromObject(obj); // 將json對象轉換爲字符串 String str = json.toString(); return str; } }