扫二维码自动跳转【java】详解
这个帖子网上很多了,但是都是讲理论知识,我呢,喜欢搞代码。既然搞完了,就贴出来备忘一下,也可以分享一下。
重复理论步骤:
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,结束
源码下载地址:
以上所述是小编给大家介绍的java扫二维码自动跳转详解整合,希望对大家有所帮助