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

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

事件推送

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

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

	<xml>
	<ToUserName><![CDATA[gh_7f083739789a]]></ToUserName>
	<FromUserName><![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8]]></FromUserName>
	<CreateTime>1395658920</CreateTime>
	<MsgType><![CDATA[event]]></MsgType>
	<Event><![CDATA[TEMPLATESENDJOBFINISH]]></Event>
	<MsgID>200163836</MsgID>
	<Status><![CDATA[success]]></Status>
	</xml>

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

	<xml>
	<ToUserName><![CDATA[gh_7f083739789a]]></ToUserName>
	<FromUserName><![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8]]></FromUserName>
	<CreateTime>1395658984</CreateTime>
	<MsgType><![CDATA[event]]></MsgType>
	<Event><![CDATA[TEMPLATESENDJOBFINISH]]></Event>
	<MsgID>200163840</MsgID>
	<Status><![CDATA[failed:user block]]></Status>
	</xml>

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

	<xml>
	<ToUserName><![CDATA[gh_7f083739789a]]></ToUserName>
	<FromUserName><![CDATA[oia2TjuEGTNoeX76QEjQNrcURxG8]]></FromUserName>
	<CreateTime>1395658984</CreateTime>
	<MsgType><![CDATA[event]]></MsgType>
	<Event><![CDATA[TEMPLATESENDJOBFINISH]]></Event>
	<MsgID>200163840</MsgID>
	<Status><![CDATA[failed: system failed]]></Status>
	</xml>
返回码说明

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

{
	"errcode":0,
	"errmsg":"ok",
	"msgid":200228332
}

错误时的返回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":{存放变量参数的值和其字体对应颜色}

这五个参数再加上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";
    }

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

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6</version>
        </dependency>

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

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

    /**
     * 发送模板消息
     *
     * @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;
    }

postman调用参数:

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

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

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

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

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

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

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

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

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

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

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

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

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值