原文:https://www.jianshu.com/p/6e05df377e52


微信生成小程序二维码链接
主要分两种:

  • 一种适用于需要的码数量较少的业务场景。通过该接口生成的小程序码,永久有效,有数量限制。重点是只能直接定位到小程序中某个页面,不能传参数,所以这个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测试这个接口如下写法:

 

 

 

 

        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+端口+路径+图片名 访问图片的形式)。所以我这里相当于多了一个过程。
然後可以开始判断这个接口的实现遇到的坑了:
我之前都说了这个就是个简单的接口访问,难是不难,但是出于我的马虎大意,所以也是调了一下午。下面一一道来。

  1. 作为一个面向百度的程序员,第一反应是拿现成的,所以百度几个帖子cv,个个都出错。最后发现百度靠前的几个帖子代码是一样一样的。然後错误原因是人家用的是第一种获取二维码的方式,这种方式要求必须有page且没有scene参数。反正就是接口路径错了!
  2. 这两个方法分开写的一大问题:最开始获取accesstoken的时候appid和secret都是参数的形式。注意这个appid并没有遵循常规的驼峰法。这个i是小写的。
  3. 建议多看看这个错误码。反正我在测试接口的时候,41001.44002,42001等等,什么xxx159(xxx是 我忘了是啥的)之类的好多都遇到了,面向错误码编程,倒是没必要记住,但是起码知道出错了去哪里查问题。下面附上微信错误码页面:
    微信全局返回码说明