栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

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

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

java实现简单扫码登录功能

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

生成qrcode相关js jquery.qrcode.js

代码

页面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 map = new HashMap(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 cookieSession = new HashMap();
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{

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

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

  
 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 cacheMap = new HashMap();

 //List
 //public static CopyOnWriteArrayList> copyonWriteArrayList = new CopyOnWriteArrayList>();

 //专用于高并发的map类-----Map的并发处理(ConcurrentHashMap)
 public static ConcurrentHashMap cacheMap = new ConcurrentHashMap();


 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 (cacheMap.keySet().size() > 0) {
Iterator 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.jb51.net/article/160745.htm

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

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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/138280.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号