java实现简单扫码登录功能(模仿微信网页版扫码)
java实现简单扫码登录功能
- 模仿微信pc网页版扫码登录
- 使用js代码生成qrcode二维码减轻服务器压力
- js循环请求服务端,判断是否qrcode被扫
- 二维码超时失效功能
- 二维码被扫成功登录,服务端产生sessionId,传到页面使用js保存cookie
- 多线程
生成qrcode相关js jquery.qrcode.js
-
代码
页面div
<div class="pc_qr_code"><input type="hidden" id="uuid" value="${uuid }"/>
</div><div id="result">请使用手机扫码</div>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
主要js
//生成二维码!function(){var uuid = $("#uuid").val();var content;content = "..........do?uuid="+uuid;//console.dir(content);$('.pc_qr_code').qrcode({render:"canvas",width:200,height:200,correctLevel:0,text:content,background:"#ffffff",foreground:"black",src:"/logo.png"}); setCookie("sid", 123, -1*60*60*1000);keepPool();//自动循环调用}();function keepPool(){var uuid = $("#uuid").val();$.get(ctx+"/web/login/pool.do",{uuid:uuid,},function(msg){//如果放入一个不存在的网址怎么办?//console.log(msg);if(msg.successFlag == '1'){$("#result").html("扫码成功");setCookie(msg.data.cname, msg.data.cvalue, 3*60*60*1000);//alert("将跳转...");window.location.href = ctx +"/webstage/login/success.do";}else if(msg.successFlag == '0'){$("#result").html("该二维码已经失效,请重新获取");}else{keepPool();}}); }//设置cookiefunction setCookie(cname, cvalue, expireTime) {var d = new Date();d.setTime(d.getTime() + expireTime);//设置过期时间var expires = "expires="+d.toUTCString();var path = "path=/"document.cookie = cname + "=" + cvalue + "; " + expires + "; " + path;}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
“
java代码
//二维码首页
public String index() {try {uuid = UUID.randomUUID().toString();super.getRequest().setAttribute("uuid", uuid);ScanPool pool = new ScanPool();pool.setCreateTime(System.currentTimeMillis());Map<String, ScanPool> map = new HashMap<String, ScanPool>(1);map.put(uuid, pool);PoolCache.cacheMap.put(uuid, pool);pool = null;} catch (Exception e) {Log4jUtil.CommonLog.error("pc生成二维码登录", e);}return "index";}
//判断二维码是否被扫描
public void pool() {DataResultInfo result = null;System.out.println("检测[ " + uuid + " ]是否登录");ScanPool pool = null; if(MapUtils.isNotEmpty(PoolCache.cacheMap)) pool = PoolCache.cacheMap.get(uuid);try {if (pool == null) {// 扫码超时,进线程休眠result = DataResultInfo.getInstance().failure();result.setSuccessFlag(CommonConstant.Zero);result.setExtension(CommonConstant.Zero, "该二维码已经失效,请重新获取");Thread.sleep(10 * 1000L);} else {// 使用计时器,固定时间后不再等待扫描结果--防止页面访问超时new Thread(new ScanCounter(uuid, pool)).start();boolean scanFlag = pool.getScanStatus(); //这里得到的ScanPool(时间靠前)和用户使用手机扫码后得到的不是一个,用户扫码后又重新更新了ScanPool对象,并重新放入了redis中,,所以这里要等待上面的计时器走完,才能获得最新的ScanPoolif (scanFlag) {result = DataResultInfo.getSuccess();// 根据uuid从redis中获取pool对象,得到对应的sessionId,返给页面,通过js存cookie中JSONObject jsonObj = new JSONObject();jsonObj.put("cname", CookieConstant.SESSION_KEY);jsonObj.put("cvalue", pool.getSession());result.setData(jsonObj);} else {result = DataResultInfo.getInstance().failure();result.setMessage("等待扫描");}}} catch (Exception e) {e.printStackTrace();}sendJsonMessage(result);}//手机扫码接口(以id和token作为用户身份登录)public String phoneScanLogin() {DataResultInfo result = null;ScanPool pool = null; if(MapUtils.isNotEmpty(PoolCache.cacheMap)) pool = PoolCache.cacheMap.get(uuid);try {if (pool == null) {result = DataResultInfo.getInstance().failure();result.setMessage("该二维码已经失效,请重新获取");} else {if (StringUtils.isNotEmpty(id) && StringUtils.isNotEmpty(token)) {//根据id和token查询后台,获取用户信息userBeanString redisToken = redisUtil.getRedis(RedisKeyConstant.APP_TOKEN+userId);if(redisToken != null && redisToken.equals(token)){UserBean userBean = userService.findByUserId(Long.valueOf(userId));if (userBean != null) {String sessionId = SessionConstant.SESSION_ID_PRE+ FormatUtils.password(userBean.getId().toString());Map<String, String> cookieSession = new HashMap<String, String>();cookieSession.put(CookieConstant.SESSION_KEY, sessionId);// WrCookie.writeCookie(getResponse(),cookieSession);// 添加用户信息到redisboolean re = redisUtil.addUserInfo( RedisKeyConstant.SESSION + sessionId, BeanUtils.toBean(userBean, UserInfo.class));getSession().setAttribute( SessionConstant.USER_INFO_WEB, BeanUtils.toBean(userBean, UserInfo.class));getSession().setAttribute( DomainConstant.USER_CENTER_KEY, DomainConstant.USER_CENTER);pool.setSession(sessionId);pool.scanSuccess();}else{result = DataResultInfo.getInstance().failure();result.setMessage("用户信息获取异常!请稍后再试");}} else {result = DataResultInfo.getInstance().failure();result.setExtension("11", "用户身份信息失效,请重新登录!");}} else {result = DataResultInfo.getInstance().failure();result.setMessage("请求参数有误!");return "error";}// 不能清除,否则conn方法得不到pool对象,不会进入线程休眠// System.out.println("清除扫描过的uuid");//PoolCache.cacheMap.remove(uuid);}} catch (Exception e) {Log4jUtil.CommonLog.error("手机扫码 后访问 异常", e);}sendJsonMessage(result);return null;}//扫码成功跳转页public String success() {String sessionId = WrCookie.getCookie(super.getRequest(), CookieConstant.SESSION_KEY);UserInfo userInfo = redisUtil.getUserInfo(RedisKeyConstant.SESSION + sessionId);super.getRequest().setAttribute(SessionConstant.USER_INFO_WEB, userInfo);return SUCCESS;}//线程判断二维码是否超时
class ScanCounter implements Runnable {public Long timeout = 30 * 1000L; //超时时长// 传入的对象private String uuid;private ScanPool scanPool;public ScanCounter(String p, ScanPool scanPool) {uuid = p;this.scanPool = scanPool;}@Overridepublic void run() {try {Thread.sleep(timeout);} catch (InterruptedException e) {e.printStackTrace();}notifyPool(uuid, scanPool);}public synchronized void notifyPool(String uuid, ScanPool scanPool) {if (scanPool != null) scanPool.notifyPool();}public String getUuid() {return uuid;}public void setUuid(String uuid) {this.uuid = uuid;}public ScanPool getScanPool() {return scanPool;}public void setScanPool(ScanPool scanPool) {this.scanPool = scanPool;}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
ScanPool.java(存放uuid的bean)
public class ScanPool implements Serializable{/*** @Fields serialVersionUID : TODO(用一句话描述这个变量表示什么) */private static final long serialVersionUID = -9117921544228636689L;private Object session ;//创建时间 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()) { System.err.println("手机扫描完成设置getScanStatus..true...........");return true; } } catch (InterruptedException e) { e.printStackTrace(); } return false; } /** * 扫码之后设置扫码状态 * @param token * @param id */ public synchronized void scanSuccess(){ try { System.err.println("手机扫描完成setScan(true)....同时释放notifyAll(手机扫码时,根据uuid获得的scanpool对象)");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; }public Object getSession() {return session;}public void setSession(Object session) {this.session = session;}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
PoolCache.java(定时清理二维码uuid的类)
public class PoolCache {// 缓存超时时间 10分钟private static Long timeOutSecond = 10 * 60 * 1000L;// 每半小时清理一次缓存private static Long cleanIntervalSecond = 30 * 60 * 1000L;//此map在多线程中会出现 ConcurrentModificationException//public static Map<String, ScanPool> cacheMap = new HashMap<String, ScanPool>();//List//public static CopyOnWriteArrayList<Map<String, ScanPool>> copyOnWriteArrayList = new CopyOnWriteArrayList<Map<String,ScanPool>>();//专用于高并发的map类-----Map的并发处理(ConcurrentHashMap)public static ConcurrentHashMap<String, ScanPool> cacheMap = new ConcurrentHashMap<String, ScanPool>();static {new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(cleanIntervalSecond);} catch (InterruptedException e) {e.printStackTrace();}clean();}}public void clean() {try {/*if (copyOnWriteArrayList.size() > 0) {Iterator<Map<String, ScanPool>> iterator = copyOnWriteArrayList.iterator();while (iterator.hasNext()) {Map<String, ScanPool> map = iterator.next();Iterator<String> it2 = map.keySet().iterator();while (it2.hasNext()){String uuid = it2.next();ScanPool pool = map.get(uuid);if (System.currentTimeMillis() - pool.getCreateTime() > timeOutSecond ) {copyOnWriteArrayList.remove(map);System.err.println("失效了: .. "+ uuid);System.err.println("失效了: .. "+ map);break;}}}}*/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 ) {cacheMap.remove(key);}}}} catch (Exception e) {Log4jUtil.CommonLog.error("定时清理uuid异常", e);}}}).start();}}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
扫码流程 图:
流程图:
使用线程实时监听扫码状态;
用户扫描二维码相当于使用 用户名密码 在网页端登录,需要存浏览器cookie
,而用户通过使用手机扫码,直接请求服务器,登陆成功,js中得到用户数据及cookie,把cookie返给页面,再通过js存入cookie中,
本文借鉴与此大神的代码,稍作了修改,参考 扫二维码自动跳转(java),
++++++++demo源码地址:
**应大佬们的要求
附上github源码地址供大家参考*: https://github.com/luuuuuuuuu/qrscan
java实现简单扫码登录功能(模仿微信网页版扫码)相关推荐
- java实现扫码微信登录_java实现简单扫码登录功能(模仿微信网页版扫码)
public class PoolCache { // 缓存超时时间 10分钟 private static Long timeOutSecond = 10 * 60 * 1000L; // 每半小时 ...
- [微信] 微信网页版扫码登录的实现
我们先来回顾一下微信网页版的扫码登录过程 1. 打开微信网页版,https://wx.qq.com/ 2. 打开手机微信客户端,扫一扫 3. 点击确定,登录 看似简单的操作流程,中间涉及的数据交互有很 ...
- lol微信登录服务器,lol开放微信登录功能 lol微信怎么登陆
lol开放微信登录功能 lol微信登录功能开放大区有哪些 英雄联盟在5月6日开放了部分大区的微信登录功能,玩家们现在可在目前开放了微信登录功能的 大区使用微信登录,但需要将微信账号与已有QQ账号进行绑 ...
- 手把手教程用Java实现微信公众号扫码登录功能
文章目录 前言 一.环境准备 二.使用步骤 1. 使用微信工具包 2. 创建数据表 3. 登录页面代码逻辑 4. 验证微信公众号登录 总结 前言 微信现今是我们必不可少的社交工具了,围绕微信这个生态实 ...
- 项目整合微信扫码登录功能
项目整合微信登录功能 一.准备工作 https://open.weixin.qq.com 1.注册 2.邮箱激活 3.完善开发者资料 4.开发者资质认证 准备营业执照,1-2个工作日审批.300元 5 ...
- 微信扫码登录功能实现
原因:很简单,公司的账号登录需要用到微信扫码登录与QQ的登录功能,所以,在做好了微信的扫码登录之后,本人就写这篇微信扫码登录功能实现的教程 教程开始 需要用到的网站: https://open.wei ...
- IM要做手机扫码登录?先看看微信的扫码登录功能技术原理
本文原文由作者Amazing10原创发布于公众号业余码农,收录时有改动,感谢原作者的技术分享. 1.引言 某天中午,吃完午饭,摊在自己的躺椅上,想趁吃饱喝足的午后时间静静享受独自的静谧. 干点什么好呢 ...
- IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够
本文引用了作者"大古同学"的"二维码扫码登录是什么原理"一文的主要内容,为了更好的理解和阅读,即时通讯网收录时有修订和改动,感谢原作者的分享. 1.引言 自从微 ...
- IM的扫码登录功能如何实现?一文搞懂主流的扫码登录技术原理
本文引用了3位作者"精品唯居"." Yangfan2016"." MrYun"的部分文章内容,一并感谢. 1.引言 扫码登录这个功能,最早 ...
最新文章
- (最新最全)windows使用anaconda安装pytorch进行深度学习并使用GPU加速
- 逆生长!小鼠「逆龄疗法」登Nature子刊,有望用于人类
- 数据类型的转换(范围最大的)
- android 6.0 logcat机制(二)logcat从logd中获取log保存到文件中
- 第六次的服务端课程:JDBC,数据源配置
- shell命令之---sed
- DOCKER windows安装
- matlab二元一次方程求解_2-函数的求解计算
- curl工具使用实例
- 做数据中心,腾讯是认真的!
- node.js服务器+mongodb数据库(重拾)
- 怎么画单极交流放大电路波形图_直流电和交流电的电流方向
- 1470. 重新排列数组
- winhex 15.6 和 HexWorkshop 6.01注册机
- 装饰器只有python才有吗_Python装饰器入门详解
- Excel怎么合并两个或者多个单元格里面的内容
- Matlab二元函数图像绘制
- 动物识别系统c语言编程,人工智能期末论文-简单动物识别系统的知识表示.doc
- 获取当天的0点0分0秒的日期和23点59分59秒的日期
- 计算机查看用户 组,查看工作组计算机的方法介绍