首页 > 编程 > Java > 正文

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

2019-11-26 09:02:31
字体:
来源:转载
供稿:网友

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

重复理论步骤:

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 生成二位码,我这里使用的google的zxing

@RequestMapping("/qrcode/{uuid}")	@ResponseBody	String createQRCode(@PathVariable String uuid,HttpServletResponse response)	{		System.out.println("生成二维码");				String text = "http://172.20.16.194:8080/login/"+uuid;		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,结束

源码下载地址:http://xz.VeVB.COm:81/201905/yuanma/springboot(VeVB.COm).rar

以上所述是小编给大家介绍的java扫二维码自动跳转详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表