上一篇博文是介绍如何进行服务器端配置,配置的至关于为微信的消息接口,微信向服务器端推送消息或者推送用户发送的消息就会推送到该配置的URL中,配置好了事后,咱们就须要在服务器端接收用户发送的一系列消息。html
服务器端接收用户消息和接收微信推送消息是使用的同一个地址,可是有一个区别接收推送消息为GET方法,接收用户发送的消息为POST方法。java
使用流接收POST消息转为String结果为XML的消息体,若是是在微信后台选择的为安全模式则须要解密,如果明文模式,那就直接解析XML就是了,此处为加密模式需用到解密类,本博文使用的为微信提供的解密类。连接为:安全
微信加解密文档:
http://mp.weixin.qq.com/wiki/11/2d2d1df945b75605e7fea9ea2573b667.html
加解密代码:
http://mp.weixin.qq.com/wiki/static/assets/a5a22f38cb60228cb32ab61d9e4c414b.zip服务器
环境为:SpringMvc4
栗子:微信
//微信接收消息接口 @ResponseBody @RequestMapping(value = "signature",method = RequestMethod.POST) public String signature(HttpServletRequest request) throws AesException{ try { //接收流 ServletInputStream sis = request.getInputStream(); StringBuilder xmlMsg = new StringBuilder(); byte[] b = new byte[4096]; for (int n; (n = sis.read(b)) != -1;) { xmlMsg.append(new String(b, 0, n, "UTF-8")); } System.out.println(xmlMsg); //接收加密的xml Object[] encrypt = XMLParse.extract(xmlMsg.toString()); //解密 WXBizMsgCrypt wxcpt = new WXBizMsgCrypt("token", "encodingAesKey", "appid"); //获取解密后的XML String msg = wxcpt.decrypt(encrypt[1].toString()); //转对象 WxMsgRequest wmr = this.convertWxMesgToObj(msg); System.out.println(wmr); if(wmr.getMsgType().equals(WxRequestMsgType.MSG_TEXT)){ WxTextMsgResponse wtmr = new WxTextMsgResponse(); wtmr.setContent("点点与麦兜的TEST"); Long createTime = System.currentTimeMillis() / 1000; wtmr.setCreateTime(createTime.toString()); wtmr.setFromUserName(wmr.getToUserName()); wtmr.setToUserName(wmr.getFromUserName()); wtmr.setMsgType(WxRequestMsgType.MSG_TEXT); String returnStr = this.convertObjToXml(wtmr); return returnStr; } } catch (Exception e) { e.printStackTrace(); } return null; } //微信验证接口 @ResponseBody @RequestMapping(value = "signature",method=RequestMethod.GET) public String signature(String signature, String timestamp, String nonce, String echostr){ try { String shaPw = SHA1.getSHA1("xiaofli007", timestamp, nonce); if(signature.equals(shaPw)) return echostr; else return null; } catch (Exception e) { e.printStackTrace(); } return null; } //将xml数据解析为对象 private WxMsgRequest convertWxMesgToObj(String msg) throws JAXBException{ JAXBContext context = JAXBContext.newInstance(WxMsgRequest.class); Unmarshaller unmarshaller = context.createUnmarshaller(); return (WxMsgRequest)unmarshaller.unmarshal(new StringReader(msg)); } //将对象转为xml字符串 public String convertObjToXml(Object obj) throws JAXBException{ JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); StringWriter writer = new StringWriter(); marshaller.marshal(obj, writer); String temp = writer.toString(); return temp; }
解密前消息: 微信开发
<xml> <ToUserName><![CDATA[gh_e1c44a3a9f81]]></ToUserName> <Encrypt><![CDATA[HusAtbuEO8XmYaH4tzuZHcdi7Kg2e6szJfZrzdQLnpEs6D0jrNWKLFYftafLyKLFy7sOPbQUYI8DaVPPV/0npFSRym2oskoN0ip3q93XXtunbz5OBmWlYsvKnJuYK/UlIttgrJbrRFJlz4AKiHYUnJx7vaSAFvErAlhudPA1rhPEa64sARRGRQhrP1m/zffbSRl6uI7Wz1jsIsfiZAPg0nxqfxdDXh9Gklcp6DNHhf3phAx9pt8kyZKh4n8yhHV1+R+WU0c86YEgwQ7NHgA0CaryQPemkNRF06YrWEvE0meToeT08sm2A0bZJUiGGmj8dD9/b6KsESaQmfsF2JzdRvSq79gLO+Mn0swQS4wjOnbrgw7otvlYCZnDu4+xcfv+lGgMIc0YfG/jtT4VH6pboBtm1xCRs01N14SHB8pGryA=]]></Encrypt> </xml>
解密后的消息:app
<xml> <ToUserName><![CDATA[gh_e1c44a3a9f81]]></ToUserName> <FromUserName><![CDATA[oMffXwBl4N4F29vbH3UAbrdhMq4Y]]></FromUserName> <CreateTime>1475129963</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[11]]></Content> <MsgId>6335634948877288984</MsgId> </xml>
文本消息(text)
图片消息(image)
语音消息(voice)
视频消息(video)
小视频消息 (shortvideo)
地理位置消息(location)
连接消息(link)curl
建立一个实体类,用于接受消息(为了方便我是所有字段写到一个类中,也能够先判断类型:再指定接受的类型):ide
@XmlRootElement(name = "xml") public class WxMsgRequest { /*** 开发者微信号 */ private String ToUserName; /*** 发送方账号(一个OpenID)*/ private String FromUserName; /*** 消息建立时间 (整型)*/ private String CreateTime; /*** 消息类型有:text ; event ; 语音为voice*/ private String MsgType; /*** 消息id*/ private String MsgId; /*** 语音消息媒体id,能够调用多媒体文件下载接口拉取数据。*/ private String MediaId; /*** 语音格式,如amr,speex等*/ private String Format; /*** 视频消息缩略图的媒体id,能够调用多媒体文件下载接口拉取数据。*/ private String ThumbMediaId; /*** 文本消息内容*/ private String Content; /*** 图片消息URL*/ private String picUrl; /*** 地理位置消息 地理位置纬度*/ private String gpsX; /*** 地理位置消息 地理位置经度*/ private String gpsY; /*** 地理位置消息 地图缩放大小*/ private String scale; /*** 地理位置消息 地理位置信息*/ private String label; /*** 连接消息 消息标题*/ private String title; /*** 连接消息 消息描述*/ private String description; /*** 连接消息 消息连接*/ private String url; /** * 事件类型,subscribe(订阅)、unsubscribe(取消订阅)、CLICK(自定义菜单点击事件) * WeixinRequestMsgType#SUBSCRIBE_EVENT */ private String Event; /*** 事件KEY值,与自定义菜单接口中KEY值对应*/ private String EventKey; /** 二维码的ticket,可用来换取二维码图片 **/ private String Ticket; @XmlElement(name = "Ticket") public String getTicket() { return Ticket; } public void setTicket(String ticket) { Ticket = ticket; } //因为文章篇幅问题,下面的参数set方法和get方法就不展现了。。每一个get方法加@XmlElement(name="参数名") }
将xml解析成对象:ui
private WxMsgRequest convertWxMesgToObj(String msg) throws JAXBException{ JAXBContext context = JAXBContext.newInstance(WxMsgRequest.class); Unmarshaller unmarshaller = context.createUnmarshaller(); return (WxMsgRequest)unmarshaller.unmarshal(new StringReader(msg)); }
文本消息(text)
图片消息 ( image )
语音消息 ( voice )
视频消息 ( video )
音乐消息 ( music )
图文消息 ( picurl )
此处栗子为文本消息回复。
建立一个微信消息类型实体,用于判断消息类型:
public class WxRequestMsgType { /*** 请求的,应答的,文本推送消息 */ public static final String MSG_TEXT = "text"; /**** 请求的, 图片推送消息*/ public static final String MSG_IMAGE = "image"; /*** 请求的, 地理位置信息*/ public static final String MSG_LOCATION = "location"; /*** 请求的, 连接信息*/ public static final String MSG_LINK = "link"; /*** 请求的,事件推送消息*/ public static final String MSG_EVENT = "event"; /*** 应答的,图文消息体*/ public static final String MSG_NEW = "news"; /*** 请求的,语音推送消息*/ public static final String MSG_VOICE = "voice"; /*** 事件类型订阅*/ public static final String EVENT_SUBSCRIBE = "subscribe"; /*** 事件取消订阅*/ public static final String EVENT_UNSUBSCRIBE = "unsubscribe"; /*** 自定义菜单的点击事件*/ public static final String EVENT_CLICK = "CLICK"; public static final String EVENT_SCAN = "SCAN"; /** * 若是公众号处于开发模式,须要在接收到用户发送的消息时, 返回一个MsgType为transfer_customer_service的消息, * 微信服务器在收到这条消息时,会把此次发送的消息转到多客服系统。 用户被客服接入之后,客服关闭会话之前,处于会话过程当中, * 用户发送的消息均会被直接转发至客服系统 */ public static final String TRANSFER_CUSTOMER_SERVICE_MSG = "transfer_customer_service"; }
建立文本回复实体:
@XmlRootElement(name = "xml") public class WxTextMsgResponse{ /*** 开发者微信号*/ private String ToUserName; /*** 发送方账号(一个OpenID)*/ private String FromUserName; /*** 消息建立时间 (整型)*/ private String CreateTime; /*** 应答消息类型有: news ;text;*/ private String MsgType; /*** 文本消息内容*/ private String Content; /** * 位0x0001被标志时,星标刚收到的消息。 */ private String FuncFlag; @XmlElement(name = "Content") public String getContent() { return Content; } public void setContent(String content) { Content = content; } //省略其余get、set方法 }
JAXB2对象转为XML字符串:
public String convertObjToXml(Object obj) throws JAXBException{ JAXBContext context = JAXBContext.newInstance(obj.getClass()); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); StringWriter writer = new StringWriter(); marshaller.marshal(obj, writer); String temp = writer.toString(); return temp; }
在signature、POST方法中加入文本消息的判断进行回复:
if(wmr.getMsgType().equals(WxRequestMsgType.MSG_TEXT)){ WxTextMsgResponse wtmr = new WxTextMsgResponse(); wtmr.setContent("点点与麦兜的TEST"); Long createTime = System.currentTimeMillis() / 1000; wtmr.setCreateTime(createTime.toString()); wtmr.setFromUserName(wmr.getToUserName()); wtmr.setToUserName(wmr.getFromUserName()); wtmr.setMsgType(WxRequestMsgType.MSG_TEXT); String returnStr = this.convertObjToXml(wtmr); return returnStr; }
此处只举例了消息接受和文本消息的回复,后面还有主动推送消息、还有其余事件,好比关注事件,取消关注事件等、这里就不一一举例了,其余事件接受和回复请查看微信开发文档(实际上是大同小异)
1,这个回复其实能够作一个后台自动回复管理。好比后台设置关键字回复、被添加回复、自动回复,发送过来的消息进行内容识别,是否为关键字,或者自动回复等。