Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

时间:2023-12-04 23:56:14

在前几节文章中我们讲述了微信公众号环境的搭建如何接入微信公众平台、以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装;接下来我们重点说一下-微信服务器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中:

 /**
* @Title parseXml
* @Description 将用户的xml消息提取成map key value 类型
* @param request
* @param response
* @return
* @throws Exception
*/
public static Map<String, String> parseXml(HttpServletRequest request, HttpServletResponse response)
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();
// 得到根元素的所有子节点
List<Element> elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList) {
map.put(e.getName(), e.getText());
}
// 释放资源
inputStream.close();
inputStream = null;
return map;
}

将响应消息转换成xml格式返回给微信服务器,我是直接把各种消息类型封装成xml文件,你们也可以利用xstream-1.3.1.jar 或 xmlpull-1.1.3.1.jar来实现Java类到xml的转换

构建回复消息ReplyMessageUtil类

 package com.webchat.util.weixin;

 import java.io.Serializable;

 import com.webchat.entity.output.Articles;
import com.webchat.entity.output.ImageOutputMessage;
import com.webchat.entity.output.MusicOutputMessage;
import com.webchat.entity.output.NewsOutputMessage;
import com.webchat.entity.output.TextMessage;
import com.webchat.entity.output.VideoOutPutMessage;
import com.webchat.entity.output.VoiceOutputMessage; /**
* 构建回复消息
*
* @author Administrator
*
*/
public class ReplyMessageUtil implements Serializable {
private static final long serialVersionUID = 1L;
/**
* <xml> <ToUserName><![CDATA[toUser]]></ToUserName>
* <FromUserName><![CDATA[fromUser]]></FromUserName>
* <CreateTime>12345678</CreateTime> <MsgType><![CDATA[news]]></MsgType>
* <ArticleCount>2</ArticleCount> <Articles> <item>
* <Title><![CDATA[title1]]></Title>
* <Description><![CDATA[description1]]></Description>
* <PicUrl><![CDATA[picurl]]></PicUrl> <Url><![CDATA[url]]></Url> </item>
* <item> <Title><![CDATA[title]]></Title>
* <Description><![CDATA[description]]></Description>
* <PicUrl><![CDATA[picurl]]></PicUrl> <Url><![CDATA[url]]></Url> </item>
* </Articles> </xml>
*
* @Title sendImageTextMessage
* @Description 回复图文消息
* @param message
* @return
*/
public static String sendImageTextMessage(NewsOutputMessage message) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>");
sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>");
sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>");
sb.append("<MsgType><![CDATA[" + MessageType.IMAGE_TEXT_MESSAGE + "]]></MsgType>");
sb.append("<ArticleCount>" + message.getArticleCount() + "</ArticleCount>");
sb.append("<Articles> ");
for (Articles article : message.getArticles()) {
sb.append("<item>");
if(article.getTitle()!=null && article.getTitle()!=""){
sb.append("<Title><![CDATA[").append(article.getTitle()).append("]]></Title>");
}
if(article.getDescription()!=null && article.getDescription()!=""){
sb.append("<Description><![CDATA[").append(article.getDescription()).append("]]></Description>");
}
if(article.getPicUrl()!=null && article.getPicUrl()!=""){
sb.append("<PicUrl><![CDATA[").append(article.getPicUrl()).append("]]></PicUrl>");
}
if(article.getUrl()!=null && article.getUrl()!=""){
sb.append("<Url><![CDATA[").append(article.getUrl()).append("]]></Url>");
}
sb.append("</item>");
}
sb.append("</Articles>");
sb.append("</xml>");
return sb.toString();
} /**
* <xml> <ToUserName><![CDATA[toUser]]></ToUserName>
* <FromUserName><![CDATA[fromUser]]></FromUserName>
* <CreateTime>12345678</CreateTime> <MsgType><![CDATA[music]]></MsgType>
* <Music> <Title><![CDATA[TITLE]]></Title>
* <Description><![CDATA[DESCRIPTION]]></Description>
* <MusicUrl><![CDATA[MUSIC_Url]]></MusicUrl>
* <HQMusicUrl><![CDATA[HQ_MUSIC_Url]]></HQMusicUrl>
* <ThumbMediaId><![CDATA[media_id]]></ThumbMediaId> </Music> </xml>
*
* @Title sendMusicMessage
* @Description 回复音乐消息
* @param message
* @return
*/
public static String sendMusicMessage(MusicOutputMessage message) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>");
sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>");
sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>");
sb.append("<MsgType><![CDATA[" + MessageType.MUSIC_MESSAGE + "]]></MsgType>");
sb.append("<Music>");
if (message.getMusic().getTitle() != null && !"".equals(message.getMusic().getTitle())) {
sb.append("<Title><![CDATA[" + message.getMusic().getTitle() + "]]></Title>");
}
if (message.getMusic().getDescription() != null && !"".equals(message.getMusic().getDescription())) {
sb.append("<Description><![CDATA[" + message.getMusic().getDescription() + "]]></Description>");
}
if (message.getMusic().getMusicUrl() != null && !"".equals(message.getMusic().getMusicUrl())) {
sb.append("<MusicUrl><![CDATA[" + message.getMusic().getMusicUrl() + "]]></MusicUrl>");
}
if (message.getMusic().getHQMusicUrl() != null && !"".equals(message.getMusic().getHQMusicUrl())) {
sb.append("<HQMusicUrl><![CDATA[" + message.getMusic().getHQMusicUrl() + "]]></HQMusicUrl>");
} sb.append("<ThumbMediaId><![CDATA[" + message.getMusic().getThumbMediaId() + "]]></ThumbMediaId>");
sb.append("</Music>");
sb.append("</xml>");
return sb.toString();
} /**
* <xml> <ToUserName><![CDATA[toUser]]></ToUserName>
* <FromUserName><![CDATA[fromUser]]></FromUserName>
* <CreateTime>12345678</CreateTime> <MsgType><![CDATA[video]]></MsgType>
* <Video> <MediaId><![CDATA[media_id]]></MediaId>
* <Title><![CDATA[title]]></Title>
* <Description><![CDATA[description]]></Description> </Video> </xml>
*
* @Title sendVideoMessage
* @Description 回复视频消息
* @param message
* @return
*/
public static String sendVideoMessage(VideoOutPutMessage message) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>");
sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>");
sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>");
sb.append("<MsgType><![CDATA[" + MessageType.VIDEO_MESSAGE + "]]></MsgType>");
sb.append("<Video>");
sb.append("<MediaId><![CDATA[" + message.getVideo().getMediaId() + "]]></MediaId>");
if (message.getVideo().getTitle() != null && !"".equals(message.getVideo().getTitle())) {
sb.append("<Title><![CDATA[" + message.getVideo().getTitle() + "]]></Title>");
}
if (message.getVideo().getDescription() != null && !"".equals(message.getVideo().getDescription())) {
sb.append("<Description><![CDATA[" + message.getVideo().getDescription() + "]]></Description>");
}
sb.append("</Video>");
sb.append("</xml>");
return sb.toString();
} /**
* <xml> <ToUserName><![CDATA[toUser]]></ToUserName>
* <FromUserName><![CDATA[fromUser]]></FromUserName>
* <CreateTime>12345678</CreateTime> <MsgType><![CDATA[voice]]></MsgType>
* <Voice> <MediaId><![CDATA[media_id]]></MediaId> </Voice> </xml>
* @Title sendVoiceMessage
* @Description 回复语音消息
* @param message
* @return
*/
public static String sendVoiceMessage(VoiceOutputMessage message) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>");
sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>");
sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>");
sb.append("<MsgType><![CDATA[" + MessageType.VOICE_MESSAGE + "]]></MsgType>");
sb.append("<Voice>");
sb.append("<MediaId><![CDATA[" + message.getVoice().getMediaId() + "]]></MediaId>");
sb.append("</Voice>");
sb.append("</xml>");
return sb.toString();
} /**
* <xml> <ToUserName><![CDATA[toUser]]></ToUserName>
* <FromUserName><![CDATA[fromUser]]></FromUserName>
* <CreateTime>12345678</CreateTime> <MsgType><![CDATA[image]]></MsgType>
* <Image> <MediaId><![CDATA[media_id]]></MediaId> </Image> </xml>
* @Title sendImageMessage
* @Description 回复图片消息
* @param message
*/
public static String sendImageMessage(ImageOutputMessage message) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>");
sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>");
sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>");
sb.append("<MsgType><![CDATA[" + MessageType.IMAGE_MESSAGE + "]]></MsgType>");
sb.append("<Image>");
sb.append("<MediaId><![CDATA[" + message.getImage().getMediaId() + "]]></MediaId>");
sb.append("</Image>");
sb.append("</xml>");
return sb.toString();
}
/**
* <xml> <ToUserName>< ![CDATA[toUser] ]></ToUserName> <FromUserName><
* ![CDATA[fromUser] ]></FromUserName> <CreateTime>12345678</CreateTime>
* <MsgType>< ![CDATA[text] ]></MsgType> <Content>< ![CDATA[你好] ]></Content>
* </xml> sendTextMessage
* @param message
* @return
*/
public static String sendTextMessage(TextMessage message) {
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
sb.append("<ToUserName><![CDATA[" + message.getToUserName() + "]]></ToUserName>");
sb.append("<FromUserName><![CDATA[" + message.getFromUserName() + "]]></FromUserName>");
sb.append("<CreateTime>" + message.getCreateTime() + "</CreateTime>");
sb.append("<MsgType><![CDATA[" + MessageType.TEXT_MESSAGE + "]]></MsgType>");
sb.append("<Content><![CDATA[" + message.getContent() + "]]></Content>");
sb.append("</xml>");
return sb.toString();
}
}

我们在接收微信发送的消息时,需要根据消息的不同类别来进行处理,这是我们就需要一个工具类来处理事件类型的消息和普通消息类型的工具类:WebChatService

 package com.webchat.service;

 import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import com.webchat.entity.output.Articles;
import com.webchat.entity.output.NewsOutputMessage;
import com.webchat.entity.output.TextMessage;
import com.webchat.util.weixin.MessageType;
import com.webchat.util.weixin.ReplyMessageUtil;
import com.webchat.util.weixin.utils.XmlUtil; /**
* 处理接收信息和回复消息的服务类接口
*
* @author Administrator
*
*/
public class WebChatService {
// 处理微信发来的请求 map 消息业务处理分发
public static String parseMessage(Map<String, String> map) {
String respXml = null;
try {
// 发送方帐号
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
// 取得消息类型
String MsgType = map.get("MsgType");
// 发现直接把要返回的信息直接封装成replyMap集合,然后转换成 xml文件,是不是实体类可以不用了
Map<String, String> replyMap = new HashMap<String, String>();
replyMap.put("ToUserName", fromUserName);
replyMap.put("FromUserName", toUserName);
replyMap.put("CreateTime", String.valueOf(new Date().getTime()));
if (MsgType.equals(MessageType.TEXT_MESSAGE)) {
// 封装文本返回消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setContent("您发送的是文本消息");
textMessage.getMsgType();
// respXml = ReplyMessageUtil.sendTextMessage(textMessage); // 用map集合封装
replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT);
replyMap.put("Content", "您发送的是文本消息");
respXml = XmlUtil.xmlFormat(replyMap, true);
} else if (MsgType.equals(MessageType.IMAGE_MESSAGE)) {
// 这里回复图片 或者图文消息 以图文消息为例
NewsOutputMessage message = new NewsOutputMessage();
message.setToUserName(fromUserName);
message.setFromUserName(toUserName);
message.setCreateTime(new Date().getTime());
message.getMsgType(); Articles article = new Articles();
article.setDescription("图文消息 "); // 图文消息的描述
article.setPicUrl("https://p4.ssl.cdn.btime.com/dmfd/192_108_/t019d0b65e33000f8a0.jpg?size=458x240"); // 图文消息图片地址
article.setTitle("图文消息 "); // 图文消息标题
article.setUrl("http://www.baidu.com"); // 图文 url 链接
List<Articles> list = new ArrayList<Articles>();
list.add(article);// 这里发送的是单图文,如果需要发送多图文则在这里 list 中加入多个
// Articles! message.setArticleCount(list.size());
message.setArticles(list);
respXml = ReplyMessageUtil.sendImageTextMessage(message);
} else if (MsgType.equals(MessageType.VOICE_MESSAGE)) {
// 以下方式根据需要来操作
replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT);
replyMap.put("Content", "您发送的是语音消息");
respXml = XmlUtil.xmlFormat(replyMap, true);
} else if (MsgType.equals(MessageType.VIDEO_MESSAGE)) {
replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT);
replyMap.put("Content", "您发送的是视频消息");
respXml = XmlUtil.xmlFormat(replyMap, true);
} else if (MsgType.equals(MessageType.SHORTVIDEO_MESSAGE)) {
replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT);
replyMap.put("Content", "您发送的是小视频消息");
respXml = XmlUtil.xmlFormat(replyMap, true);
} else if (MsgType.equals(MessageType.POSOTION_MESSAGE)) {
replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT);
replyMap.put("Content", "您发送的是地理位置消息");
respXml = XmlUtil.xmlFormat(replyMap, true);
} else if (MsgType.equals(MessageType.LINK_MESSAGE)) {
replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT);
replyMap.put("Content", "您发送的是链接消息");
respXml = XmlUtil.xmlFormat(replyMap, true);
}
} catch (Exception e) {
e.printStackTrace();
}
return respXml;
} // 事件消息业务分发
public static String parseEvent(Map<String, String> map) {
String respXml = null;
try {
// 发送方帐号
String fromUserName = map.get("FromUserName");
// 开发者微信号
String toUserName = map.get("ToUserName");
// 取得消息类型
String MsgType = map.get("MsgType");
//获取事件类型
String eventType = map.get("Event"); // 发现直接把要返回的信息直接封装成replyMap集合,然后转换成 xml文件,是不是实体类可以不用了
Map<String, String> replyMap = new HashMap<String, String>();
replyMap.put("ToUserName", fromUserName);
replyMap.put("FromUserName", toUserName);
replyMap.put("CreateTime", String.valueOf(new Date().getTime()));
if (eventType.equals(MessageType.EVENT_TYPE_SUBSCRIBE)) {// 关注
// 用map集合封装
replyMap.put("MsgType", MessageType.RESP_MESSAGE_TYPE_TEXT);
replyMap.put("Content", MessageType.menuText());
respXml = XmlUtil.xmlFormat(replyMap, true);
}
if (eventType.equals(MessageType.EVENT_TYPE_UNSUBSCRIBE)) {// 取消关注 }
if (eventType.equals(MessageType.EVENT_TYPE_SCAN)) {// 用户已关注时的扫描带参数二维码 }
if (eventType.equals(MessageType.EVENT_TYPE_LOCATION)) {// 上报地理位置 }
if (eventType.equals(MessageType.EVENT_TYPE_CLICK)) {// 自定义菜单 }
} catch (Exception e) {
e.printStackTrace();
}
return respXml;
}
}

通过查看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工具类:

 package com.webchat.util.weixin.utils;

 import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry; import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
/**
* 封装和处理xml文件
* @author Administrator
*
*/
public class XmlUtil { private static final String PREFIX_XML = "<xml>"; private static final String SUFFIX_XML = "</xml>"; private static final String PREFIX_CDATA = "<![CDATA["; private static final String SUFFIX_CDATA = "]]>"; /**
* 转化成xml, 单层无嵌套
*
* @param map
* @param isAddCDATA ture 加CDATA标签 false 不加CDATA标签
* @return
*/
public static String xmlFormat(Map<String, String> parm, boolean isAddCDATA) { StringBuffer strbuff = new StringBuffer(PREFIX_XML);
if (CollectionUtil.isNotEmpty(parm)) {
for (Entry<String, String> entry : parm.entrySet()) {
strbuff.append("<").append(entry.getKey()).append(">");
if (isAddCDATA) {
strbuff.append(PREFIX_CDATA);
if (StringUtil.isNotEmpty(entry.getValue())) {
strbuff.append(entry.getValue());
}
strbuff.append(SUFFIX_CDATA);
} else {
if (StringUtil.isNotEmpty(entry.getValue())) {
strbuff.append(entry.getValue());
}
}
strbuff.append("</").append(entry.getKey()).append(">");
}
}
return strbuff.append(SUFFIX_XML).toString();
} /**
* 解析xml
*
* @param xml
* @return
* @throws XmlPullParserException
* @throws IOException
*/
public static Map<String, String> xmlParse(String xml) throws XmlPullParserException, IOException {
Map<String, String> map = null;
if (StringUtil.isNotEmpty(xml)) {
InputStream inputStream = new ByteArrayInputStream(xml.getBytes());
XmlPullParser pullParser = XmlPullParserFactory.newInstance().newPullParser();
pullParser.setInput(inputStream, "UTF-8"); // 为xml设置要解析的xml数据
int eventType = pullParser.getEventType(); while (eventType != XmlPullParser.END_DOCUMENT) {
switch (eventType) {
case XmlPullParser.START_DOCUMENT:
map = new HashMap<String, String>();
break;
case XmlPullParser.START_TAG:
String key = pullParser.getName();
if (key.equals("xml"))
break;
String value = pullParser.nextText().trim();
map.put(key, value);
break;
case XmlPullParser.END_TAG:
break;
}
eventType = pullParser.next();
}
}
return map;
}
}

XmlUtil 工具类关联的类CollectionUtil 和StringUtil

 package com.webchat.util.weixin.utils;

 import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern; /**
* String工具类
*/
public class StringUtil { private StringUtil() {
super();
} /**
* 出去null和""
* @param src
* @return
*/
public static String formatNull(String src) {
return (src == null || "null".equals(src)) ? "" : src;
} /**
* 判断字符串是否为空的正则表达式,空白字符对应的unicode编码
*/
private static final String EMPTY_REGEX = "[\\s\\u00a0\\u2007\\u202f\\u0009-\\u000d\\u001c-\\u001f]+"; /**
* 验证字符串是否为空
*
* @param input
* @return
*/
public static boolean isEmpty(String input) {
return input == null || input.equals("") || input.matches(EMPTY_REGEX);
} public static boolean isNotEmpty(String input){
return !isEmpty(input);
} private static final String NUM_REG = "(\\+|\\-)?\\s*\\d+(\\.\\d+)?"; /**
* 判断是否数字
*
* @param str
* @return
*/
public static boolean isNumber(String str) {
if (isEmpty(str)) {
return false;
} if (str.trim().matches(NUM_REG)) {
return true;
} return false;
} /**
* 判断是否包含有乱码的数据,如果字符串中包含有替换字符就认为是乱码
*
* @param str
* @return
*/
public static boolean containUnreadableCode(String str) {
return contain(str, "\\ufffd");
} /**
* 判读是否包含数字
*
* @param str
* @return
*/
public static boolean containNumber(String str) {
return contain(str, "\\d");
} /**
* 判断是否包含a-zA-Z_0-9
*
* @param str
* @return
*/
public static boolean containWord(String str) {
return contain(str, "\\w");
} /**
* 是否包含有标点符号
*
* @param str
* @return
*/
public static boolean containPunct(String str) {
return contain(str, PUNCT_REG);
} public static boolean contain(String str, String regex) {
if (isEmpty(str) || isEmpty(regex)) {
return false;
} if (str.trim().matches(regex)) {
return true;
} Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
if (matcher.find()) {
return true;
} return false;
} /**
* 替换所有的(不区分大小写)
*
* @param input
* @param regex
* @param replacement
* @return
*/
public static String replaceAll(String input, String regex,
String replacement) {
return Pattern.compile(regex, Pattern.CASE_INSENSITIVE).matcher(input)
.replaceAll(replacement);
} /**
* 移除所有的空格
*
* @param text
* @return
*/
public static String removeAllSpace(String text) {
if (isEmpty(text)) {
return text;
} return text.replaceAll("[ ]+", "");
} private static final String PUNCT_REG = "[^a-zA-Z0-9\\u4e00-\\u9fa5]"; /**
* 移除字符串中的所有的中英文标点符号
*
* @param str
* @return
*/
public static String removeAllPunct(String str) {
if (isEmpty(str)) {
return str;
} return str.replaceAll(PUNCT_REG, "");
} /**
* 计算str中包含多少个子字符串sub
*
* @param str
* @param sub
* @return
*/
public static int countMatches(String str, String sub) {
if (isEmpty(str) || isEmpty(sub)) {
return 0;
} int count = 0;
int idx = 0;
while ((idx = str.indexOf(sub, idx)) != -1) {
count++;
idx += sub.length();
} return count;
} /**
* 获得源字符串的一个子字符串
*
* @param str
* :源字符串
* @param beginIndex
* :开始索引(包括)
* @param endIndex
* :结束索引(不包括)
* @return
*/
public static String substring(String str, int beginIndex, int endIndex) {
if (isEmpty(str)) {
return str;
} int length = str.length(); if (beginIndex >= length || endIndex <= 0 || beginIndex >= endIndex) {
return null;
} if (beginIndex < 0) {
beginIndex = 0;
}
if (endIndex > length) {
endIndex = length;
} return str.substring(beginIndex, endIndex);
} /**
* 计算str中包含子字符串sub所在位置的前一个字符或者后一个字符和sub所组成的新字符串
*
* @param str
* @param sub
* @return
*/
public static Set<String> substring(String str, String sub) {
if (isEmpty(str) || isEmpty(sub)) {
return null;
} Set<String> result = new HashSet<String>();
int idx = 0;
while ((idx = str.indexOf(sub, idx)) != -1) {
String temp = substring(str, idx - 1, idx + sub.length());
if (!isEmpty(temp)) {
temp = removeAllPunct(temp);
if (!sub.equalsIgnoreCase(temp) && !containWord(temp)) {
result.add(temp);
} } temp = substring(str, idx, idx + sub.length() + 1);
if (!isEmpty(temp)) {
temp = removeAllPunct(temp);
if (!sub.equalsIgnoreCase(temp) && !containWord(temp)) {
result.add(temp);
}
} idx += sub.length();
} return result;
} /**
* 过滤掉XML中无法解析的非法字符
*
* @param content
* @return
*/
public static String wrapXmlContent(String content) {
if (isEmpty(content)) {
return "";
} StringBuilder result = new StringBuilder(); for (int i = 0; i < content.length(); i++) {
char ch = content.charAt(i);
if ((ch == '\t') || (ch == '\n') || (ch == '\r')
|| ((ch >= ' ') && (ch <= 55295))
|| ((ch >= 57344) && (ch <= 65533))
|| ((ch >= 65536) && (ch <= 1114111))) {
result.append(ch);
}
} return result.toString();
} /**
* 判断字符串的长度
*
* @param str
* @return
*/
public static boolean overLength(String str) {
if (isEmpty(str)) {
return false;
} return str.length() > 1 ? true : false;
} /**
* 字符串中含有特殊字符的处理
*
* @param str
* @return
*/
public static String specialStr(String str) {
str = str.replaceAll("[^\\u4e00-\\u9fa5 | 0-9| a-zA-Z | \\.]+", " ")
.replaceAll("[\\.]{2,}", " ").trim();
return str;
} /**
* 将特殊符号去掉,但是保留空格
*
* @param str
* @return
*/
public static String replaceInValidateChar(String str) {
return str.replaceAll("[^a-zA-Z0-9\\u4e00-\\u9fa5\\s+]", " ");
} /**
* 返回字符串对应的unicode编码
*
* @param str
* @return
*/
public static String[] toHexString(String str) {
char[] chars = str.toCharArray(); String[] result = new String[chars.length]; for (int i = 0; i < chars.length; i++) {
result[i] = Integer.toHexString((int) chars[i]);
} return result;
} public static String getUuid() {
return UUID.randomUUID().toString();
} public static boolean isUrl(String src) {
String regex = "http[s]?:\\/\\/([\\w-]+\\.[\\w-]+)(\\.[\\w-])+(:\\d{2,10})?.*";
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(src);
return matcher.matches();
} /**
* sql 查询转义
* @param str
* @return
*/
public static String escapeSql(String str){
if (StringUtil.isNotEmpty(str)) {
StringBuffer strbuff = new StringBuffer();
for (String s : str.split("")) {
if (s.equals("%") || s.equals("_") || s.equals("\\")) {
strbuff.append("\\");
}
strbuff.append(s);
}
return strbuff.toString();
}
return str;
}
}
 package com.webchat.util.weixin.utils;

 import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map; public class CollectionUtil { private CollectionUtil() {
super();
} // 判断一个集合是否为空
public static <T> boolean isEmpty(Collection<T> col) {
if (col == null || col.isEmpty()) {
return true;
} return false;
} // 判断一个集合是否不为空
public static <T> boolean isNotEmpty(Collection<T> col) {
return !isEmpty(col);
} // 判断Map是否为空
public static <K, V> boolean isEmpty(Map<K, V> map) {
if (map == null || map.isEmpty()) {
return true;
} return false;
} // 判断Map是否不为空为空
public static <K, V> boolean isNotEmpty(Map<K, V> map) {
return !isEmpty(map);
} // 去除list中的重复数据
public static <T> List<T> removeRepeat(List<T> list) {
if (isEmpty(list)) {
return list;
} List<T> result = new ArrayList<T>();
for (T e : list) {
if (!result.contains(e)) {
result.add(e);
}
} return result;
} // 将集合转换为String数组
public static <T> String[] toArray(List<T> list) {
if (isEmpty(list)) {
return null;
} String[] result = new String[list.size()];
for (int i = 0; i < list.size(); i++) {
result[i] = String.valueOf(list.get(i));
} return result;
} }

这个时候我们需要我们来完善消息入口【WebChatController.java】中的 post 方法,最终结果如下:

 /**
* 接收微信消息处理并做分发
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(method=RequestMethod.POST)
public void post(HttpServletRequest request, HttpServletResponse response) throws Exception {
// TODO 消息的接收、处理、响应
//消息来源可靠性验证
String signature = request.getParameter("signature");// 微信加密签名
String timestamp = request.getParameter("timestamp");// 时间戳
String nonce = request.getParameter("nonce"); // 随机数
//确认此次GET请求来自微信服务器,原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败
if (!WebChatUtil.checkSignature(signature, timestamp, nonce)) {
//消息不可靠,直接返回
response.getWriter().write("");
return;
}
//用户每次向公众号发送消息、或者产生自定义菜单点击事件时,响应URL将得到推送
try {
response.setCharacterEncoding("UTF-8");
response.setContentType("text/xml");
//调用parseXml方法解析请求消息
Map<String, String> map = MessageType.parseXml(request, response);
String MsgType = map.get("MsgType");
String xml = null;//处理输入消息,返回结果的xml
if(MessageType.REQ_MESSAGE_TYPE_EVENT.equals(MsgType)){
xml = WebChatService.parseEvent(map);
}else{
xml = WebChatService.parseMessage(map);
}
//返回封装的xml
//System.out.println(xml);
response.getWriter().write(xml);
} catch (Exception ex) {
response.getWriter().write("");
}
}

好了,现在让我们启动本地服务来测试一下吧,打开微信测试号管理:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login,配置可以参考:Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发 和 Java开发微信公众号(一)---初识微信公众号以及环境搭建

扫描二维码,关注你的测试公众号:然后你可以发送消息来测试

Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

效果如下:

Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理

如果在操作过程中有问题,欢迎随时讨论^.^

其他文章关联

(一)Java开发微信公众号(一)---初识微信公众号以及环境搭建

(二)Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发

(三)Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装

(四)Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理