• springboot进行微信公众号相关开发:(三)发送模板消息并设置通用回调消息接收接口


    在微信公众号相关的功能开发中,时常涉及一些与用户的消息交互,微信为了公众号运行方不对用户进行骚扰操作,所以对公众号方发送给用户方的消息设置了很多限制。在公众号方涉及一些需要主动提醒、通知用户的提升用户体验的操作时,允许开发者在公众平台网站中模板消息库中选择模板,选择后获得模板ID,再根据模板ID向用户主动推送提醒、通知消息。本文主要讲述模板消息的模板创建,消息发送,通用回调消息接收等功能的使用方式。

    本文还是以测试号为例,测试号页面:
    在这里插入图片描述

    我们可以看到测试号二维码模块,首先我们使用微信扫码关注这个测试号,关注成功后再用户列表会多出一条用户信息,昵称即为关注方的微信昵称,而微信号即为关注方的微信在本测试号的内唯一标识,我们可以通过该标识跟该关注用户实现交互,在正式公众号内这个标识叫做openId。

    (一)模板消息的设定

    在二维码的下方可以看到模板消息接口模块,我们点击新增测试模板创建新的消息模板:
    在这里插入图片描述

    需要注意到相关消息提示:

    • 1、测试模板的模板ID仅用于测试,不能用来给正式帐号发送模板消息
    • 2、为方便测试,测试模板可任意指定内容,但实际上正式帐号的模板消息,只能从模板库中获得
    • 3、需为正式帐号申请新增符合要求的模板,需使用正式号登录公众平台,按指引申请
    • 4、模板内容可设置参数(模板标题不可),供接口调用时使用,参数需以{{开头,以.DATA}}结尾

    本文模拟以核酸报告提醒为主题,设定完毕后,如图所示:
    在这里插入图片描述

    其中模板ID是我们调用这个消息模板的标识,可以看到我在模板内容中设定了三个变量参数,“one”、“two”、“three”,我们调用这个模板的时候必须携带这三个参数的值,否则就会报格式错误等提示。

    (二)模板消息的发送

    我们点击下方模板消息的功能接口调用文档,文档内有详细的调用说明和示例:

    具体调用方法

    第一步:获取template_id(注意:仅微信开放平台同事可获取)

    通过向微信公众平台申请模板,来获取模板id。

    第二步:请求接口
    请注意,URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击(android)。

    POST请求

    https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN

    请求包为一个json:

    {
     "touser":"OPENID",
     "template_id":"ngqIpbwh8bUfcSsECmogfXcV14J0tQlEpBO27izEYtY","url":"http://weixin.qq.com/download",
     "topcolor":"#FF0000",
     "data":{
             "User": {
                 "value":"黄先生",
                 "color":"#173177"
             },
             "Date":{
                 "value":"06月07日 19时24分",
                 "color":"#173177"
             },
             "CardNumber": {
                 "value":"0426",
                 "color":"#173177"
             },
             "Type":{
                 "value":"消费",
                 "color":"#173177"
             },
             "Money":{
                 "value":"人民币260.00元",
                 "color":"#173177"
             },
             "DeadTime":{
                 "value":"06月07日19时24分",
                 "color":"#173177"
             },
             "Left":{
                 "value":"6504.09",
                 "color":"#173177"
             }
     }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    发送效果图:
    在这里插入图片描述

    事件推送

    在模版消息发送任务完成后,微信服务器会将是否送达成功作为通知,发送到开发者在开发模式中填写的URL中。

    1、送达成功时,推送的XML如下:

    	
    	
    	
    	1395658920
    	
    	
    	200163836
    	
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2、送达由于用户拒收(用户设置拒绝接收公众号消息)而失败时,推送的XML如下:

    	
    	
    	
    	1395658984
    	
    	
    	200163840
    	
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3、送达由于其他原因失败时,推送的XML如下:

    	
    	
    	
    	1395658984
    	
    	
    	200163840
    	
    	
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    返回码说明

    在调用模板消息接口后,会返回JSON数据包。正常时的返回JSON数据包示例:

    {
    	"errcode":0,
    	"errmsg":"ok",
    	"msgid":200228332
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    错误时的返回JSON数据,形式类似,错误码请见本页下方返回码说明。

    返回码说明
    -1系统繁忙
    0请求成功
    40001验证失败
    40002不合法的凭证类型
    40003不合法的OpenID
    40004不合法的媒体文件类型
    40005不合法的文件类型
    40006不合法的文件大小
    40007不合法的媒体文件id
    40008不合法的消息类型
    40009不合法的图片文件大小
    40010不合法的语音文件大小
    40011不合法的视频文件大小
    40012不合法的缩略图文件大小
    40013不合法的APPID
    41001缺少access_token参数
    41002缺少appid参数
    41003缺少refresh_token参数
    41004缺少secret参数
    41005缺少多媒体文件数据
    41006access_token超时
    42001需要GET请求
    43002需要POST请求
    43003需要HTTPS请求
    44001多媒体文件为空
    44002POST的数据包为空
    44003图文消息内容为空
    45001多媒体文件大小超过限制
    45002消息内容超过限制
    45003标题字段超过限制
    45004描述字段超过限制
    45005链接字段超过限制
    45006图片链接字段超过限制
    45007语音播放时间超过限制
    45008图文消息超过限制
    45009接口调用超过限制
    46001不存在媒体数据
    47001解析JSON/XML内容错误

    可以看到我们只需要

    "touser":"用户微信号/openId",
    "template_id":"模板消息Id",
    "url":"用户点击模板消息跳转到的页面或调用的接口",
    "topcolor":"模板消息顶部背景色",
    "data":{存放变量参数的值和其字体对应颜色}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    这五个参数再加上access_token即可实现对模板消息的发送,其中变量的值需要以字段名对应一个value和color对象的方式统一包裹在“data”中。

    另外,调用说明中:

    在模版消息发送任务完成后,微信服务器会将是否送达成功作为通知,发送到开发者在开发模式中填写的URL中

    所以,据此我们可以了解到模板消息的发送在微信内应该是一个异步操作,微信收到我们的调用请求后立即回复给我们能不能执行,但执行是否成功了它会通过一个额外的接口给我们提醒,这个接口就是我们最初绑定激活所用的配置信息内的URL,它承担了所有微信功能接口调用的回调消息接收操作。但需要注意的是,此时承担接收回调消息的接口类型是POST,所以接口地址不变的情况下我们还需要设定一个接收消息的POST接口,接收成功后统一回复字符串“success”即可,否则微信会重发三次左右,编写代码如下:

        /**
         * 恒定配置接口,post类型用于接收各种消息推送和回调
         *
         * @param request 请求体
         * @return 请求合法的情况下恒定返回字符串 “success”
         */
        @PostMapping("/auth")
        public String sayHi(HttpServletRequest request) {
            //获取param参数(可用以验签,确定请求方身份是否合法)
            String reqStr = "";
            try {
                Map<String, String[]> parameterMap = request.getParameterMap();
                if (ObjectUtil.isNotEmpty(parameterMap)) {
                    reqStr = JSONObject.toJSONString(parameterMap, SerializerFeature.WriteMapNullValue);
                }
            } catch (Exception e) {
                log.error("接收param消息异常" + e.getMessage(), e);
            }
            log.info("恒定配置接口接收param参数:" + reqStr);
    
            //获取xml参数(可用以具体业务处理)
            Map<String, String> xmlMap = new HashMap<>(16);
            try {
                // 从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) {
                    xmlMap.put(e.getName(), e.getText());
                }
            } catch (Exception e) {
                log.error("接收xml消息异常" + e.getMessage(), e);
            }
            log.info("恒定配置接口接收xml参数:" + JSONObject.toJSONString(xmlMap, SerializerFeature.WriteMapNullValue));
    
            return "success";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    因为回调业务消息基本为xml消息,所以我们需要从流中获取xml消息并转换为java对象,所需pom依赖:

            <dependency>
                <groupId>dom4jgroupId>
                <artifactId>dom4jartifactId>
                <version>1.6version>
            dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    另外,回调消息内也会携带相关签名身份信息,可以用以确定身份是否合法,正式号还可以设置消息使用密钥加密传输,此处不涉及。

    编写好了回调消息接收方法,我们再编写模板消息调用方法:

        /**
         * 发送模板消息
         *
         * @param reqMap 包含所需参数的集合
         * @return 响应结果
         */
        @PostMapping("/tem-msg")
        public String sendTemplateMsg(@RequestBody Map<String, String> reqMap) {
            String uri = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN";
            String accessToken = reqMap.get("accessToken");
            uri = uri.replace("ACCESS_TOKEN", accessToken);
    
            String temId = reqMap.get("temId");
            String redirectUri = reqMap.get("redirectUri");
            String openId = reqMap.get("openId");
    
            Map<String, Object> wxMap = new HashMap<>(16);
            wxMap.put("touser", openId);
            wxMap.put("template_id", temId);
            wxMap.put("url", redirectUri);
            wxMap.put("topcolor", "#FF0000");
    
            Map<String, Map<String, String>> dataMap = new HashMap<>(16);
            Map<String, String> map1 = new HashMap<>(2);
            map1.put("value", "孙武");
            map1.put("color", "#173177");
            dataMap.put("one", map1);
    
            Map<String, String> map2 = new HashMap<>(2);
            map2.put("value", "核酸检测报告");
            map2.put("color", "#173177");
            dataMap.put("two", map2);
    
            Map<String, String> map3 = new HashMap<>(2);
            map3.put("value", "http://www.baidu.com");
            map3.put("color", "#173177");
            dataMap.put("three", map3);
    
            wxMap.put("data", dataMap);
    
            JSONObject jsonObject = JSONObject.parseObject(JSONObject.toJSONString(wxMap));
            String res = RestClientUtils.sendPostString(restTemplate, uri, null, jsonObject, null);
    
            return res;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    postman调用参数:

    {
    	"accessToken": "59_qzI8PAKyHTPtYbFU2VNOxYqoef2JRiOcfFESsCWJh8CAzGnFZALWH4-gtaU3H52KZgYcbN7T4v6FfkRkAlReDgtxZ02TC7i9EQvk7OEOtSBdWuMVNZ0voVnq6FYL1AANWkScYEYE_eQObTJJUBNjACAFMY",
    	"temId": "EWxi5NXmiZkJIHiYtfnA_WOTPosRqt6UR7li4RCRODw",
    	"redirectUri": "https://XXXXXXXX.wocp.fun/module/wx/v1/init/redirect-page",
    	"openId": "xxxxxwbxxxxxE-Whk"
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    PS: Hutool工具的post调用方法博主在使用时,微信一直提示参数格式异常,所以这里使用是自己的一个工具类,工具类在之前博文,具体链接

    因为博主没有页面部署,所以跳转路径url使用的是一个接口用以测试,接口编写如下:

        /**
         * 点击模板消息跳转的页面路径或接口(此处使用接口,一般情况下应为前端页面路径)
         *
         * @return 处理结果
         */
        @GetMapping("/redirect-page")
        public String senTemplateMsgCallback() {
            log.info("进入页面跳转接口......");
            return "success页面消息";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    至此,代码编写完成,我们首先获取access_token,然后再postman调用接口进行模板消息的发送操作:
    在这里插入图片描述

    可以看到,响应消息提示成功,我们再查看springboot日志:
    在这里插入图片描述

    可以看到,在回调消息接收方法内接受到了模板消息发送的结果为success。xml参数内,ToUserName接收者即为我们的公众号微信号,FromUserName发送者即为用户的微信号(openId)。

    打开我们的手机,可以看到订阅号内有一条提示消息:
    在这里插入图片描述

    我们点击这个消息:
    在这里插入图片描述

    可以看到,页面参数和颜色都是跟我们设定发送的一致,我们再点击这个消息:
    在这里插入图片描述

    可以看到页面消息与我们跳转接口内返回参数一致,查看后端日志:
    在这里插入图片描述

    至此,模板消息发送功能完成!

  • 相关阅读:
    基于单片机的电子万年历设计
    Python分享之数学与随机数 (math包,random包)
    JSD-2204-跨域问题-总结Spring框架-Day08
    2022阿里云金秋上云双十一轻量服务器2核2G 2核4G
    数据安全事故频发以及防范措施
    计算机组成原理(一)计算机系统概论
    yaml数据格式
    Spring Security Taglibs 简介
    6月26日第壹简报,星期日,农历五月廿八
    Mac 通过docker安装MinIO
  • 原文地址:https://blog.csdn.net/yssa1125001/article/details/126352199