微信小程序订阅消息推送:参考官方文档
关于小程序订阅消息
「订阅消息」需要用户主动订阅消息通知,开发者才可向用户推送,也就是需要做本文第二大点,第1小点的操作,且用户同意之后才可
1、一次性订阅消息:用户订阅一次后,开发者可下发一条消息,不限时间。
若用户勾选了“总是保持以上选择,不再询问”且点击了允许,那么以后都默认同意订阅这条消息。用户不再做多次选择,开发者也避免了更繁琐的提醒。
2、长期性订阅消息:用户订阅一次后,可长期下发多条消息。目前长期性订阅消息向政务、医疗、交通、金融、教育等线下公共服务开放,后续将综合评估行业需求和用户体验持续完善(长期订阅消息只针对特定行业开放,所以普通开发者并无法使用)
需要注意的是,一次性订阅消息,用户订阅一次才能发送一次消息,订阅一次是无法多次发送的!
先给大家看看模板消息推送之后的效果图
接下来我们上代码
一、配置小程序相关参数
1、微信小程序相关参数
application.yml 文件中做如下配置
#微信小程序
wx:
#微信小程序的 appId
appId: 小程序的appId
#微信小程序的 appSecret
appSecret: 小程序的appSecret
#模板 ID
templateId: 小程序订阅消息的模板id
2、全局配置文件参数读取类
@Configuration
public class BaseConfiguration {
//微信小程序
public static String WX_APPID;
public static String WX_APPSECRET;
public static String WX_TEMPLATE_ID;
@Value("${wx.appId}")
public void setWxAppid(String param){
WX_APPID = param;
}
@Value("${wx.appSecret}")
public void setWxAppsecret(String param){
WX_APPSECRET = param;
}
@Value("${wx.templateId}")
public void setWxTemplateId(String param){
WX_TEMPLATE_ID = param;
}
}
二、发送订阅消息前必要参数的获取工作
1、订阅消息认证
这一步一般是小程序代码进行实现
调起客户端小程序订阅消息界面,返回用户订阅消息的操作结果。当用户勾选了订阅面板中的“总是保持以上选择,不再询问”时,模板消息会被添加到用户的小程序设置页,通过 wx.getSetting 接口可获取用户对相关模板消息的订阅状态
wx.requestSubscribeMessage({
tmplIds: [''],//你的模板id
success (res) {
if (res.errMsg == "requestSubscribeMessage:ok") {
//表示用户同意订阅
}
}//回调函数
})
2、获取登录凭证(code)
因为获取用户 openid 需要通过调用接口获取登录凭证(code),通过凭证也就是 code 进而换取用户登录态信息,包括用户的唯一标识(openid)及本次登录的会话密钥(session_key)等
小程序代码中调用接口获取登陆凭证,也就是获取 code ,然后将 code 传到后端,后端通过 code 获取用户 openid
wx.login({
success (res) {
if (res.code) {
//这里可以调用后端方法,让后端去获取 openid
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
3、根据小程序传入的 code 获取 openid
public class HttpURLConnectionUtil {
private static final CloseableHttpClient httpclient = HttpClients.createDefault();
/**
* 发送HttpGet请求
* @param url
* @return
*/
public static String sendGet(String url) {
HttpGet httpget = new HttpGet(url);
CloseableHttpResponse response = null;
try {
response = httpclient.execute(httpget);
} catch (IOException e1) {
e1.printStackTrace();
}
String result = null;
try {
HttpEntity entity = response.getEntity();
if (entity != null) {
result = EntityUtils.toString(entity);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return result;
}
}
//根据微信用户 code 获取 openID
String requestUrl = "https://api.weixin.qq.com/sns/jscode2session?appid=" + BaseConfiguration.WX_APPID + "&secret=" + BaseConfiguration.WX_APPSECRET + "&js_code=" + baseRequest.getCode() + "&grant_type=authorization_code";
Map<String, Object> result = new HashMap<String, Object>();
String response = HttpURLConnectionUtil.sendGet(requestUrl);
JSONObject OpenidJSONO = JSONObject.fromObject(response);
//OpenidJSONO可以得到的内容:access_token expires_in refresh_token openid scope
String Openid = String.valueOf(OpenidJSONO.get("openid"));
String AccessToken = String.valueOf(OpenidJSONO.get("access_token"));
String Scope = String.valueOf(OpenidJSONO.get("scope"));//用户保存的作用域
String refresh_token = String.valueOf(OpenidJSONO.get("refresh_token"));
result.put("openid", Openid);
result.put("AccessToken", AccessToken);
result.put("scope", Scope);
result.put("refresh_token", refresh_token);
4、获取 access_token
获取小程序全局唯一后台接口调用凭据(access_token)。调用绝大多数后台接口时都需使用 access_token
/**
* 获取access_token
*
* @return
*/
public static String getAccessToken() {
String url="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential" +
"&appid=" + BaseConfiguration.WX_APPID +
"&secret=" + BaseConfiguration.WX_APPSECRET;
String result = HttpURLConnectionUtil.sendGet(url);
JSONObject object=JSON.parseObject(result);
String accessToken = object.getString("access_token");
String errcode = object.getString("errcode");
String errmsg = object.getString("errmsg");
if (StringUtils.isNotBlank(accessToken)) {
log.info("获取 access_token 成功, Send Success");
return accessToken;
} else {
log.info("获取 access_token 失败:", errcode, errmsg);
}
return null;
}
三、封装订阅消息的模板参数
1、模板参数类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TemplateParam {
private String key;
private String value;
}
2、订阅消息参数对象
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Template {
//用户 openid
private String touser;
//模板id
private String template_id;
//点击模板跳转的页面
private String page;
//模板参数
private List<TemplateParam> data;
//由于模板参数格式问题,自定义转换 JSON
public String toJSON() {
StringBuffer buffer = new StringBuffer();
buffer.append("{");
//"touser":"1234"
buffer.append(String.format("\"touser\":\"%s\"", this.touser)).append(",");
//"template_id":"1234"
buffer.append(String.format("\"template_id\":\"%s\"", this.template_id)).append(",");
//"page":"pages/index/index"
buffer.append(String.format("\"page\":\"%s\"", this.page)).append(",");
buffer.append("\"data\":{");
TemplateParam param = null;
for (int i = 0; i < this.data.size(); i++) {
param = data.get(i);
// 判断是否追加逗号
if (i < this.data.size() - 1){
//"thing1": {"value":"001"},
buffer.append(String.format("\"%s\": {\"value\":\"%s\"},", param.getKey(), param.getValue()));
}else{
//"thing1": {"value":"001"}
buffer.append(String.format("\"%s\": {\"value\":\"%s\"}", param.getKey(), param.getValue()));
}
}
buffer.append("}");
buffer.append("}");
return buffer.toString();
}
//格式转换测试
public static void main(String[] args) {
System.out.println(String.format("\"%s\": {\"value\":\"%s\"}", "thing1", "001"));//"thing1": {"value":"001"}
}
}
四、开始推送模板消息
@RestController
@RequestMapping("/sendMessageWx")
@Slf4j
public class SendMessageWxController {
@GetMapping("/sendMessageWx")
@ApiOperation("订阅消息推送测试")
public static void SendMessage() {
String accessToken = SendMessageWxController.getAccessToken();
List<TemplateParam> templateParams = new ArrayList<>();
//当前进度
templateParams.add(TemplateParam.builder().key("thing3").value("创建").build());
//事项编码
templateParams.add(TemplateParam.builder().key("character_string6").value("001").build());
//事项名称
templateParams.add(TemplateParam.builder().key("thing2").value("这里是事项名称").build());
//备注
templateParams.add(TemplateParam.builder().key("thing9").value("这里是备注").build());
Template template = Template.builder()
.template_id(BaseConfiguration.WX_TEMPLATE_ID)//模板 ID
.touser("填写获取到的用户openid")//用户 openid
.data(templateParams) //模板参数
.page("填写你要跳转的小程序的页面")//点击消息跳转页面
.build();
//请求地址
String requestUrl = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="+accessToken;
log.info("推送的模板参数信息:"+ template.toJSON());
String jsonResult = null;
try {
jsonResult = HttpURLConnectionUtil.GetPostUrl(requestUrl, template.toJSON());
} catch (IOException e) {
e.printStackTrace();
}
if (jsonResult != null) {
JSONObject OpenidJSONO = JSONObject.parseObject(jsonResult);
System.out.println(jsonResult);
String errorCode = OpenidJSONO.get("errcode").toString();
String errorMessage = OpenidJSONO.get("errmsg").toString();
if ("0".equals(errorCode)) {
log.info("推送订阅消息: Send Success");
} else {
log.info("订阅消息发送失败:"+ errorCode+errorMessage);
}
} else {
log.info("订阅消息发送失败");
}
}
五、效果图
本效果图来自电脑微信