微信公众号消息管理 - 接收用户信息与被动回复用户信息

前几天开发了微信公众号,趁今天有时间,总结一下。

接收普通消息要注意几点:

1 . 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次。假如服务器无法保证在五秒内处理并回复,可以直接回复空串,微信服务器不会对此作任何处理,并且不会发起重试。

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

3 .如果开发者需要对用户消息在5秒内立即做出回应,即使用“发送消息-被动回复消息”接口向用户被动回复消息时,可以在公众平台官网的开发者中心处设置消息加密。开启加密后,用户发来的消息和开发者回复的消息都会被加密(但开发者通过客服接口等API调用形式向用户发送消息,则不受影响)。

被动回复用户消息要注意几点:

1 .当用户发送消息给公众号时(或某些特定的用户操作引发的事件推送时),会产生一个POST请求,开发者可以在响应包(Get)中返回特定XML结构,来对该消息进行响应(现支持回复文本、图片、图文、语音、视频、音乐)。严格来说,发送被动响应消息其实并不是一种接口,而是对微信服务器发过来消息的一次回复。

2 .微信服务器在将用户的消息发给公众号的开发者服务器地址(开发者中心处配置)后,微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次,如果在调试中,发现用户无法收到响应的消息,可以检查是否消息处理超时。关于重试的消息排重,有msgid的消息推荐使用msgid排重。事件类型消息推荐使用FromUserName + CreateTime 排重。

3 .开发者希望增强安全性,可以在开发者中心处开启消息加密,这样,用户发给公众号的消息以及公众号被动回复用户消息都会继续加密(但),详见被动回复消息加解密说明。

4 .假如服务器无法保证在五秒内处理并回复,必须做出下述回复,这样微信服务器才不会对此作任何处理,并且不会发起重试(这种情况下,可以使用客服消息接口进行异步回复),否则,将出现严重的错误提示。1、直接回复success(推荐方式) 2、直接回复空串(指字节长度为0的空字符串,而不是XML结构体中content字段的内容为空)

注: 发消息注册6种格式,本文只讲述文本格式消息,如果你想找支持6种消息格式的,可以直接退出,去找其他资料。

注意看:
1 .接收普通消息数据格式:

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

2 .被动回复用户信息

<xml>
  <ToUserName><![CDATA[toUser]]></ToUserName>
  <FromUserName><![CDATA[fromUser]]></FromUserName>
  <CreateTime>12345678</CreateTime>
  <MsgType><![CDATA[text]]></MsgType>
  <Content><![CDATA[你好]]></Content>
</xml>

以下是代码:

1.工具类,作用: 解析微信请求并且读取XML,我这只是进行学习,没有封装,全部放在一起了。

  /**
     * 解析微信请求并读取XML
     * @param request
     * @return
     * @throws IOException
     * @throws DocumentException
     */
    public static Map<String,String> readWeixinXml(HttpServletRequest request) throws IOException, DocumentException {
        Map<String,String> map = new HashMap<String,String>();
        //获取输入流
        InputStream input = request.getInputStream();
        //使用dom4j的SAXReader读取(org.dom4j.io.SAXReader;)
        SAXReader sax = new SAXReader();
        Document doc = sax.read(input);
        //获取XML数据包根元素
        Element root = doc.getRootElement();
        //得到根元素的所有子节点
        @SuppressWarnings("unchecked")
        List<Element> elementList = root.elements();
        //遍历所有节点并将其放进map
        for(Element e : elementList){
            map.put(e.getName(), e.getText());
        }
        //释放资源
        input.close();
        input = null;
        return map;
    }

2 .Controller层,你也可以写Service层,与实现层Impl

 @RequestMapping("/replyTextMessage")
  @ResponseBody
 public static void replyTextMessage(HttpServletRequest request, HttpServletResponse response){
        Map<String,String> map = null;
        //从工具类中获取XML解析之后的map
        try {
            map =  WeiXinController.readWeixinXml(request);
        } catch (IOException e) {
            System.out.println("获取输入流失败");
        } catch (DocumentException e) {
            System.out.println("读取XML失败");
        }
        //获取发送方账号
        String fromUserName = map.get("FromUserName");
        //接收方账号(开发者微信号)
        String toUserName = map.get("ToUserName");
        //消息类型
        String msgType = map.get("MsgType");
        //文本内容
        String content = map.get("Content");
        System.out.println("发送方账号:"+fromUserName+",接收方账号(开发者微信号):"+toUserName+",消息类型:"+msgType+",文本内容:"+content);
        //回复消息
        if(msgType.equals("text")){
            //根据开发文档要求构造XML字符串,本文为了让流程更加清晰,直接拼接
            //这里在开发的时候可以优化,将回复的文本内容构造成一个java类
            //然后使用XStream(com.thoughtworks.xstream.XStream)将java类转换成XML字符串,后面将会使用这个方法。
            //而且由于参数中没有任何特殊字符,为简单起见,没有添加<![CDATA[xxxxx]]>
            String replyMsg = "<xml>"+
                    "<ToUserName>"+fromUserName+"</ToUserName>"+
                    "<FromUserName>"+toUserName+"</FromUserName>"+
                    "<CreateTime>"+System.currentTimeMillis()/1000+"</CreateTime>"+
                    "<MsgType>"+msgType+"</MsgType>"+
                    "<Content>"+content+"</Content>"+
                    "</xml>";
            //响应消息
            System.out.println("响应消息:"+replyMsg);
            PrintWriter out = null;
            try {
                //设置回复内容编码方式为UTF-8,防止乱码
                response.setCharacterEncoding("UTF-8");
                out = response.getWriter();
                //我们这里将用户发送的消息原样返回
                out.print(replyMsg);
                System.out.println("响应成功");
            } catch (IOException e) {
                System.out.println("获取输出流失败");
            }finally {
                if(out != null){
                    out.close();
                    out = null;
                }
            }
        }
    }

这个实现的是你在公众号发信息,公众号会返回相同的信息,你可以自己进行封装,改动。代码是完整的,希望可以帮助到大家!

发布了72 篇原创文章 · 获赞 16 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_40206199/article/details/103237380