Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理
在前几节文章中我们讲述了微信公众号环境的搭建、如何接入微信公众平台、以及微信服务器请求消息,响应消息,事件消息以及工具处理类的封装;接下来我们重点说一下-微信服务器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开发微信公众号(一)---初识微信公众号以及环境搭建
(二)Java开发微信公众号(二)---开启开发者模式,接入微信公众平台开发
(三)Java开发微信公众号(三)---微信服务器请求消息,响应消息,事件消息以及工具处理类的封装
(四)Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理
Java开发微信公众号(四)---微信服务器post消息体的接收及消息的处理的更多相关文章
- JAVA版开源微信管家—JeeWx捷微3.2版本发布,支持微信公众号,微信企业号,支付窗、小程序
JeeWx捷微3.2微信企业号升级版本发布^_^ JeeWx捷微V3.2——多触点管理平台(支持微信公众号,微信企业号,支付窗.小程序) JeeWx捷微V3.2.0版本引入了更多新特性,支持微信公 ...
- JeeWx捷微3.1小程序版本发布,支持微信公众号,微信企业号,支付窗——JAVA版开源微信管家
支持小程序,JeeWx捷微3.1小程序版本发布^_^ JeeWx捷微V3.1——多触点小程序版本管理平台(支持微信公众号,微信企业号,支付窗) JeeWx捷微V3.1.0版本紧跟微信小程序更新,在 ...
- JAVA版开源微信管家—JeeWx捷微3.1小程序版本发布,支持微信公众号,微信企业号,支付窗
支持小程序,JeeWx捷微3.1小程序版本发布^_^ JeeWx捷微V3.1--多触点小程序版本管理平台(支持微信公众号,微信企业号,支付窗) JeeWx捷微V3.1.0版本紧跟微信小程序更新,在原有 ...
- JAVA开源微信管家平台——JeeWx捷微V3.3版本发布(支持微信公众号,微信企业号,支付窗)
JeeWx捷微V3.3版本紧跟微信小程序更新,在原有多触点版本基础上,引入了更多的新亮点:支持微信公众号.微信企业号.支付宝服务窗等多触点开发:采用微服务框架实现,可插拔可集成,轻量级开发:对小程序的 ...
- 微信公众号支付|微信H5支付|微信扫码支付|小程序支付|APP微信支付解决方案总结
最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付.APP微信支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存. 先说注意 ...
- C#版微信公众号支付|微信H5支付|微信扫码支付问题汇总及解决方案总结
最近负责的一些项目开发,都用到了微信支付(微信公众号支付.微信H5支付.微信扫码支付).在开发的过程中,在调试支付的过程中,或多或少都遇到了一些问题,今天总结下,分享,留存.代码在文章结尾处,有需要的 ...
- CabloyJS的微信API对接模块:当前支持微信公众号和微信小程序
Cabloy-微信是什么 Cabloy-微信是基于CabloyJS全栈业务开发框架开发的微信接口模块,当前整合了微信公众号和微信小程序的接口,达到开箱即用的使用效果.在Cabloy-微信的基础上,可以 ...
- 使用 nodeJs 开发微信公众号(配置服务器)
流程如下: 1. 申请微信公众号:企业号.服务号.订阅号(前两个要钱) 2. 配置微信公众号后台 选择基本配置,获得 AppId 和 AppSecret ,点击服务器配置 URL:你服务器地址,不能是 ...
- TP3.2校验微信公众号||小程序 服务器地址
1.在TP3.2里面,写一个控制器,用来校验微信公众号||小程序的服务器地址 <?php namespace Home\Controller; use Think\Controller; hea ...
随机推荐
- linux 命令——13 less(转)
less 工 具也是对文件或其它输出进行分页显示的工具,应该说是linux正统查看文件内容的工具,功能极其强大.less 的用法比起 more 更加的有弹性. 在 more 的时候,我们并没有办法向前 ...
- innobackupex 全备、增备脚本
全备脚本:innobackupex --defaults-file=/etc/my.cnf --user root --password mypasswd /mydata/fullbak/ 增备脚本: ...
- Android(java)学习笔记93:为什么局部内部类只能访问外部类中的 final型的常量
为什么匿名内部类参数必须为final类型: 1) 从程序设计语言的理论上:局部内部类(即:定义在方法中的内部类),由于本身就是在方法内部(可出现在形式参数定义处或者方法体处),因而访问方法中的局部变 ...
- 浅谈 import / export
import { ngModule } from '@angular/core'; import { AppComponent } from './app.component'; export cla ...
- IPC Gateway 设计
1. IPC Gateway对外提供的功能: IPC的register/request/reply/notification服务. 2. IPC Gatew的实现原理: 各个具体的服务注册自己的回调函 ...
- 2017.12.24 Java序列化你不知道的事(二)
1 序列化允许重构 序列化允许一定数量的类变种,甚至重构之后也是如此,ObjectInputStream 仍可以很好地将其读出来. Java Object Serialization 规范可以自动管理 ...
- python_42_文件补充
m=['红烧肉\n','熘肝尖','西红柿炒鸡蛋','腊八粥','油焖大虾'] fname=input("请输入文件名:")#输入xxx f=open(fname,'w',enco ...
- 简单ssh
#!/usr/bin/env python #-*- coding:utf-8 -*- # datetime:2019/5/22 14:20 # software: PyCharm #服务端 impo ...
- css与html结合四种方式
方式一:每个标签加一个属性法 <div style="background-color:red;color:green;"></div> 方式二:head中 ...
- 1047: [HAOI2007]理想的正方形
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4075 Solved: 2277[Submit][Status][Discuss] Descript ...