微信小程序订阅消息开发指南(java)

第一步 准备阶段

1、你得有一个小程序并且认证了个人的也行

2、开通订阅消息

小程序后台->功能->订阅消息

3、公共模板库选择一个模板

选择的时候,选择你需要的字段,因为字段有限制

4、我的模板点击详情

详情内容,模板 id 都是需要提供个服务端开发人员的

第二步 编码阶段

小程序端

小程序消息订阅,需要用户确认

1、首先小程序授权登陆获取 code

官网示例:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html

wx.login({
success (res) {
if (res.code) {
//发起网络请求
wx.request({
url: 'https://example.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
// 结果 {errMsg: "login:ok", code: "0a3kK4Ga10Gk3F0oBAHa1mGyRl3kK4Gd"}

uni-App 示例:https://uniapp.dcloud.net.cn/api/plugins/login.html#login

uni.login({
provider: 'weixin', //使用微信登录
success: function (loginRes) {
console.log(loginRes)
}
});
// 结果 {errMsg: "login:ok", code: "0a3kK4Ga10Gk3F0oBAHa1mGyRl3kK4Gd"}

2、将 code 传给服务端 获取用户唯一标识 openId

3、通过代码起小程序消息订阅界面、用户点击确定ok,小程序工作结束

官方示例:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/subscribe-message/wx.requestSubscribeMessage.html

tmplIds 填写模板 id 即可,最多三个

wx.requestSubscribeMessage({
tmplIds: [''],
success (res) {
console.log(res)
}
})

4、注意事项:

避免重复拉起用户订阅通知,可以通过微信提供的 getSetting 判断用户是否订阅了,如果没有就拉起。

注意下面是用uniapp写的,方法前缀是uni 如果你小程序代码记得修改 wx 以及提示组件

到此小程序工作结束

getSetting() {
uni.getSetting({
withSubscriptions: true, // 获取用户订阅状态
success(res) {
// false 表示用户未订阅改消息
if (!res.subscriptionsSetting.mainSwitch) {
this.subscribeMessage();
} else {
uni.showToast({
title: '已订阅',
icon: 'none'
})
}
}
})
},
subscribeMessage() {
uni.requestSubscribeMessage({
tmplIds: ['模板id'],
success(res) {
if (res.errMsg === 'requestSubscribeMessage:ok') {
uni.showToast({
title: '订阅成功',
icon: 'none'
})
}
}
})
}

服务端

微信小程序的 appidsecret 小程序后台->开发->开发管理->开发设置->开发者 ID

注意事项

  1. http 请求这里使用 apache 的工具类,你也可以使用别的
  2. 微信消息模板字段 thing 字段有长度限制20,超过会失败
  3. 以下演示代码,生产环境还需进行优化

1、通过 code 获取用户 open id 官网文档

 public String getOpenId(String code) throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
params.put("appid", Constants.APPLET_APP_ID);
params.put("secret", Constants.APPLET_SECRET);
params.put("js_code", code);
params.put("grant_type", "authorization_code"); String url = handleParams("https://api.weixin.qq.com/sns/jscode2session", params);
HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
} public static void main(String[] args) throws IOException {
HttpUtils httpUtils = new HttpUtils();
String token = httpUtils.getToken();
System.out.println(token);
}

响应结果:

{"access_token":"67_u22CQaWq22222222Q4griDE6kiT5hwg7jVxedn8J9te17Az1oWGGxPgB22222229Y4Wm6h_Yzci7-FSDjeH8YG6DsCOYrQXJCWsPXhT6nWbKIWCXfABACID","expires_in":7200}

2、通过 appidsecret 获取 token 超时 7200 秒 可 redis 缓存 官方文档

public String getToken() throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
params.put("appid", Constants.APPLET_APP_ID);
params.put("secret", Constants.APPLET_SECRET);
params.put("grant_type", "client_credential"); String url = handleParams("https://api.weixin.qq.com/cgi-bin/token", params);
HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity(); // 响应结果 return EntityUtils.toString(entity, CharSetType.UTF8.getType());
}

3、指定用户推送消息结束 官方文档

public String pushMsg(String token) throws IOException {

        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>(); // 处理微信推送数据结构
JSONObject mapData = new JSONObject();
Map<String, Object> map1 = new HashMap<>();
map1.put("value", "任务名称");
mapData.put("thing2", map1); Map<String, Object> map2 = new HashMap<>();
map2.put("value", "2022-04-03 10:00:00");
mapData.put("time3", map2); Map<String, Object> map3 = new HashMap<>();
map3.put("value", "描述信息");
mapData.put("thing4", map3); Map<String, Object> map4 = new HashMap<>();
map4.put("value", "备注信息");
mapData.put("thing10", map4); Map<String, Object> map5 = new HashMap<>();
map5.put("value", "任务来源");
mapData.put("thing11", map5); params.put("template_id", "templateId");// 模板 id
params.put("touser", "openId"); // open id
params.put("data", mapData); // 数据
params.put("page", "page"); // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转
params.put("miniprogram_state", "trial"); //developer为开发版;trial为体验版;formal为正式版;默认为正式版
params.put("lang", "zh_CN"); // HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + token);
httpPost.addHeader("ContentTyp", "application/json"); // 参数转 JSON 格式
String json = objToStr(params);
StringEntity stringEntity = new StringEntity(json, CharSetType.UTF8.getType());
stringEntity.setContentEncoding(CharSetType.UTF8.getType());
httpPost.setEntity(stringEntity); CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
}

4、完整代码

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.github.chenlijia1111.utils.core.enums.CharSetType;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.jeecg.modules.video.utitls.Constants; import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors; /**
* @description:
* @author: Mr.Fang
* @create: 2023-04-03 17:06
**/ public class HttpUtils { /**
* description: 获取token,返回结果为 JSON 自行转 map
* create by: Mr.Fang
*
* @return: java.lang.String
* @date: 2023/4/3 17:46
*/
public String getToken() throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
params.put("appid", Constants.APPLET_APP_ID);
params.put("secret", Constants.APPLET_SECRET);
params.put("grant_type", "client_credential"); String url = handleParams("https://api.weixin.qq.com/cgi-bin/token", params);
HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity(); // 响应结果 return EntityUtils.toString(entity, CharSetType.UTF8.getType());
} /**
* description: 获取 open id,返回结果为 JSON 自行转 map
* create by: Mr.Fang
*
* @param: [code]
* @return: java.lang.String
* @date: 2023/4/3 17:46
*/
public String getOpenId(String code) throws IOException {
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>();
params.put("appid", Constants.APPLET_APP_ID);
params.put("secret", Constants.APPLET_SECRET);
params.put("js_code", code);
params.put("grant_type", "authorization_code"); String url = handleParams("https://api.weixin.qq.com/sns/jscode2session", params);
HttpGet httpGet = new HttpGet(url); CloseableHttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
} /**
* description: 消息推送 返回结果为 JSON 自行转 map;token 调用 getToken获取
* create by: Mr.Fang
*
* @param: [token]
* @return: java.lang.String
* @date: 2023/4/3 17:46
*/
public String pushMsg(String token) throws IOException { CloseableHttpClient httpClient = HttpClientBuilder.create().build();
Map<String, Object> params = new HashMap<>(); // 处理微信推送数据结构
JSONObject mapData = new JSONObject();
Map<String, Object> map1 = new HashMap<>();
map1.put("value", "任务名称");
mapData.put("thing2", map1); Map<String, Object> map2 = new HashMap<>();
map2.put("value", "2023-04-03 12:00:00");
mapData.put("time3", map2); Map<String, Object> map3 = new HashMap<>();
map3.put("value", "描述信息");
mapData.put("thing4", map3); Map<String, Object> map4 = new HashMap<>();
map4.put("value", "备注系信息");
mapData.put("thing10", map4); Map<String, Object> map5 = new HashMap<>();
map5.put("value", "抖音");
mapData.put("thing11", map5); params.put("template_id", "templateId");// 模板 id
params.put("touser", "openId"); // open id
params.put("data", mapData); // 数据
params.put("page", "page"); // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)。该字段不填则模板无跳转
params.put("miniprogram_state", "trial"); //developer为开发版;trial为体验版;formal为正式版;默认为正式版
params.put("lang", "zh_CN"); // HttpPost httpPost = new HttpPost("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + token);
httpPost.addHeader("ContentTyp", "application/json"); // 参数转 JSON 格式
String json = objToStr(params);
StringEntity stringEntity = new StringEntity(json, CharSetType.UTF8.getType());
stringEntity.setContentEncoding(CharSetType.UTF8.getType());
httpPost.setEntity(stringEntity); CloseableHttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity(); // 响应结果
return EntityUtils.toString(entity, CharSetType.UTF8.getType());
} /**
* description: 对象转 字符串
* create by: Mr.Fang
*
* @param: [obj]
* @return: java.lang.String
* @date: 2023/4/3 17:45
*/
public static String objToStr(Object obj) { ObjectMapper objectMapper = new ObjectMapper();
if (Objects.nonNull(obj)) {
try {
String jsonStr = objectMapper.writeValueAsString(obj);
return jsonStr;
} catch (JsonProcessingException var2) {
var2.printStackTrace();
}
} return null;
} /**
* description: map 转 URL 地址拼接
* create by: Mr.Fang
*
* @param: [url, params]
* @return: java.lang.String
* @date: 2023/4/3 17:45
*/
public String handleParams(String url, Map<String, Object> params) {
if (params.size() != 0) {
Set<Map.Entry<String, Object>> entries = params.entrySet();
String paramsString = entries.stream().map((e) -> {
try {
StringBuilder sb = new StringBuilder();
sb.append(URLEncoder.encode(e.getKey(), CharSetType.UTF8.getType()));
sb.append("=");
if (Objects.nonNull(e.getValue())) {
sb.append(URLEncoder.encode(e.getValue().toString(), CharSetType.UTF8.getType()));
} return sb.toString();
} catch (UnsupportedEncodingException var2) {
var2.printStackTrace();
return null;
}
}).collect(Collectors.joining("&"));
return url + "?" + paramsString;
}
return url;
} }

微信小程序订阅消息开发指南(java)的更多相关文章

  1. uni-app + .NET 7实现微信小程序订阅消息推送

    微信小程序的订阅消息是小程序的重要能力之一,为实现服务的闭环提供更优的体验.订阅消息我们应该经常见到,比如下单成功之后的服务通知,支付成功后的支付成功通知,都属于小程序的订阅消息. 本文只实现一次性订 ...

  2. 微信小程序订阅消息,我踩过的坑都在这里了!

    旧的模板消息将在 2020 年 1 月 10 号全面下架,也就是今天,不过貌似现在还可以用!!!我已经改好了,只不过还没有上线,准备坚持到最后一天! 0.订阅消息 简单介绍一下订阅消息的特点: 用户授 ...

  3. 微信小程序订阅消息

    概述 消息能力是小程序能力中的重要组成,我们为开发者提供了订阅消息能力,以便实现服务的闭环和更优的体验. 订阅消息推送位置:服务通知 订阅消息下发条件:用户自主订阅 订阅消息卡片跳转能力:点击查看详情 ...

  4. 微信小程序订阅消息调研

    相关资料 背景:微信模板消息已正式下架,改为订阅消息,详情如下: 服务变更通知 订阅消息:订阅消息相关内容如下: 订阅消息 接口设计 获取接口访问凭证 :根据appId和secret获取接口访问凭证a ...

  5. 微信小程序的模板消息与小程序订阅消息

    小程序订阅消息 功能介绍 消息能力是小程序能力中的重要组成,我们为开发者提供了订阅消息能力,以便实现服务的闭环和更优的体验. 订阅消息推送位置:服务通知 订阅消息下发条件:用户自主订阅 订阅消息卡片跳 ...

  6. node配置微信小程序解密消息以及推送消息

    上一篇文章介绍过 微信小程序配置消息推送,没有看过的可以先去查看一下,这里就直接去把那个客服消息接口去解密那个消息了. 在这里我选择的还是json格式的加密. 也就是给小程序客服消息发送的消息都会被微 ...

  7. node.js微信小程序配置消息推送

    在开发微信小程序时,有一个消息推送,它的解释是这样的. 消息推送具体的内容是下面的这个网址   https://developers.weixin.qq.com/miniprogram/dev/fra ...

  8. 微信小程序的功能开发工具跟公众号的差别,小程序是一种减负思维对简单APP是巨大打击

    微信小程序的功能开发工具跟公众号的差别,小程序是一种减负思维对简单APP是巨大打击 摘要: 小程序和公众号最大的区别有如下四点:1.小程序没有粉丝,开发者在后台能看到的只能是累计用户访问数以及实时统计 ...

  9. 微信小程序模板消息后端代码

    利用spring 事件发送模板消息 1.定义事件 import com.ruoyi.project.salerauth.domain.TemplateMessage; import org.sprin ...

  10. 微信小程序订阅

    微信小程序订阅 摘要 1.基于promise封装微信小程序订阅 2.解决由于微信基础库版本低下的兼容 3.解决“总是保持以上选择,不再询问”的取消状态 主要运用API: requestSubscrib ...

随机推荐

  1. jsPDF 添加 中文字体 分页打印 移除空白页

    jsPDF2.5版本 默认不支持utf-8的字体 具体看官方的说明,默认是不支持中文的.要使用中文需要自己添加字体. 1 将字体转换为base64编码 然后引入.也可以直接引入二进制文件,但没试过这个 ...

  2. 域名之A记录,CNAME,NS联系和区别

    域名解析中常常涉及:A记录,CNAME,NS 1. A记录 又称IP指向,用户可以在此设置子域名并指向到自己的目标主机地址上,从而实现通过域名找到服务器.说明:指向的目标主机地址类型只能使用IP地址; ...

  3. Java多线程之Callable和Future

    Java多线程之Callable和Future 本篇说明的是Callable和Future,它俩很有意思的,一个产生结果,一个拿到结果. Callable接口类似于Runnable,从名字就可以看出来 ...

  4. centos8 \CentOS 9 Stream \Oracle Linux8\Oracle Linux 9 rpm 安装mysql8.0.28 mysql8.0.34

    centos8 rpm 安装mysql8.0.28 检查 检测系统是否自带安装 MySQL 命令如下: rpm -qa | grep mysql 如果如下存在已安装的包,就需要卸载 mysql80-c ...

  5. 重新整理.net core 计1400篇[十] (.net core 中的依赖注入的服务的生命周期)

    前言 首先我们知道一个东西,那就是生命周期和timelife 的配置有关. 正文 首先看下IServiceProvider的数据结构: 其数据结构是一颗树: 我是一个抽象画家,红色部分是IServic ...

  6. vue watch的this 到底是什么?

    正文 watch: { value: (newV, oldV) => { this.a = newV; } } 加入该vue对象中,data 有: { data:{ a:5 } } 那么请问,如 ...

  7. 使用OpenMMLab系列的开源库时,常用的脚本合集。

    使用OpenMMLab系列的开源库时,常用的脚本合集. 开源仓库:gy-7/mmlab_scripts 脚本解释: anchor_visiual.py 生成的锚框可视化 aug_test.py 自动数 ...

  8. 手动给docusaurus添加一个搜索

    新版博客用docusaurus重构已经有些日子了,根据docusaurus的文档上也申请了Algolia,想一劳永逸的解决博客的搜索问题.但是流水有意,落花无情. algolia总是不给我回复,我只能 ...

  9. 痞子衡嵌入式:在i.MXRT1xxx系列上用NAND型启动设备时可用两级设计缩短启动时间

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家分享的是在i.MXRT1xxx系列上用NAND型启动设备时可用两级设计缩短启动时间. 去年痞子衡写过一篇骚操作文章 <借助i.MXRT10 ...

  10. 力扣1077(MySQL)-项目员工Ⅲ(中等)

    题目: 写 一个 SQL 查询语句,报告在每一个项目中经验最丰富的雇员是谁.如果出现经验年数相同的情况,请报告所有具有最大经验年数的员工. 查询结果格式在以下示例中: employee_id 为 1 ...