【微信公众号开发】【4】接收消息和消息回复

前言:

1,消息推送—— 当普通用户向公众帐号发消息时,微信服务器将POST该消息到填写的URL上(发消息=操作,包括扫描二维码,点击菜单等;URL:coreServlet)

2,消息回复——对每一个POST请求,开发者可以在响应包中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)

3,消息回复——假如服务器无法保证在五秒内处理回复,则必须回复“success”或者“”(空串),否则微信后台会发起三次重试。

4,主动发送消息——模板消息(该章节并未提及)

正文:

1,接收消息的封装(message.req)

接收消息之基类

public class BaseMessage {  
    private String ToUserName;  // 开发者微信号     
    private String FromUserName;  // 发送方帐号(一个OpenID)   
    private long CreateTime;  // 消息创建时间 (整型)   
    private String MsgType;  // 消息类型(text/image/location/link)  
    private long MsgId;  // 消息id,64位整型  
  
    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 class TextMessage extends BaseMessage {  
    // 消息内容  
    private String Content;  
  
    public String getContent() {  
        return Content;  
    }  
  
    public void setContent(String content) {  
        Content = content;  
    }  
}  

接收消息之图片消息

public class ImageMessage extends BaseMessage {  
    // 图片链接  
    private String PicUrl;  
  
    public String getPicUrl() {  
        return PicUrl;  
    }  
  
    public void setPicUrl(String picUrl) {  
        PicUrl = picUrl;  
    }  
} 

接收消息之地理位置消息

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;  
    }  
}  

接收消息之链接消息

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;  
    }  
}  

接收消息之语音消息

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;  
    }  
}  

2,响应消息的封装(message.resp)

响应消息之基类

public class BaseMessage {    
    private String ToUserName;  // 接收方帐号(收到的OpenID)
    private String FromUserName;  // 开发者微信号  
    private long CreateTime;  // 消息创建时间 (整型)
    private String MsgType;  // 消息类型(text/music/news)
    private int FuncFlag;  // 位0x0001被标志时,星标刚收到的消息  
  
    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;  
    }  
}  

响应消息之文本消息

public class TextMessage extends BaseMessage {  
    // 回复的消息内容  
    private String Content;  
  
    public String getContent() {  
        return Content;  
    }  
  
    public void setContent(String content) {  
        Content = content;  
    }  
} 

响应消息之音乐消息

public class MusicMessage extends BaseMessage {  
    // 音乐  
    private Music Music;  
  
    public Music getMusic() {  
        return Music;  
    }  
  
    public void setMusic(Music music) {  
        Music = music;  
    }  
}  

音乐消息中Music类的定义

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;  
    }  
  
}  

响应消息之图文消息

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;  
    }  
}  

图文消息中Article类的定义

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 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;  
    }  
  
}  

3,解析接收到的消息及将响应消息转换成xml返回

前言中说的URL

@ResponseBody  
@RequestMapping(value = "coreServlet", method = RequestMethod.POST)
public void coreServletPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    
  //获取微信POST过来的内容。消息为xml格式
  // 将请求、响应的编码均设置为UTF-8(防止中文乱码)  
  request.setCharacterEncoding("UTF-8");  
  response.setCharacterEncoding("UTF-8");  
  //从请求中读取整个post数据
  InputStream inputStream = request.getInputStream();
  String postData = IOUtils.toString(inputStream, "UTF-8");
  logger.info("postData = " + postData);
  // 调用核心业务类接收消息、处理消息  
  Message message = CoreService.processRequest(postData);
  String respMessage = message.getRespMessage();         
          
  // 响应消息  
  PrintWriter out = response.getWriter();  
  out.print(respMessage);  
  out.close();  
} 
调用核心业务类接收消息、处理消息 CoreService.processRequest
    private static String UPDATE_MENU = "menu";//更新自定义菜单的口令
    public static Message processRequest(String msg) { 
        Message message = new Message(); 
        String param1 = "";//二维码带的参数  
        
        try {                         
            Map<String, String> requestMap = MessageUtil.parseXml(msg);  // xml请求解析                 
            String fromUserName = requestMap.get("FromUserName");  // 发送方帐号  
            String toUserName = requestMap.get("ToUserName");  // 接收方帐号                 
            String msgType = requestMap.get("MsgType");  // 消息类型               
            String eventKey = requestMap.get("EventKey");  // 事件KEY值,与创建自定义菜单时指定的KEY值对应   
            String respContent = "请求处理中...";  // 默认返回的文本消息内容     
            // 回复文本消息  
            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);  
            // 创建图文消息  
            NewsMessage newsMessage = new NewsMessage();  
            newsMessage.setToUserName(fromUserName);  
            newsMessage.setFromUserName(toUserName);  
            newsMessage.setCreateTime(new Date().getTime());  
            newsMessage.setMsgType(MessageUtil.RESP_MESSAGE_TYPE_NEWS);  
            newsMessage.setFuncFlag(0); 

            // 文本消息  
            if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {  
                respContent = "您发送的是文本消息!"; 
                if((UPDATE_MENU).equals(requestMap.get("Content"))){ 
                    respContent = MenuManager.menuManager();//更新自定义菜单
                } 
                // 回复包含“定位跑”
                else if ( requestMap.get("Content").contains("定位跑")) {
                    respContent = "您的愿望我们已经收到,请关注8月8日将发布的中奖名单信息";
                }
            }            
            // 图片消息  
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_IMAGE)) {  
                respContent = "您发送的是图片消息!";              
            }  
            // 地理位置消息  
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LOCATION)) {  
                respContent = "您发送的是地理位置消息!";  
            }  
            // 链接消息  
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_LINK)) {  
                respContent = "您发送的是链接消息!";  
            }  
            // 音频消息  
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_VOICE)) {  
            }  
            // 事件推送  
            else if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_EVENT)) {  
                // 事件类型  
                String eventType = requestMap.get("Event");  
                // 订阅  
                if (eventType.equals(MessageUtil.EVENT_TYPE_SUBSCRIBE)) {  
                    respContent = "欢迎关注爱关节网";  
                    if(!StringUtils.isEmpty(eventKey)){
                        param1 = eventKey.substring(eventKey.indexOf("_")+1);
                    }
                } 
                // 扫描  
                if (eventType.equals(MessageUtil.EVENT_TYPE_SCAN)) {  
                    respContent = "";
                    if(!StringUtils.isEmpty(eventKey)){
                        param1 =  eventKey;                        
                    }
                }
                // 取消订阅  
                else if (eventType.equals(MessageUtil.EVENT_TYPE_UNSUBSCRIBE)) {  
                    // TODO 取消订阅后用户再收不到公众号发送的消息,因此不需要回复消息  
                }             
                // 自定义菜单点击事件  
                else if (eventType.equals(MessageUtil.EVENT_TYPE_CLICK)) {                        
                    List<Article> articleList = new ArrayList<Article>(); 
                    
                    if (eventKey.equals("13")) {  
                        respContent = "内容建设中,敬请期待";  
                    } else if (eventKey.equals("14")) {  
                        //单图文消息
                        Article article = new Article();  
                        article.setTitle("灵动中国|爱关节·不等待 广场舞公益活动川渝开赛");  
                        article.setDescription("灵动中国|爱关节·不等待 广场舞公益活动川渝开赛");  
                        article.setPicUrl(Config.domain() + "/UCenter/wx_marathon/img/zuimeiguangchangwu.png");  
                        article.setUrl("http://mp.weixin.qq.com/s/6_-hwdJ6fFV58UD8SLAtcg");  
                        articleList.add(article);  
                        // 设置图文消息个数  
                        newsMessage.setArticleCount(articleList.size());  
                        // 设置图文消息包含的图文集合  
                        newsMessage.setArticles(articleList);  
                        // 将图文消息对象转换成xml字符串  
                        respMessage = MessageUtil.newsMessageToXml(newsMessage);
                        message.setParam1("");
                        message.setRespMessage(respMessage);
                        message.setFromUserName(fromUserName);
                        message.setToUserName(toUserName);                                
                        return message;  
                    }
                }  
            }              
            textMessage.setContent(respContent);  
            respMessage = MessageUtil.textMessageToXml(textMessage); 
            message.setParam1(param1);
            message.setRespMessage(respMessage);
            message.setFromUserName(fromUserName);
            message.setToUserName(toUserName);
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
  
        return message;  
    }
MessageUtil
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_EVENT = "event";  //请求消息类型:推送 
    public static final String EVENT_TYPE_SUBSCRIBE = "subscribe";  //事件类型:subscribe(订阅) 
    public static final String EVENT_TYPE_UNSUBSCRIBE = "unsubscribe";  //事件类型:unsubscribe(取消订阅) 
    public static final String EVENT_TYPE_CLICK = "CLICK";  //事件类型:CLICK(自定义菜单点击事件) 
    public static final String EVENT_TYPE_SCAN = "SCAN";  //事件类型:SCAN(扫描)
  
    //解析微信发来的请求(XML) 
    @SuppressWarnings("unchecked") 
    public static Map<String, String> parseXml(String msg) throws IOException 
    {  
        // 将解析结果存储在HashMap中  
        Map<String, String> map = new HashMap<String, String>();            
 
        //读取输入流  
        SAXReader reader = new SAXReader();
        try {
            InputStream inputStream = new ByteArrayInputStream(msg.getBytes("UTF-8")); 
            Document document = reader.read(inputStream);  
            Element root = document.getRootElement();         // 得到xml根元素               
            List<Element> elementList = root.elements();      // 得到根元素的所有子节点  
       
             for (Element e : elementList)  
                 map.put(e.getName(), e.getText()); 
       
             inputStream.close(); 
             inputStream = null;  
        } catch (DocumentException e) {
            logger.error("解析失败",e);
        }
  
        return map;  
    }  
  
   
    //文本消息对象转换成xml 
    public static String textMessageToXml(TextMessage textMessage) {  
        xstream.alias("xml", textMessage.getClass());  
        return xstream.toXML(textMessage);  
    }  
  
    //音乐消息对象转换成xml  
    public static String musicMessageToXml(MusicMessage musicMessage) {  
        xstream.alias("xml", musicMessage.getClass());  
        return xstream.toXML(musicMessage);  
    }  
  
    //图文消息对象转换成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;  
  
                @SuppressWarnings("unchecked")  
                public void startNode(String name, Class clazz) {  
                    super.startNode(name, clazz);  
                }  
  
                protected void writeText(QuickWriter writer, String text) {  
                    if (cdata) {  
                        writer.write("<![CDATA[");  
                        writer.write(text);  
                        writer.write("]]>");  
                    } else {  
                        writer.write(text);  
                    }  
                }  
            };  
        }  
    });  

    //将java对象转换为json对象  
    public static String Object2Json(Object obj){  
        JSONObject json = JSONObject.fromObject(obj);
        // 将json对象转换为字符串
        String str = json.toString();
        return str;  
    }  
}  
 
原文地址:https://www.cnblogs.com/huashengweilong/p/7701009.html