Javaweb項(xiàng)目session超時(shí)解決方案
在Java Web開(kāi)發(fā)中,Session為我們提供了很多方便,Session是由瀏覽器和服務(wù)器之間維護(hù)的。Session超時(shí)理解為:瀏覽器和服務(wù)器之間創(chuàng)建了一個(gè)Session,由于客戶端長(zhǎng)時(shí)間(休眠時(shí)間)沒(méi)有與服務(wù)器交互,服務(wù)器將此Session銷毀,客戶端再一次與服務(wù)器交互時(shí)之前的Session就不存在了。
0.需求
需要對(duì)所有的/web/**請(qǐng)求進(jìn)行登錄攔截,Session超時(shí)時(shí)跳轉(zhuǎn)到登錄頁(yè)面。
1.引入
一般來(lái)說(shuō),在項(xiàng)目使用中都會(huì)配置Session超時(shí)時(shí)間,如果不配置,則默認(rèn)值為30分鐘,即用戶不操作30分鐘以后,Session就會(huì)失效,此時(shí)用戶就需要重新登錄系統(tǒng)。
Session超時(shí)時(shí)間的配置主要的項(xiàng)目的web.xml中進(jìn)行配置,如下:
<span style="font-size: 14px;"> <!-- 設(shè)置Session超時(shí)時(shí)間 -->
<session-config>
<!-- 分鐘 -->
<session-timeout>60</session-timeout>
<!-- 去除URL上顯示的jsessionid, 防止打開(kāi)Tab頁(yè)時(shí)出現(xiàn)JS錯(cuò)誤 -->
<tracking-mode>COOKIE</tracking-mode>
</session-config></span><span style="font-size:24px;">
</span>
2.請(qǐng)求的分類
現(xiàn)在的項(xiàng)目中請(qǐng)求主要分為兩種:一種是普通請(qǐng)求,即發(fā)起請(qǐng)求返回視圖和模型;另外一種是Ajax請(qǐng)求,主要返回模型數(shù)據(jù)。后端進(jìn)行處理時(shí)就要根據(jù)不同的請(qǐng)求返回不同的內(nèi)容。
對(duì)于普通請(qǐng)求,我們直接返回JavaScript腳本,腳本內(nèi)容可以是將頁(yè)面跳轉(zhuǎn)到登錄頁(yè)面。
對(duì)于Ajax請(qǐng)求,則需要返回非200的狀態(tài)碼,這樣ajax請(qǐng)求才會(huì)進(jìn)入到error回調(diào)函數(shù)中以及全局的Ajax錯(cuò)誤回調(diào)函數(shù)AjaxError中。
3.后端處理Session超時(shí)
后端采用SpringMVC的攔截器處理,這里為什么用攔截器呢?一方面,請(qǐng)求URL不能限制的太死,比如/*,這樣對(duì)所有的請(qǐng)求都進(jìn)行過(guò)濾是浪費(fèi)資源的。另一方面,有些URL不需要進(jìn)行攔截處理,比如到登錄頁(yè)面的請(qǐng)求肯定是不能攔截,要不然會(huì)循環(huán)重定向。再一方面,我們只需要攔截控制器請(qǐng)求,其它請(qǐng)求不攔截。
下面看一下攔截器的實(shí)現(xiàn):
/**
* Web端登錄攔截器
* 處理請(qǐng)求時(shí)Session失效的問(wèn)題,包含Ajax請(qǐng)求和普通請(qǐng)求
* @ClassName WebLoginInterceptor
* @author zhangshun
* @date 2016年10月20日 上午11:14:52
*/
public class WebLoginInterceptor extends HandlerInterceptorAdapter{
/**
* 日志對(duì)象
*/
private Logger logger = LoggerFactory.getLogger(WebLoginInterceptor.class);
/**
* 默認(rèn)注銷URL
* 即Session超時(shí)后,發(fā)起請(qǐng)求到此地址,只對(duì)普通請(qǐng)求有效
*/
private static final String DEFAULT_LOGOUT_URL = "/web/logout";
/**
* 注銷URL
*/
private String logoutUrl;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
User user = SessionUtils.getUserFromRequestAcrossCas(request);
String uri = request.getRequestURI();
if(user == null){
response.setContentType("text/html;charset=UTF-8");
if(request.getHeader("x-requested-with") != null
&& request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")){
// Ajax請(qǐng)求, 前段根據(jù)此header進(jìn)行處理
response.setHeader("sessionTimeout", "Session time out, you need relogin !");
// 返回未認(rèn)證的狀態(tài)碼(401)
response.setStatus(HttpStatus.UNAUTHORIZED.value());
logger.debug("請(qǐng)求路徑:" + uri + ", 請(qǐng)求方式 :Ajax請(qǐng)求, Session超時(shí), 需要重新登錄!");
}else{
// 普通請(qǐng)求
String path = request.getContextPath();
StringBuffer basePath = new StringBuffer()
.append(request.getScheme())
.append("://")
.append(request.getServerName())
.append(":")
.append(request.getServerPort())
.append(path)
.append("/");
StringBuffer responseStr = new StringBuffer()
.append("<html><header><script type=\"text/javascript\">")
.append("window.location.href=\"")
.append(basePath).append(getLogoutUrl()).append("\";")
.append("</script></header></html>");
response.getWriter().write(responseStr.toString());
logger.debug("請(qǐng)求路徑:" + uri + ",請(qǐng)求方式 :普通請(qǐng)求, Session超時(shí), 需要重新登錄!");
}
return false;
}
return true;
}
public String getLogoutUrl() {
// 使用默認(rèn)值
if(StringUtils.isEmpty(logoutUrl)){
return DEFAULT_LOGOUT_URL;
}
return logoutUrl;
}
public void setLogoutUrl(String logoutUrl) {
this
}
通過(guò)獲取Session中的User對(duì)象是否存在來(lái)判斷Session是否超時(shí),如果Session超時(shí),則根據(jù)不同的請(qǐng)求方式進(jìn)行返回。如果是普通請(qǐng)求,則直接返回JavaScript腳本,該腳本可以將頁(yè)面跳轉(zhuǎn)到其它URL。如果是Ajax請(qǐng)求,則返回401狀態(tài)碼,并且在返回的header中加入sessionTimeout,該數(shù)據(jù)將會(huì)在前端使用。
該攔截器在SpringMVC配置文件中的配置如下:
<span style="font-size:14px;"><!-- MVC攔截器 --> <mvc:interceptors> <!-- Web登錄攔截器 --> <mvc:interceptor> <mvc:mapping path="/web/**"/> <mvc:exclude-mapping path="/web/index"/><!-- 防止循環(huán)重定向到首頁(yè) --> <mvc:exclude-mapping path="/web/login"/> <mvc:exclude-mapping path="/web/logout"/> <mvc:exclude-mapping path="/web/doLogin"/> <bean class="com.woyi.mhub.interceptor.WebLoginInterceptor"/> </mvc:interceptor> </mvc:interceptors></span><span style="font-size:24px;"> </span>
4.前端處理Session超時(shí)
對(duì)于普通請(qǐng)求,后端返回的是JavaScript腳本,會(huì)立刻執(zhí)行,這里前端不需要任何處理。
對(duì)于Ajax請(qǐng)求,后端返回401狀態(tài)碼,并在header中設(shè)置的sessionTimeout。這里使用jQuery的ajaxComplete回調(diào)函數(shù)處理,具體如下:
// 實(shí)現(xiàn)ajax請(qǐng)求時(shí)判斷Session是否失效 $(document).ajaxComplete(function(event, response, settings) { var sessionTimeout = response.getResponseHeader("SessionTimeout"); if(sessionTimeout != null && typeof sessionTimeout != "undefined" && sessionTimeout.length > 0){ // 這里寫Session超時(shí)后的處理方法 } });
好了,可以了,Session超時(shí)的用戶都會(huì)得到處理。
總結(jié)
關(guān)于Javaweb項(xiàng)目session超時(shí)解決方案就到這里,希望對(duì)大家有所幫助。
相關(guān)文章
java簡(jiǎn)單實(shí)現(xiàn)多線程及線程池實(shí)例詳解
這篇文章主要為大家詳細(xì)介紹了java簡(jiǎn)單實(shí)現(xiàn)多線程,及java爬蟲使用線程池實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-03-03教你創(chuàng)建springcloud微服務(wù)的基礎(chǔ)子服務(wù)的超詳細(xì)過(guò)程
這篇文章主要介紹了創(chuàng)建springcloud微服務(wù)的基礎(chǔ)子服務(wù),主要是創(chuàng)建兩個(gè)springboot服務(wù),在教程中增加springcloud相關(guān)組件,本文分步驟給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-04-04java開(kāi)發(fā)命名規(guī)范總結(jié)
包名的書寫規(guī)范 (Package)推薦使用公司或機(jī)構(gòu)的頂級(jí)域名為包名的前綴,目的是保證各公司/機(jī)構(gòu)內(nèi)所使用的包名的唯一性。包名全部為小寫字母,且具有實(shí)際的區(qū)分意義2013-10-10Java讀取txt文件中的數(shù)據(jù)賦給String變量方法
今天小編就為大家分享一篇Java讀取txt文件中的數(shù)據(jù)賦給String變量方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-07-07SpringBoot統(tǒng)計(jì)一個(gè)Bean中方法的調(diào)用次數(shù)的實(shí)現(xiàn)步驟
這篇文章主要給大家介紹了SpringBoot統(tǒng)計(jì)一個(gè)Bean中方法的調(diào)用次數(shù)的實(shí)現(xiàn)步驟,文中通過(guò)代碼示例和圖文結(jié)合的方式給大家講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)具有一定的幫助,需要的朋友可以參考下2024-01-01