最近项目需要一个获取微信小程序菊花码的接口,查看了官方文档,发现有两个获取菊花码的api:wxacode.get
与wxacode.getUnlimited
。
这两个的区别的主要是wxacode.get
用的path, path最大长度 128 字节,有数量限制。
wxacode.getUnlimited
用scene且最大32个可见字符,只支持数字,大小写英文以及部分特殊字符,path不支持带参数,数量暂无限制
共同点就是生成的菊花码永久有效,这里我根据我的业务需求选择的是wxacode.getUnlimited
。
但是官方文档描述的不是那么容易明白,只能从网上去找下别人做的示例,但是我发现其他人写的都没有把返回的错误信息给转换出来,例如,小程序没有发布或者page页面找不到的话,他返回的是json格式的错误信息的。如果不小心把这串信息给转换成图片,图片是肯定打不开的。
下面是我项目中用到的基本没啥问题的逻辑,供大家参考。
1.首先需要获取微信的access_token
注意的是这个token的时效是两个小时,而且一旦获取就会被刷新,所以我这里做的操作是把生成的access_token放到Redis,然后用appid来做主键,然后设置过期时间7150s
/**
* 获取微信accesstoken
*
* @param wxappid
* @param wxappkey
* @return
*/
@Override
public ResultMsg getWxAcesstoken(String wxappid, String wxappkey) {
ResultMsg msg=new ResultMsg();
logger.info("活跃accesstoken:appid="+wxappid);
String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+wxappid+"&secret="+wxappkey;
if (redisUtil.isExists("wxaccesstoken_"+wxappid)){
msg.setData(redisUtil.getString("wxaccesstoken_"+wxappid));
msg.setResult(true);
return msg;
}
try {
String jsonstr = httpClient.request(tokenUrl);
JSONObject jsonObject =JSON.parseObject(jsonstr);
if (jsonObject.containsKey("access_token")){
String accesstoken=jsonObject.getString("access_token");
redisUtil.save("wxaccesstoken_"+wxappid,accesstoken,7150);
msg.setData(accesstoken);
msg.setResult(true);
return msg;
}else{
msg.setErrorMsg("未获取到token");
msg.setResult(false);
return msg;
}
}catch (Exception e){
getLogger().error("获取token异常:",e);
msg.setResult(false);
msg.setErrorMsg(e.getLocalizedMessage());
return msg;
}
}
注:这里的ResultMsg是我们项目中统一的数据返回格式。
2.第二步就是http请求
我根据需求又重写了一个方法,返回的格式是ByteArrayInputStream,它是一个访问数组的字节输入流
public static ByteArrayInputStream sendPost(String URL, String json) {
InputStream inputStream = null;
ByteArrayInputStream byteArrayInputStream = null;
// 创建默认的httpClient实例.
CloseableHttpClient httpclient = HttpClients.createDefault();
// 创建httppost
HttpPost httppost = new HttpPost(URL);
httppost.addHeader("Content-type", "application/json; charset=utf-8");
httppost.setHeader("Accept", "application/json");
try {
StringEntity s = new StringEntity(json, Charset.forName("UTF-8"));
s.setContentEncoding("UTF-8");
httppost.setEntity(s);
HttpResponse response = httpclient.execute(httppost);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
// 获取相应实体
HttpEntity entity = response.getEntity();
inputStream = entity.getContent();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
// 创建一个Buffer字符串
byte[] buffer = new byte[1024];
// 每次读取的字符串长度,如果为-1,代表全部读取完毕
int len = 0;
// 使用一个输入流从buffer里把数据读取出来
while ((len = inputStream.read(buffer)) != -1) {
// 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
outStream.write(buffer, 0, len);
}
// 关闭输入流
inputStream.close();
// 把outStream里的数据写入内存
byteArrayInputStream = new ByteArrayInputStream(outStream.toByteArray());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
// 关闭连接,释放资源
try {
httpclient.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return byteArrayInputStream;
}
3.第三步就是用来生成菊花码的逻辑了
/**
* 获取小程序菊花码
* @Description //TODO
* @Author zhaowx
* @Date 2020/3/25 15:23
**/
@Override
public ResultMsg getWXCode() {
ResultMsg msg = new ResultMsg();
try {
//这里调用的是上面的获取access_token方法
ResultMsg wxAcesstoken = userService.getWxAcesstoken(appid,secret);
if (!wxAcesstoken.getResult() || StringUtils.isBlank(wxAcesstoken.getData().toString()) || wxAcesstoken.getData() == null){
return wxAcesstoken;
}
String access_token = (String) wxAcesstoken.getData();
String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+access_token;
String scene = "p="+phone;
Map<String, String> param = new HashMap<>();
param.put("scene",scene);
//这里的page如果没有的话可以不写,默认是跳主页,如果写了没有的页面的话,会返回错误信息
param.put("page","pages/webview/index");
String json = JSON.toJSONString(param);
ByteArrayInputStream inputStream = httpClient.sendPost(url, json);
//这里判断的是返回的图片还是错误信息,一般错误信息不会大于200
if (inputStream.available() <= 200){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
int i;
byte[] buffer = new byte[200];
while ((i = inputStream.read(buffer)) != -1){
byteArrayOutputStream.write(buffer,0,i);
}
String str = new String(byteArrayOutputStream.toByteArray());
//错误信息的格式在官方文档里有
JSONObject jsonObject = JSONObject.parseObject(str);
if ("41030".equals(jsonObject.getString("errcode"))){
msg.setResult(false);
msg.setMsg("所传page页面不存在,或者小程序没有发布");
}else if ("45009".equals(jsonObject.getString("errcode"))){
msg.setResult(false);
msg.setMsg("调用分钟频率受限");
}
byteArrayOutputStream.close();
return msg;
}
//这里我选择是上传到了oss,你也可以选择输出到本地
String fileName = "noilCode_userNo"+".jpeg";
String path = "wxcode/noilCode";
String imgUrl = ossClientUtil.UploadImgAndReturnImgUrlInputStream(inputStream, fileName, path);
//输出到本地的代码
FileOutputStream fileOutputStream = new FileOutputStream("D:/123.png");
int i;
byte[] buffer = new byte[200];
while ((i = inputStream.read(buffer)) != -1){
fileOutputStream.write(buffer,0,i);
}
fileOutputStream.flush();
fileOutputStream.close();
inputStream.close();
msg.setMsg("菊花码生成成功");
msg.setResult(true);
}catch (Exception e){
msg.setMsg("获取菊花码异常");
msg.setResult(false);
}
return msg;
}
到这里基本就完成了,生成的小程序图片我就不贴出来了。