欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解java實(shí)現(xiàn)簡(jiǎn)單掃碼登錄功能(模仿微信網(wǎng)頁(yè)版掃碼)

 更新時(shí)間:2019年05月06日 10:12:54   作者:那一年丶天空很高丶風(fēng)很清澈  
這篇文章主要介紹了java實(shí)現(xiàn)簡(jiǎn)單掃碼登錄功能(模仿微信網(wǎng)頁(yè)版掃碼),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

java實(shí)現(xiàn)簡(jiǎn)單掃碼登錄功能

  1. 模仿微信pc網(wǎng)頁(yè)版掃碼登錄
  2. 使用js代碼生成qrcode二維碼減輕服務(wù)器壓力
  3. js循環(huán)請(qǐng)求服務(wù)端,判斷是否qrcode被掃
  4. 二維碼超時(shí)失效功能
  5. 二維碼被掃成功登錄,服務(wù)端產(chǎn)生sessionId,傳到頁(yè)面使用js保存cookie
  6. 多線(xiàn)程

生成qrcode相關(guān)js jquery.qrcode.js

代碼

頁(yè)面div

<div class="pc_qr_code">
    <input type="hidden" id="uuid" value="${uuid }"/>
</div>
 <div id="result">請(qǐng)使用手機(jī)掃碼</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();//自動(dòng)循環(huán)調(diào)用
  }();

  function keepPool(){
   var uuid = $("#uuid").val();
   $.get(ctx+"/web/login/pool.do",{uuid:uuid,},function(msg){//如果放入一個(gè)不存在的網(wǎng)址怎么辦?
    //console.log(msg);
    if(msg.successFlag == '1'){
     $("#result").html("掃碼成功");
     setCookie(msg.data.cname, msg.data.cvalue, 3*60*60*1000);
     //alert("將跳轉(zhuǎn)...");
     window.location.href = ctx +"/webstage/login/success.do";
    }else if(msg.successFlag == '0'){
     $("#result").html("該二維碼已經(jīng)失效,請(qǐng)重新獲取");
    }else{
     keepPool();
    }

   }); 
  }

  //設(shè)置cookie
  function setCookie(cname, cvalue, expireTime) {
   var d = new Date();
   d.setTime(d.getTime() + expireTime);//設(shè)置過(guò)期時(shí)間
   var expires = "expires="+d.toUTCString();
   var path = "path=/"
   document.cookie = cname + "=" + cvalue + "; " + expires + "; " + path;
  }

java代碼

//二維碼首頁(yè)
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("檢測(cè)[ " + uuid + " ]是否登錄");
  ScanPool pool = null; 
  if(MapUtils.isNotEmpty(PoolCache.cacheMap)) pool = PoolCache.cacheMap.get(uuid);

  try {
   if (pool == null) {
    // 掃碼超時(shí),進(jìn)線(xiàn)程休眠
    result = DataResultInfo.getInstance().failure();
    result.setSuccessFlag(CommonConstant.Zero);
    result.setExtension(CommonConstant.Zero, "該二維碼已經(jīng)失效,請(qǐng)重新獲取");
    Thread.sleep(10 * 1000L);
   } else {
    // 使用計(jì)時(shí)器,固定時(shí)間后不再等待掃描結(jié)果--防止頁(yè)面訪(fǎng)問(wèn)超時(shí)
    new Thread(new ScanCounter(uuid, pool)).start();

    boolean scanFlag = pool.getScanStatus(); //這里得到的ScanPool(時(shí)間靠前)和用戶(hù)使用手機(jī)掃碼后得到的不是一個(gè),用戶(hù)掃碼后又重新更新了ScanPool對(duì)象,并重新放入了redis中,,所以這里要等待上面的計(jì)時(shí)器走完,才能獲得最新的ScanPool
    if (scanFlag) {
     result = DataResultInfo.getSuccess();
     // 根據(jù)uuid從redis中獲取pool對(duì)象,得到對(duì)應(yīng)的sessionId,返給頁(yè)面,通過(guò)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);
 }

//手機(jī)掃碼接口(以id和token作為用戶(hù)身份登錄)
 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("該二維碼已經(jīng)失效,請(qǐng)重新獲取");
   } else {
    if (StringUtils.isNotEmpty(id) && StringUtils.isNotEmpty(token)) {
     //根據(jù)id和token查詢(xún)后臺(tái),獲取用戶(hù)信息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);
       // 添加用戶(hù)信息到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("用戶(hù)信息獲取異常!請(qǐng)稍后再試");
      }
     } else {
      result = DataResultInfo.getInstance().failure();
      result.setExtension("11", "用戶(hù)身份信息失效,請(qǐng)重新登錄!");
     }
    } else {
     result = DataResultInfo.getInstance().failure();
     result.setMessage("請(qǐng)求參數(shù)有誤!");
     return "error";
    }
    // 不能清除,否則conn方法得不到pool對(duì)象,不會(huì)進(jìn)入線(xiàn)程休眠
    // System.out.println("清除掃描過(guò)的uuid");
    //PoolCache.cacheMap.remove(uuid);
   }
  } catch (Exception e) {
   Log4jUtil.CommonLog.error("手機(jī)掃碼 后訪(fǎng)問(wèn) 異常", e);
  }

  sendJsonMessage(result);
  return null;
 }

//掃碼成功跳轉(zhuǎn)頁(yè)
 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;
 }

//線(xiàn)程判斷二維碼是否超時(shí)
class ScanCounter implements Runnable {

 public Long timeout = 30 * 1000L; //超時(shí)時(shí)長(zhǎng)

 // 傳入的對(duì)象
 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(用一句話(huà)描述這個(gè)變量表示什么) 
  */
 private static final long serialVersionUID = -9117921544228636689L;


 private Object session ;
 //創(chuàng)建時(shí)間 
 private Long createTime = System.currentTimeMillis(); 

 //登錄狀態(tài) 
 private boolean scanFlag = false; 

 public boolean isScan(){ 
  return scanFlag; 
 } 

 public void setScan(boolean scanFlag){ 
  this.scanFlag = scanFlag; 
 } 

 /** 
  * 獲取掃描狀態(tài),如果還沒(méi)有掃描,則等待固定秒數(shù) 
  * @param wiatSecond 需要等待的秒數(shù) 
  * @return 
  */ 
 public synchronized boolean getScanStatus(){ 
  try 
  { 
   if(!isScan()){ //如果還未掃描,則等待 
    this.wait(); 
   } 
   if (isScan()) 
   { System.err.println("手機(jī)掃描完成設(shè)置getScanStatus..true...........");
    return true; 
   } 
  } catch (InterruptedException e) 
  { 
   e.printStackTrace(); 
  } 
  return false; 
 } 

 /** 
  * 掃碼之后設(shè)置掃碼狀態(tài) 
  * @param token 
  * @param id 
  */ 
 public synchronized void scanSuccess(){ 
  try 
  { System.err.println("手機(jī)掃描完成setScan(true)....同時(shí)釋放notifyAll(手機(jī)掃碼時(shí),根據(jù)uuid獲得的scanpool對(duì)象)");
   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(定時(shí)清理二維碼uuid的類(lèi))

public class PoolCache {
 // 緩存超時(shí)時(shí)間 10分鐘
 private static Long timeOutSecond = 10 * 60 * 1000L;

 // 每半小時(shí)清理一次緩存
 private static Long cleanIntervalSecond = 30 * 60 * 1000L;

 //此map在多線(xiàn)程中會(huì)出現(xiàn) ConcurrentModificationException
 //public static Map<String, ScanPool> cacheMap = new HashMap<String, ScanPool>();

 //List
 //public static CopyOnWriteArrayList<Map<String, ScanPool>> copyOnWriteArrayList = new CopyOnWriteArrayList<Map<String,ScanPool>>();

 //專(zhuān)用于高并發(fā)的map類(lèi)-----Map的并發(fā)處理(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("定時(shí)清理uuid異常", e);
     }
   }
  }).start();
 }

}

掃碼流程圖:

流程圖:

使用線(xiàn)程實(shí)時(shí)監(jiān)聽(tīng)掃碼狀態(tài);
用戶(hù)掃描二維碼相當(dāng)于使用 用戶(hù)名密碼 在網(wǎng)頁(yè)端登錄,需要存瀏覽器cookie
,而用戶(hù)通過(guò)使用手機(jī)掃碼,直接請(qǐng)求服務(wù)器,登陸成功,js中得到用戶(hù)數(shù)據(jù)及cookie,把cookie返給頁(yè)面,再通過(guò)js存入cookie中

參考http://www.dbjr.com.cn/article/160745.htm

**應(yīng)大佬們的要求
附上github源碼地址供大家參考*: https://github.com/luuuuuuuuu/qrscan

以上所述是小編給大家介紹的java實(shí)現(xiàn)簡(jiǎn)單掃碼登錄功能(模仿微信網(wǎng)頁(yè)版掃碼)詳解整合,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • 關(guān)于SpringBoot的異常回滾和事務(wù)的使用詳解

    關(guān)于SpringBoot的異常回滾和事務(wù)的使用詳解

    這篇文章主要介紹了關(guān)于SpringBoot的異?;貪L和事務(wù)的使用詳解,Spring中 @Transactional 注解,默認(rèn)情況下,只對(duì)拋出的RuntimeException 異常,才會(huì)事務(wù)回滾,需要的朋友可以參考下
    2023-05-05
  • SpringMVC的自定義攔截器詳解

    SpringMVC的自定義攔截器詳解

    這篇文章主要介紹了SpringMVC的自定義攔截器詳解,攔截器只會(huì)攔截訪(fǎng)問(wèn)的控制器方法, 如果訪(fǎng)問(wèn)的是jsp/html/css/image/js是不會(huì)進(jìn)行攔截的,需要的朋友可以參考下
    2023-07-07
  • 在deepin上如何使用Fleet開(kāi)發(fā)SpringBoot?3.0.0項(xiàng)目

    在deepin上如何使用Fleet開(kāi)發(fā)SpringBoot?3.0.0項(xiàng)目

    這篇文章主要介紹了在deepin上使用Fleet開(kāi)發(fā)SpringBoot?3.0.0項(xiàng)目的過(guò)程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-09-09
  • java instanceof操作符使用及原理解析

    java instanceof操作符使用及原理解析

    這篇文章主要介紹了java instanceof操作符使用及原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-12-12
  • Java中雙向鏈表詳解及實(shí)例

    Java中雙向鏈表詳解及實(shí)例

    這篇文章主要介紹了Java中雙向鏈表詳解及實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • SpringBoot項(xiàng)目集成日志的實(shí)現(xiàn)方法

    SpringBoot項(xiàng)目集成日志的實(shí)現(xiàn)方法

    這篇文章主要介紹了SpringBoot項(xiàng)目集成日志的實(shí)現(xiàn)方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02
  • Java并發(fā)之ReentrantLock類(lèi)源碼解析

    Java并發(fā)之ReentrantLock類(lèi)源碼解析

    這篇文章主要為大家詳細(xì)介紹了Java并發(fā)系列之ReentrantLock源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • Java分布式服務(wù)框架Dubbo介紹

    Java分布式服務(wù)框架Dubbo介紹

    這篇文章介紹了Java分布式服務(wù)框架Dubbo,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • 詳解Spring循環(huán)依賴(lài)的解決方案

    詳解Spring循環(huán)依賴(lài)的解決方案

    這篇文章主要介紹了詳解Spring循環(huán)依賴(lài)的解決方案,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • 解析JPA的視圖查詢(xún)問(wèn)題

    解析JPA的視圖查詢(xún)問(wèn)題

    這篇文章主要是對(duì)JPA的視圖查詢(xún)問(wèn)題進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助
    2013-12-12

最新評(píng)論