模板消息
由于微信自 2023 年 9 月 20 日起,下发统一消息接口将被收回,无法下发小程序模板消息与公众号模板消息。
如业务需下发模板消息,只能通过公众号模板消息或者小程序订阅模板消息能力满足需求:公众号模板消息
、小程序订阅模板消息
。
获取 ACCESS_TOKEN
获取公众号、小程序全局唯一后台接口调用凭据,token
有效期为 7200s
,简单做缓存存储(资质不同获取次数是有限的)。
接口地址:
代码语言:javascript复制GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=&secret=
代码语言:javascript复制@Slf4j
public class WxapiUtil {
private static ConcurrentHashMap<String, JSONObject> accessTokenMap = new ConcurrentHashMap();
/**
* @MonthName: getToken
* @Description: 获取token
* @Param: [appid, secret]
* @return: java.lang.String
**/
public synchronized static String getToken(String appid, String secret) {
JSONObject obj = accessTokenMap.get(appid);
if (Objects.isNull(obj) || Duration.between((Instant) obj.get("time"), Instant.now()).getSeconds() > 7100) {
String token = getAccessToken(appid, secret);
if (Objects.nonNull(token) && token.length() > 10) {
accessTokenMap.put(appid, JSONObject.of("token", token, "time", Instant.now()));
log.info("========获取 AccessToken======:{}", accessTokenMap.get(appid));
}
return token;
} else {
log.info("========缓存取 AccessToken======:{}", obj);
return obj.getString("token");
}
}
public static String getAccessToken(String appid, String secret) {
String AccessTokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" appid "&secret=" secret;
HttpClient client = null;
String accessToken = null;
try {
client = new DefaultHttpClient();
HttpGet httpget = new HttpGet(AccessTokenUrl);
ResponseHandler<String> responseHandler = new BasicResponseHandler();
String response = client.execute(httpget, responseHandler);
log.info("获取AccessToken返回值:{}", response);
JSONObject json = JSONObject.parseObject(response);
accessToken = String.valueOf(json.get("access_token"));
} catch (Exception e) {
log.error("获取token异常:", e);
} finally {
client.getConnectionManager().shutdown();
}
return accessToken;
}
}
公众号模板消息
模板消息仅用于公众号向用户发送重要的服务通知,只能用于符合其要求的服务场景中,如信用卡刷卡通知,商品购买成功通知等。不支持广告等营销类消息以及其它所有可能对用户造成骚扰的消息。
当前每个账号的模板消息的日调用上限为
10万
次,单个模板没有特殊限制。 当账号粉丝数超过10W/100W/1000W
时,模板消息的日调用上限会相应提升,以公众号MP后台开发者中心页面中标明的数字为准。
发送模板消息
该接口用于发送订阅消息
文档地址:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Template_Message_Interface.html
接口地址:
代码语言:javascript复制POST https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
模板申请
登录 微信公众平台
在 广告与服务-模板消息
中开通模板消息。
在 模板消息
中选择符合自己业务需求的模板开通,如没有自己业务需求的模板,可申请符合自己需求的模板。
服务端消息发送
代码语言:javascript复制/**
* @MonthName: sendTemplateMessage
* @Description: 公众号模板消息
* @Param:
* appid:公众号 appid,
* secret:公众号 secret,
* mappId: 小程序 appid,
* openId:用户 openid (公众号授权的 openid),
* pagepath:小程序跳转地址,如:pages/home/home,
* url:公众号模板消息所要跳转的url(可以为空),
* templateId:公众号模板id,
* data:公众号模板消息的数据,如:{"thing1":{"value":"测试"}}
* @return: java.lang.String
**/
public static String sendTemplateMessage(String appid, String secret, String mappId, String openId, String pagepath, String url, String templateId, JSONObject data) {
HttpClient client = null;
try {
client = HttpClients.createDefault();
// 获取 access_token
String token = getToken(appid, secret);
if (Objects.isNull(token) && Objects.equals("", token)) {
log.error("获取AccessToken异常");
return "获取 AccessToken 异常";
}
// 发送消息
String messageUrl = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
HttpPost httpPost = new HttpPost(messageUrl token);
JSONObject params = new JSONObject();
params.put("touser", openId); // 接收者openid
params.put("template_id", templateId); // 模板ID
params.put("url", url); // 模板跳转链接
params.put("data", data); // 模板数据
// 跳小程序所需数据,不需跳小程序可不用传该数据
JSONObject miniprogram = new JSONObject();
miniprogram.put("appid", mappId);
miniprogram.put("pagepath", pagepath);
params.put("miniprogram", miniprogram);
httpPost.setEntity(new StringEntity(params.toString(), "UTF-8"));
String res = client.execute(httpPost, new BasicResponseHandler());
if (Objects.nonNull(res) && !Objects.equals("", res)) {
JSONObject obj = JSONObject.parseObject(res);
if (Objects.equals("0", obj.getString("errcode"))) {
return "发送消息成功!";
}
return obj.getString("errmsg");
}
} catch (Exception e) {
log.error("发送模板消息异常:{}", e);
} finally {
client.getConnectionManager().shutdown();
}
return "发送消息失败!";
}
注意:url 和 miniprogram 都是非必填字段,若都不传则模板无跳转;若都传,会优先跳转至小程序。开发者可根据实际需要选择其中一种跳转方式即可。当用户的微信客户端版本不支持跳小程序时,将会跳转至url。
小程序模板消息
发送模板消息
该接口用于发送模板消息
接口名称:sendMessage
文档地址:https://developers.weixin.qq.com/miniprogram/dev/OpenApiDoc/mp-message-management/subscribe-message/sendMessage.html
接口地址:
代码语言:javascript复制POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN
模板申请
登录 微信公众平台
在 功能-订阅消息
中开通订阅消息。
在 订阅消息
中选择符合自己业务需求的模板开通,模板分为 一次性订阅
和 长期订阅
。
- • 一次性订阅:用户授权一次,即可发送一次模板消息,无法再次发送;
- • 长期订阅:用户授权一次,可发送多次模板消息。
长期订阅模板:
- • 长期订阅消息目前只对
政务民生
、医疗
、交通
、金融
、教育
等部分二级行业类目进行开放,长期订阅模板库有模板可以进行调用,没有模板说明暂时不支持; - • 长期订阅模板目前没有提供线上申请方式。
如不满足以上条件如何开通长期订阅模板,可以在小程序类目中添加 工具-设备管理
, 在 功能-硬件设备-设备消息
即可使用设备相关的长期订阅模板(无奈之举)。
小程序调起订阅授权
调起客户端小程序订阅消息界面,返回用户订阅消息的操作结果。当用户勾选了订阅面板中的“总是保持以上选择,不再询问”时,模板消息会被添加到用户的小程序设置页,通过 wx.getSetting
接口可获取用户对相关模板消息的订阅状态。
订阅消息:wx.requestSubscribeMessage(Object object)
wx.requestSubscribeMessage({
tmplIds: [''], // 需要订阅的消息模板的id的集合,一次调用最多可订阅3条消息
success (res) { }
})
注意:一次性模板 id 和永久模板 id 不可同时使用。
官方文档:https://developers.weixin.qq.com/miniprogram/dev/api/open-api/subscribe-message/wx.requestSubscribeMessage.html
服务端消息发送
发送小程序订阅信息 Java 工具方法封装。
代码语言:javascript复制/**
* @MonthName: sendMessage
* @Description: 发送小程序订阅信息
* @Param:
* appid:小程序 appid
* secret:小程序 secret
* openid:用户 openid (对应的小程序的 openid)
* templateId:小程序订阅的模板id
* page:点击模板卡片后的跳转页面
* data:模板消息的数据,如:{"thing1":{"value":"测试"}}
* @return: java.lang.String
**/
public static String sendMessage(String appid, String secret, String openId, String templateId, String page, Map<String, Object> data) {
HttpClient client = null;
try {
client = HttpClients.createDefault();
// 获取 access_token
String token = getToken(appid, secret);
if (Objects.isNull(token) && Objects.equals("", token)) {
log.error("获取AccessToken异常");
return "获取 AccessToken 异常";
}
// 发送消息
String messageUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
HttpPost httpPost = new HttpPost(messageUrl token);
JSONObject params = new JSONObject();
params.put("touser", openId); // 接收者 openid
params.put("template_id", templateId); // 模板ID
params.put("page", page); // 点击模板卡片后的跳转页面,仅限本小程序内的页面。支持带参数,(示例index?foo=bar)
params.put("lang", "zh_CN"); // 进入小程序查看”的语言类型,支持zh_CN(简体中文)、en_US(英文)、zh_HK(繁体中文)、zh_TW(繁体中文),默认为zh_CN
params.put("miniprogram_state", "formal"); // 跳转小程序类型:developer为开发版;trial为体验版;formal为正式版;默认为正式版
params.put("data", data); // 数据
httpPost.setEntity(new StringEntity(params.toString(), "UTF-8"));
String res = client.execute(httpPost, new BasicResponseHandler());
if (Objects.nonNull(res) && !Objects.equals("", res)) {
JSONObject obj = JSONObject.parseObject(res);
if (Objects.equals("0", obj.getString("errcode"))) {
return "发送消息成功!";
}
return obj.getString("errmsg");
}
} catch (Exception e) {
log.error("发送模板消息异常:{}", e);
} finally {
client.getConnectionManager().shutdown();
}
return "发送消息失败!";
}