转自:https://i-blog.csdnimg.cn/blog_migrate/0e1f5a1d9b6f6503038060d27f5d4dcc.png
本人在网上找了很多 关于java接收并解析微信返回XML数据包的问题,很多都是写得很简单,对于我这种菜鸟来说,根本看不明白。下面是我自己结合本人遇到的问题和参考网上的大神些的知识总结一下。
第一步:
用户同意上报地理位置后,每次进入公众号会话时,都会在进入时上报地理位置,或在进入会话后每5秒上报一次地理位置,公众号可以在公众平台网站中修改以上设置。上报地理位置时,微信会将上报地理位置事件推送到开发者填写的URL。
这里填写的url,如图
url填写为自己服务器的域名 如:http://www.xxxx.com/weixin/chat
/weixin/chat 是下面wxEventController ,推送的链接。
Token(令牌) : 随意
EncodingAESKey :随机生成就可以
第二步:创建自己的controller,并解析 微信返回xml数据包
- package com.dxx.function.sdweixin.controller;
- import java.io.IOException;
- import java.util.Calendar;
- import java.util.Date;
- import javax.servlet.ServletInputStream;
- import javax.servlet.http.HttpServletRequest;
- import javax.servlet.http.HttpServletResponse;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.RequestMethod;
- import org.springframework.web.bind.annotation.ResponseBody;
- import com.dxx.function.sdweixin.vo.ImageMessage;
- import com.dxx.function.sdweixin.vo.InputMessage;
- import com.dxx.utils.MsgType;
- import com.dxx.utils.OutputMessage;
- import com.dxx.utils.SerializeXmlUtil;
- import com.thoughtworks.xstream.XStream;
- @Controller
- @RequestMapping("/weixin")
- public class wxEventController {
- Log logger = LogFactory.getLog(wxEventController.class);
- private String Token = "sdapp080808";
- @RequestMapping(value = "/chat", method = { RequestMethod.GET, RequestMethod.POST })
- @ResponseBody
- public void liaotian(Model model, HttpServletRequest request, HttpServletResponse response) {
- System.out.println("进入chat");
- boolean isGet = request.getMethod().toLowerCase().equals("get");
- if (isGet) {
- String signature = request.getParameter("signature");
- String timestamp = request.getParameter("timestamp");
- String nonce = request.getParameter("nonce");
- String echostr = request.getParameter("echostr");
- System.out.println(signature);
- System.out.println(timestamp);
- System.out.println(nonce);
- System.out.println(echostr);
- //access(request, response);
- } else {
- // 进入POST聊天处理
- System.out.println("enter post");
- try {
- // 接收消息并返回消息
- acceptMessage(request, response);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- /**
- * 验证URL真实性
- *
- * @author morning
- * @date 2015年2月17日 上午10:53:07
- * @param request
- * @param response
- * @return String
- */
- // private String access(HttpServletRequest request, HttpServletResponse response) {
- // // 验证URL真实性
- // System.out.println("进入验证access");
- // String signature = request.getParameter("signature");// 微信加密签名
- // String timestamp = request.getParameter("timestamp");// 时间戳
- // String nonce = request.getParameter("nonce");// 随机数
- // String echostr = request.getParameter("echostr");// 随机字符串
- // List<String> params = new ArrayList<String>();
- // params.add(Token);
- // params.add(timestamp);
- // params.add(nonce);
- // // 1. 将token、timestamp、nonce三个参数进行字典序排序
- // Collections.sort(params, new Comparator<String>() {
- // @Override
- // public int compare(String o1, String o2) {
- // return o1.compareTo(o2);
- // }
- // });
- // // 2. 将三个参数字符串拼接成一个字符串进行sha1加密
- // String temp = SHA1.encode(params.get(0) + params.get(1) + params.get(2));
- // if (temp.equals(signature)) {
- // try {
- // response.getWriter().write(echostr);
- // System.out.println("成功返回 echostr:" + echostr);
- // return echostr;
- // } catch (IOException e) {
- // e.printStackTrace();
- // }
- // }
- // System.out.println("失败 认证");
- // return null;
- // }
- private void acceptMessage(HttpServletRequest request, HttpServletResponse response) throws IOException {
- // 处理接收消息
- ServletInputStream in = request.getInputStream();
- // 将POST流转换为XStream对象
- XStream xs = SerializeXmlUtil.createXstream();
- xs.processAnnotations(InputMessage.class);
- xs.processAnnotations(OutputMessage.class);
- // 将指定节点下的xml节点数据映射为对象
- xs.alias("xml", InputMessage.class);
- // 将流转换为字符串
- StringBuilder xmlMsg = new StringBuilder();
- byte[] b = new byte[4096];
- for (int n; (n = in.read(b)) != -1;) {
- xmlMsg.append(new String(b, 0, n, "UTF-8"));
- }
- // 将xml内容转换为InputMessage对象
- InputMessage inputMsg = (InputMessage) xs.fromXML(xmlMsg.toString());
- String servername = inputMsg.getToUserName();// 服务端
- String custermname = inputMsg.getFromUserName();// 客户端
- long createTime = inputMsg.getCreateTime();// 接收时间
- Long returnTime = Calendar.getInstance().getTimeInMillis() / 1000;// 返回时间
- // 取得消息类型
- String msgType = inputMsg.getMsgType();
- // 根据消息类型获取对应的消息内容
- if (msgType.equals(MsgType.Text.toString())) {
- // 文本消息
- System.out.println("开发者微信号:" + inputMsg.getToUserName());
- System.out.println("发送方帐号:" + inputMsg.getFromUserName());
- System.out.println("消息创建时间:" + inputMsg.getCreateTime() + new Date(createTime * 1000l));
- System.out.println("消息内容:" + inputMsg.getContent());
- System.out.println("消息Id:" + inputMsg.getMsgId());
- StringBuffer str = new StringBuffer();
- str.append("<xml>");
- str.append("<ToUserName><![CDATA[" + custermname + "]]></ToUserName>");
- str.append("<FromUserName><![CDATA[" + servername + "]]></FromUserName>");
- str.append("<CreateTime>" + returnTime + "</CreateTime>");
- str.append("<MsgType><![CDATA[" + msgType + "]]></MsgType>");
- str.append("<Content><![CDATA[你说的是:" + inputMsg.getContent() + ",吗?]]></Content>");
- str.append("</xml>");
- System.out.println(str.toString());
- response.getWriter().write(str.toString());
- }
- // 获取并返回多图片消息
- if (msgType.equals(MsgType.Image.toString())) {
- System.out.println("获取多媒体信息");
- System.out.println("多媒体文件id:" + inputMsg.getMediaId());
- System.out.println("图片链接:" + inputMsg.getPicUrl());
- System.out.println("消息id,64位整型:" + inputMsg.getMsgId());
- OutputMessage outputMsg = new OutputMessage();
- outputMsg.setFromUserName(servername);
- outputMsg.setToUserName(custermname);
- outputMsg.setCreateTime(returnTime);
- outputMsg.setMsgType(msgType);
- ImageMessage images = new ImageMessage();
- images.setMediaId(inputMsg.getMediaId());
- outputMsg.setImage(images);
- System.out.println("xml转换:/n" + xs.toXML(outputMsg));
- response.getWriter().write(xs.toXML(outputMsg));
- }
- }
- }
第三步:其他用到的类
- package com.dxx.utils;
- import java.io.Writer;
- import java.lang.reflect.Field;
- import com.dxx.function.sdweixin.service.XStreamCDATA;
- import com.thoughtworks.xstream.XStream;
- import com.thoughtworks.xstream.annotations.XStreamAlias;
- 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;
- /**
- * xml 转换工具类
- *
- * @author morning
- * @date 2015年2月16日 下午2:42:50
- */
- public class SerializeXmlUtil {
- public static XStream createXstream() {
- return new XStream(new XppDriver() {
- @Override
- public HierarchicalStreamWriter createWriter(Writer out) {
- return new PrettyPrintWriter(out) {
- boolean cdata = false;
- Class<?> targetClass = null;
- @Override
- public void startNode(String name, @SuppressWarnings("rawtypes") Class clazz) {
- super.startNode(name, clazz);
- // 业务处理,对于用XStreamCDATA标记的Field,需要加上CDATA标签
- if (!name.equals("xml")) {
- cdata = needCDATA(targetClass, name);
- } else {
- targetClass = clazz;
- }
- }
- @Override
- protected void writeText(QuickWriter writer, String text) {
- if (cdata) {
- writer.write("<![CDATA[");
- writer.write(text);
- writer.write("]]>");
- } else {
- writer.write(text);
- }
- }
- };
- }
- });
- }
- private static boolean needCDATA(Class<?> targetClass, String fieldAlias) {
- boolean cdata = false;
- // first, scan self
- cdata = existsCDATA(targetClass, fieldAlias);
- if (cdata)
- return cdata;
- // if cdata is false, scan supperClass until java.lang.Object
- Class<?> superClass = targetClass.getSuperclass();
- while (!superClass.equals(Object.class)) {
- cdata = existsCDATA(superClass, fieldAlias);
- if (cdata)
- return cdata;
- superClass = superClass.getClass().getSuperclass();
- }
- return false;
- }
- private static boolean existsCDATA(Class<?> clazz, String fieldAlias) {
- if ("MediaId".equals(fieldAlias)) {
- return true; // 特例添加 morning99
- }
- // scan fields
- Field[] fields = clazz.getDeclaredFields();
- for (Field field : fields) {
- // 1. exists XStreamCDATA
- if (field.getAnnotation(XStreamCDATA.class) != null) {
- XStreamAlias xStreamAlias = field.getAnnotation(XStreamAlias.class);
- // 2. exists XStreamAlias
- if (null != xStreamAlias) {
- if (fieldAlias.equals(xStreamAlias.value()))// matched
- return true;
- } else {// not exists XStreamAlias
- if (fieldAlias.equals(field.getName()))
- return true;
- }
- }
- }
- return false;
- }
- }
- package com.dxx.function.sdweixin.vo;
- import java.io.Serializable;
- import com.thoughtworks.xstream.annotations.XStreamAlias;
- /**
- * POST的XML数据包转换为消息接受对象
- *
- * <p>
- * 由于POST的是XML数据包,所以不确定为哪种接受消息,<br/>
- * 所以直接将所有字段都进行转换,最后根据<tt>MsgType</tt>字段来判断取何种数据
- * </p>
- *
- */
- @XStreamAlias("xml")
- public class InputMessage implements Serializable {
- /**
- *
- */
- private static final long serialVersionUID = 1L;
- @XStreamAlias("ToUserName")
- private String ToUserName;
- @XStreamAlias("FromUserName")
- private String FromUserName;
- @XStreamAlias("CreateTime")
- private Long CreateTime;
- @XStreamAlias("MsgType")
- private String MsgType = "text";
- @XStreamAlias("MsgId")
- private Long MsgId;
- // 文本消息
- @XStreamAlias("Content")
- private String Content;
- // 图片消息
- @XStreamAlias("PicUrl")
- private String PicUrl;
- // 位置消息
- @XStreamAlias("LocationX")
- private String LocationX;
- @XStreamAlias("LocationY")
- private String LocationY;
- @XStreamAlias("Scale")
- private Long Scale;
- @XStreamAlias("Label")
- private String Label;
- // 链接消息
- @XStreamAlias("Title")
- private String Title;
- @XStreamAlias("Description")
- private String Description;
- @XStreamAlias("Url")
- private String URL;
- // 语音信息
- @XStreamAlias("MediaId")
- private String MediaId;
- @XStreamAlias("Format")
- private String Format;
- @XStreamAlias("Recognition")
- private String Recognition;
- // 事件
- @XStreamAlias("Event")
- private String Event;
- @XStreamAlias("EventKey")
- private String EventKey;
- @XStreamAlias("Ticket")
- private String Ticket;
- 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 Long getMsgId() {
- return MsgId;
- }
- public void setMsgId(Long msgId) {
- MsgId = msgId;
- }
- public String getContent() {
- return Content;
- }
- public void setContent(String content) {
- Content = content;
- }
- public String getPicUrl() {
- return PicUrl;
- }
- public void setPicUrl(String picUrl) {
- PicUrl = picUrl;
- }
- public String getLocationX() {
- return LocationX;
- }
- public void setLocationX(String locationX) {
- LocationX = locationX;
- }
- public String getLocationY() {
- return LocationY;
- }
- public void setLocationY(String locationY) {
- LocationY = locationY;
- }
- public Long getScale() {
- return Scale;
- }
- public void setScale(Long scale) {
- Scale = scale;
- }
- public String getLabel() {
- return Label;
- }
- public void setLabel(String label) {
- Label = label;
- }
- 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 getURL() {
- return URL;
- }
- public void setURL(String uRL) {
- URL = uRL;
- }
- public String getEvent() {
- return Event;
- }
- public void setEvent(String event) {
- Event = event;
- }
- public String getEventKey() {
- return EventKey;
- }
- public void setEventKey(String eventKey) {
- EventKey = eventKey;
- }
- public String getMediaId() {
- return MediaId;
- }
- public void setMediaId(String mediaId) {
- MediaId = mediaId;
- }
- public String getFormat() {
- return Format;
- }
- public void setFormat(String format) {
- Format = format;
- }
- public String getRecognition() {
- return Recognition;
- }
- public void setRecognition(String recognition) {
- Recognition = recognition;
- }
- public String getTicket() {
- return Ticket;
- }
- public void setTicket(String ticket) {
- Ticket = ticket;
- }
- }
- package com.dxx.utils;
- import com.dxx.function.sdweixin.service.XStreamCDATA;
- import com.dxx.function.sdweixin.vo.ImageMessage;
- import com.thoughtworks.xstream.annotations.XStreamAlias;
- @XStreamAlias("xml")
- public class OutputMessage {
- @XStreamAlias("ToUserName")
- @XStreamCDATA
- private String ToUserName;
- @XStreamAlias("FromUserName")
- @XStreamCDATA
- private String FromUserName;
- @XStreamAlias("CreateTime")
- private Long CreateTime;
- @XStreamAlias("MsgType")
- @XStreamCDATA
- private String MsgType = "text";
- private ImageMessage Image;
- 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 ImageMessage getImage() {
- return Image;
- }
- public void setImage(ImageMessage image) {
- Image = image;
- }
- }
- package com.dxx.function.sdweixin.vo;
- import com.thoughtworks.xstream.annotations.XStreamAlias;
- @XStreamAlias("Image")
- public class ImageMessage extends MediaIdMessage {
- }
- package com.dxx.function.sdweixin.vo;
- import com.dxx.function.sdweixin.service.XStreamCDATA;
- import com.thoughtworks.xstream.annotations.XStreamAlias;
- public class MediaIdMessage {
- @XStreamAlias("MediaId")
- @XStreamCDATA
- private String MediaId;
- public String getMediaId() {
- return MediaId;
- }
- public void setMediaId(String mediaId) {
- MediaId = mediaId;
- }
- }
- package com.dxx.function.sdweixin.service;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- @Retention(RetentionPolicy.RUNTIME)
- @Target({ ElementType.FIELD })
- public @interface XStreamCDATA {
- }
- package com.dxx.utils;
- public enum MsgType {
- Text("text"),
- Image("image"),
- Music("music"),
- Video("video"),
- Voice("voice"),
- Location("location"),
- Link("link");
- private String msgType = "";
- MsgType(String msgType) {
- this.msgType = msgType;
- }
- /**
- * @return the msgType
- */
- @Override
- public String toString() {
- return msgType;
- }
- }
- package com.dxx.utils;
- import java.security.MessageDigest;
- /**
- * <p>
- * Title: SHA1算法
- * </p>
- *
- */
- public final class SHA1 {
- private static final char[] HEX_DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
- /**
- * Takes the raw bytes from the digest and formats them correct.
- *
- * @param bytes
- * the raw bytes from the digest.
- * @return the formatted bytes.
- */
- private static String getFormattedText(byte[] bytes) {
- int len = bytes.length;
- StringBuilder buf = new StringBuilder(len * 2);
- // 把密文转换成十六进制的字符串形式
- for (int j = 0; j < len; j++) {
- buf.append(HEX_DIGITS[(bytes[j] >> 4) & 0x0f]);
- buf.append(HEX_DIGITS[bytes[j] & 0x0f]);
- }
- return buf.toString();
- }
- public static String encode(String str) {
- if (str == null) {
- return null;
- }
- try {
- MessageDigest messageDigest = MessageDigest.getInstance("SHA1");
- messageDigest.update(str.getBytes());
- return getFormattedText(messageDigest.digest());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
第四步:引用maven的包
<dependency><groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.9</version>
</dependency>