1.设计思路

思路参考:一篇大神的笔记
主要就是通过用sessionid请求微信服务器生成临时二维码,客户扫码后微信服务器会将对应数据发给本地服务器,本地根据openid在关联关系表中找出userid,取出用户信息,放入缓存中,即为登录成功。我使用的是微信测试公众号,未关注公众号和已关注公众号触发的事件不同。

2.获取二维码字节流


    /**
     * 获取生成临时二维码的ticke
     */
    public static String createForeverTicket(String accessToken, String sceneId) {
        String ticke = null;
        String requestUrl = " https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN";
        requestUrl = requestUrl.replace("TOKEN", accessToken);

        String ticketParam = "{\"expire_seconds\": 1200, \"action_name\": \"QR_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"" + sceneId + "\"}}}";
        String reString = CheckoutUtil.httpsRequest(requestUrl, "POST", ticketParam, null);
        JSONObject jsonObject = JSONObject.parseObject(reString);
        if (null != jsonObject) {

            try {
                ticke = jsonObject.getString("ticket");
            } catch (Exception e) {
                int err = jsonObject.getInteger("errcode");
                String errormsg = jsonObject.getString("errmsg");
                System.out.println("获取失败errcode=" + err + "errmsg=" + errormsg);
            }
        }
        return ticke;
    }
    /**
     * 换取二维码字节流
     *
     */
    public static byte[] sendHttpByGet(String ticket){
        String requestUrl = "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET";
        requestUrl = requestUrl.replace("TICKET", ticket);
        try {
            URL urlGet = new URL(requestUrl);
            URLConnection urlConnection = urlGet.openConnection();
            InputStream is = urlConnection.getInputStream();
            byte[] bytes = toByteArray(is);
            is.close();
            return bytes;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * InputStream转化为byte[]数组
     */
    public static byte[] toByteArray(InputStream input) throws IOException {
        ByteArrayOutputStream output = new ByteArrayOutputStream();
        byte[] buffer = new byte[4096];
        int n = 0;
        while (-1 != (n = input.read(buffer))) {
            output.write(buffer, 0, n);
        }
        return output.toByteArray();
    }

3.将二维码以图片流传给前端

QRcode.getQRcodeImg(request)输出的就是上面的byte[] sendHttpByGet

 @GetMapping("/getImg")
    public void getImg(HttpServletRequest request, HttpServletResponse response) throws IOException {
        //设置响应类型
        response.setContentType("image/png");
        //输出图片到页面
        PrintWriter out = response.getWriter();
        InputStream is = new ByteArrayInputStream(QRcode.getQRcodeImg(request));
        int a = is.read();
        while (a != -1) {
            out.print((char) a);
            a = is.read();
        }
        out.flush();
        out.close();
    }

4.前端接收显示二维码

async WeChatToken() {
      const { data: res } = await this.$http.get('WeChatToken/getImg', {
        responseType: 'arraybuffer'
      });
      this.imgUrl = 'data:image/png;base64,' + btoa(new Uint8Array(res).reduce((data, byte) => data + String.fromCharCode(byte), ''));
      this.dialogVisible = true;
      this.timer = setInterval(async () => {
        const { data: res } = await this.$http.get('WeChatToken/isLogin');
        console.log(res);
        if (res.status == '200') {
          //登陆成功
        }
      }, 2000);
    }

5.服务器接收扫码事件

我是将sessionid做为key对应的用户数据为value存入application

 @PostMapping
    protected void toVatifyTokenPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException  {
        //防止进行post提交和响应的消息乱码
        request.setCharacterEncoding("UTF-8");
        response.setHeader("Content-type", "text/html;charset=UTF-8");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        try{

            //将发送过来的消息XML形式转为map内容
            Map<String , String> map = MessageUtils.xmlToMap(request);

            String fromUserName = map.get("FromUserName");

            String toUserName = map.get("ToUserName");
            String msgType = map.get("MsgType");
            String content = map.get("Content");
            String message = null ;
            if(MessageUtils.MESSAGE_EVENT.equals(msgType)){
                String eventType = map.get("Event");
                //订阅事件 或 未关注扫描二维码事件
                if(MessageUtils.MESSAGE_SUBSCRIBE .equals(eventType)){
                    message = meUtils.initText(fromUserName,toUserName , MessageUtils.menuText());
                }else if(MessageUtils.MESSAGE_SCANCODE .equals(eventType)) {
                    //进行的是扫码事件
                    String key = map.get("EventKey");
                    message = meUtils.initText(fromUserName,toUserName , "已验证信息,请稍后。");
                    User selUser= weChatServiceImpl.selUserByOpenid(fromUserName);
                    System.out.println(key);
                    ServletContext application = request.getSession().getServletContext();
                    application.setAttribute(key,selUser);
                }else if(MessageUtils.MESSAGE_UNSUBSCRIBE .equals(eventType)) {
                    //进行的是取消关注事件
                    weChatServiceImpl.delUserOpenid(fromUserName);
                }
            }else {
                message = meUtils.initText(fromUserName,toUserName , "自动回复:测试服务器,功能未完善。");
            }

            out.print(message);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            out.close();
        }

    }

6.vue前端获取到二维码后会定时查询是否登陆成功

   /**
     *判断扫码登陆
     */
    @GetMapping("/isLogin")
    public JSONResult isLogin(HttpServletRequest request) {
        ServletContext application = request.getSession().getServletContext();
        String sessionId=request.getSession().getId();
        User user = (User) application.getAttribute(sessionId);
        if(user!=null){
            application.removeAttribute(sessionId);
            return   JSONResult.custom("200", getToken(user), user);
        }
        return JSONResult.failMsg("未登录");
    }

在这里插入图片描述

Logo

前往低代码交流专区

更多推荐