亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java 多用戶登錄限制的實(shí)現(xiàn)方法

 更新時(shí)間:2016年11月08日 09:10:02   作者:weixin_36638714  
最近沒有事情做,閑的發(fā)呆,于是寫個(gè)東東練練手。這篇文章主要介紹了Java 多用戶登錄限制的實(shí)現(xiàn)方法的相關(guān)資料,需要的朋友可以參考下

最近比較空閑沒有項(xiàng)目做,于是乎捋了捋平時(shí)工作會(huì)遇到的一些常見問題,首先想到了多用戶登錄限制問題,下面就對(duì)此問題做一點(diǎn)思考講解。

相關(guān)閱讀:

Java Web開發(fā)防止多用戶重復(fù)登錄的完美解決方案

1、設(shè)計(jì)場(chǎng)景

  1)同一時(shí)刻不允許某個(gè)用戶多地登錄

  2)用戶已在A處登錄,現(xiàn)在從B處登錄是允許的,但會(huì)把A處擠掉(考慮到用戶在A處登錄后因某些情況跑到了B處,但還想繼續(xù)之前的工作,所以需要登錄系統(tǒng))

  3)B處擠掉A后,A再做其它操作的時(shí)候系統(tǒng)會(huì)給出提示,該用戶在別處登錄,如不是本人操作可能密碼泄漏,請(qǐng)修改密碼。

2、思路導(dǎo)圖

  每個(gè)用戶登錄的時(shí)候,通常我們會(huì)將用戶信息存入session,以便用戶進(jìn)行操作的時(shí)候系統(tǒng)方便得到用戶的基本信息。但這個(gè)session具有私有性,只對(duì)當(dāng)前用戶可見(如果同意用戶在不同瀏覽器登錄會(huì)得到不同的session,這也是為什么可以多用戶登錄的根源所在)。那么接著問題就來(lái)了,某個(gè)用戶登錄的時(shí)候如何能知道自己是否在線,相信聰明的你已經(jīng)想到,這還不好半,把在線的用戶信息存儲(chǔ)在一個(gè)公共的地方問題不就迎刃而解了么,網(wǎng)上一查,解決方案無(wú)出其右,大致為以下兩種

  1)數(shù)據(jù)庫(kù)中標(biāo)識(shí)在線用戶

  2)存儲(chǔ)到application中

  經(jīng)過重重考慮,我們會(huì)發(fā)現(xiàn)方案一需要解決許多棘手的問題(用戶異常退出未來(lái)得及修改狀態(tài),頻繁訪問數(shù)據(jù)庫(kù)影響性能等),這對(duì)于一個(gè)要求完美的你來(lái)說(shuō)顯然是不合時(shí)宜的,于是我們采用了方案二,將在線用戶信息保存到application中,具體設(shè)計(jì)如下。

  1)登錄流程圖

  2)被擠掉后操作流程圖

3、代碼

  1)登錄方法

@RequestMapping(value = "/login", method = RequestMethod.POST)
public String login(String userName, String password, RedirectAttributes redirectAttributes, HttpServletRequest request) {
//判斷用戶是否已經(jīng)在線及處理(已在線則剔除)
String loginLimite = limiteLogin.loginLimite(request, userName);
//判斷用戶名、密碼是否正確
String result = userService.login(userName, password);
if (result.equals("success")) {
request.getSession().setAttribute("now_user", userService.findByUserName(userName));
//創(chuàng)建token及驗(yàn)證
String jwtToken = tokenService.createUserAuthToken(userService.findByUserName(userName));//生成token
System.out.println(jwtToken);
UserAuthenticationToken authToken = tokenService.retrieveUserAuthToken(jwtToken);//token解析
System.out.println(authToken.isAuthenticated());
System.out.println("id = " + UserAuthenticationToken.getCurrentToken().getUserUuid());
//用戶掉線,登錄后重定向到保存的鏈接
Object url = request.getSession().getAttribute("redirect_link");
if (url != null) {
request.getSession().removeAttribute("redirect_link");
return "redirect:" + url.toString();
}
return "index";
}
redirectAttributes.addFlashAttribute("message", result);
return "redirect:/other/toLogin";
}

  2)登錄判斷是否已經(jīng)在線

@Service
@Transactional
public class LimiteLogin {
private static Logger log = Logger.getLogger(SessionListener.class);
private static Map<String, String> loginUserMap = new HashMap<>();//存儲(chǔ)在線用戶
private static Map<String, String> loginOutTime = new HashMap<>();//存儲(chǔ)剔除用戶時(shí)間
@Autowired
private UserService userService;
public String loginLimite(HttpServletRequest request, String userName) {
User user = userService.findByUserName(userName);
String sessionId = request.getSession().getId();
for (String key : loginUserMap.keySet()) {
//用戶已在另一處登錄
if (key.equals(user.getUserName()) && !loginUserMap.containsValue(sessionId)) {
log.info("用戶:" + user.getUserName() + ",于" + DateUtil.dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss") + "被剔除!");
loginOutTime.put(user.getUserName(), DateUtil.dateFormat(new Date(), "yyyy-MM-dd HH:mm:ss"));
loginUserMap.remove(user.getUserName());
break;
}
}
loginUserMap.put(user.getUserName(), sessionId);
request.getSession().getServletContext().setAttribute("loginUserMap", loginUserMap);
request.getSession().getServletContext().setAttribute("loginOutTime", loginOutTime);
return "success";
}
}

  3)登錄攔截器(未登錄跳轉(zhuǎn)登錄頁(yè))

public class LoginInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
HttpSession session = request.getSession();
User user = (User) session.getAttribute("now_user");
if (session.getAttribute("now_user") == null) {
response.sendRedirect(request.getContextPath() + "/other/toLogin");
return false;
}
//多用戶登錄限制判斷,并給出提示信息
boolean isLogin = false;
if (user != null) {
Map<String, String> loginUserMap = (Map<String, String>) session.getServletContext().getAttribute("loginUserMap");
String sessionId = session.getId();
for (String key : loginUserMap.keySet()) {
//用戶已在另一處登錄
if (key.equals(user.getUserName()) && !loginUserMap.containsValue(sessionId)) {
isLogin = true;
break;
}
}
}
if (isLogin) {
Map<String, String> loginOutTime = (Map<String, String>) session.getServletContext().getAttribute("loginOutTime");
session.setAttribute("mess", "用戶:" + user.getUserName() + ",于 " + loginOutTime.get(user.getUserName()) + " 已在別處登錄!");
loginOutTime.remove(user.getUserName());
session.getServletContext().setAttribute("loginUserMap", loginOutTime);
response.sendRedirect(request.getContextPath() + "/other/toLogin");
return false;
}
return super.preHandle(request, response, handler);
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
super.postHandle(request, response, handler, modelAndView);
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
super.afterCompletion(request, response, handler, ex);
}
}

  4)在session銷毀的時(shí)候,把loginUserMap中保存的鍵值對(duì)清除

public classSessionListener implements HttpSessionListener {
private static Logger log = Logger.getLogger(SessionListener.class);
@Override
public void sessionCreated(HttpSessionEvent event) {
}
@Override
public void sessionDestroyed(HttpSessionEvent event) {
HttpSession session = event.getSession();
String sessionId = session.getId();
//在session銷毀的時(shí)候,把loginUserMap中保存的鍵值對(duì)清除
User user = (User) session.getAttribute("now_user");
if (user != null) {
Map<String, String> loginUserMap = (Map<String, String>) event.getSession().getServletContext().getAttribute("loginUserMap");
if(loginUserMap.get(user.getUserName()).equals(sessionId)){
log.info("clean user from application : " + user.getUserName());
loginUserMap.remove(user.getUserName());
event.getSession().getServletContext().setAttribute("loginUserMap", loginUserMap);
}
}
}
}

  5)web.xml

<!-- session listener 多用戶登錄限制,退出清除session信息的同時(shí)清除application中存放用戶登錄信息-->
<listener>
<listener-class>com.service.limitelogin.SessionListener</listener-class>
</listener>

  6)頁(yè)面代碼(用于給出提示的同時(shí),清除被擠掉用戶的session信息,否則提示信息會(huì)一直顯示) 

<script type="text/javascript">
$(document).ready(function () {
var message='${mess}';
if (message != "") {
$.ajax({
type: 'GET',
async: false,
cache: false,
url: '/other/clearUserSession',
dataType: '',
data: {},
success: function (data) {
}
});
$('#mess').html(message);
}
});
</script>

  7)清除擠掉用戶session代碼

/**
* 多用戶登錄限制,清除session信息(登錄信息、提示信息)
*
* @param request
* @return
*/
@ResponseBody
@RequestMapping(value = "/clearUserSession")
public String clearUserSession(HttpServletRequest request) {
HttpSession httpSession = request.getSession();
//httpSession.invalidate();
httpSession.removeAttribute("now_user");
httpSession.removeAttribute("mess");
return "success";
}

到此開發(fā)工作完成

4、運(yùn)行結(jié)果

以上所述是小編給大家介紹的Java 多用戶登錄限制的實(shí)現(xiàn)方法,希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!

相關(guān)文章

  • Java中對(duì)象快速?gòu)?fù)制的幾種方式詳解

    Java中對(duì)象快速?gòu)?fù)制的幾種方式詳解

    這篇文章主要介紹了Java中對(duì)象快速?gòu)?fù)制的幾種方式詳解,對(duì)象的克隆是指創(chuàng)建一個(gè)新的對(duì)象,且新的對(duì)象的狀態(tài)與原始對(duì)象的狀態(tài)相同,當(dāng)對(duì)克隆的新對(duì)象進(jìn)行修改時(shí),不會(huì)影響原始對(duì)象的狀態(tài),需要的朋友可以參考下
    2023-08-08
  • Java 讀取PDF中的文本和圖片的方法

    Java 讀取PDF中的文本和圖片的方法

    本文將介紹通過Java程序來(lái)讀取PDF文檔中的文本和圖片的方法。分別調(diào)用方法extractText()和extractImages()來(lái)讀取,需要的朋友可以參考下
    2019-07-07
  • Java數(shù)據(jù)結(jié)構(gòu)及算法實(shí)例:插入排序 Insertion Sort

    Java數(shù)據(jù)結(jié)構(gòu)及算法實(shí)例:插入排序 Insertion Sort

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)及算法實(shí)例:插入排序 Insertion Sort,本文直接給出實(shí)例代碼,代碼中包含詳細(xì)注釋,需要的朋友可以參考下
    2015-06-06
  • MyBatis實(shí)現(xiàn)MySQL批量插入的示例代碼

    MyBatis實(shí)現(xiàn)MySQL批量插入的示例代碼

    本文主要介紹了MyBatis實(shí)現(xiàn)MySQL批量插入的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • java生成excel并導(dǎo)出到對(duì)應(yīng)位置的方式

    java生成excel并導(dǎo)出到對(duì)應(yīng)位置的方式

    這篇文章主要介紹了java生成excel并導(dǎo)出到對(duì)應(yīng)位置的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java中泛型使用的簡(jiǎn)單方法介紹

    Java中泛型使用的簡(jiǎn)單方法介紹

    這篇文章主要給大家介紹了關(guān)于Java中泛型使用的簡(jiǎn)單方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Java后端接入微信小程序登錄功能(登錄流程)

    Java后端接入微信小程序登錄功能(登錄流程)

    這篇文章主要介紹了Java后端接入微信小程序登錄功能,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • Java實(shí)現(xiàn)發(fā)送手機(jī)短信語(yǔ)音驗(yàn)證功能代碼實(shí)例

    Java實(shí)現(xiàn)發(fā)送手機(jī)短信語(yǔ)音驗(yàn)證功能代碼實(shí)例

    這篇文章主要介紹了Java實(shí)現(xiàn)發(fā)送手機(jī)短信語(yǔ)音驗(yàn)證功能代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09
  • Java緩存池代碼實(shí)例詳解

    Java緩存池代碼實(shí)例詳解

    本篇文章主要介紹了Java實(shí)現(xiàn)簡(jiǎn)單的緩存方法實(shí)例,需要的朋友可以參考下
    2017-04-04
  • SpringBoot @Validated注解實(shí)現(xiàn)參數(shù)分組校驗(yàn)的方法實(shí)例

    SpringBoot @Validated注解實(shí)現(xiàn)參數(shù)分組校驗(yàn)的方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于SpringBoot @Validated注解實(shí)現(xiàn)參數(shù)分組校驗(yàn)的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09

最新評(píng)論