分享

扫二维码自动跳转【java】

 喜乐猪猪侠 2018-01-24


这个帖子网上很多了,但是都是讲理论知识,我呢,喜欢搞代码。既然搞完了,就贴出来备忘一下,也可以分享一下。


重复理论步骤:

1、进入网站-生成UUID

2、跳转到二维码页面(二维码包含UUID)

3、二维码页面写一个js,自动请求服务器查询二维码是否被扫

4、服务器收到请求,查询,如果还没被扫,进入等待,先不返回结果

5、一旦被扫,立即返回结果,页面js收到响应,做后续处理


OK,步骤是这样的没错,不过有一点缺点,步骤3中如果请求超时怎么办。

这个微信web登录有示例,服务器被请求后,持续等待25秒左右,然后结束请求,js端重新发起请求,就这样25秒为周期,不停发起长链接请求。

看下微信web的长连接


不说了,贴代码了,我这里使用的是spring-boot ,spring版本是4.3.6

1、生成UUID

  1. @RequestMapping("/")  
  2. String index(HttpServletRequest request,HttpServletResponse response)  
  3. {  
  4.     System.out.println("进入首页,先生成UUID");  
  5.       
  6.     request.setAttribute("uuid", UUID.randomUUID());  
  7.       
  8.     return "pages/index";  
  9. }  


2、生成二维码,页面部分

  1. <body>  
  2.     <div class="main">  
  3.         <div class="title">  
  4.             <img id="qrcode" alt="" src="">  
  5.         </div>  
  6.         <div id="result" class="title"></div>  
  7.     </div>  
  8.   
  9. </body>  

页面js:

[javascript] view plain copy
print?
  1. $(function() {  
  2.         // 文档就绪  
  3.         $("#qrcode").attr("src", "/qrcode/${uuid}");  
  4.         $("#result").html("使用手机扫描二维码");  
  5.         keepPool();//一加载就进入自动请求-见步骤3  
  6.     });  


3、页面js自动请求服务器查询是否被扫

[javascript] view plain copy
print?
  1. function keepPool(){  
  2.         $.post("/pool", {  
  3.             uuid : "${uuid}",  
  4.         }, function(data) {  
  5.             if(data=='success'){  
  6.               $("#result").html("登录成功");  
  7.             }else if(data=='timeout'){  
  8.                 $("#result").html("登录超时,请刷新重试");  
  9.             }else{  
  10.                 keepPool();  
  11.             }  
  12.         });  
  13.     }  

4、服务器收到请求,这里服务器端的事情还是蛮多的,分解一下

      1、首先要生成二位码,对应 $("#qrcode").attr("src", "/qrcode/${uuid}");

      2、生成二位码后,需要将uuid放入到缓存,我是将UUID作为建,新建一个对象作为值(这里可以采用redis),我为了学习方便,自己写了个缓存

      3、查询是否被扫,对应$.post("/pool", { uuid : "${uuid}"}......,这时候有一个等待的功能(缓存中的对象来控制,这个对象的键就是UUID)

      4、被扫后,立马通知等待者(这里是通过缓存中的对象来通知消息的)

      5、上面说了好多次对象了,对的,都是同一个,接着贴代码了


4.1-4.2 生成二位码,我这里使用的google的zxing

  1. @RequestMapping("/qrcode/{uuid}")  
  2.     @ResponseBody  
  3.     String createQRCode(@PathVariable String uuid,HttpServletResponse response)  
  4.     {  
  5.         System.out.println("生成二维码");  
  6.           
  7.         String text = "http://172.20.16.194:8080/login/"+uuid;  
  8.         int width = 300;     
  9.         int height = 300;     
  10.         String format = "png";     
  11.         //将UUID放入缓存  
  12.         ScanPool pool = new ScanPool();  
  13.         PoolCache.cacheMap.put(uuid, pool);  
  14.         try  
  15.         {  
  16.             Map<EncodeHintType, Object> hints= new HashMap<EncodeHintType, Object>();     
  17.             hints.put(EncodeHintType.CHARACTER_SET, "utf-8");  
  18.             //hints.put(EncodeHintType.MARGIN, 1);  
  19.             hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //容错率  
  20.             BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height,hints);  
  21.             MatrixToImageWriter.writeToStream(bitMatrix, format, response.getOutputStream());  
  22.         } catch (WriterException e)  
  23.         {  
  24.             // TODO Auto-generated catch block  
  25.             e.printStackTrace();  
  26.         } catch (IOException e)  
  27.         {  
  28.             // TODO Auto-generated catch block  
  29.             e.printStackTrace();  
  30.         }  
  31.         return null;  
  32.     }  

看到对象ScanPool没有,这就是那个对象,PoolCache是那个缓存,既然说了,先贴这两个类。

ScanPool.java

  1. public class ScanPool  
  2. {  
  3.   
  4.     //创建时间  
  5.     private Long createTime = System.currentTimeMillis();  
  6.       
  7.     //登录状态  
  8.     private boolean scanFlag = false;  
  9.       
  10.     public boolean isScan(){  
  11.         return scanFlag;  
  12.     }  
  13.       
  14.     public void setScan(boolean scanFlag){  
  15.         this.scanFlag = scanFlag;  
  16.     }  
  17.       
  18.     /** 
  19.      * 获取扫描状态,如果还没有扫描,则等待固定秒数 
  20.      * @param wiatSecond 需要等待的秒数 
  21.      * @return 
  22.      */  
  23.     public synchronized boolean getScanStatus(){  
  24.         try  
  25.         {  
  26.             if(!isScan()){ //如果还未扫描,则等待  
  27.                 this.wait();  
  28.             }  
  29.             if (isScan())  
  30.             {  
  31.                 return true;  
  32.             }  
  33.         } catch (InterruptedException e)  
  34.         {  
  35.             // TODO Auto-generated catch block  
  36.             e.printStackTrace();  
  37.         }  
  38.         return false;  
  39.     }  
  40.       
  41.     /** 
  42.      * 扫码之后设置扫码状态 
  43.      */  
  44.     public synchronized void scanSuccess(){  
  45.         try  
  46.         {  
  47.             setScan(true);  
  48.             this.notifyAll();  
  49.         } catch (Exception e)  
  50.         {  
  51.             // TODO Auto-generated catch block  
  52.             e.printStackTrace();  
  53.         }  
  54.     }  
  55.       
  56.     public synchronized void notifyPool(){  
  57.         try  
  58.         {  
  59.             this.notifyAll();  
  60.         } catch (Exception e)  
  61.         {  
  62.             // TODO Auto-generated catch block  
  63.             e.printStackTrace();  
  64.         }  
  65.     }  
  66.   
  67.     public Long getCreateTime()  
  68.     {  
  69.         return createTime;  
  70.     }  
  71.   
  72.     public void setCreateTime(Long createTime)  
  73.     {  
  74.         this.createTime = createTime;  
  75.     }  
  76.   
  77. }  

PoolCache.java

  1. public class PoolCache  
  2. {  
  3.     //缓存超时时间 10分钟  
  4.     private static Long timeOutSecond = 600L;  
  5.       
  6.     //每半小时清理一次缓存  
  7.     private static Long cleanIntervalSecond = 1800L;  
  8.       
  9.     public static Map<String, ScanPool> cacheMap = new HashMap<String, ScanPool>();  
  10.       
  11.     static{  
  12.         new Thread(new Runnable()  
  13.         {  
  14.               
  15.             @Override  
  16.             public void run()  
  17.             {  
  18.                 // TODO Auto-generated method stub  
  19.                 while (true)  
  20.                 {  
  21.                     try  
  22.                     {  
  23.                         Thread.sleep(cleanIntervalSecond*1000);  
  24.                     } catch (InterruptedException e)  
  25.                     {  
  26.                         // TODO Auto-generated catch block  
  27.                         e.printStackTrace();  
  28.                     }  
  29.                     clean();  
  30.                 }  
  31.             }  
  32.               
  33.             public void clean(){  
  34.                 if(cacheMap.keySet().size() > 0){  
  35.                     Iterator<String> iterator = cacheMap.keySet().iterator();  
  36.                     while (iterator.hasNext())  
  37.                     {  
  38.                         String key = iterator.next();  
  39.                         ScanPool pool = cacheMap.get(key);  
  40.                         if(System.currentTimeMillis() - pool.getCreateTime() > timeOutSecond * 1000){  
  41.                             cacheMap.remove(key);  
  42.                         }  
  43.                     }  
  44.                 }  
  45.             }  
  46.         }).start();  
  47.     }  
  48.   
  49. }  


4.3.查询是否被扫

  1. @RequestMapping("/pool")  
  2.     @ResponseBody  
  3.     String pool(String uuid){  
  4.         System.out.println("检测["+uuid+"]是否登录");  
  5.           
  6.         ScanPool pool = PoolCache.cacheMap.get(uuid);  
  7.           
  8.         if(pool == null){  
  9.             return "timeout";  
  10.         }  
  11.           
  12.         //使用计时器,固定时间后不再等待扫描结果--防止页面访问超时  
  13.         new Thread(new ScanCounter(uuid)).start();  
  14.           
  15.         boolean scanFlag = pool.getScanStatus();  
  16.         if(scanFlag){  
  17.             return "success";  
  18.         }else{  
  19.             return "fail";  
  20.         }  
  21.     }  

这里看到,有一个防止页面请求超时的,是写了一个计时器,达到固定时长就停掉,返回一个fail,这里我就不贴了,有需要的可以下载我源码看


4.4.被扫后

  1. @RequestMapping("/login/{uuid}")  
  2.     @ResponseBody  
  3.     String login(@PathVariable String uuid){  
  4.           
  5.         ScanPool pool = PoolCache.cacheMap.get(uuid);  
  6.           
  7.         if(pool == null){  
  8.             return "timeout,scan fail";  
  9.         }  
  10.           
  11.         pool.scanSuccess();  
  12.           
  13.         return "scan success";  
  14.     }  


ok,结束



       


    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多