在开发之前我们要先知道用户发送的信息是先传送到微信服务器,微信服务器在以xml的格式发送给进行公众号
开发流程图
代码实现
控制层代码
/**
* 微信核心控制器(验证服务号是否合法,以及消息转发都需要通过此controller)
*/
package com.b505.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.b505.tool.DataProcess;
import com.b505.trycatch.TryCatchWeixinCoreService;
import com.b505.weixin.util.WeixinSignUtil;
import com.b505.weixin.util.WeixinVerification;
/**
* <p>Company: B505信息技术研究所 </p>
* @Description: 微信核心controller,接入微信服务层
* @Create Date: 2017年10月9日下午7:31:29
* @Version: V1.00
* @Author: 来日可期
*/
@RestController
@RequestMapping(value = "/wechat")
public class WeixinCoreController {
private static Logger logger = LoggerFactory.getLogger(WeixinCoreController.class);
@Autowired
private WeixinSignUtil weixinSignUtil;
@Autowired
private DataProcess dataProcess;
@Autowired
private WeixinCoreService weixinCoreService;
@RequestMapping(value="/access", method=RequestMethod.POST)
public String getWeiXinMessage(HttpServletRequest request, HttpServletResponse response)throws Exception{
logger.info("----------------开始处理微信发过来的消息------------------");
// 微信服务器POST消息时用的是UTF-8编码,在接收时也要用同样的编码,否则中文会乱码;
request.setCharacterEncoding("UTF-8");
// 在响应消息(回复消息给用户)时,也将编码方式设置为UTF-8,原理同上;
response.setCharacterEncoding("UTF-8");
String respXml = weixinCoreService.weixinMessageHandelCoreService(request, response);
if (dataProcess.dataIsNull(respXml)){
logger.error("-------------处理微信消息失败-----------------------");
return null;
}else {
logger.info("----------返回微信消息处理结果-----------------------:"+respXml);
return respXml;
}
}
}
private WeixinCoreService weixinCoreService;
@RequestMapping(value="/access", method=RequestMethod.POST)
public String getWeiXinMessage(HttpServletRequest request, HttpServletResponse response)throws Exception{
logger.info("----------------开始处理微信发过来的消息------------------");
// 微信服务器POST消息时用的是UTF-8编码,在接收时也要用同样的编码,否则中文会乱码;
request.setCharacterEncoding("UTF-8");
// 在响应消息(回复消息给用户)时,也将编码方式设置为UTF-8,原理同上;
response.setCharacterEncoding("UTF-8");
String respXml = weixinCoreService.weixinMessageHandelCoreService(request, response);
if (dataProcess.dataIsNull(respXml)){
logger.error("-------------处理微信消息失败-----------------------");
return null;
}else {
logger.info("----------返回微信消息处理结果-----------------------:"+respXml);
return respXml;
}
}
}
service层代码
/**
* 微信消息处理核心service实现类
*/
package com.b505.service.impl;
import java.util.Date;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.b505.dao.UserDao;
import com.b505.service.WeixinCoreService;
import com.b505.tool.DataProcess;
import com.b505.weixin.message.resp.TextMessage;
import com.b505.weixin.pojo.WeixinMessageInfo;
import com.b505.weixin.util.WeixinMessageModelUtil;
import com.b505.weixin.util.WeixinMessageUtil;
/**
* <p>Company: B505信息技术研究所 </p>
* @Description: 微信消息处理核心service实现类
* @Create Date: 2017年10月10日下午3:33:16
* @Version: V1.00
* @Author: 来日可期
*/
@Service("weixinCoreService")
public class WeixinCoreServiceImpl implements WeixinCoreService {
private static Logger logger = LoggerFactory.getLogger(WeixinCoreServiceImpl.class);
@Autowired
private WeixinMessageUtil weixinMessageUtil;
@Autowired
private WeixinMessageInfo weixinMessageInfo;
@Autowired
private WeixinMessageModelUtil weixinMessageModelUtil;
@Autowired
private UserDao userDao;
@Autowired
private DataProcess dataProcess;
@Override
public String weixinMessageHandelCoreService(HttpServletRequest request,
HttpServletResponse response) {
logger.info("------------微信消息开始处理-------------");
// 返回给微信服务器的消息,默认为null
String respMessage = null;
try {
// 默认返回的文本消息内容
String respContent = null;
// xml分析
// 调用消息工具类MessageUtil解析微信发来的xml格式的消息,解析的结果放在HashMap里;
Map<String, String> map = weixinMessageUtil.parseXml(request);
// 发送方账号
String fromUserName = map.get("FromUserName");
weixinMessageInfo.setFromUserName(fromUserName);
System.out.println("fromUserName--->"+fromUserName);
// 接受方账号(公众号)
String toUserName = map.get("ToUserName");
weixinMessageInfo.setToUserName(toUserName);
System.out.println("toUserName----->"+toUserName);
// 消息类型
String msgType = map.get("MsgType");
weixinMessageInfo.setMessageType(msgType);
logger.info("fromUserName is:" +fromUserName+" toUserName is:" +toUserName+" msgType is:" +msgType);
// 默认回复文本消息
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(weixinMessageUtil.RESP_MESSAGE_TYPE_TEXT);
textMessage.setFuncFlag(0);
// 分析用户发送的消息类型,并作出相应的处理
// 文本消息
if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_TEXT)){
respContent = "亲,这是文本消息!";
textMessage.setContent(respContent);
respMessage = weixinMessageUtil.textMessageToXml(textMessage);
}
// 图片消息
else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
respContent = "您发送的是图片消息!";
textMessage.setContent(respContent);
respMessage = weixinMessageUtil.textMessageToXml(textMessage);
}
// 语音消息
else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
respContent = "您发送的是语音消息!";
textMessage.setContent(respContent);
respMessage = weixinMessageUtil.textMessageToXml(textMessage);
}
// 视频消息
else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_VIDEO)) {
respContent = "您发送的是视频消息!";
textMessage.setContent(respContent);
respMessage = weixinMessageUtil.textMessageToXml(textMessage);
}
// 地理位置消息
else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
respContent = "您发送的是地理位置消息!";
textMessage.setContent(respContent);
respMessage = weixinMessageUtil.textMessageToXml(textMessage);
}
// 链接消息
else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_LINK)) {
respContent = "您发送的是链接消息!";
textMessage.setContent(respContent);
respMessage = weixinMessageUtil.textMessageToXml(textMessage);
}
// 事件推送(当用户主动点击菜单,或者扫面二维码等事件)
else if (msgType.equals(weixinMessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType =map.get("Event");
System.out.println("eventType------>"+eventType);
// 关注
if (eventType.equals(weixinMessageUtil.EVENT_TYPE_SUBSCRIBE)){
respMessage = weixinMessageModelUtil.followResponseMessageModel(weixinMessageInfo);
}
// 取消关注
else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {
weixinMessageModelUtil.cancelAttention(fromUserName);
}
// 扫描带参数二维码
else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_SCAN)) {
System.out.println("扫描带参数二维码");
}
// 上报地理位置
else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_LOCATION)) {
System.out.println("上报地理位置");
}
// 自定义菜单(点击菜单拉取消息)
else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_CLICK)) {
// 事件KEY值,与创建自定义菜单时指定的KEY值对应
String eventKey=map.get("EventKey");
System.out.println("eventKey------->"+eventKey);
}
// 自定义菜单((自定义菜单URl视图))
else if (eventType.equals(weixinMessageUtil.EVENT_TYPE_VIEW)) {
System.out.println("处理自定义菜单URI视图");
}
}
} catch (Exception e) {
e.printStackTrace();
logger.error("系统出错");
System.err.println("系统出错");
respMessage = null;
}
finally{
if (null == respMessage) {
respMessage = weixinMessageModelUtil.systemErrorResponseMessageModel(weixinMessageInfo);
}
}
return respMessage;
}
}
工具类
/**
* 封装微信消息类型,有一个解析微信发过的xml消息的工具
*/
package com.b505.weixin.util;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.stereotype.Component;
import com.b505.Message.model.Article;
import com.b505.weixin.message.resp.ImageMessage;
import com.b505.weixin.message.resp.MusicMessage;
import com.b505.weixin.message.resp.NewsMessage;
import com.b505.weixin.message.resp.TextMessage;
import com.b505.weixin.message.resp.VideoMessage;
import com.b505.weixin.message.resp.VoiceMessage;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.core.util.QuickWriter;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.XppDriver;
/**
* <p>Company: B505信息技术研究所 </p>
* @Description: 封装微信消息类型,有一个解析xml格式的工具
* @Create Date: 2017年10月11日上午11:28:48
* @Version: V1.00
* @Author: 来日可期
*/
@Component
public class WeixinMessageUtil {
/**
* 请求消息类型:文本
*/
public final String REQ_MESSAGE_TYPE_TEXT = "text";
/**
* 请求消息类型:图片
*/
public final String REQ_MESSAGE_TYPE_IMAGE="image";
/**
* 请求消息类型:语音
*/
public final String REQ_MESSAGE_TYPE_VOICE="voice";
/**
* 请求消息类型:视频
*/
public final String REQ_MESSAGE_TYPE_VIDEO="video";
/**
* 请求消息类型:链接
*/
public final String REQ_MESSAGE_TYPE_LINK = "link";
/**
* 请求消息类型:地理位置
*/
public final String REQ_MESSAGE_TYPE_LOCATION="location";
/**
* 请求消息类型:小视频
*/
public final String REQ_MESSAGE_TYPE_SHORTVIDEO="shortvideo";
/**
*请求消息类型:事件推送
*/
public final String REQ_MESSAGE_TYPE_EVENT = "event";
/**
* 返回消息类型:文本
*/
public final String RESP_MESSAGE_TYPE_TEXT = "text";
/**
* 消息返回类型:图片
*/
public final String RESP_MESSAGE_TYPE_IMAGE="image";
/**
* 消息返回类型:语音
*/
public final String RESP_MESSAGE_TYPE_VOICE = "voice";
/**
* 消息返回类型:音乐
*/
public final String RESP_MESSAGE_TYPE_MUSIC = "music";
/**
* 消息返回类型:图文
*/
public final String RESP_MESSAGE_TYPE_NEWS = "news";
/**
* 消息返回类型:视频
*/
public final String RESP_MESSAGE_TYPE_VIDEO="video";
/**
* 事件类型:订阅
*/
public final String EVENT_TYPE_SUBSCRIBE = "subscribe";
/**
* 事件类型:取消订阅
*/
public final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
/**
* 事件类型:scan(关注用户扫描带参二维码)
*/
public final String EVENT_TYPE_SCAN = "scan";
/**
* 事件类型:location(上报地理位置)
*/
public final String EVENT_TYPE_LOCATION = "location";
/**
* 事件类型:CLICK(点击菜单拉取消息)
*/
public final String EVENT_TYPE_CLICK ="CLICK";
/**
* 事件类型:VIEW(自定义菜单URl视图)
*/
public final String EVENT_TYPE_VIEW ="VIEW";
/**
* 事件类型:TEMPLATESENDJOBFINISH(模板消息送达情况提醒)
*/
public final String EVENT_TYPE_TEMPLATESENDJOBFINISH="TEMPLATESENDJOBFINISH";
/**
* @Description: 解析微信服务器发过来的xml格式的消息将其转换为map
* @Parameters: WeixinMessageUtil
* @Return: Map<String, String>
* @Create Date: 2017年10月11日上午11:41:23
* @Version: V1.00
* @author:来日可期
*/
public Map<String, String> parseXml(HttpServletRequest request)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();
// 得到根元素的所有子节点
@SuppressWarnings("unchecked")
List<Element> elementList = root.elements();
// 判断又没有子元素列表
if (elementList.size()==0){
map.put(root.getName(), root.getText());
}else {
for (Element e : elementList)
map.put(e.getName(), e.getText());
}
// 释放资源
inputStream.close();
inputStream = null;
System.out.println("---------xml转换为map-----:"+map);
return map;
}
/**
* @Description: 文本消息对象转换成xml
* @param textMessage
* @date 2016-12-01
* @return xml
*/
public String textMessageToXml(TextMessage textMessage) {
xstream.alias("xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
/**
* @Description: 图文消息对象转换成xml
* @param newsMessage
* @date 2016-12-01
* @return xml
*/
public String newsMessageToXml(NewsMessage newsMessage) {
xstream.alias("xml", newsMessage.getClass());
xstream.alias("item", new Article().getClass());
return xstream.toXML(newsMessage);
}
/**
* @Description: 图片消息对象转换成xml
* @param imageMessage
* @date 2016-12-01
* @return xml
*/
public String imageMessageToXml(ImageMessage imageMessage) {
xstream.alias("xml", imageMessage.getClass());
return xstream.toXML(imageMessage);
}
/**
* @Description: 语音消息对象转换成xml
* @param voiceMessage
* @date 2016-12-01
* @return xml
*/
public String voiceMessageToXml(VoiceMessage voiceMessage) {
xstream.alias("xml", voiceMessage.getClass());
return xstream.toXML(voiceMessage);
}
/**
* @Description: 视频消息对象转换成xml
* @param videoMessage
* @date 2016-12-01
* @return xml
*/
public String videoMessageToXml(VideoMessage videoMessage) {
xstream.alias("xml", videoMessage.getClass());
return xstream.toXML(videoMessage);
}
/**
* @Description: 音乐消息对象转换成xml
* @param MusicMessage
* @date 2016-12-01
* @return xml
*/
public String musicMessageToXml(MusicMessage musicMessage) {
xstream.alias("xml", musicMessage.getClass());
return xstream.toXML(musicMessage);
}
/**
* 对象到xml的处理
* 扩展xstream,使其支持CDATA块
*/
private XStream xstream = new XStream(new XppDriver() {
@Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
// 对所有xml节点的转换都增加CDATA标记
boolean cdata = true;
@Override
@SuppressWarnings("rawtypes")
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
}
@Override
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("<![CDATA[");
writer.write(text);
writer.write("]]>");
} else {
writer.write(text);
}
}
};
}
});
}
封装的WeixinMessageInfo类
/**
* 将发送方,接收方,微信用户名等封装成类
*/
package com.b505.weixin.pojo;
import java.io.Serializable;
import org.springframework.stereotype.Component;
/**
* <p>Company: B505信息技术研究所 </p>
* @Description: 将发送方,接收方,微信用户名封装
* @Create Date: 2017年10月23日上午11:45:44
* @Version: V1.00
* @Author: 来日可期
*/
@Component
public class WeixinMessageInfo implements Serializable{
private static final long serialVersionUID = 1L;
private String fromUserName; // 发送发微信账号
private String toUserName; // 接收方微信账号
private String weixinUserName; // 微信用户名
private String messageType; // 消息类型
/**
* @return the fromUserName
*/
public String getFromUserName() {
return fromUserName;
}
/**
* @param fromUserName the fromUserName to set
*/
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
}
/**
* @return the toUserName
*/
public String getToUserName() {
return toUserName;
}
/**
* @param toUserName the toUserName to set
*/
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
}
/**
* @return the weixinUserName
*/
public String getWeixinUserName() {
return weixinUserName;
}
/**
* @param weixinUserName the weixinUserName to set
*/
public void setWeixinUserName(String weixinUserName) {
this.weixinUserName = weixinUserName;
}
/**
* @return the messageType
*/
public String getMessageType() {
return messageType;
}
/**
* @param messageType the messageType to set
*/
public void setMessageType(String messageType) {
this.messageType = messageType;
}
@Override
public String toString() {
return "WeixinMessageInfo [fromUserName=" + fromUserName
+ ", toUserName=" + toUserName + ", weixinUserName="
+ weixinUserName + ", messageType=" + messageType + "]";
}
}
文中涉及到的图文消息等回复的消息将在下节中介绍