一、创建消息模板
在微信公众平台-小程序里,选择订阅消息,简单起见,可以从公共模板库选择一个合适的(如公共模板库没有合适的,则可以自己创建,但是需要审核)。
二、获取模板消息的参数
点击模板消息详情查看模板消息参数。
三、获取openId
先拿到用户的openId(如已获取,则跳过)。
3.1 前端从小程序获取登录凭证code
前端先从小程序端拿到用户code,然后将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)
}
}
})
3.2 后端解析code,拿到openId
官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
登录凭证校验。通过 wx.login 接口获得临时登录凭证 code 后传到开发者服务器调用此接口完成登录流程。
请求地址:
GET https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
Java代码如下:
/**
* 解析code,获取openId
* @param appId 小程序的appId
* @param appSecret 小程序的appSecret
* @param code 前端传过来的code
* @return WechatAppToken
*/
public WechatAppToken getOpenIdInMiniApp(String appId, String appSecret, String code) {
if (code.isEmpty()) {
System.out.println("code不能为空");
}
private RestTemplate restTemplate = new RestTemplate();
String requestUrl = UriComponentsBuilder.fromHttpUrl(
"https://api.weixin.qq.com/sns/jscode2session")
.queryParam("appid", appId)
.queryParam("secret", appSecret)
.queryParam("js_code", code)
.queryParam("grant_type", "authorization_code")
.build().encode().toUriString();
try {
WechatAppToken result = restTemplate.getForObject(requestUrl, WechatAppToken.class);
System.out.println("wxchat Result:{}" + result);
if (result == null || result.errcode != null) {
System.out.println("getUnionIdInMiniApp error");
// 抛个异常
}
return result;
} catch (RestClientResponseException ex) {
System.out.println("getUnionIdInMiniApp error");
}
}
其中,WechatAppToken
是根据小程序接口返回值建的一个类:
@Data
public class WechatAppToken {
public Integer errcode;
public String errmsg;
public String openid;
public String sessionKey;
public String unionId;
}
四、获取access_token
官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/access-token/auth.getAccessToken.html
获取小程序全局唯一后台接口调用凭据(access_token
)。调用绝大多数后台接口时都需使用 access_token,开发者需要进行妥善保存。
请求地址:
GET https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
Java代码如下:
/**
* 缓存的access_token
*/
private static String accessToken;
/**
* access_token的失效时间
*/
private static long expiresTime;
public String getAccessToken() {
// 判断accessToken是否已经过期,如果过期需要重新获取
if (accessToken == null || expiresTime < System.currentTimeMillis()) {
RestTemplate restTemplate = new RestTemplate();
Map<String, String> params = new HashMap<>(2);
params.put("APPID", "小程序的APPID");
params.put("APPSECRET", "小程序的APPSECRET");
ResponseEntity<String> responseEntity = restTemplate.getForEntity(
"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={APPID}&secret={APPSECRET}", String.class, params);
String body = responseEntity.getBody();
JSONObject object = JSON.parseObject(body);
Integer errcode = object.getInteger("errcode");
if (errcode != null && errcode != 0) {
String errmsg = object.getString("errmsg");
System.out.println("请求accessToken失败,返回码:" + errcode + ",错误信息:" + errmsg);
// 抛个异常
}
// 缓存accessToken
accessToken = object.getString("access_token");
// 设置accessToken的失效时间
long expires_in = object.getLong("expires_in");
// 失效时间 = 当前时间 + 有效期(提前一分钟,也可不提前,这里只是稳妥一下)
expiresTime = System.currentTimeMillis() + (expires_in - 60) * 1000;
}
return accessToken;
}
五、发送消息
官方文档:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
发送订阅消息。
请求地址:
POST https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN
需要注意的是,该接口是有次数限制的。
开通支付能力的是3kw/日,没开通的是1kw/日。
Java代码:
/**
* 发送视频完成模板消息
* @param openid 用户的openid
* @return 结果。发送成功,返回值实例:{"errcode":0,"errmsg":"ok","msgid":11111}
*/
public String sendVlogCompleteTemplateMsg(String openid) {
RestTemplate restTemplate = new RestTemplate();
//发送订阅消息的url,官网地址:https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/subscribe-message/subscribeMessage.send.html
String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=" + getAccessToken();
//拼接推送的模版
WxMsgDto wxMsgDto = new WxMsgDto();
//用户的openid(要发送给的那个用户)
wxMsgDto.setTouser(openid);
//订阅消息模板id
wxMsgDto.setTemplate_id("小程序中选择的模板的模板id");
//点击消息跳转的页面
wxMsgDto.setPage("pages/index/index");
Map<String, WxTemplateDataDto> map = new HashMap<>(5);
//根据从小程序中的模板获取的参数,进行赋值
map.put("thing5", new WxTemplateDataDto("西湖"));
map.put("thing6", new WxTemplateDataDto("断桥景点"));
map.put("time7", new WxTemplateDataDto("2022-01-13 02:31:36"));
map.put("time4", new WxTemplateDataDto("2022-01-13 02:31:36"));
map.put("thing3", new WxTemplateDataDto("您的视频已生成,赶紧去查看吧~"));
wxMsgDto.setData(map);
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, wxMsgDto, String.class);
return responseEntity.getBody();
}
其中WxMsgDto
类代码如下:
@Data
public class WxMsgDto {
/**
* 接收者(用户)的 openid
*/
private String touser;
/**
* 所需下发的订阅模板id
*/
private String template_id;
/**
* 点击模板卡片后的跳转页面,仅限本小程序内的页面
*/
private String page = "pages/index/index";
/**
* 模板内容,格式形如 { "key1": { "value": any }, "key2": { "value": any } }
*/
private Map<String, WxTemplateDataDto> data;
}
WxTemplateDataDto
代码如下:
@Data
@AllArgsConstructor
public class WxTemplateDataDto {
private String value;
}
成品图
通过上述步骤,若发送消息返回值成功,则小程序会通过微信的服务通知
发送一条消息至指定用户,效果如下: