在前几节文章中我们讲述了微信公众号环境的搭建、如何接入微信公众平台、以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装;接下来我们重点说一下-微信服务器post消息体的接收及消息的处理,这个post方法定义在如何接入微信公众平台的【controller】中。
/** * 接收微信消息处理并做分发 * @param request * @param response * @throws Exception */ @RequestMapping(method=RequestMethod.POST) public void post(HttpServletRequest request, HttpServletResponse response) throws Exception { // TODO 消息的接收、处理、响应 }
post方法有两个参数:
1.request中封装了请求相关的所有内容,可以从request中取出微信服务器发来的消息;
2.response我们可以对接收到的消息进行响应,即发送消息。
因为微信服务器发送过来的是xml格式的消息,所以我们可以采用 开源框架dom4j去解析xml 。在pom.xml文件中加:
<dependency> <groupId>org.apache.directory.studio</groupId> <artifactId>org.dom4j.dom4j</artifactId> <version>1.6.1</version> </dependency>
处理xml格式消息的方法 前面也提到过的工具类MessageType中:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /** 2 * @Title parseXml 3 * @Description 将用户的xml消息提取成map key value 类型 4 * @param request 5 * @param response 6 * @return 7 * @throws Exception 8 */ 9 public static Map<String, String> parseXml(HttpServletRequest request, HttpServletResponse response) 10 throws Exception { 11 // 将解析结果存储在HashMap中 12 Map<String, String> map = new HashMap<String, String>(); 13 // 从request中取得输入流 14 InputStream inputStream = request.getInputStream(); 15 // 读取输入流 16 SAXReader reader = new SAXReader(); 17 Document document = reader.read(inputStream); 18 // 得到xml根元素 19 Element root = document.getRootElement(); 20 // 得到根元素的所有子节点 21 List<Element> elementList = root.elements(); 22 // 遍历所有子节点 23 for (Element e : elementList) { 24 map.put(e.getName(), e.getText()); 25 } 26 // 释放资源 27 inputStream.close(); 28 inputStream = null; 29 return map; 30 }
将响应消息转换成xml格式返回给微信服务器,我是直接把各种消息类型封装成xml文件,你们也可以利用xstream-1.3.1.jar 或 xmlpull-1.1.3.1.jar来实现Java类到xml的转换
构建回复消息ReplyMessageUtil类
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.webchat.util.weixin; 2 3 import java.io.Serializable; 4 5 import com.webchat.entity.output.Articles; 6 import com.webchat.entity.output.ImageOutputMessage; 7 import com.webchat.entity.output.MusicOutputMessage; 8 import com.webchat.entity.output.NewsOutputMessage; 9 import com.webchat.entity.output.TextMessage; 10 import com.webchat.entity.output.VideoOutPutMessage; 11 import com.webchat.entity.output.VoiceOutputMessage; 12 13 /** 14 * 构建回复消息 15 * 16 * @author Administrator 17 * 18 */ 19 public class ReplyMessageUtil implements Serializable { 20 private static final long serialVersionUID = 1L; 21 /** 22 * <xml> <ToUserName><![CDATA[toUser]]></ToUserName> 23 * <FromUserName><![CDATA[fromUser]]></FromUserName> 24 * <CreateTime>12345678</CreateTime> <MsgType><![CDATA[news]]></MsgType> 25 * <ArticleCount>2</ArticleCount> <Articles> <item> 26 * <Title><![CDATA[title1]]></Title> 27 * <Description><![CDATA[description1]]></Description> 28 * <PicUrl><![CDATA[picurl]]></PicUrl> <Url><![CDATA[url]]></Url> </item> 29 * <item> <Title><![CDATA[title]]></Title> 30 * <Description><![CDATA[description]]></Description> 31 * <PicUrl><![CDATA[picurl]]></PicUrl> <Url><![CDATA[url]]></Url> </item> 32 * </Articles> </xml> 33 * 34 * @Title sendImageTextMessage 35 * @Description 回复图文消息 36 * @param message 37 * @return 38 */ 39 public static String sendImageTextMessage(NewsOutputMessage message) { 40 StringBuffer sb = new StringBuffer(); 41 sb.append("<xml>"); 42 sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>"); 43 sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>"); 44 sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>"); 45 sb.append("<MsgType><![CDATA[" + MessageType.IMAGE_TEXT_MESSAGE + "]]></MsgType>"); 46 sb.append("<ArticleCount>" + message.getArticleCount() + "</ArticleCount>"); 47 sb.append("<Articles> "); 48 for (Articles article : message.getArticles()) { 49 sb.append("<item>"); 50 if(article.getTitle()!=null && article.getTitle()!=""){ 51 sb.append("<Title><![CDATA[").append(article.getTitle()).append("]]></Title>"); 52 } 53 if(article.getDescription()!=null && article.getDescription()!=""){ 54 sb.append("<Description><![CDATA[").append(article.getDescription()).append("]]></Description>"); 55 } 56 if(article.getPicUrl()!=null && article.getPicUrl()!=""){ 57 sb.append("<PicUrl><![CDATA[").append(article.getPicUrl()).append("]]></PicUrl>"); 58 } 59 if(article.getUrl()!=null && article.getUrl()!=""){ 60 sb.append("<Url><![CDATA[").append(article.getUrl()).append("]]></Url>"); 61 } 62 sb.append("</item>"); 63 } 64 sb.append("</Articles>"); 65 sb.append("</xml>"); 66 return sb.toString(); 67 } 68 69 /** 70 * <xml> <ToUserName><![CDATA[toUser]]></ToUserName> 71 * <FromUserName><![CDATA[fromUser]]></FromUserName> 72 * <CreateTime>12345678</CreateTime> <MsgType><![CDATA[music]]></MsgType> 73 * <Music> <Title><![CDATA[TITLE]]></Title> 74 * <Description><![CDATA[DESCRIPTION]]></Description> 75 * <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl> 76 * <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl> 77 * <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId> </Music> </xml> 78 * 79 * @Title sendMusicMessage 80 * @Description 回复音乐消息 81 * @param message 82 * @return 83 */ 84 public static String sendMusicMessage(MusicOutputMessage message) { 85 StringBuffer sb = new StringBuffer(); 86 sb.append("<xml>"); 87 sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>"); 88 sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>"); 89 sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>"); 90 sb.append("<MsgType><![CDATA[" + MessageType.MUSIC_MESSAGE + "]]></MsgType>"); 91 sb.append("<Music>"); 92 if (message.getMusic().getTitle() != null && !"".equals(message.getMusic().getTitle())) { 93 sb.append("<Title><![CDATA[" + message.getMusic().getTitle() + "]]></Title>"); 94 } 95 if (message.getMusic().getDescription() != null && !"".equals(message.getMusic().getDescription())) { 96 sb.append("<Description><![CDATA[" + message.getMusic().getDescription() + "]]></Description>"); 97 } 98 if (message.getMusic().getMusicUrl() != null && !"".equals(message.getMusic().getMusicUrl())) { 99 sb.append("<MusicUrl><![CDATA[" + message.getMusic().getMusicUrl() + "]]></MusicUrl>"); 100 } 101 if (message.getMusic().getHQMusicUrl() != null && !"".equals(message.getMusic().getHQMusicUrl())) { 102 sb.append("<HQMusicUrl><![CDATA[" + message.getMusic().getHQMusicUrl() + "]]></HQMusicUrl>"); 103 } 104 105 sb.append("<ThumbMediaId><![CDATA[" + message.getMusic().getThumbMediaId() + "]]></ThumbMediaId>"); 106 sb.append("</Music>"); 107 sb.append("</xml>"); 108 return sb.toString(); 109 } 110 111 /** 112 * <xml> <ToUserName><![CDATA[toUser]]></ToUserName> 113 * <FromUserName><![CDATA[fromUser]]></FromUserName> 114 * <CreateTime>12345678</CreateTime> <MsgType><![CDATA[video]]></MsgType> 115 * <Video> <MediaId><![CDATA[media_id]]></MediaId> 116 * <Title><![CDATA[title]]></Title> 117 * <Description><![CDATA[description]]></Description> </Video> </xml> 118 * 119 * @Title sendVideoMessage 120 * @Description 回复视频消息 121 * @param message 122 * @return 123 */ 124 public static String sendVideoMessage(VideoOutPutMessage message) { 125 StringBuffer sb = new StringBuffer(); 126 sb.append("<xml>"); 127 sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>"); 128 sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>"); 129 sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>"); 130 sb.append("<MsgType><![CDATA[" + MessageType.VIDEO_MESSAGE + "]]></MsgType>"); 131 sb.append("<Video>"); 132 sb.append("<MediaId><![CDATA[" + message.getVideo().getMediaId() + "]]></MediaId>"); 133 if (message.getVideo().getTitle() != null && !"".equals(message.getVideo().getTitle())) { 134 sb.append("<Title><![CDATA[" + message.getVideo().getTitle() + "]]></Title>"); 135 } 136 if (message.getVideo().getDescription() != null && !"".equals(message.getVideo().getDescription())) { 137 sb.append("<Description><![CDATA[" + message.getVideo().getDescription() + "]]></Description>"); 138 } 139 sb.append("</Video>"); 140 sb.append("</xml>"); 141 return sb.toString(); 142 } 143 144 /** 145 * <xml> <ToUserName><![CDATA[toUser]]></ToUserName> 146 * <FromUserName><![CDATA[fromUser]]></FromUserName> 147 * <CreateTime>12345678</CreateTime> <MsgType><![CDATA[voice]]></MsgType> 148 * <Voice> <MediaId><![CDATA[media_id]]></MediaId> </Voice> </xml> 149 * @Title sendVoiceMessage 150 * @Description 回复语音消息 151 * @param message 152 * @return 153 */ 154 public static String sendVoiceMessage(VoiceOutputMessage message) { 155 StringBuffer sb = new StringBuffer(); 156 sb.append("<xml>"); 157 sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>"); 158 sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>"); 159 sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>"); 160 sb.append("<MsgType><![CDATA[" + MessageType.VOICE_MESSAGE + "]]></MsgType>"); 161 sb.append("<Voice>"); 162 sb.append("<MediaId><![CDATA[" + message.getVoice().getMediaId() + "]]></MediaId>"); 163 sb.append("</Voice>"); 164 sb.append("</xml>"); 165 return sb.toString(); 166 } 167 168 /** 169 * <xml> <ToUserName><![CDATA[toUser]]></ToUserName> 170 * <FromUserName><![CDATA[fromUser]]></FromUserName> 171 * <CreateTime>12345678</CreateTime> <MsgType><![CDATA[image]]></MsgType> 172 * <Image> <MediaId><![CDATA[media_id]]></MediaId> </Image> </xml> 173 * @Title sendImageMessage 174 * @Description 回复图片消息 175 * @param message 176 */ 177 public static String sendImageMessage(ImageOutputMessage message) { 178 StringBuffer sb = new StringBuffer(); 179 sb.append("<xml>"); 180 sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>"); 181 sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>"); 182 sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>"); 183 sb.append("<MsgType><![CDATA[" + MessageType.IMAGE_MESSAGE + "]]></MsgType>"); 184 sb.append("<Image>"); 185 sb.append("<MediaId><![CDATA[" + message.getImage().getMediaId() + "]]></MediaId>"); 186 sb.append("</Image>"); 187 sb.append("</xml>"); 188 return sb.toString(); 189 } 190 /** 191 * <xml> <ToUserName>< ![CDATA[toUser] ]></ToUserName> <FromUserName>< 192 * ![CDATA[fromUser] ]></FromUserName> <CreateTime>12345678</CreateTime> 193 * <MsgType>< ![CDATA[text] ]></MsgType> <Content>< ![CDATA[你好] ]></Content> 194 * </xml> sendTextMessage 195 * @param message 196 * @return 197 */ 198 public static String sendTextMessage(TextMessage message) { 199 StringBuffer sb = new StringBuffer(); 200 sb.append("<xml>"); 201 sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>"); 202 sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>"); 203 sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>"); 204 sb.append("<MsgType><![CDATA[" + MessageType.TEXT_MESSAGE + "]]></MsgType>"); 205 sb.append("<Content><![CDATA[" + message.getContent() + "]]></Content>"); 206 sb.append("</xml>"); 207 return sb.toString(); 208 } 209 }
我们在接收微信发送的消息时,需要根据消息的不同类别来进行处理,这是我们就需要一个工具类来处理事件类型的消息和普通消息类型的工具类:WebChatService
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.webchat.service; 2 3 import java.util.ArrayList; 4 import java.util.Date; 5 import java.util.HashMap; 6 import java.util.List; 7 import java.util.Map; 8 9 import com.webchat.entity.output.Articles; 10 import com.webchat.entity.output.NewsOutputMessage; 11 import com.webchat.entity.output.TextMessage; 12 import com.webchat.util.weixin.MessageType; 13 import com.webchat.util.weixin.ReplyMessageUtil; 14 import com.webchat.util.weixin.utils.XmlUtil; 15 16 /** 17 * 处理接收信息和回复消息的服务类接口 18 * 19 * @author Administrator 20 * 21 */ 22 public class WebChatService { 23 // 处理微信发来的请求 map 消息业务处理分发 24 public static String parseMessage(Map<String, String> map) { 25 String respXml = null; 26 try { 27 // 发送方帐号 28 String fromUserName = map.get("FromUserName"); 29 // 开发者微信号 30 String toUserName = map.get("ToUserName"); 31 // 取得消息类型 32 String MsgType = map.get("MsgType"); 33 // 发现直接把要返回的信息直接封装成replyMap集合,然后转换成 xml文件,是不是实体类可以不用了 34 Map<String, String> replyMap = new HashMap<String, String>(); 35 replyMap.put("ToUserName", fromUserName); 36 replyMap.put("FromUserName", toUserName); 37 replyMap.put("CreateTime", String.valueOf(new Date().getTime())); 38 if (MsgType.equals(MessageType.TEXT_MESSAGE)) { 39 // 封装文本返回消息 40 TextMessage textMessage = new TextMessage(); 41 textMessage.setToUserName(fromUserName); 42 textMessage.setFromUserName(toUserName); 43 textMessage.setCreateTime(new Date().getTime()); 44 textMessage.setContent("您发送的是文本消息"); 45 textMessage.getMsgType(); 46 // respXml = ReplyMessageUtil.sendTextMessage(textMessage); 47 48 // 用map集合封装 49 replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT); 50 replyMap.put("Content", "您发送的是文本消息"); 51 respXml = XmlUtil.xmlFormat(replyMap, true); 52 } else if (MsgType.equals(MessageType.IMAGE_MESSAGE)) { 53 // 这里回复图片 或者图文消息 以图文消息为例 54 NewsOutputMessage message = new NewsOutputMessage(); 55 message.setToUserName(fromUserName); 56 message.setFromUserName(toUserName); 57 message.setCreateTime(new Date().getTime()); 58 message.getMsgType(); 59 60 Articles article = new Articles(); 61 article.setDescription("图文消息 "); // 图文消息的描述 62 article.setPicUrl("https://p4.ssl.cdn.btime.com/dmfd/192_108_/t019d0b65e33000f8a0.jpg?size=458x240"); // 图文消息图片地址 63 article.setTitle("图文消息 "); // 图文消息标题 64 article.setUrl("http://www.baidu.com"); // 图文 url 链接 65 List<Articles> list = new ArrayList<Articles>(); 66 list.add(article);// 这里发送的是单图文,如果需要发送多图文则在这里 list 中加入多个 67 // Articles! 68 69 message.setArticleCount(list.size()); 70 message.setArticles(list); 71 respXml = ReplyMessageUtil.sendImageTextMessage(message); 72 } else if (MsgType.equals(MessageType.VOICE_MESSAGE)) { 73 // 以下方式根据需要来操作 74 replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT); 75 replyMap.put("Content", "您发送的是语音消息"); 76 respXml = XmlUtil.xmlFormat(replyMap, true); 77 } else if (MsgType.equals(MessageType.VIDEO_MESSAGE)) { 78 replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT); 79 replyMap.put("Content", "您发送的是视频消息"); 80 respXml = XmlUtil.xmlFormat(replyMap, true); 81 } else if (MsgType.equals(MessageType.SHORTVIDEO_MESSAGE)) { 82 replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT); 83 replyMap.put("Content", "您发送的是小视频消息"); 84 respXml = XmlUtil.xmlFormat(replyMap, true); 85 } else if (MsgType.equals(MessageType.POSOTION_MESSAGE)) { 86 replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT); 87 replyMap.put("Content", "您发送的是地理位置消息"); 88 respXml = XmlUtil.xmlFormat(replyMap, true); 89 } else if (MsgType.equals(MessageType.LINK_MESSAGE)) { 90 replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT); 91 replyMap.put("Content", "您发送的是链接消息"); 92 respXml = XmlUtil.xmlFormat(replyMap, true); 93 } 94 } catch (Exception e) { 95 e.printStackTrace(); 96 } 97 return respXml; 98 } 99 100 // 事件消息业务分发 101 public static String parseEvent(Map<String, String> map) { 102 String respXml = null; 103 try { 104 // 发送方帐号 105 String fromUserName = map.get("FromUserName"); 106 // 开发者微信号 107 String toUserName = map.get("ToUserName"); 108 // 取得消息类型 109 String MsgType = map.get("MsgType"); 110 //获取事件类型 111 String eventType = map.get("Event"); 112 113 // 发现直接把要返回的信息直接封装成replyMap集合,然后转换成 xml文件,是不是实体类可以不用了 114 Map<String, String> replyMap = new HashMap<String, String>(); 115 replyMap.put("ToUserName", fromUserName); 116 replyMap.put("FromUserName", toUserName); 117 replyMap.put("CreateTime", String.valueOf(new Date().getTime())); 118 if (eventType.equals(MessageType.EVENT_TYPE_SUBSCRIBE)) {// 关注 119 // 用map集合封装 120 replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT); 121 replyMap.put("Content", MessageType.menuText()); 122 respXml = XmlUtil.xmlFormat(replyMap, true); 123 } 124 if (eventType.equals(MessageType.EVENT_TYPE_UNSUBSCRIBE)) {// 取消关注 125 126 } 127 if (eventType.equals(MessageType.EVENT_TYPE_SCAN)) {// 用户已关注时的扫描带参数二维码 128 129 } 130 if (eventType.equals(MessageType.EVENT_TYPE_LOCATION)) {// 上报地理位置 131 132 } 133 if (eventType.equals(MessageType.EVENT_TYPE_CLICK)) {// 自定义菜单 134 135 } 136 } catch (Exception e) { 137 e.printStackTrace(); 138 } 139 return respXml; 140 } 141 }
通过查看WebChatService工具类,你会发现我里面既有通过回复消息实体类 获取回复信息然后调用ReplyMessageUtil类中对应的方法来返回信息,还有通过集合Map(replyMap)key,value的方法来添加数据,然后调用XmlUtil.java 的xmlFormat()方法返回消息的,有兴趣的可以都研究下:现在提供需要的工具类和jar文件
在pom.xml文件加入xmlpull-1.1.3.1.jar
<dependency> <groupId>xmlpull</groupId> <artifactId>xmlpull</artifactId> <version>1.1.3.1</version> </dependency>
XmlUtil工具类:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.webchat.util.weixin.utils; 2 3 import java.io.ByteArrayInputStream; 4 import java.io.IOException; 5 import java.io.InputStream; 6 import java.util.HashMap; 7 import java.util.Map; 8 import java.util.Map.Entry; 9 10 import org.xmlpull.v1.XmlPullParser; 11 import org.xmlpull.v1.XmlPullParserException; 12 import org.xmlpull.v1.XmlPullParserFactory; 13 /** 14 * 封装和处理xml文件 15 * @author Administrator 16 * 17 */ 18 public class XmlUtil { 19 20 private static final String PREFIX_XML = "<xml>"; 21 22 private static final String SUFFIX_XML = "</xml>"; 23 24 private static final String PREFIX_CDATA = "<![CDATA["; 25 26 private static final String SUFFIX_CDATA = "]]>"; 27 28 /** 29 * 转化成xml, 单层无嵌套 30 * 31 * @param map 32 * @param isAddCDATA ture 加CDATA标签 false 不加CDATA标签 33 * @return 34 */ 35 public static String xmlFormat(Map<String, String> parm, boolean isAddCDATA) { 36 37 StringBuffer strbuff = new StringBuffer(PREFIX_XML); 38 if (CollectionUtil.isNotEmpty(parm)) { 39 for (Entry<String, String> entry : parm.entrySet()) { 40 strbuff.append("<").append(entry.getKey()).append(">"); 41 if (isAddCDATA) { 42 strbuff.append(PREFIX_CDATA); 43 if (StringUtil.isNotEmpty(entry.getValue())) { 44 strbuff.append(entry.getValue()); 45 } 46 strbuff.append(SUFFIX_CDATA); 47 } else { 48 if (StringUtil.isNotEmpty(entry.getValue())) { 49 strbuff.append(entry.getValue()); 50 } 51 } 52 strbuff.append("</").append(entry.getKey()).append(">"); 53 } 54 } 55 return strbuff.append(SUFFIX_XML).toString(); 56 } 57 58 /** 59 * 解析xml 60 * 61 * @param xml 62 * @return 63 * @throws XmlPullParserException 64 * @throws IOException 65 */ 66 public static Map<String, String> xmlParse(String xml) throws XmlPullParserException, IOException { 67 Map<String, String> map = null; 68 if (StringUtil.isNotEmpty(xml)) { 69 InputStream inputStream = new ByteArrayInputStream(xml.getBytes()); 70 XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser(); 71 pullParser.setInput(inputStream, "UTF-8"); // 为xml设置要解析的xml数据 72 int eventType = pullParser.getEventType(); 73 74 while (eventType != XmlPullParser.END_DOCUMENT) { 75 switch (eventType) { 76 case XmlPullParser.START_DOCUMENT: 77 map = new HashMap<String, String>(); 78 break; 79 case XmlPullParser.START_TAG: 80 String key = pullParser.getName(); 81 if (key.equals("xml")) 82 break; 83 String value = pullParser.nextText().trim(); 84 map.put(key, value); 85 break; 86 case XmlPullParser.END_TAG: 87 break; 88 } 89 eventType = pullParser.next(); 90 } 91 } 92 return map; 93 } 94 }
XmlUtil 工具类关联的类CollectionUtil 和StringUtil
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.webchat.util.weixin.utils; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 import java.util.UUID; 6 import java.util.regex.Matcher; 7 import java.util.regex.Pattern; 8 9 /** 10 * String工具类 11 */ 12 public class StringUtil { 13 14 private StringUtil() { 15 super(); 16 } 17 18 /** 19 * 出去null和"" 20 * @param src 21 * @return 22 */ 23 public static String formatNull(String src) { 24 return (src == null || "null".equals(src)) ? "" : src; 25 } 26 27 /** 28 * 判断字符串是否为空的正则表达式,空白字符对应的unicode编码 29 */ 30 private static final String EMPTY_REGEX = "[\\s\\u00a0\\u2007\\u202f\\u0009-\\u000d\\u001c-\\u001f]+"; 31 32 /** 33 * 验证字符串是否为空 34 * 35 * @param input 36 * @return 37 */ 38 public static boolean isEmpty(String input) { 39 return input == null || input.equals("") || input.matches(EMPTY_REGEX); 40 } 41 42 public static boolean isNotEmpty(String input){ 43 return !isEmpty(input); 44 } 45 46 private static final String NUM_REG = "(\\+|\\-)?\\s*\\d+(\\.\\d+)?"; 47 48 /** 49 * 判断是否数字 50 * 51 * @param str 52 * @return 53 */ 54 public static boolean isNumber(String str) { 55 if (isEmpty(str)) { 56 return false; 57 } 58 59 if (str.trim().matches(NUM_REG)) { 60 return true; 61 } 62 63 return false; 64 } 65 66 /** 67 * 判断是否包含有乱码的数据,如果字符串中包含有替换字符就认为是乱码 68 * 69 * @param str 70 * @return 71 */ 72 public static boolean containUnreadableCode(String str) { 73 return contain(str, "\\ufffd"); 74 } 75 76 /** 77 * 判读是否包含数字 78 * 79 * @param str 80 * @return 81 */ 82 public static boolean containNumber(String str) { 83 return contain(str, "\\d"); 84 } 85 86 /** 87 * 判断是否包含a-zA-Z_0-9 88 * 89 * @param str 90 * @return 91 */ 92 public static boolean containWord(String str) { 93 return contain(str, "\\w"); 94 } 95 96 /** 97 * 是否包含有标点符号 98 * 99 * @param str 100 * @return 101 */ 102 public static boolean containPunct(String str) { 103 return contain(str, PUNCT_REG); 104 } 105 106 public static boolean contain(String str, String regex) { 107 if (isEmpty(str) || isEmpty(regex)) { 108 return false; 109 } 110 111 if (str.trim().matches(regex)) { 112 return true; 113 } 114 115 Pattern pattern = Pattern.compile(regex); 116 Matcher matcher = pattern.matcher(str); 117 if (matcher.find()) { 118 return true; 119 } 120 121 return false; 122 } 123 124 /** 125 * 替换所有的(不区分大小写) 126 * 127 * @param input 128 * @param regex 129 * @param replacement 130 * @return 131 */ 132 public static String replaceAll(String input, String regex, 133 String replacement) { 134 return Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(input) 135 .replaceAll(replacement); 136 } 137 138 /** 139 * 移除所有的空格 140 * 141 * @param text 142 * @return 143 */ 144 public static String removeAllSpace(String text) { 145 if (isEmpty(text)) { 146 return text; 147 } 148 149 return text.replaceAll("[ ]+", ""); 150 } 151 152 private static final String PUNCT_REG = "[^a-zA-Z0-9\\u4e00-\\u9fa5]"; 153 154 /** 155 * 移除字符串中的所有的中英文标点符号 156 * 157 * @param str 158 * @return 159 */ 160 public static String removeAllPunct(String str) { 161 if (isEmpty(str)) { 162 return str; 163 } 164 165 return str.replaceAll(PUNCT_REG, ""); 166 } 167 168 /** 169 * 计算str中包含多少个子字符串sub 170 * 171 * @param str 172 * @param sub 173 * @return 174 */ 175 public static int countMatches(String str, String sub) { 176 if (isEmpty(str) || isEmpty(sub)) { 177 return 0; 178 } 179 180 int count = 0; 181 int idx = 0; 182 while ((idx = str.indexOf(sub, idx)) != -1) { 183 count++; 184 idx += sub.length(); 185 } 186 187 return count; 188 } 189 190 /** 191 * 获得源字符串的一个子字符串 192 * 193 * @param str 194 * :源字符串 195 * @param beginIndex 196 * :开始索引(包括) 197 * @param endIndex 198 * :结束索引(不包括) 199 * @return 200 */ 201 public static String substring(String str, int beginIndex, int endIndex) { 202 if (isEmpty(str)) { 203 return str; 204 } 205 206 int length = str.length(); 207 208 if (beginIndex >= length || endIndex <= 0 || beginIndex >= endIndex) { 209 return null; 210 } 211 212 if (beginIndex < 0) { 213 beginIndex = 0; 214 } 215 if (endIndex > length) { 216 endIndex = length; 217 } 218 219 return str.substring(beginIndex, endIndex); 220 } 221 222 /** 223 * 计算str中包含子字符串sub所在位置的前一个字符或者后一个字符和sub所组成的新字符串 224 * 225 * @param str 226 * @param sub 227 * @return 228 */ 229 public static Set<String> substring(String str, String sub) { 230 if (isEmpty(str) || isEmpty(sub)) { 231 return null; 232 } 233 234 Set<String> result = new HashSet<String>(); 235 int idx = 0; 236 while ((idx = str.indexOf(sub, idx)) != -1) { 237 String temp = substring(str, idx - 1, idx + sub.length()); 238 if (!isEmpty(temp)) { 239 temp = removeAllPunct(temp); 240 if (!sub.equalsIgnoreCase(temp) && !containWord(temp)) { 241 result.add(temp); 242 } 243 244 } 245 246 temp = substring(str, idx, idx + sub.length() + 1); 247 if (!isEmpty(temp)) { 248 temp = removeAllPunct(temp); 249 if (!sub.equalsIgnoreCase(temp) && !containWord(temp)) { 250 result.add(temp); 251 } 252 } 253 254 idx += sub.length(); 255 } 256 257 return result; 258 } 259 260 /** 261 * 过滤掉XML中无法解析的非法字符 262 * 263 * @param content 264 * @return 265 */ 266 public static String wrapXmlContent(String content) { 267 if (isEmpty(content)) { 268 return ""; 269 } 270 271 StringBuilder result = new StringBuilder(); 272 273 for (int i = 0; i < content.length(); i++) { 274 char ch = content.charAt(i); 275 if ((ch == '\t') || (ch == '\n') || (ch == '\r') 276 || ((ch >= ' ') && (ch <= 55295)) 277 || ((ch >= 57344) && (ch <= 65533)) 278 || ((ch >= 65536) && (ch <= 1114111))) { 279 result.append(ch); 280 } 281 } 282 283 return result.toString(); 284 } 285 286 /** 287 * 判断字符串的长度 288 * 289 * @param str 290 * @return 291 */ 292 public static boolean overLength(String str) { 293 if (isEmpty(str)) { 294 return false; 295 } 296 297 return str.length() > 1 ? true : false; 298 } 299 300 /** 301 * 字符串中含有特殊字符的处理 302 * 303 * @param str 304 * @return 305 */ 306 public static String specialStr(String str) { 307 str = str.replaceAll("[^\\u4e00-\\u9fa5 | 0-9| a-zA-Z | \\.]+", " ") 308 .replaceAll("[\\.]{2,}", " ").trim(); 309 return str; 310 } 311 312 /** 313 * 将特殊符号去掉,但是保留空格 314 * 315 * @param str 316 * @return 317 */ 318 public static String replaceInValidateChar(String str) { 319 return str.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5\\s+]", " "); 320 } 321 322 /** 323 * 返回字符串对应的unicode编码 324 * 325 * @param str 326 * @return 327 */ 328 public static String[] toHexString(String str) { 329 char[] chars = str.toCharArray(); 330 331 String[] result = new String[chars.length]; 332 333 for (int i = 0; i < chars.length; i++) { 334 result[i] = Integer.toHexString((int) chars[i]); 335 } 336 337 return result; 338 } 339 340 public static String getUuid() { 341 return UUID.randomUUID().toString(); 342 } 343 344 public static boolean isUrl(String src) { 345 String regex = "http[s]?:\\/\\/([\\w-]+\\.[\\w-]+)(\\.[\\w-])+(:\\d{2,10})?.*"; 346 Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE); 347 Matcher matcher = pattern.matcher(src); 348 return matcher.matches(); 349 } 350 351 /** 352 * sql 查询转义 353 * @param str 354 * @return 355 */ 356 public static String escapeSql(String str){ 357 if (StringUtil.isNotEmpty(str)) { 358 StringBuffer strbuff = new StringBuffer(); 359 for (String s : str.split("")) { 360 if (s.equals("%") || s.equals("_") || s.equals("\\")) { 361 strbuff.append("\\"); 362 } 363 strbuff.append(s); 364 } 365 return strbuff.toString(); 366 } 367 return str; 368 } 369 }
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 package com.webchat.util.weixin.utils; 2 3 import java.util.ArrayList; 4 import java.util.Collection; 5 import java.util.List; 6 import java.util.Map; 7 8 public class CollectionUtil { 9 10 private CollectionUtil() { 11 super(); 12 } 13 14 // 判断一个集合是否为空 15 public static <T> boolean isEmpty(Collection<T> col) { 16 if (col == null || col.isEmpty()) { 17 return true; 18 } 19 20 return false; 21 } 22 23 // 判断一个集合是否不为空 24 public static <T> boolean isNotEmpty(Collection<T> col) { 25 return !isEmpty(col); 26 } 27 28 // 判断Map是否为空 29 public static <K, V> boolean isEmpty(Map<K, V> map) { 30 if (map == null || map.isEmpty()) { 31 return true; 32 } 33 34 return false; 35 } 36 37 // 判断Map是否不为空为空 38 public static <K, V> boolean isNotEmpty(Map<K, V> map) { 39 return !isEmpty(map); 40 } 41 42 // 去除list中的重复数据 43 public static <T> List<T> removeRepeat(List<T> list) { 44 if (isEmpty(list)) { 45 return list; 46 } 47 48 List<T> result = new ArrayList<T>(); 49 for (T e : list) { 50 if (!result.contains(e)) { 51 result.add(e); 52 } 53 } 54 55 return result; 56 } 57 58 // 将集合转换为String数组 59 public static <T> String[] toArray(List<T> list) { 60 if (isEmpty(list)) { 61 return null; 62 } 63 64 String[] result = new String[list.size()]; 65 for (int i = 0; i < list.size(); i++) { 66 result[i] = String.valueOf(list.get(i)); 67 } 68 69 return result; 70 } 71 72 }
这个时候我们需要我们来完善消息入口【WebChatController.java】中的 post 方法,最终结果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /** 2 * 接收微信消息处理并做分发 3 * @param request 4 * @param response 5 * @throws Exception 6 */ 7 @RequestMapping(method=RequestMethod.POST) 8 public void post(HttpServletRequest request, HttpServletResponse response) throws Exception { 9 // TODO 消息的接收、处理、响应 10 //消息来源可靠性验证 11 String signature = request.getParameter("signature");// 微信加密签名 12 String timestamp = request.getParameter("timestamp");// 时间戳 13 String nonce = request.getParameter("nonce"); // 随机数 14 //确认此次GET请求来自微信服务器,原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败 15 if (!WebChatUtil.checkSignature(signature, timestamp, nonce)) { 16 //消息不可靠,直接返回 17 response.getWriter().write(""); 18 return; 19 } 20 //用户每次向公众号发送消息、或者产生自定义菜单点击事件时,响应URL将得到推送 21 try { 22 response.setCharacterEncoding("UTF-8"); 23 response.setContentType("text/xml"); 24 //调用parseXml方法解析请求消息 25 Map<String, String> map = MessageType.parseXml(request, response); 26 String MsgType = map.get("MsgType"); 27 String xml = null;//处理输入消息,返回结果的xml 28 if(MessageType.REQ_MESSAGE_TYPE_EVENT.equals(MsgType)){ 29 xml = WebChatService.parseEvent(map); 30 }else{ 31 xml = WebChatService.parseMessage(map); 32 } 33 //返回封装的xml 34 //System.out.println(xml); 35 response.getWriter().write(xml); 36 } catch (Exception ex) { 37 response.getWriter().write(""); 38 } 39 }
好了,现在让我们启动本地服务来测试一下吧,打开微信测试号管理:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login,配置可以参考:Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发 和 Java开发微信公众号(一)---初识微信公众号以及环境搭建;
扫描二维码,关注你的测试公众号:然后你可以发送消息来测试
效果如下:
如果在操作过程中有问题,欢迎随时讨论^.^
其他文章关联
(一)Java开发微信公众号(一)---初识微信公众号以及环境搭建
(二)Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发
(三)Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装
(四)Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理