首先说下业务场景
需要从某个页面生成二维码,用户扫描二维码,如果已关注公众号,跳到公众号页面,推送小程序链接
如果还未关注公众号,跳转到关注页面,关注公众号后推送小程序链接。
当然从公众号跳转到小程序,多多少少是需要带一点业务相关参数的。
本篇主要将二维码生成,以及事件推送
一、二维码生成
根据官方文档介绍,目前公众号二维码主要有永久和临时两种,但是永久二维码是有数量限制的,临时二维码携带参数又有限制。
所以我们一般都使用临时二维码
生成二维码的动作主要有两步,第一步根据参数拿到二维码ticket,第二步根据ticket换取二维码
首先看获取二维码的参数
拼接结构如下:{“action_name”: “QR_LIMIT_SCENE”, “action_info”: {“scene”: {“scene_id”: 123}}}
注意scene是在action_info 里面的
请求URL为 :https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN 类型为POST
返回数据是这样的
{“ticket”:“gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm
3sUw==”,“expire_seconds”:60,“url”:“http://weixin.qq.com/q/kZgfwMTm72WWPkovabbI”}
下面上具体代码
/**
* 创建临时带参二维码
*
* @param accessToken 接口访问凭证
* @param expireSeconds 二维码有效时间,单位为秒,最大不超过1800
* @param sceneId 场景ID
* @return WeixinQRCode
*/
public WeixinQRCode createTemporaryQRCode(String accessToken, int expireSeconds, String sceneStr) {
QRCodeParMapping byMappingValue = qrCodeParamMappingUtil.getQrcodeParMappingByMappingValue(sceneStr);
Integer mappingID = null;
if (byMappingValue == null) {
byMappingValue = new QRCodeParMapping();
byMappingValue.setMappingValue(sceneStr);
qrCodeParamMappingUtil.save(byMappingValue);
}
mappingID = byMappingValue.getMappingID();
sceneStr = mappingID.toString();
System.out.println("二维码携带参数为" + sceneStr);
WeixinQRCode weixinQRCode = null;
// 拼接请求地址
String requestUrl = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=ACCESS_TOKEN";
requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken);
// 需要提交的json数据
String jsonMsg = "{\"expire_seconds\": %d, \"action_name\": \"QR_SCENE\", \"action_info\": {\"scene\": {\"scene_id\": %s}}}";
// 创建临时带参二维码
JSONObject jsonObject = WechatUtil.httpsRequest(requestUrl, "POST",
String.format(jsonMsg, expireSeconds, sceneStr));
if (null != jsonObject) {
try {
weixinQRCode = new WeixinQRCode();
weixinQRCode.setTicket(jsonObject.getString("ticket"));
weixinQRCode.setExpireSeconds(jsonObject.getInt("expire_seconds"));
logger.info("创建临时带参二维码成功 ticket:{} expire_seconds:{}", weixinQRCode.getTicket(),
weixinQRCode.getExpireSeconds());
} catch (Exception e) {
weixinQRCode = null;
int errorCode = jsonObject.getInt("errcode");
String errorMsg = jsonObject.getString("errmsg");
logger.error("创建临时带参二维码失败 errcode:{} errmsg:{}", errorCode, errorMsg);
}
}
return weixinQRCode;
}
/**
* 发起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;
StringBuffer buffer = new StringBuffer();
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 httpUrlConn = (HttpsURLConnection) url.openConnection();
httpUrlConn.setSSLSocketFactory(ssf);
httpUrlConn.setDoOutput(true);
httpUrlConn.setDoInput(true);
httpUrlConn.setUseCaches(false);
// 设置请求方式(GET/POST)
httpUrlConn.setRequestMethod(requestMethod);
if ("GET".equalsIgnoreCase(requestMethod))
httpUrlConn.connect();
// 当有数据需要提交时
if (null != outputStr) {
OutputStream outputStream = httpUrlConn.getOutputStream();
// 注意编码格式,防止中文乱码
outputStream.write(outputStr.getBytes("UTF-8"));
outputStream.close();
}
// 将返回的输入流转换成字符串
InputStream inputStream = httpUrlConn.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
// 释放资源
inputStream.close();
inputStream = null;
httpUrlConn.disconnect();
jsonObject = JSONObject.fromObject(buffer.toString());
} catch (ConnectException ce) {
log.error("Weixin server connection timed out.");
} catch (Exception e) {
log.error("https request error:{}", e);
}
return jsonObject;
}
/**
* 临时二维码信息
*
* @author liufeng
* @date 2013-11-10
*/
public class WeixinQRCode {
// 获取的二维码ticket
private String ticket;
// 二维码的有效时间,单位为秒,最大不超过1800
private int expireSeconds;
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public int getExpireSeconds() {
return expireSeconds;
}
public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}
}
一共两个方法 一个类
第一个方法是生成二维码的步骤,三个参数:1、accessToken 请自备2、过期时间 3、二维码携带参数
第二个方法是访问微信的GET请求
第三个二维码实体类
这里要额外说一个事情,
第一个查询映射的方法,是干什么的
首先上面参数有说过,二维码可携带参数有scene_id 和scene_str 但是临时二维码 只能用ID(关乎于后面的事件推送) 并且是32位非零整型,长度有限制,所以个人做了个参数映射,生成二维码码的参数在数据库关联一个ID,每次ID自增,每次传参要查询是否有对应的ID,没有就生成一个新的
这部分逻辑很简单先不上代码了,如不需要,可自行注释代码,有需要可能后面会补。
这样我们就拿到了二维码的ticket
获取二维码就很简单了
通过访问链接就可以直接拿到二维码
官方是这么写的:
HTTP GET请求(请使用https协议)https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
提醒:TICKET记得进行UrlEncode
ticket正确的情况下,状态码200,是一张图片可以下载。错误的话可能是404
这里额外再说一句,那个携带参数,即使是它不支持或者超出限制了,二维码仍然会正常返回,但是参数不会正常携带到后面的事件里面
二、事件接收以及消息推送
首先说事件接收,这个事件接收是一个很广的概念,可以接收很多类型的事件,官方是这么写的
事件推送的URL需要在公众号后台自行配置,是一个URL哦~不同的事件按照分类进行区别开发
二维码的推送参数如下:
这是我代码中打印的 已关注用户推送的
根据这个我们能拿到二维码携带过来的参数 就是Eventkey。
未关注用户推送的:
注意未关注用户的参数前面带一个qrscene_ 获取时自行截取
事件到了 我们需要做处理
这里返回的不是模版消息,是客服消息
看官方文档
消息类型是这样,我的需求是要跳转到小程序 并没有链接类型
所以就使用文本类型,里面自己嵌入链接,官方给出了方法
发送文本消息时,支持插入跳小程序的文字链
文本内容<a href="http://www.qq.com" data-miniprogram-appid="appid" data-miniprogram-path="pages/index/index">点击跳小程序</a>
说明: 1.data-miniprogram-appid 项,填写小程序appid,则表示该链接跳小程序; 2.data-miniprogram-path项,填写小程序路径,路径与app.json中保持一致,可带参数; 3.对于不支持data-miniprogram-appid 项的客户端版本,如果有herf项,则仍然保持跳href中的网页链接; 4.data-miniprogram-appid对应的小程序必须与公众号有绑定关系。
下一篇详细介绍怎么回消息以及代码~