好吧,其实这个通篇没有啥大的知识点,但是细节上又不是那么简单的。所以这里整理一下以便以后使用。
首先简单介绍下,微信小程序二维码是微信官方提供的接口,有多种实现方式。附上官网链接:
微信生成小程序二维码链接
主要分两种:
- 一种适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制。重点是只能直接定位到小程序中某个页面,不能传参数,所以这个pass。
- 一种适用于需要的码数量极多的业务场景。通过该接口生成的小程序码,永久有效,数量暂无限制。只不过每分钟调用次数有限,但是一分钟好5000次,这个大多数时候都不会超出,所以相当于无限制。
我们这个项目需求是要每个码带参数的,所以选择了第二种方式。
然後其实两种方法使用的时候都需要一个必须的参数:接口调用凭证——access_token.
这个参数是由appId和secret一起获取的。至于这两个参数怎么来的就没法再往下说了。我今天的讲解从 获取access_token开始:
这个方法中的appId和secret是事先定义好的。无论是静态变量还是配置文件中都可以。
public static String getAccessToken() throws Exception {
String requestUrl ="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appid+"&secret="+secret;
URL url = new URL(requestUrl);
// 打开和URL之间的连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
// 设置通用的请求属性
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setUseCaches(false);
connection.setDoOutput(true);
connection.setDoInput(true);
// 得到请求的输出流对象
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes("");
out.flush();
out.close();
// 建立实际的连接
connection.connect();
// 定义 BufferedReader输入流来读取URL的响应
BufferedReader in = null;
if (requestUrl.contains("nlp"))
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "GBK"));
else
in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
String result = "";
String getLine;
while ((getLine = in.readLine()) != null) {
result += getLine;
}
in.close();
JSONObject jsonObject = JSON.parseObject(result);
String accesstoken=jsonObject.getString("access_token");
return accesstoken;
}
这个方法就是一个简单的获取凭证。这里做了个简单的转json获取access_token的处理,所以返回的直接是accesstoken的值。如果不做这步处理是一个map。一个是accesstoken一个是过期时间。(这个token的过期时间大概是两个小时左右。反正我们项目是生成一次二维码都重新获取下这个token,省的过期了)
然後重点来了!用这个token去生成二维码。
话说这里比较复杂的是accesstoken要在路径传参,但是别的参数必须是post的body里以json的形式传参。所以这个其实是很麻烦的。如果想用postman测试这个接口如下写法:
我上面例子中只有简单的scene,如果还有page则继续写k-v对。
然後这个要求放在java代码中也略有不同。下面附上java代码:
public String getQRCode(HttpServletResponse response,Long id, HttpServletRequest request) {
try
{
String wxCodeURL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+getAccessToken();
URL url = new URL(wxCodeURL);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestMethod("POST");// 提交模式
// 发送POST请求必须设置如下两行
httpURLConnection.setDoOutput(true);
httpURLConnection.setDoInput(true);
// 获取URLConnection对象对应的输出流
PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
// 发送请求参数
JSONObject paramJson = new JSONObject();
paramJson.put("scene", "id="+id);
// paramJson.put("page", "pages/index/index"); //小程序暂未发布我没有带page参数
printWriter.write(paramJson.toString());
// flush输出流的缓冲
printWriter.flush();
//开始获取数据
BufferedInputStream bis = new BufferedInputStream(httpURLConnection.getInputStream());
OutputStream os = new FileOutputStream(new File("D:/wechat/qr"+id+".png"));
int len;
byte[] arr = new byte[1024];
while ((len = bis.read(arr)) != -1)
{
os.write(arr, 0, len);
os.flush();
}
os.close();
//实现了生成二维码并保存在本地电脑的硬盘中。
File file = new File("D:/wechat/qr"+id+".png");
FileInputStream fis = new FileInputStream(file);
long size = file.length();
byte[] temp = new byte[(int) size];
fis.read(temp, 0, (int) size);
fis.close();
byte[] data = temp;
response.setContentType("image/png");
OutputStream out = response.getOutputStream();
out.write(data);
out.flush();
out.close();
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
其实以上是两个行为掺在一起的代码。
上面这个方法我中间有段注释:生成了二维码并保存在了电脑中。其实到这里就已经实现了一个保存二维码到服务器的功能。至此一种办法就是直接返回这个图片的可访问路径给前端,前端直接获取服务器资源就ok了。
但是!!我题目上就说了的返回给前端不是返回地址,而是图片直接返回去。所以才有了下面的代码:其实就是读取本地图片再用response流的形式返回去。具体怎么做要看业务需求。主要是我们这个项目不打算让前端可以直接获取服务器资源(ip+端口+路径+图片名 访问图片的形式)。所以我这里相当于多了一个过程。
然後可以开始判断这个接口的实现遇到的坑了:
我之前都说了这个就是个简单的接口访问,难是不难,但是出于我的马虎大意,所以也是调了一下午。下面一一道来。
- 作为一个面向百度的程序员,第一反应是拿现成的,所以百度几个帖子cv,个个都出错。最后发现百度靠前的几个帖子代码是一样一样的。然後错误原因是人家用的是第一种获取二维码的方式,这种方式要求必须有page且没有scene参数。反正就是接口路径错了!
- 这两个方法分开写的一大问题:最开始获取accesstoken的时候appid和secret都是参数的形式。注意这个appid并没有遵循常规的驼峰法。这个i是小写的。
- 建议多看看这个错误码。反正我在测试接口的时候,41001.44002,42001等等,什么xxx159(xxx是 我忘了是啥的)之类的好多都遇到了,面向错误码编程,倒是没必要记住,但是起码知道出错了去哪里查问题。下面附上微信错误码页面:
微信全局返回码说明
然後这个简单的小需求就实现了,如果本文帮到了你记得点个喜欢点个关注。如果有什么问题也欢迎留言或者私信一起探讨。另外祝大家工作顺顺利利!java技术交流群:130031711,欢迎各位萌新大佬踊跃加入,共同学习进步!