【controller】中我定义了一个get方法和一个post方法,但是在使用过程中我们就用了get方法,这里我们就来说说我们预留的post的方法的使用
@RequestMapping(value="getSign",method=RequestMethod.POST)
public void postSignature(HttpServletRequest request,HttpServletResponse response) throws AesException, IOException{
// 微信加密签名
String msg_signature = request.getParameter("msg_signature");
// 时间戳
String timestamp = request.getParameter("timestamp");
// 随机数
String nonce = request.getParameter("nonce");
//从请求中读取整个post数据
InputStream inputStream = request.getInputStream();
String postData = IOUtils.toString(inputStream, "UTF-8");
System.out.println(postData);
String msg = "";
WXBizMsgCrypt wxcpt = null;
try {
wxcpt = new WXBizMsgCrypt(Constants.token, Constants.encodingAESKey, Constants.appid);
//解密消息
msg = wxcpt.DecryptMsg(msg_signature, timestamp, nonce, postData);
} catch (AesException e) {
e.printStackTrace();
}
System.out.println("msg=" + msg);
// 调用核心业务类接收消息、处理消息
String respMessage = CoreService.processRequest(msg);
System.out.println("respMessage=" + respMessage);
String encryptMsg = "";
try {
//加密回复消息
encryptMsg = wxcpt.EncryptMsg(respMessage, timestamp, nonce);
} catch (AesException e) {
e.printStackTrace();
}
response.getWriter().print(encryptMsg);
response.getWriter().close();
}
上一篇(服务器配置): 连接
调用的相关类:
WXBizMsgCrypt 在文章最后
当我们在完成了服务器验证之后,此后用户每次向公众号发送消息、或者产生自定义菜单点击事件时,开发者填写的服务器配置URL将得到微信服务器推送过来的消息和事件,然后开发者可以依据自身业务逻辑进行响应,例如回复消息等!通过这句话我们能知道后面所有的微信服务器和我们应用服务器之间的沟通都是通过post消息体来完成的,那么我们这里将讲述如何接受微信post的消息体!
(一)消息类型和消息格式
上面有说道我们所有的和微信服务器之间进行沟通基本都是通过post消息体完成的,首先我们了解下消息体的类型,大致类型有两种:
-
普通消息类型:文本消息、图片消息、语音消息、视频消息、小视频消息、地理位置消息、链接消息
-
事件消息类型:关注/取消关注事件、扫描带参数二维码事件、上报地理位置事件、自定义菜单事件、点击菜单拉取消息时的事件推送、点击菜单跳转链接时的事件推送
消息类型:微信服务端推送的所有消息体的类型格式都是xml格式;
(二)消息重试机制
微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试,但是这里后期可以使用【客服消息接口】去完成消息再次推送。
(三)消息接收处理
package com.gzkit.ddkx.core.service.weixin;
import java.util.Date;
import java.util.Map;
import com.gzkit.ddkx.core.entity.weixin.resp.TextMessage;
import com.gzkit.ddkx.util.MessageUtil;
/**
* 处理微信发来的信息
* @author yuki_ho
*
*/
public class CoreService {
public static String processRequest(String msg) {
String respMessage = null;
try {
// 默认返回的文本消息内容
String respContent = "请求处理异常,请稍候尝试!";
// xml请求解析
Map
requestMap = MessageUtil.parseXml(msg);
System.out.println("Event=="+requestMap.get("Event"));
// 发送方帐号(open_id)
String fromUserName = requestMap.get("FromUserName");
// 公众帐号
String toUserName = requestMap.get("ToUserName");
// 消息类型
String msgType = requestMap.get("MsgType");
//-----------------------------------------------------------
// 回复文本消息 //暂时默认回复这个
TextMessage textMessage = new TextMessage();
textMessage.setToUserName(fromUserName);
textMessage.setFromUserName(toUserName);
textMessage.setCreateTime(new Date().getTime());
textMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_TEXT);
textMessage.setFuncFlag(0);
//-----------------------------------------------------------
// 文本消息
if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
String content = requestMap.get("Content");
respContent = "yuki提示:您发送的是文本消息!内容是:"+content;
}
// 图片消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {
respContent = "yuki提示:您发送的是图片消息!";
}
// 地理位置消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {
respContent = "yuki提示:您发送的是地理位置消息!";
}
// 链接消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {
respContent = "yuki提示:您发送的是链接消息!";
}
// 音频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {
respContent = "yuki提示:您发送的是音频消息!";
}
// 视频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VODEO)) {
respContent = "yuki提示:您发送的是视频消息!";
}
// 小音频消息
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_SHORTVODEO)) {
respContent = "yuki提示:您发送的是小视频消息!";
}
// 事件推送
else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {
// 事件类型
String eventType = requestMap.get("Event");
// 自定义菜单点击事件
if (eventType.equalsIgnoreCase(MessageUtil.EVENT_TYPE_CLICK)) {
// 事件KEY值,与创建自定义菜单时指定的KEY值对应
String eventKey = requestMap.get("EventKey");
System.out.println("EventKey="+eventKey);
respContent = "yuki提示:您点击的菜单KEY是"+eventKey;
// 后面还有更多事件
}
}
textMessage.setContent(respContent);
respMessage = MessageUtil.textMessageToXml(textMessage);
} catch (Exception e) {
e.printStackTrace();
System.out.println(e);
respMessage="有异常了。。。";
}
return respMessage;
}
}
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
i
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;
/**
* 消息工具类
* @author yuki_ho
*
*/
public class MessageUtil {
/**
* 返回消息类型:文本
*/
public static final String RESP_MESSAGE_TYPE_TEXT = "text";
/**
* 返回消息类型:音乐
*/
public static final String RESP_MESSAGE_TYPE_MUSIC = "music";
/**
* 返回消息类型:图文
*/
public static final String RESP_MESSAGE_TYPE_NEWS = "news";
/**
* 请求消息类型:文本
*/
public static final String REQ_MESSAGE_TYPE_TEXT = "text";
/**
* 请求消息类型:图片
*/
public static final String REQ_MESSAGE_TYPE_IMAGE = "image";
/**
* 请求消息类型:链接
*/
public static final String REQ_MESSAGE_TYPE_LINK = "link";
/**
* 请求消息类型:地理位置
*/
public static final String REQ_MESSAGE_TYPE_LOCATION = "location";
/**
* 请求消息类型:音频
*/
public static final String REQ_MESSAGE_TYPE_VOICE = "voice";
/**
* 请求消息类型:视频
*/
public static final String REQ_MESSAGE_TYPE_VODEO = "video";
/**
* 请求消息类型:短视频
*/
public static final String REQ_MESSAGE_TYPE_SHORTVODEO = "shortvideo";
/**
* 请求消息类型:推送
*/
public static final String REQ_MESSAGE_TYPE_EVENT = "event";
/**
* 事件类型:subscribe(订阅)
*/
public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";
/**
* 事件类型:unsubscribe(取消订阅)
*/
public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";
/**
* 事件类型:CLICK(自定义菜单点击事件)
*/
public static final String EVENT_TYPE_CLICK = "CLICK";
/**
* 解析微信发来的请求(XML)
*
* @param request
* @return
* @throws Exception
*/
@SuppressWarnings("unchecked")
public static Map
parseXml(String msg)
throws Exception {
// 将解析结果存储在HashMap中
Map
map = new HashMap
();
// 从request中取得输入流
InputStream inputStream = new ByteArrayInputStream(msg.getBytes("UTF-8"));
// 读取输入流
SAXReader reader = new SAXReader();
Document document = reader.read(inputStream);
// 得到xml根元素
Element root = document.getRootElement();
// 得到根元素的所有子节点
List
elementList = root.elements();
// 遍历所有子节点
for (Element e : elementList)
map.put(e.getName(), e.getText());
// 释放资源
inputStream.close();
inputStream = null;
return map;
}
/**
* @Description: 文本消息对象转换成xml
* @param @param textMessage
* @param @return
* @author dapengniao
* @date 2016年3月8日 下午4:13:22
*/
public static String textMessageToXml(TextMessage textMessage) {
xstream.alias("xml", textMessage.getClass());
return xstream.toXML(textMessage);
}
/**
* @Description: 图文消息对象转换成xml
* @param @param newsMessage
* @param @return
* @author dapengniao
* @date 2016年3月8日 下午4:14:09
*/
public static String newsMessageToXml(NewsMessage newsMessage) {
xstream.alias("xml", newsMessage.getClass());
xstream.alias("item", new Article().getClass());
return xstream.toXML(newsMessage);
}
/**
* @Description: 图片消息对象转换成xml
* @param @param imageMessage
* @param @return
* @author dapengniao
* @date 2016年3月9日 上午9:25:51
*/
public static String imageMessageToXml(ImageMessage imageMessage) {
xstream.alias("xml", imageMessage.getClass());
return xstream.toXML(imageMessage);
}
/**
* @Description: 语音消息对象转换成xml
* @param @param voiceMessage
* @param @return
* @author dapengniao
* @date 2016年3月9日 上午9:27:26
*/
public static String voiceMessageToXml(VoiceMessage voiceMessage) {
xstream.alias("xml", voiceMessage.getClass());
return xstream.toXML(voiceMessage);
}
/**
* @Description: 视频消息对象转换成xml
* @param @param videoMessage
* @param @return
* @author dapengniao
* @date 2016年3月9日 上午9:31:09
*/
public static String videoMessageToXml(VideoMessage videoMessage) {
xstream.alias("xml", videoMessage.getClass());
return xstream.toXML(videoMessage);
}
/**
* 扩展xstream,使其支持CDATA块
*
* @date 2013-05-19
*/
private static 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("");
} else {
writer.write(text);
}
}
};
}
});
}
(四)响应的消息体
/**
* 响应消息的基类
*
* @author yuki_ho
*
*/
public class BaseMessage {
/**
* 接收方帐号(收到的OpenID)
*/
private String ToUserName;
/**
* 开发者微信号
*/
private String FromUserName;
/**
* 消息创建时间 (整型)
*/
private long CreateTime;
/**
* 消息类型(text/music/news)
*/
private String MsgType;
/**
* 位0x0001被标志时,星标刚收到的消息
*/
private int FuncFlag;
public String getToUserName() {
return ToUserName;
}
public void setToUserName(String toUserName) {
ToUserName = toUserName;
}
public String getFromUserName() {
return FromUserName;
}
public void setFromUserName(String fromUserName) {
FromUserName = fromUserName;
}
public long getCreateTime() {
return CreateTime;
}
public void setCreateTime(long createTime) {
CreateTime = createTime;
}
public String getMsgType() {
return MsgType;
}
public void setMsgType(String msgType) {
MsgType = msgType;
}
public int getFuncFlag() {
return FuncFlag;
}
public void setFuncFlag(int funcFlag) {
FuncFlag = funcFlag;
}
}
// -----------------------相关扩展
/**
* 响应消息之文本消息
* @author yuki_ho
*
*/
public class TextMessage extends BaseMessage {
/**
* 回复的消息内容
*/
private String Content;
public String getContent() {
return Content;
}
public void setContent(String content) {
Content = content;
}
}
/**
* 图文消息中Article类的定义
*
* @author yuki_ho
*
*/
public class Article {
/**
* 图文消息名称
*/
private String Title;
/**
* 图文消息描述
*/
private String Description;
/**
* 图片链接,支持JPG、PNG格式,较好的效果为大图640*320,小图80*80,限制图片链接的域名需要与开发者填写的基本资料中的Url一致
*/
private String PicUrl;
/**
* 点击图文消息跳转链接
*/
private String Url;
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public String getPicUrl() {
return PicUrl;
}
public void setPicUrl(String picUrl) {
PicUrl = picUrl;
}
public String getUrl() {
return Url;
}
public void setUrl(String url) {
Url = url;
}
}
/**
* 响应消息之图文消息
*
* @author yuki_ho
*
*/
public class NewsMessage extends BaseMessage {
/**
* 图文消息个数,限制为10条以内
*/
private int ArticleCount;
/**
* 多条图文消息信息,默认第一个item为大图
*/
private List<Article> Articles;
public int getArticleCount() {
return ArticleCount;
}
public void setArticleCount(int articleCount) {
ArticleCount = articleCount;
}
public List<Article> getArticles() {
return Articles;
}
public void setArticles(List<Article> articles) {
Articles = articles;
}
}
/**
* 图片消息中Image类的定义
* @author yuki_ho
*
*/
public class Image {
private String MediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
/**
* 响应消息之图片消息
* @author yuki_ho
*
*/
public class ImageMessage extends BaseMessage {
private Image Image;
public Image getImage() {
return Image;
}
public void setImage(Image image) {
Image = image;
}
}
/**
* 音乐消息中Music类的定义
*
* @author yuki_ho
*
*/
public class Music {
/**
* 音乐名称
*/
private String Title;
/**
* 音乐描述
*/
private String Description;
/**
* 音乐链接
*/
private String MusicUrl;
/**
* 高质量音乐链接,WIFI环境优先使用该链接播放音乐
*/
private String HQMusicUrl;
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public String getMusicUrl() {
return MusicUrl;
}
public void setMusicUrl(String musicUrl) {
MusicUrl = musicUrl;
}
public String getHQMusicUrl() {
return HQMusicUrl;
}
public void setHQMusicUrl(String hQMusicUrl) {
HQMusicUrl = hQMusicUrl;
}
}
/**
* 视频消息中Video类的定义
* @author yuki_ho
*
*/
public class Video {
private String MediaId;
private String Title;
private String Description;
public String getTitle() {
return Title;
}
public void setTitle(String title) {
Title = title;
}
public String getDescription() {
return Description;
}
public void setDescription(String description) {
Description = description;
}
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
}
/**
* 响应消息之视频消息
* @author yuki_ho
*
*/
public class VideoMessage extends BaseMessage {
private Video Video;
public Video getVideo() {
return Video;
}
public void setVideo(Video video) {
Video = video;
}
}
/**
* 音频消息中Voice类的定义
* @author yuki_ho
*
*/
public class Voice {
private String MediaId;
public String getMediaId() {
return MediaId;
}
public void setMediaId(String mediaId) {
MediaId = mediaId;
}
}
/**
* 响应消息之语音消息
* @author yuki_ho
*
*/
public class VoiceMessage extends BaseMessage {
private Voice Voice;
public Voice getVoice() {
return Voice;
}
public void setVoice(Voice voice) {
Voice = voice;
}
}
微信 (加密、解密)帮助类: 连接
微信相关:连接