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

扫码流程 图:

流程图:

Created with Raphaël 2.1.2index.jsp(进入扫码页面)循环请求服务器,检查是否被扫pool.doA:扫描成功success.do ; B:二维码超时,清空超时的uuid,刷新页面重新获取新的二维码以及uuidsuccess.jsp(扫码成功跳转页)yes

使用线程实时监听扫码状态;
用户扫描二维码相当于使用 用户名密码 在网页端登录,需要存浏览器cookie
,而用户通过使用手机扫码,直接请求服务器,登陆成功,js中得到用户数据及cookie,把cookie返给页面,再通过js存入cookie中,

本文借鉴与此大神的代码,稍作了修改,参考 扫二维码自动跳转(java),


++++++++demo源码地址:

**应大佬们的要求
附上github源码地址供大家参考*: https://github.com/luuuuuuuuu/qrscan



java实现简单扫码登录功能(模仿微信网页版扫码)相关推荐

  1. java实现扫码微信登录_java实现简单扫码登录功能(模仿微信网页版扫码)

    public class PoolCache { // 缓存超时时间 10分钟 private static Long timeOutSecond = 10 * 60 * 1000L; // 每半小时 ...

  2. [微信] 微信网页版扫码登录的实现

    我们先来回顾一下微信网页版的扫码登录过程 1. 打开微信网页版,https://wx.qq.com/ 2. 打开手机微信客户端,扫一扫 3. 点击确定,登录 看似简单的操作流程,中间涉及的数据交互有很 ...

  3. lol微信登录服务器,lol开放微信登录功能 lol微信怎么登陆

    lol开放微信登录功能 lol微信登录功能开放大区有哪些 英雄联盟在5月6日开放了部分大区的微信登录功能,玩家们现在可在目前开放了微信登录功能的 大区使用微信登录,但需要将微信账号与已有QQ账号进行绑 ...

  4. 手把手教程用Java实现微信公众号扫码登录功能

    文章目录 前言 一.环境准备 二.使用步骤 1. 使用微信工具包 2. 创建数据表 3. 登录页面代码逻辑 4. 验证微信公众号登录 总结 前言 微信现今是我们必不可少的社交工具了,围绕微信这个生态实 ...

  5. 项目整合微信扫码登录功能

    项目整合微信登录功能 一.准备工作 https://open.weixin.qq.com 1.注册 2.邮箱激活 3.完善开发者资料 4.开发者资质认证 准备营业执照,1-2个工作日审批.300元 5 ...

  6. 微信扫码登录功能实现

    原因:很简单,公司的账号登录需要用到微信扫码登录与QQ的登录功能,所以,在做好了微信的扫码登录之后,本人就写这篇微信扫码登录功能实现的教程 教程开始 需要用到的网站: https://open.wei ...

  7. IM要做手机扫码登录?先看看微信的扫码登录功能技术原理

    本文原文由作者Amazing10原创发布于公众号业余码农,收录时有改动,感谢原作者的技术分享. 1.引言 某天中午,吃完午饭,摊在自己的躺椅上,想趁吃饱喝足的午后时间静静享受独自的静谧. 干点什么好呢 ...

  8. IM扫码登录技术专题(三):通俗易懂,IM扫码登录功能详细原理一篇就够

    本文引用了作者"大古同学"的"二维码扫码登录是什么原理"一文的主要内容,为了更好的理解和阅读,即时通讯网收录时有修订和改动,感谢原作者的分享. 1.引言 自从微 ...

  9. IM的扫码登录功能如何实现?一文搞懂主流的扫码登录技术原理

    本文引用了3位作者"精品唯居"."  Yangfan2016"." MrYun"的部分文章内容,一并感谢. 1.引言 扫码登录这个功能,最早 ...

最新文章

  1. (最新最全)windows使用anaconda安装pytorch进行深度学习并使用GPU加速
  2. 逆生长!小鼠「逆龄疗法」登Nature子刊,有望用于人类
  3. 数据类型的转换(范围最大的)
  4. android 6.0 logcat机制(二)logcat从logd中获取log保存到文件中
  5. 第六次的服务端课程:JDBC,数据源配置
  6. shell命令之---sed
  7. DOCKER windows安装
  8. matlab二元一次方程求解_2-函数的求解计算
  9. curl工具使用实例
  10. 做数据中心,腾讯是认真的!
  11. node.js服务器+mongodb数据库(重拾)
  12. 怎么画单极交流放大电路波形图_直流电和交流电的电流方向
  13. 1470. 重新排列数组
  14. winhex 15.6 和 HexWorkshop 6.01注册机
  15. 装饰器只有python才有吗_Python装饰器入门详解
  16. Excel怎么合并两个或者多个单元格里面的内容
  17. Matlab二元函数图像绘制
  18. 动物识别系统c语言编程,人工智能期末论文-简单动物识别系统的知识表示.doc
  19. 获取当天的0点0分0秒的日期和23点59分59秒的日期
  20. 计算机查看用户 组,查看工作组计算机的方法介绍

热门文章

  1. 开运算—lhMorpOpen
  2. Matlab 结构体(struct)使用
  3. 【蔬菜怎么吃最营养】
  4. 多媒体计算机系统主要分为三类,03多媒体计算机系统组成.ppt
  5. 仿热血江湖帮战客方血帮战 开始对战记时器结束事件
  6. 常见的几种网络Hack方式
  7. YOLO工程代码如何在windows上配置和运行!window上YOLO训练样本的制作
  8. 定制 CFileDialog 的相关 ID
  9. 机器学习系列--数据预处理
  10. win7系统突然变慢的解决方法