• 微信小程序消息订阅Java


    前言

    编写日期 : 2022-11-04

    写这篇文章原因

    公司给政府做一个订餐系统,需要在员工在小程序上发起订餐后经过部门领导和书记的审批后,再由食堂确认订餐结果。在订餐审批单在各个节点流转的过程中,需要给每一个节点的审批人发送微信订阅消息手机短信,通知订餐流程所在节点的人有新的订餐审批单需要审批,最终将订餐结果通过微信订阅消息手机短信反馈给订餐人员。手机短信那块后端很好整,没啥问题,但是这个微信小程序发送订阅消息这个没有整过,有点懵,但不慌。本来这个微信的消息订阅前端已经做好了,但是架构师说这块的逻辑后端做,所以我就来搞这个了。

    官方文档说明

    链接 :>>>微信小程序发送订阅消息官方文档 <<<

    调用方式 HTTPS 调用
    POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN

    请求参数

    属性类型类型说明
    access_tokenString需要用小程序的appid和密钥secret去调用 官方 接口获取
    template_idString所需下发的订阅模板id
    pageString点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转
    touserString接收者(用户)的 openid,
    dataString模板内容,格式形如 { “key1”: { “value”: any }, “key2”: { “value”: any } }的object
    miniprogram_stateString跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
    langString进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN

    申请的微信订阅消息模板

    在这里插入图片描述

    访问接口传参示例

    {
      "touser": "OPENID",
      "template_id": "TEMPLATE_ID",
      "page": "index",
      "miniprogram_state":"developer",
      "lang":"zh_CN",
      "data": {
          "thing1": {
              "value": "金先生"
          },
          "time2": {
              "value": "2020-05-01"
          },
          "phrase13": {
              "value": "成功"
          } ,
          "thing17": {
              "value": "xx地方"
          }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    代码

    需要用到的当前小程序的参数

    • appid 小程序的appid
    • secret 小程序密钥
    • TempId 申请的订阅消息模板id

    获取access_token

    
    	@Value("${wx.xiaochengxu.appid}")
        private String appid;
        @Value("${wx.xiaochengxu.secret}")
        private String secret;
    
     /**
      *	@param appid secret
      */
      	@Override
    	public String getAccessToken() {
    	        HttpResponse response = HttpRequest.get("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + appid + "&secret=" + secret + "").execute();
    	        JSONObject tokenJson = JSON.parseObject(response.body());
    	        String accessToken =  tokenJson.get("access_token").toString();
    	        return accessToken;
    	    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    发送订阅消息

    请求参数
    public class SendMsgBody {
    
        /*接收者(用户)的 openid*/
        private String touser;
    
        /*所需下发的订阅模板id*/
        private String template_id;
    
        /*点击消息后跳转的页面*/
        private String page;
    
        /*跳转小程序类型:developer 为开发版;trial 为体验版;formal 为正式版;默认为正式版*/
        private String miniprogram_state="developer";
    
        /*进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN返回值*/
        private String lang="zh_CN";
    
        /*模板数据,这里定义为object是希望所有的模板都能使用这个消息配置*/
        private Object data;
    
    
        public String getTouser() {
            return touser;
        }
        public void setTouser(String touser) {
            this.touser = touser;
        }
    	//template_id、page、data ==>getset
    }
    
    • 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
    请求参数中的data
    public class MsgSuccess {
    
        /*姓  名*/
        private Map<String, String> thing1;
    
        /*预约时间*/
        private Map<String, String> time2;
    
        /*预约状态*/
        private Map<String, String> phrase13;
    
        /*预约地点*/
        private Map<String, String> thing17;
    
        public Map<String, String> getThing1() {
            return thing1;
        }
    
        public Map<String, String> getTime2() {
            return time2;
        }
    
        public Map<String, String> getPhrase13() {
            return phrase13;
        }
    
        public Map<String, String> getThing17() {
            return thing17;
        }
    
        public void setThing1(String thing1) {
            this.thing1 = getFormat(thing1);
        }
    
        public void setTime2(String time2) {
            this.time2 = getFormat(time2);
        }
    
        public void setPhrase13(String phrase13) {
            this.phrase13 = getFormat(phrase13);
        }
    
        public void setThing17(String thing17) {
            this.thing17 = getFormat(thing17);
        }
    
        public HashMap<String, String> getFormat(String str) {
            return new HashMap<String, String>() {{
                put("value", str);
            }};
        }
    
        @Override
        public String toString() {
            return "DCSuccess{" +
                    "thing1=" + thing1 +
                    ", time2=" + time2 +
                    ", phrase13=" + phrase13 +
                    ", thing17=" + thing17 +
                    '}';
        }
    }
    
    • 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
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    发送消息
    	@Value("${wx.xiaochengxu.sendMsg.successTempId}")
        private String tempId;//模板id
    
    	@Override
    	public void wxSendMsgSuccess(String openId, Map<String, String> node) {
    	        String accessToken = getAccessToken() ;
    	
    	        //先填充请求体中data的数据
    	        MsgSuccess msgSuccess = new MsgSuccess ();
    	        msgSuccess .setThing1(node.get("thing1"));
    	        msgSuccess .setTime2(node.get("time2"));
    	        msgSuccess .setPhrase13("成功");
    	        msgSuccess .setThing17(node.get("thing17"));
    	
    			//请求参数数据填充
    	        SendMsgBody sendMsgBody = new SendMsgBody();
    	        sendMsgBody.setTouser(openId);
    	        sendMsgBody.setTemplate_id(tempId);
    	        sendMsgBody.setData(msgSuccess);
    	
    	        String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + accessToken;
    	
    	        //发送请求
    	        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
    	        HttpHeaders headers = new HttpHeaders();
    	        headers.setContentType(type);
    	        HttpEntity<SendMsgBody> httpEntity = new HttpEntity<>(sendMsgBody, headers);
    	        JSONObject jsonResult = restTemplate.postForObject(url, httpEntity, JSONObject.class);
    	        JSONObject responseData = jsonResult ;
    	
    	        Integer errorCode = responseData.getInteger("errcode");
    	        String errorMessage = responseData.getString("errmsg");
    	        if (errorCode == 0) {
    	            log.info("订餐通知消息发送成功");
    	        } else {
    	            log.info("订餐通知消息发送失败,errcode:{},errorMessage:{}", errorCode, errorMessage);
    	        }
    	    }
    
    • 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
    调用
        @GetMapping("wxSendSuccess")
        @ApiOperation(value = "微信小程序发送订阅消息通知")
        public boolean wxSendSuccess(){
            String openId = "oks*******************Gk";
            HashMap<String, String> map = new HashMap<>();
            map.put("thing1","***");
            map.put("time2","2022-11-03 12:13");
            map.put("thing17","405");
            return wxService.wxSendMsgSuccess(openId,map);
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    结果

    在这里插入图片描述

    总结

    咱们这个消息的订阅前端授权一次后,咱们也就只能发送成功一次,在接收订阅消息的用户没有同意接收订阅信息的时候,我们调用接口给用户发送订阅消息基本都会被拒绝。请求结果如下:

    errcode:43101,errorMessage:user refuse to accept the msg rid: 6363495-2267c4de-7aa0fab1

    如果你的小程序没有进行政府 医疗等认证,那你就不能长期订阅,所以每一次订阅消息的发送都需要接收方的一次授权,并且接收放的授权次数是可以累加的,比如说这次订阅了你没发订阅消息,下次再继续订阅,你就可以连续发两条订阅成功。但是在特殊情况下小程序方也会清楚所有的授权次数。

  • 相关阅读:
    论文阅读(11) 操纵涡环来提高机动性 (2015)
    【51单片机】:串口通信控制LED亮灭任务
    展会预告丨中国海洋装备博览会盛大开幕!箱讯科技亮相1T18展位
    超视频时代,什么样的技术会成为底座?
    改进粒子速度和位置更新公式的粒子群优化算法
    SQL命令及MariaDB(一)
    Java开发者的Python快速进修指南:实战之跳表pro版本
    动态规划:砍死怪兽的概率
    【ES】springboot集成ES
    docker logs命令详解
  • 原文地址:https://blog.csdn.net/m0_46636892/article/details/127709917