• 微信公众号开发小记(三)识别文本信息


    经过上一篇的讲解,我们已经将自己的服务器与微信服务器完成对接,现在,如果你在微信公众号上发消息,就会产生一个请求,而这个请求就会由我们写的CoreServlet来处理。

    这次要实现的功能是,微信公众号可以识别你发送的文本消息类型,比如你回复个”你好”,微信公众号会回复给你一句“你发送的是文本消息:你好”,就类似这样的功能,我们来看该怎么实现。

    首先你要知道的是,你向微信公众号发送一个文本消息,这样会产生一个post请求给微信服务器,而微信服务器会将这个请求转发给我们的服务器,准确来说是交给我们的CoreServlet来处理。

    要处理这块我们需要查看官方技术文档,也就是这块—接收普通消息

    这个需要你自己去仔细看看,然后我们会发现我们发送的消息最终是一个XML数据包,看官方的一句解释

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

    文本消息的XML数据包结构是这样的

    <xml>  <ToUserName>< ![CDATA[toUser] ]></ToUserName>  <FromUserName>< ![CDATA[fromUser] ]></FromUserName>  <CreateTime>1348831860</CreateTime>  <MsgType>< ![CDATA[text] ]></MsgType>  <Content>< ![CDATA[this is a test] ]></Content>  <MsgId>1234567890123456</MsgId>  </xml>

    这里面包含一些参数如下

    ToUserName 开发者微信号
    FromUserName 发送方帐号(一个OpenID)
    CreateTime 消息创建时间 (整型)
    MsgType text
    Content 文本消息内容
    MsgId 消息id,64位整型

    也就是说,现在你往微信公众号上发送一段文字,然后最终会形成一个XML数据包,我们通过我们的CoreServlet去处理这个数据包,也就是这些数据包含在request当中。

    那接下来的重点就是去解析request中的XML数据包了,那么该如何解析,观察XML数据,可以将数据存放在Map集合中,然后将XML中的数据映射成一个object对象,这其中用到了一些开源库,首先我们需要创建一个Javabean对应着我们的文本消息XML数据结构中的那些参数

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

    接下来的重点就是要去解析我们的请求,将xml数据映射成JavaBean,我们新建一个CoreService去处理我们的请求,在C哦热Servlet中这样操作请求

     @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
            // 将请求、响应的编码均设置为UTF-8(防止中文乱码)
            req.setCharacterEncoding("UTF-8");
            resp.setCharacterEncoding("UTF-8");
            PrintWriter out = resp.getWriter();
    
            CoreService coreService = new CoreService();
            String s = coreService.parseWxRequest(req);
    
            // 响应消息,将相应的xml数据转发给微信服务器
            out.print(s);
            System.out.println("消息:"+s);
            out.close();
        }

    也就是将微信请求交给CoreService去解析,到这里要知道就是微信请求中是XML数据格式,所以我们返回给微信服务器的也应该是Xml数据,因此,这个parseWxRequest返回的应该是一个字符串,但是这个字符串是一个XML数据,下面看具体的如何解析请求,下面是CoreService的具体写法

    public class CoreService {
        public static String parseWxRequest(HttpServletRequest request) {
            // xml格式的消息数据
            String respXml = null;
            // 默认返回的文本消息内容
            String respContent = "未知的消息类型!";
    
            try {
                // 调用parseXml方法解析请求消息
                Map<String, String> requestMap = MessageUtil.parseXml(request);
                // 发送方帐号,一个openID
                String fromUserName = requestMap.get("FromUserName");
                // 开发者微信号
                String toUserName = requestMap.get("ToUserName");
                // 消息类型
                String msgType = requestMap.get("MsgType");
                // 接收用户发送的文本消息内容
                String content = requestMap.get("Content");
                //回复文本消息
                TextMessage textMessage = new TextMessage();
                textMessage.setToUserName(fromUserName);
                textMessage.setFromUserName(toUserName);
                textMessage.setCreateTime(System.currentTimeMillis());
                textMessage.setMsgType(MessageUtil.REQ_MESSAGE_TYPE_TEXT);
    
                // 文本消息
                if (msgType.equals(MessageUtil.REQ_MESSAGE_TYPE_TEXT)) {
                    respContent = "你回复的是文本消息:"+content;
                    textMessage.setContent(respContent);
                    String xml = MessageUtil.messageToXml(textMessage);
                    respXml = xml;
    
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return respXml;
        }
    
    }

    可以看出这里只是对解析后的消息做一个响应,通过

    MessageUtil.parseXml(request);

    将请求中的XML数据解析出来放在Map集合当中,然后从集合中拿出数据生成一个具体的TextMessage类供我们使用,那么具体的是如何将请求中的XML数据解析成一个Map集合呢

    public class MessageUtil {
        // 请求消息类型:文本
        public static final String REQ_MESSAGE_TYPE_TEXT = "text";
        /**
         * 解析微信发来的请求(XML)
         *
         * @param request
         * @return Map<String, String>
         * @throws Exception
         */
        @SuppressWarnings("unchecked")
        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();
            // 得到根元素的所有子节点
            List<Element> elementList = root.elements();
    
            // 遍历所有子节点
            for (Element e : elementList){
                map.put(e.getName(), e.getText());
            }
    
            // 释放资源
            inputStream.close();
            inputStream = null;
    
            return map;
        }
    
        /**
         * 扩展xstream使其支持CDATA
         */
        private static XStream xstream = new XStream(new XppDriver() {
            @Override
            public HierarchicalStreamWriter createWriter(Writer out) {
                return new PrettyPrintWriter(out) {
                    // 对所有xml节点的转换都增加CDATA标记
                    boolean cdata = true;
    
                    @Override
                    @SuppressWarnings("unchecked")
                    public void startNode(String name, Class clazz) {
                        super.startNode(name, clazz);
                    }
    
                    @Override
                    protected void writeText(QuickWriter writer, String text) {
                        if (cdata) {
                            writer.write("<![CDATA[");
                            writer.write(text);
                            writer.write("]]>");
                        } else {
                            writer.write(text);
                        }
                    }
                };
            }
        });
    
        /**
         * 文本消息对象转换成xml
         *
         * @param textMessage 文本消息对象
         * @return xml
         */
        public static String messageToXml(TextMessage textMessage) {
            xstream.alias("xml", textMessage.getClass());
            return xstream.toXML(textMessage);
        }
    
    }
    

    我们知道微信请求是一个XML格式的数据,这个类可以将XML的数据解析成Java对象,当然也提供方法将Java对象再次转换成XML,以便我们作为响应数据返回给微信服务器。

    这个类主要用到了dom4j和XStream,感兴趣的可以研究一下,不然这块看起来还是有点小难度的。

    接下来将我们的项目打包上传到服务器,上传成功之后可以在公众号回复一个文字测试,如下

    未完待续

  • 相关阅读:
    Oracle 10g 体系结构及安全管理
    Oracle 10g数据库概述
    jQuery Ajax应用
    ASP.NET Ajax核心对象
    ASP.NET XML
    jQuery插件的使用和编写
    jQuery中的Ajax应用
    弹窗下面的页面滚动问题
    报文过长,华为手机自动拦截报文
    手机抓包 配置步骤
  • 原文地址:https://www.cnblogs.com/ithuangqing/p/12113661.html
Copyright © 2020-2023  润新知