微信小程序--订阅消息
更新:
关于小程序订阅消息之一次性订阅:
一次性订阅是指授权一次方可接收一次消息;这个最好的应用场景就是自己给自己发送消息,比如订单,当自己下单成功时,调用此接口,会在微信服务消息收到下单成功通知等具体详情。 如果是给别人发,一次性订阅就不适合,类似你想给某个人发送消息,那你还得提前跟他说你进小程序授权一下消息模板,不然就收不到消息.....WTF....这样就很鸡肋! 一次性消息订阅就是一对一模式,授权一次才能接收到一次消息,如果你发送了两条消息,但对方只授权一次,那他也只能接收一次消息。
微信小程序之订阅消息(一次性订阅示例)
第一步. 订阅消息模板
可选公共模板,如果不满足可以自己申请;
记住模板Id,之后需要用到。
第二步. 调用微信订阅消息服务:
登录成功时调用微信订阅消息服务(也可以用在发送方法里边,我想的是登录成功后提示一次就行):
uni.requestSubscribeMessage({ //获取下发权限
tmplIds: ['fWxR5XXXXXXXXXXXX'], //模板ID
success(res) {
console.log('已授权接收订阅消息')
}
});
//这里的tmplIds是消息模板集合,可放多个如:
// tmplIds: ['fWxR5XXXXXXXXXXXXXXXXX','xxxxxxxxxxxxx'.....],
第三步 获取用户OpenId
openId:微信编码,唯一标识,消息发送给谁就填谁的openId。
我的思路是登录成功之后就调用接口获取到用户openid,之后存到数据库对应用户,用的时候直接取;
要获取openid就得先获取授权code,微信有接口:
1.前端:
wx.login({
success (res) {
if (res.code) {
//发起网络请求
//使用 code 换取 openid 和 session_key 等信息
//将code传到后台服务器获取openId
wx.request({
url: 'https://test.com/getOpenId', //仅为示例,并非真实的接口地址
data: {
code: res.code
},
header: {
'content-type': 'application/json' // 默认值
},
success (res) {
//成功获取到openid
console.log(res.data)
}
})
} else {
console.log('登录失败!' + res.errMsg)
}
}
})
2.java后端:
@PostMapping(value="/getOpenId")
public String getOpenId(String code) throws Exception{
String appId = "你的小程序AppId";
String appSecret ="你的小程序AppSecret ";
//微信小程序固定接口
String WX_URL = "https://api.weixin.qq.com/sns/jscode2session?appid="+appId +"&secret="+appSecret+"&js_code="+code+"&grant_type=authorization_code";
if(StringUtil.isEmpty(code)){
//缺少参数code
return null;
}else {
String requestUrl = WX_URL;
// 发起GET请求获取凭证
JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
if (jsonObject != null) {
try {
//获取成功
String openid = jsonObject.getString("openid");
String sessionKey = jsonObject.getString("session_key");
return openid;
} catch (JSONException e) {
//失败
return null;
}
}else {
//失败
return null;
}
}
return null;
}
我的做法:
在用户登录时,就主动获取code和用户id发送到后台获取到openid,根据用户id将openid存到对应数据库,用的时候取出来。
第四步 发送消息
1.前端:
var Obj = {
"touser": openId,//接收人的openId
"template_id": "fWxR5XXXXXXXXXXX",//订阅消息模板ID
"page":"pages/business/business-audit/business-audit",//微信端收到消息时,点击进入的页面
"miniprogram_state":"trial",//这是代表体验版,上线需该为正式版(默认为正式版)
"lang":"zh_CN",//语言
"data": {
"thing6": {
"value": "外出报备审核"
},
"thing18": {
"value": "您有1条新的待审核数据"
},
"thing37": {
"value": myself.tools.getUserInfo().name //人名
} ,
"time38": {
"value": myself.tools.dateFormate(new Date(), "YYYY-MM-DD HH:mm:ss")//时间
}
}
}
var jsonData = JSON.stringify(Obj );
wx.request({
url: 'https://test.com/gsendWxTempleMsg', //仅为示例,并非真实的接口地址
data:{
jsonData:jsonData
},
header: {
'content-type': 'application/json' // 默认值
},
success (res) {
//成功
}
})
其中,data对应模板:
2.java后端:
@PostMapping(value = "/wx/sendMessage")
public AjaxJson sendWxTempleMsg(String jsonData) throws Exception {
if(StringUtil.isBlank(jsonData)){
return error("消息推送失败,缺少消息模板信息");
}
String appId = "你的小程序AppId";
String appSecret ="你的小程序AppSecret ";
String ACCESS_TOKEN = getToken(appId, appSecret);//这里需要获取access_token
String url = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token="+ACCESS_TOKEN;
// 发起请求,返回JSON字符串
JSONObject jsonObject = CommonUtil.httpsRequest(url , "POST", jsonData);//官方文档指定POST方式发送
if(jsonObject.get("errcode").equals("0")||jsonObject.get("errmsg").equals("ok")){
return success("消息推送成功");
}else{
return error("消息推送失败");
}
}
其中getToken方法:
/**
* @param appId
* @param appSecret
* @return
*/
public static String getToken(String appId, String appSecret) {
String requestUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+appSecret+"";
// logger.info(requestUrl);
// 发起GET请求获取凭证
JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
if (jsonObject != null) {
if (jsonObject.getString("errcode") == null) {
return jsonObject.getString("access_token");
} else {
return null;
}
} else {
return null;
}
}
至此,消息发送成功!
注:java后台用到的工具类
CommonUtil:
/**
* 类名: CommonUtil.java</br>
* 描述: http请求工具类</br>
*/
public class CommonUtil {
private static Logger log = LoggerFactory.getLogger(CommonUtil.class);//日志类(可删除)
/**
* 发送https请求
* @param requestUrl 请求地址
* @param requestMethod 请求方式(GET、POST)
* @param outputStr 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
JSONObject jsonObject = null;
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = conn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
// 释放资源
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
conn.disconnect();
jsonObject = JSONObject.parseObject(buffer.toString());
} catch (ConnectException ce) {
log.error("连接超时:{}", ce);
} catch (Exception e) {
log.error("https请求异常:{}", e);
}
return jsonObject;
}
/**
* 发送https请求
*
* @param requestUrl
* 请求地址
* @param requestMethod
* 请求方式(GET、POST)
* @param outputStr
* 提交的数据
* @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
*/
public static AjaxJson httpsRequestStream(String requestUrl, String requestMethod, String outputStr,
String basePath, Long id) {
AjaxJson aj = new AjaxJson();
try {
// 创建SSLContext对象,并使用我们指定的信任管理器初始化
TrustManager[] tm = { new MyX509TrustManager() };
SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
sslContext.init(null, tm, new java.security.SecureRandom());
// 从上述SSLContext对象中得到SSLSocketFactory对象
SSLSocketFactory ssf = sslContext.getSocketFactory();
URL url = new URL(requestUrl);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setSSLSocketFactory(ssf);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setUseCaches(false);
// 设置请求方式(GET/POST)
conn.setRequestMethod(requestMethod);
// 当outputStr不为null时向输出流写数据
if (null != outputStr) {
OutputStream outputStream = conn.getOutputStream();
// 注意编码格式
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
InputStream inputStream = conn.getInputStream();
String fileUrl = File.separator + "images" + File.separator + "standaqrcode" + File.separator + "stand" + id + ".jpg";
String savePath = basePath + fileUrl;
// System.out.println(savePath);
aj = inputStreamToImage(inputStream, savePath, "jpg");
inputStream.close();
inputStream = null;
conn.disconnect();
// 从输入流读取返回内容
aj.setSuccess(true);
aj.put("data", fileUrl);
return aj;
} catch (ConnectException ce) {
log.error("连接超时:{}", ce);
aj.setSuccess(false);
aj.setMsg("链接超时:" + ce);
return aj;
} catch (Exception e) {
log.error("https请求异常:{}", e);
aj.setSuccess(false);
aj.setMsg("https请求异常:" + e);
return aj;
}
}
/**
* 将字符流转换为图片文件
* @param input 字符流
* @param savePath 图片需要保存的路径
* @param 类型 jpg/png等
* @return
*/
private static AjaxJson inputStreamToImage(InputStream input, String savePath, String type) {
AjaxJson aj = new AjaxJson();
try {
File file = null;
file = new File(savePath);
String paramPath = file.getParent(); // 路径
String fileName = file.getName(); //
String newName = fileName.substring(0, fileName.lastIndexOf(".")) + "." + type;// 根据实际返回的文件类型后缀
savePath = paramPath + File.separator + newName;
if (!file.exists()) {
File dirFile = new File(paramPath);
dirFile.mkdirs();
}
file = new File(savePath);
FileOutputStream output = new FileOutputStream(file);
int len = 0;
byte[] array = new byte[1024];
while ((len = input.read(array)) != -1) {
output.write(array, 0, len);
}
output.flush();
output.close();
aj.setSuccess(true);
aj.setMsg("save success!");
} catch (FileNotFoundException e) {
e.printStackTrace();
aj.setSuccess(false);
aj.setMsg(e.getMessage());
} catch (IOException e) {
e.printStackTrace();
aj.setSuccess(false);
aj.setMsg(e.getMessage());
}
return aj;
}
}