首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 移动开发 > 移动开发 >

微信公众平台开发教程Java版(3) 消息接收和发送

2014-04-18 
微信公众平台开发教程Java版(三) 消息接收和发送前面两章已经介绍了如何接入微信公众平台,这一章说说消息

微信公众平台开发教程Java版(三) 消息接收和发送

前面两章已经介绍了如何接入微信公众平台,这一章说说消息的接收和发送

可以先了解公众平台的消息api接口(接收消息,发送消息)

http://mp.weixin.qq.com/wiki/index.php


微信公众平台开发教程Java版(3) 消息接收和发送

?

接收消息

当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包到开发者填写的URL上。

?

?http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF

?

接收的消息类型有6种,分别为:

  • 123456可以根据官方的api提供的字段建立对应的实体类

    如:文本消息
    微信公众平台开发教程Java版(3) 消息接收和发送
    ?

    有很多属性是所有消息类型都需要的,可以把这些信息提取出来建立一个基类

    ?

    package com.ifp.weixin.entity.Message.req;/** * 消息基类(用户 -> 公众帐号) *  */public class BaseMessage {/** * 开发者微信号 */private String ToUserName;/** * 发送方帐号(一个OpenID) */private String FromUserName;/** * 消息创建时间 (整型) */private long CreateTime;/** * 消息类型 text、image、location、link */private String MsgType;/** * 消息id,64位整型 */private long MsgId;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;}}

    ?接收的文本消息

    ?

    package com.ifp.weixin.entity.Message.req;/** * 文本消息 */public class TextMessage extends BaseMessage {/** * 回复的消息内容 */private String Content;public String getContent() {return Content;}public void setContent(String content) {Content = content;}}

    ?接收的图片消息

    package com.ifp.weixin.entity.Message.req;public class ImageMessage extends BaseMessage{private String picUrl;public String getPicUrl() {return picUrl;}public void setPicUrl(String picUrl) {this.picUrl = picUrl;}}

    ?

    ?

    接收的链接消息

    package com.ifp.weixin.entity.Message.req;public class LinkMessage extends BaseMessage {/** * 消息标题 */private String Title;/** * 消息描述 */private String Description;/** * 消息链接 */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 getUrl() {return Url;}public void setUrl(String url) {Url = url;}}

    ?

    ?接收的语音消息

    ?

    package com.ifp.weixin.entity.Message.req;/** * 语音消息 *  * @author Caspar *  */public class VoiceMessage extends BaseMessage {/** * 媒体ID */private String MediaId;/** * 语音格式 */private String Format;public String getMediaId() {return MediaId;}public void setMediaId(String mediaId) {MediaId = mediaId;}public String getFormat() {return Format;}public void setFormat(String format) {Format = format;}}

    ?接收的地理位置消息

    ?

    package com.ifp.weixin.entity.Message.req;/** * 位置消息 *  * @author caspar *  */public class LocationMessage extends BaseMessage {/** * 地理位置维度 */private String Location_X;/** * 地理位置经度 */private String Location_Y;/** * 地图缩放大小 */private String Scale;/** * 地理位置信息 */private String Label;public String getLocation_X() {return Location_X;}public void setLocation_X(String location_X) {Location_X = location_X;}public String getLocation_Y() {return Location_Y;}public void setLocation_Y(String location_Y) {Location_Y = location_Y;}public String getScale() {return Scale;}public void setScale(String scale) {Scale = scale;}public String getLabel() {return Label;}public void setLabel(String label) {Label = label;}}

    ?

    ?

    发送被动响应消息

    ??? 对于每一个POST请求,开发者在响应包(Get)中返回特定XML结构,对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。请注意,回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,只支持认证服务号。

    ?

    ????同样,建立响应消息的对应实体类

    ??? 也把公共的属性提取出来,封装成基类

    ?

    ???? 响应消息的基类

    package com.ifp.weixin.entity.Message.resp;/** * 消息基类(公众帐号 -> 用户) */public class BaseMessage {/** * 接收方帐号(收到的OpenID) */private String ToUserName;/** * 开发者微信号 */private String FromUserName;/** * 消息创建时间 (整型) */private long CreateTime;/** * 消息类型 */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;}}

    ?

    ?

    ??? 响应文本消息

    ???

    package com.ifp.weixin.entity.Message.resp;/** * 文本消息 */public class TextMessage extends BaseMessage {/** * 回复的消息内容 */private String Content;public String getContent() {return Content;}public void setContent(String content) {Content = content;}}

    ?

    ?

    响应图文消息

    ???

    package com.ifp.weixin.entity.Message.resp;import java.util.List;/** * 多图文消息, * 单图文的时候 Articles 只放一个就行了 * @author Caspar.chen */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;}}

    ?图文消息的定义

    ?

    ?

    package com.ifp.weixin.entity.Message.resp;/** * 图文消息 *  */public class Article {/** * 图文消息名称 */private String Title;/** * 图文消息描述 */private String Description;/** * 图片链接,支持JPG、PNG格式,<br> * 较好的效果为大图640*320,小图80*80 */private String PicUrl;/** * 点击图文消息跳转链接 */private String Url;public String getTitle() {return Title;}public void setTitle(String title) {Title = title;}public String getDescription() {return null == Description ? "" : Description;}public void setDescription(String description) {Description = description;}public String getPicUrl() {return null == PicUrl ? "" : PicUrl;}public void setPicUrl(String picUrl) {PicUrl = picUrl;}public String getUrl() {return null == Url ? "" : Url;}public void setUrl(String url) {Url = url;}}

    ?

    ?

    响应音乐消息

    ?

    package com.ifp.weixin.entity.Message.resp;/** * 音乐消息 */public class MusicMessage extends BaseMessage {/** * 音乐 */private Music Music;public Music getMusic() {return Music;}public void setMusic(Music music) {Music = music;}}

    ?

    ?

    音乐消息的定义

    package com.ifp.weixin.entity.Message.resp;/** * 音乐消息 */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 musicUrl) {HQMusicUrl = musicUrl;}}

    ?
    ?构建好之后的项目结构图为

    ?
    微信公众平台开发教程Java版(3) 消息接收和发送

    ?

    到这里,请求消息和响应消息的实体类都定义好了

    ?

    解析请求消息

    ?

    用户向微信公众平台发送消息后,微信公众平台会通过post请求发送给我们。

    上一章中WeixinController 类的post方法我们空着

    ?

    ?现在我们要在这里处理用户请求了。

    ?

    因为微信的发送和接收都是用xml格式的,所以我们需要处理请求过来的xml格式。

    发送的时候也需要转化成xml格式再发送给微信,所以封装了消息处理的工具类,用到dome4j和xstream两个jar包

    package com.ifp.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 com.ifp.weixin.entity.Message.resp.Article;import com.ifp.weixin.entity.Message.resp.MusicMessage;import com.ifp.weixin.entity.Message.resp.NewsMessage;import com.ifp.weixin.entity.Message.resp.TextMessage;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;/** * 消息工具类 *  */public class MessageUtil {/** * 解析微信发来的请求(XML) *  * @param request * @return * @throws Exception */public static 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();// 遍历所有子节点for (Element e : elementList)map.put(e.getName(), e.getText());// 释放资源inputStream.close();inputStream = null;return map;}/** * 文本消息对象转换成xml *  * @param textMessage 文本消息对象 * @return xml */public static String textMessageToXml(TextMessage textMessage) {xstream.alias("xml", textMessage.getClass());return xstream.toXML(textMessage);}/** * 音乐消息对象转换成xml *  * @param musicMessage 音乐消息对象 * @return xml */public static String musicMessageToXml(MusicMessage musicMessage) {xstream.alias("xml", musicMessage.getClass());return xstream.toXML(musicMessage);}/** * 图文消息对象转换成xml *  * @param newsMessage 图文消息对象 * @return xml */public static String newsMessageToXml(NewsMessage newsMessage) {xstream.alias("xml", newsMessage.getClass());xstream.alias("item", new Article().getClass());return xstream.toXML(newsMessage);}/** * 扩展xstream,使其支持CDATA块 *  */private static XStream xstream = new XStream(new XppDriver() {public HierarchicalStreamWriter createWriter(Writer out) {return new PrettyPrintWriter(out) {// 对所有xml节点的转换都增加CDATA标记boolean cdata = true;protected void writeText(QuickWriter writer, String text) {if (cdata) {writer.write("<![CDATA[");writer.write(text);writer.write("]]>");} else {writer.write(text);}}};}});}

    ?接下来在处理业务逻辑,建立一个接收并响应消息的service类,并针对用户输入的1或2回复不同的信息给用户

    ?

    package com.ifp.weixin.biz.core.impl;import java.util.Date;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.log4j.Logger;import org.springframework.stereotype.Service;import com.ifp.weixin.biz.core.CoreService;import com.ifp.weixin.constant.Constant;import com.ifp.weixin.entity.Message.resp.TextMessage;import com.ifp.weixin.util.MessageUtil;@Service("coreService")public class CoreServiceImpl implements CoreService{public static Logger log = Logger.getLogger(CoreServiceImpl.class);@Overridepublic String processRequest(HttpServletRequest request) {String respMessage = null;try {// xml请求解析Map<String, String> requestMap = MessageUtil.parseXml(request);// 发送方帐号(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(Constant.RESP_MESSAGE_TYPE_TEXT);textMessage.setFuncFlag(0);// 文本消息if (msgType.equals(Constant.REQ_MESSAGE_TYPE_TEXT)) {// 接收用户发送的文本消息内容String content = requestMap.get("Content");if ("1".equals(content)) {textMessage.setContent("1是很好的");// 将文本消息对象转换成xml字符串respMessage = MessageUtil.textMessageToXml(textMessage);}else if ("2".equals(content)) {textMessage.setContent("我不是2货");// 将文本消息对象转换成xml字符串respMessage = MessageUtil.textMessageToXml(textMessage);}} } catch (Exception e) {e.printStackTrace();}return respMessage;}}

    ?接下来在controller里面的post方法里面调用即可

    ?

    WeixinController类的完整代码

    package com.ifp.weixin.controller;import java.io.IOException;import java.io.PrintWriter;import java.io.UnsupportedEncodingException;import javax.annotation.Resource;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import com.ifp.weixin.biz.core.CoreService;import com.ifp.weixin.util.SignUtil;@Controller@RequestMapping("/weixinCore")public class WeixinController {@Resource(name="coreService")private CoreService coreService;@RequestMapping(method = RequestMethod.GET)public void get(HttpServletRequest request, HttpServletResponse response) {// 微信加密签名,signature结合了开发者填写的token参数和请求中的timestamp参数、nonce参数。String signature = request.getParameter("signature");// 时间戳String timestamp = request.getParameter("timestamp");// 随机数String nonce = request.getParameter("nonce");// 随机字符串String echostr = request.getParameter("echostr");PrintWriter out = null;try {out = response.getWriter();// 通过检验signature对请求进行校验,若校验成功则原样返回echostr,否则接入失败if (SignUtil.checkSignature(signature, timestamp, nonce)) {out.print(echostr);}} catch (IOException e) {e.printStackTrace();} finally {out.close();out = null;}}@RequestMapping(method = RequestMethod.POST)public void post(HttpServletRequest request, HttpServletResponse response) {try {request.setCharacterEncoding("UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}response.setCharacterEncoding("UTF-8");// 调用核心业务类接收消息、处理消息String respMessage = coreService.processRequest(request);// 响应消息PrintWriter out = null;try {out = response.getWriter();out.print(respMessage);} catch (IOException e) {e.printStackTrace();} finally {out.close();out = null;}}}

    ?

    ?效果如下:
    微信公众平台开发教程Java版(3) 消息接收和发送
    ?

    ?ok,大功告成,消息的接收和发送就写完了。

    ?

    ?

  • 热点排行