• 【微信公众号开发】【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;  
        }  
    }  
     
  • 相关阅读:
    在asp.net中执行存储过程(转)
    Linux DM9000网卡驱动程序完全分析
    Linux内核态抢占机制分析(转)
    操作系统原理(转)
    Keil4 每次选build 编译(F7)都全部编译的解决办法
    内核必看: spinlock、 mutex 以及 semaphore
    linux内核代码container_of
    Win10玩魔兽争霸不能全屏显示的设置教程
    在vmware里面免费安装纯净的xp虚拟机
    IAR之工程配置
  • 原文地址:https://www.cnblogs.com/huashengweilong/p/7701009.html
Copyright © 2020-2023  润新知