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

网友投稿 891 2023-01-07


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

java实现简单扫码登录功能

模仿微信pc网页版扫码登录

使用js代码生成qrcode二维码减轻服务器压力

js循环请求服务端,判断是否qrcode被扫

二维码超时失效功能

二维码被扫成功登录,服务端产生sessionId,传到页面使用js保存cookie

多线程

生成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:"/UwuIjSGAfElogo.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 + sessihttp://onId, 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)

http://

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 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 (copyOnWriteArrayList.size() > 0) {

Iterator> iterator = copyOnWriteArrayList.iterator();

while (iterator.hasNext()) {

Map map = iterator.next();

Iterator 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 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://jb51.net/article/160745.htm

**应大佬们的要求

附上github源码地址供大家参考*: https://github.com/luuuuuuuuu/qrscan

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:SpringBoot错误处理机制以及自定义异常处理详解
下一篇:单一接口自动化框架(单一接口自动化框架结构)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~