官方接口链接:
一、流程:
1、准备号小程序
2、小程序在订阅消息端创建消息模板拿到TemplateID
3、 前端需要配置消息ID,订阅服务通知
4、后端调接口发送通知到用户openId
二、使用
1、小程序创建消息模板
在微信小程序添加订阅消息模板
小程序后台链接:小程序
1、注意消息模板的ID,前端和后端都需要
2、点击详情下面有对应的字段内容,后端需要返回对应字段JSON格式数据
2、 小程序后台配置
封装成工具类使用
直接调用sendTemplateMsg()方法即可。
需要参数:
a、用户的openId、
b、消息模板ID
c、消息主体的JSON字段数据
注意:注意JSON格式,参照官网
如果JSON格式不对:(时间格式不能包含字母或无关符号)
result:{"errcode":47003,"errmsg":"argument invalid! data.character_string22.value rid: 66012b9d-00baed03-2e813aea"
1、构建工具类
/**
* 微信消息通知
*/
public class WxMessageConfig {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* 发送模板消息 注意格式
*/
public static boolean sendTemplateMsg(String openId, String templateId,WxMessageDto wxMessageDto) {
String access_token = getAccessToken();
Map<String, Object> paramMap = wxMessageMap(wxMessageDto);
paramMap.put("touser", openId);
// 模版
paramMap.put("template_id", templateId);
// 跳转小程序(不加微信界面没有跳转那一行)
paramMap.put("page", "index");
String url = WxConstants.POST_MESSAGE_URL;
String jsonStr = null;
try {
// 转JSON
ObjectMapper objectMapper = new ObjectMapper();
jsonStr = objectMapper.writeValueAsString(paramMap);
} catch (JsonProcessingException e) {
log.error("消息通知转JSON格式异常");
e.printStackTrace();
}
try {
jsonStr = HttpUtil.post(url, access_token, jsonStr);
} catch (Exception e) {
log.error("小程序服务通知异常-转化异常", e);
}
JSONObject jsonObj = JSONObject.parseObject(jsonStr);
String errcode = jsonObj.get("errcode").toString();
Object errmsg = jsonObj.get("errmsg");
if (!errcode.equals("0")) {
log.error("微信通知消息发送失败:code=" + errcode + "msg=" + errmsg);
return false;
}
return true;
}
/**
* 获取access_Token(发送消息需要)
* @return
*/
private static String getAccessToken() {
/**
* 非spring环境获取bean(注入redis工具类) 工具类 redis获取缓存的的token
*/
RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
/**
* public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
*/
String access_token = redisCache.getCacheObject("wx_access_token");
if (access_token == null) {
String url = WxConstants.GET_ACCESS_TOKEN_URL.replace("APPID", WxConstants.APPID)
.replace("APPSECRET", WxConstants.SECRET);
String jsonStr = HttpUtil.httpGet(url);
JSONObject jsonObj = JSONObject.parseObject(jsonStr);
access_token = jsonObj.getString("access_token");
int expires_in = Integer.parseInt(jsonObj.getString("expires_in"));
redisCache.setCacheObject("wx_access_token", access_token, expires_in, TimeUnit.SECONDS);
}
return access_token;
}
/**
* 构建消息主体JSON数据
* @param wxMessageDto
* @return
*/
public static Map<String, Object> wxMessageMap(WxMessageDto wxMessageDto){
// 时间格式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 格式化时间
String formattedDateTime = wxMessageDto.getTime().format(formatter);
HashMap<String, Object> paramMap = new HashMap<>();
// 创建消息内容的 Map 对象
Map<String, Object> messageContent = new HashMap<>();
messageContent.put("thing13", new HashMap<String, Object>() {{
put("value", wxMessageDto.getProductName());
}});
messageContent.put("amount4", new HashMap<String, Object>() {{
put("value", wxMessageDto.getPrice());
}});
messageContent.put("character_string22", new HashMap<String, Object>() {{
put("value", wxMessageDto.getOrderNo());
}});
messageContent.put("thing24", new HashMap<String, Object>() {{
put("value", wxMessageDto.getAddress());
}});
messageContent.put("time23", new HashMap<String, Object>() {{
put("value", formattedDateTime);
}});
paramMap.put("data", messageContent);
return paramMap;
}
}
2、微信相关链接、消息模板ID常量
/**
* 微信相关参数
*/
public class WxConstants {
public static final String APPID = "wxexxxxxxxxxxx";
public static final String SECRET = "b9bc54xxxxxxxxxxxxxxxxxxxxxx";
// public static final String GET_ACK_URL = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code"; // 网页
public static final String GET_ACK_URL2 = "https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_cod"; // 小程序
public static final String GET_USER_URL = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID"; // 网页
// public static final String POST_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN";
// 小程序消息通知
public static final String GET_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";
public static final String POST_MESSAGE_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";
public static final String WX_TEMPLATE_ID_ORDER1 = "8u_2j-thz_6TDIiEZUXOWqwNNbwDoVbdXIwlWB5K91k";
}
3、消息主体的dto
/**
* 消息模类主体数据
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class WxMessageDto implements Serializable {
private String productName;
private String price;
private String orderNo;
private String address;
private LocalDateTime time;
}
4.3 前端配置
用微信开发工具做前端测试:
前端uni-app只需要发送对应请求订阅消息即可(官方规定不能页面加载触发订阅请求,只能点击某个事件触发订阅)
<template>
<view class="content">
<image class="logo" src="/static/logo.png"></image>
<view class="text-area">
<text class="title">{{title}}</text>
</view>
<view >
<text class="title">{{title}}</text>
</view>
<view class="content">
<button @click="requestSubscription">点击订阅消息</button>
</view>
</view>
</template>
<script>
export default {
data() {
return {
title: 'Hello2',
}
},
onLoad() {
const that = this; // 保存组件实例的引用
wx.login({
success (res) {
console.log('登录ok!' + res.code);
that.title = res.code;
}
});
},
methods: {
requestSubscription() {
console.log('点击了订阅1')
wx.requestSubscribeMessage({
tmplIds: ['8u_2j-thz_6TDIiEZUXOWqwNNbwDoVbdXIwlWB5K91k'], // 数组,最多3个订阅
success (res) {
console.log('订阅消息结果', res);
// 处理订阅消息的结果
},
error(){
console.error(222)
}
});
}
}
}
</script>
<style>
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
user-select: text;
}
</style>
点击订阅即可,每次最多订阅3个(手机端是下面弹出订阅,同时可以选择订阅!此处用模拟器测试前端订阅)
4.4 后端发送消息推送测试
1、springboot测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class AppTest {
@Test
public void shouldAnswerWithTrue() throws Exception {
String openId = "otvf_5HrOcky90_sqST2kvKTvr1k"; // 用户的openId
String templateId = WxConstants.WX_TEMPLATE_ID_ORDER1; // 模板消息Id
WxMessageDto wxMessageDto = new WxMessageDto(); // 消息主体
wxMessageDto.setProductName("黄铜");
wxMessageDto.setPrice("36.8元");
wxMessageDto.setOrderNo("2024032516282222hs9999");
wxMessageDto.setAddress("四川省成都市双流区龙桥地铁站");
wxMessageDto.setTime(LocalDateTime.now());
boolean boo = WxMessageConfig.sendTemplateMsg(openId, templateId, wxMessageDto);
System.out.println("=====================================");
System.out.println(boo);
}
2、控制台输出:
注意:报错就参考官方错误码。注意用户是否订阅,不然报错:
用户未订阅消息,报错如下:
或者
代码配置参数问题(注意字段格式是否满足要求):
result:{"errcode":47003,"errmsg":"argument invalid! data.character_string22.value rid: 66012b9d-00baed03-2e813aea"
成功响应如下:
发送成功字样 errcode:0 errmsg:ok
3、微信的服务通知提醒