您的位置:首页 > 教程文章 > 编程开发

扫二维码自动跳转【java】详解

:0 :2021-06-05 08:25:17

这个帖子网上很多了,但是都是讲理论知识,我呢,喜欢搞代码。既然搞完了,就贴出来备忘一下,也可以分享一下。
重复理论步骤:
1、进入网站-生成UUID
2、跳转到二维码页面(二维码包含UUID)
3、二维码页面写一个js,自动请求服务器查询二维码是否被扫
4、服务器收到请求,查询,如果还没被扫,进入等待,先不返回结果
5、一旦被扫,立即返回结果,页面js收到响应,做后续处理
OK,步骤是这样的没错,不过有一点缺点,步骤3中如果请求超时怎么办。
这个微信web登录有示例,服务器被请求后,持续等待25秒左右,然后结束请求,js端重新发起请求,就这样25秒为周期,不停发起长链接请求。
看下微信web的长连接

不说了,贴代码了,我这里使用的是spring-boot ,spring版本是4.3.6
1、生成UUID
@RequestMapping("/")
 String index(HttpServletRequest request,HttpServletResponse response)
 {
  System.out.println("进入首页,先生成UUID");
  
  request.setAttribute("uuid", UUID.randomUUID());
  
  return "pages/index";
 }
2、生成二维码,页面部分
<body>
 <div class="main">
  <div class="title">
   <img id="qrcode" alt="" src="">
  </div>
  <div id="result" class="title"></div>
 </div>
 
</body>
页面js:
$(function() {
  // 文档就绪
  $("#qrcode").attr("src", "/qrcode/${uuid}");
  $("#result").html("使用手机扫描二维码");
  keepPool();//一加载就进入自动请求-见步骤3
 });
3、页面js自动请求服务器查询是否被扫
function keepPool(){
  $.post("/pool", {
   uuid : "${uuid}",
  }, function(data) {
   if(data=='success'){
    $("#result").html("登录成功");
   }else if(data=='timeout'){
    $("#result").html("登录超时,请刷新重试");
   }else{
    keepPool();
   }
  });
 }
4、服务器收到请求,这里服务器端的事情还是蛮多的,分解一下
1、首先要生成二位码,对应 $("#qrcode").attr("src", "/qrcode/${uuid}");
2、生成二位码后,需要将uuid放入到缓存,我是将UUID作为建,新建一个对象作为值(这里可以采用redis),我为了学习方便,自己写了个缓存
3、查询是否被扫,对应$.post("/pool", { uuid : "${uuid}"}......,这时候有一个等待的功能(缓存中的对象来控制,这个对象的键就是UUID)
4、被扫后,立马通知等待者(这里是通过缓存中的对象来通知消息的)
5、上面说了好多次对象了,对的,都是同一个,接着贴代码了
4.1-4.2 生成二位码,我这里使用的的zxing
@RequestMapping("/qrcode/{uuid}")
 @ResponseBody
 String createQRCode(@PathVariable String uuid,HttpServletResponse response)
 {
  System.out.println("生成二维码");
  
  String text = "
  int width = 300;
  int height = 300;
  String format = "png";
  //将UUID放入缓存
  ScanPool pool = new ScanPool();
  PoolCache.cacheMap.put(uuid, pool);
  try
  {
   Map<EncodeHintType, Object> hints= new HashMap<EncodeHintType, Object>();
   hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
   //hints.put(EncodeHintType.MARGIN, 1);
   hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); //容错率
   BitMatrix bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height,hints);
   MatrixToImageWriter.writeToStream(bitMatrix, format, response.getOutputStream());
  } catch (WriterException e)
  {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e)
  {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return null;
 }
看到对象ScanPool没有,这就是那个对象,PoolCache是那个缓存,既然说了,先贴这两个类。
ScanPool.java
public class ScanPool
{
 
 //创建时间
 private Long createTime = System.currentTimeMillis();
 
 //登录状态
 private boolean scanFlag = false;
 
 public boolean isScan(){
  return scanFlag;
 }
 
 public void setScan(boolean scanFlag){
  this.scanFlag = scanFlag;
 }
 
 /**
  * 获取扫描状态,如果还没有扫描,则等待固定秒数
  * @param wiatSecond 需要等待的秒数
  * @return
  */
 public synchronized boolean getScanStatus(){
  try
  {
   if(!isScan()){ //如果还未扫描,则等待
    this.wait();
   }
   if (isScan())
   {
    return true;
   }
  } catch (InterruptedException e)
  {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  return false;
 }
 
 /**
  * 扫码之后设置扫码状态
  */
 public synchronized void scanSuccess(){
  try
  {
   setScan(true);
   this.notifyAll();
  } catch (Exception e)
  {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 public synchronized void notifyPool(){
  try
  {
   this.notifyAll();
  } catch (Exception e)
  {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
 }
 
 public Long getCreateTime()
 {
  return createTime;
 }
 
 public void setCreateTime(Long createTime)
 {
  this.createTime = createTime;
 }
 
}
PoolCache.java
public class PoolCache
{
 //缓存超时时间 10分钟
 private static Long timeOutSecond = 600L;
 
 //每半小时清理一次缓存
 private static Long cleanIntervalSecond = 1800L;
 
 public static Map<String, ScanPool> cacheMap = new HashMap<String, ScanPool>();
 
 static{
  new Thread(new Runnable()
  {
   
   @Override
   public void run()
   {
    // TODO Auto-generated method stub
    while (true)
    {
     try
     {
      Thread.sleep(cleanIntervalSecond*1000);
     } catch (InterruptedException e)
     {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
     clean();
    }
   }
   
   public void clean(){
    if(cacheMap.keySet().size() > 0){
     Iterator<String> iterator = cacheMap.keySet().iterator();
     while (iterator.hasNext())
     {
      String key = iterator.next();
      ScanPool pool = cacheMap.get(key);
      if(System.currentTimeMillis() - pool.getCreateTime() > timeOutSecond * 1000){
       cacheMap.remove(key);
      }
     }
    }
   }
  }).start();
 }
 
}
4.3.查询是否被扫
@RequestMapping("/pool")
 @ResponseBody
 String pool(String uuid){
  System.out.println("检测["+uuid+"]是否登录");
  
  ScanPool pool = PoolCache.cacheMap.get(uuid);
  
  if(pool == null){
   return "timeout";
  }
  
  //使用计时器,固定时间后不再等待扫描结果--防止页面访问超时
  new Thread(new ScanCounter(uuid)).start();
  
  boolean scanFlag = pool.getScanStatus();
  if(scanFlag){
   return "success";
  }else{
   return "fail";
  }
 }
这里看到,有一个防止页面请求超时的,是写了一个计时器,达到固定时长就停掉,返回一个fail,这里我就不贴了,有需要的可以下载我源码看
4.4.被扫后
@RequestMapping("/login/{uuid}")
 @ResponseBody
 String login(@PathVariable String uuid){
  
  ScanPool pool = PoolCache.cacheMap.get(uuid);
  
  if(pool == null){
   return "timeout,scan fail";
  }
  
  pool.scanSuccess();
  
  return "scan success";
 }
ok,结束
源码下载地址:
以上所述是小编给大家介绍的java扫二维码自动跳转详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对无名的支持!

Spring Cloud GateWay 路由转发规则介绍详解
Spring+SpringMVC+Hibernate项目环境搭建的步骤(图文)

同类资源