首页 > 编程 > Java > 正文

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

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

java实现简单扫码登录功能

  1. 模仿微信pc网页版扫码登录
  2. 使用js代码生成qrcode二维码减轻服务器压力
  3. js循环请求服务端,判断是否qrcode被扫
  4. 二维码超时失效功能
  5. 二维码被扫成功登录,服务端产生sessionId,传到页面使用js保存cookie
  6. 多线程

生成qrcode相关js jquery.qrcode.js

代码

页面div

<div class="pc_qr_code">    <input type="hidden" id="uuid" value="${uuid }"/></div> <div id="result">请使用手机扫码</div>

主要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();    }   });   }  //设置cookie  function 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;  }

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中,,所以这里要等待上面的计时器走完,才能获得最新的ScanPool    if (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查询后台,获取用户信息userBean     String 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);       // 添加用户信息到redis       boolean 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; } @Override public 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; }}

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; }}

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() {   @Override   public 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(); }}

扫码流程图:

流程图:

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

参考https://www.VeVB.COm/article/160745.htm

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

以上所述是小编给大家介绍的java实现简单扫码登录功能(模仿微信网页版扫码)详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对武林网网站的支持!

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