微信小程序消息订阅Java

news2024/11/28 21:51:49

前言

编写日期 : 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地方"
      }
  }
}

代码

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

  • 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;
	    }

发送订阅消息

请求参数

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
}

请求参数中的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 +
                '}';
    }
}

发送消息

	@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);
	        }
	    }

调用

    @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);
    }

结果

在这里插入图片描述

总结

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/3559.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux企业应用——Docker(三)之史上最简单,一篇学会Docker私有仓库Harbor的搭建

文章目录一、什么是Harbor二、搭建私有仓库1.安装docker-ce2.安装软件库包3.创建认证三、在另一台已安装docker的主机上四、搭建Harbor测试docker hub虽然方便&#xff0c;但是还是有限制&#xff1a;• 需要internet连接&#xff0c;速度慢• 所有人都可以访问• 由于安全原因…

SharpShooter Reports.Web 7.5 Crack

SharpShooter Reports.Web 是真正的跨平台报告查看器&#xff0c;因为它能够向 Windows、Linux、Mac OS 甚至 iOS 和 Android 平板电脑和手机提供报告。创建的报告可以轻松集成到任何网站和网页中&#xff0c;包括 MS MVC 和 ASP.NET 应用程序。by Ω578867473报告设计方便易用…

22级第三次比赛题解

文章目录A (1). Ashy与几何(贪心几何)B (2). One eye question of hengheng(前缀和)C Fox hate oranges(模拟)D KingZhangs Similar pair (思维)E (5). 38秒你敢交我A题&#xff1f;F (6). How many numbers are thereG (7). Jump lattice (思维)H (8). CCoolGuang Conjecture(…

五十万字总结,2022最新Java面试八股汇总(含答案,收藏版)

写在前面 今年的疫情&#xff0c;让招聘面试变得雪上加霜。已经有不少大厂&#xff0c;如腾讯、字节跳动的招聘名额明显减少&#xff0c;面试门槛却一再拔高&#xff0c;如果不用心准备&#xff0c;很可能就被面试官怼得哑口无言&#xff0c;甚至失去了难得的机会。 现如今&a…

【网安神器篇】——瑞士军刀Netcat

作者名&#xff1a;Demo不是emo 主页面链接&#xff1a;主页传送门创作初心&#xff1a;舞台再大&#xff0c;你不上台&#xff0c;永远是观众&#xff0c;没人会关心你努不努力&#xff0c;摔的痛不痛&#xff0c;他们只会看你最后站在什么位置&#xff0c;然后羡慕或鄙夷座右…

G1D5-Intriguing properties of neural networks

今天考完软考中项啦~~明天还有翻译&#xff0c;不过不想复习啦~ 读读论文啦~读网络安全文献课需要的叭 这篇2013年的intruging properties of neural networks的作者都好大佬&#xff01;&#xff01;&#xff01; 先来看看h指数是什么哈~ 一、h指数 一个人的所有论文中&…

C语言题解 | 去重数组合并数组

… &#x1f333;&#x1f332;&#x1f331;本文已收录至&#xff1a;C语言题解系列 更多知识尽在此专栏中&#xff01; 文章目录&#x1f349;前言&#x1f349;正文&#x1f34d;去重数组&#x1f34c;分析&#x1f34c;思路&#x1f34c;代码&#x1f34d;合并数组&#x1…

Allegro基本规则设置指导书之Physical规则设置

Allegro基本规则设置指导书之Physical规则设置 下面介绍规则设置指导书之Physical规则设置 点击Set-up-constraints-Constraint Manager打开规则管理器 设置Physical规则 打开时默认有个Default规则 从左往右 Line Width 最小线宽 最大线宽 Neck 最小线宽 Neck的走线长度 如…

动态内存分配:malloc、calloc、realloc(超详解析,多维度分析,小白一看就懂!!!!)

目录 一、前言 二、动态内存的简单介绍 &#x1f349;什么是动态内存分配 &#x1f34e;为什么要使用动态内存分配 三、动态内存函数的介绍和拓展 &#x1f34b;malloc()函数 &#x1f34a;free()函数 &#x1f34c;calloc()函数 &#x1f347;realloc()函数 四、…

UDP套接字编程详解

UDP 是OSI&#xff08;Open System Interconnection&#xff0c;开放式系统互联&#xff09; 参考模型中一种无连接的传输层协议。 UDP协议与TCP协议一样用于处理数据包。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点&#xff0c;也就是说&#xff0c;当报文发送之…

【状语从句练习题】综合训练

1. 改正错误 1.第二个 either 改为or 2.后面的 he plays 去掉&#xff0c;不必要的重复 3.but 去掉 4.cold 后 and 5.I went out. 加 个 I. 6.第一个 will 去掉&#xff0c;get 变为 ges 7.so 去掉 8.去掉第二个 either 9.去掉后面的 I need 10.Although/but 去掉一个 11.后…

【JavaSE】类和对象——上

文章目录1. 类的定义1.1 什么是类1.2 如何定义类2. 类的实例化3. this关键字3.1 this访问成员变量和成员方法3.2 构造方法及this()我们给类初始化的方法有&#xff1a;3.2.1 就地初始化3.2.2 使用 set 方法赋值3.2.3 使用构造方法4. 如何便捷的打印对象中属性1. 类的定义 1.1 什…

【Pytorch Lighting】第 1 章:PyTorch Lightning adventure

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

数据中心通识

文章目录一 数据中心定义特点二 机房定义内部物品物理环境三 服务器定义外型分类与PC相比的优点超线程技术固态硬盘和机械硬盘四 网络定义OSI模型局域网的拓扑结构TCP/IP协议常见端口号IP地址介绍、格式、分类、子网掩码DNS三层交换机五 存储格式化缓存RAID技术存储体系架构IP-…

二叉树的前中后序遍历(递归与迭代)

作者&#xff1a;~小明学编程 文章专栏&#xff1a;Java数据结构 格言&#xff1a;目之所及皆为回忆&#xff0c;心之所想皆为过往 目录 简介 前序遍历 递归法 迭代法 中序遍历 递归法 迭代法 后序遍历 递归法 迭代法 简介 前面学习二叉树的时候&#xff0c;已经学过…

渗透测试 | 域名信息收集

0x00 前言 信息收集可以说是在渗透测试中最重要的一部分&#xff0c;上文对 IP 信息收集做了一个简要的叙述&#xff0c;认识了 CDN 技术和网络空间搜索引擎。但是很多网站的主站因为访问流量过大的原因通常会使用 CDN 技术&#xff0c;同时也可以有效防止 DDOS 攻击。在域名信…

前端面经 强缓存与协商缓存

前端面经 强缓存与协商缓存 图片多来自第三方平台 文章目录前端面经 强缓存与协商缓存适用场合浏览器缓存的过程缓存规则强缓存&#xff08;本地缓存&#xff09;协商缓存缓存分为两种&#xff1a;强缓存和协商缓存&#xff0c;根据响应的header内容来决定 获取资源形式状态码…

【C++】二叉搜索树

前言 hi~大家好呀&#xff0c;欢迎点进我的C学习笔记~ 我的前一篇C笔记链接~ 【C】多态_柒海啦的博客-CSDN博客 本篇需要用到的基础二叉树C语言实现链接~ 用c语言实现一个简单的链表二叉树_柒海啦的博客-CSDN博客_c语言建立二叉树链表 我们知道&#xff0c;查找一个数据会有很多…

数据库基本操作

目录 数据库操作 创建数据库 查看数据库 选择数据库 删除数据库 注释 数据表操作 创建数据表 查看数据表 查看数据表 查看数据表的相关信息 修改数据表 修改数据表名称 修改表选项 查看表结构 查看数据表的字段信息 查看数据表的创建信息 查看数据表结构 修…

linux进程间通信之共享内存

目录 一&#xff0c;共享内存原理 二&#xff0c;创建共享内存 1&#xff0c;shmget创建共享内存 2&#xff0c;shmat挂接共享内存 3&#xff0c;shmdt取消挂接共享内存 4&#xff0c;shmctl删除共享内存 三&#xff0c;代码使用 1,com.hpp 2&#xff0c;ipc_client.c…