ExtJS4.2.1與Spring MVC實現Session超時控制

如果你的項目使用ExtJS作爲表現層,你會發現,SESSION超時控制將是一個問題。

本文將就自己的經驗,來解決這一問題,當然,解決問題並非只有一種方法,我只是提出我的方法。

首先,做超時控制,必需使用過濾器,而我們既然使用了Spring MVC,那就用攔截器取代吧,寫一個攔截器,用來攔截用戶請求,當然,這個攔截器還需要可以配置哪些請求是不需要攔截的。

/**
 * 
 */
package net.bioslink.business.intercepter;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import net.bioslink.common.util.ConfigureUtil;
import net.bioslink.common.vo.Constants;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Repository;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

/**
 * @author leoly
 * 
 */
@Repository
public class SystemAccessInterceper extends HandlerInterceptorAdapter {
	private final Logger logger = Logger.getLogger(getClass());

	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		String uri = request.getRequestURI();
		String[] noFilters = ConfigureUtil.getStringArray("no_filter_setting");
		boolean isFilter = true;
		if (!ArrayUtils.isEmpty(noFilters)) {
			for (String u : noFilters) {
				if (uri.contains(u)) {
					isFilter = false;
					break;
				}
			}
		}

		if (isFilter) {
			// Session
			Object obj = request.getSession()
					.getAttribute(Constants.SESSION_ID);
			if (null == obj) {
				logger.info("登錄超時!!");
				PrintWriter writer = response.getWriter();
				writer.print("<script>top.location='http://127.0.0.1:8080/VkDesktop/login/loginSystem.do';</script>SESSION_TIMEOUT_ERROR");
				IOUtils.closeQuietly(writer);
				return false;
			} else {
				request.setAttribute("LOG_ACCESS_TIME",
						System.currentTimeMillis());
				logger.info(obj + "訪問了" + uri);
			}
		}
		return super.preHandle(request, response, handler);
	}

	@Override
	public void afterCompletion(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex)
			throws Exception {
		// TODO Auto-generated method stub
		super.afterCompletion(request, response, handler, ex);
		Object obj = request.getAttribute("LOG_ACCESS_TIME");
		if (null != obj) {
			long accessTime = (long) obj;
			logger.info("處理請求" + request.getRequestURI() + "耗時"
					+ (System.currentTimeMillis() - accessTime) + "毫秒!");
		}
	}
}

然後,將這個攔截器註冊到Spring MVC中,在xxx-servlet.xml文件中添加註冊代碼:

	<mvc:interceptors>
		<bean class="net.bioslink.business.intercepter.SystemAccessInterceper" />
	</mvc:interceptors>

OK,現在這個攔截器已經開始工作了,它會攔截用戶請求,判斷SESSION中是否存在登錄信息,如果不存在,則說明已經超時,攔截器向客戶問寫一段代碼
writer.print("<script>top.location='http://127.0.0.1:8080/VkDesktop/login/loginSystem.do';</script>SESSION_TIMEOUT_ERROR");
這樣,如果客戶端是網頁,它就會自動跳到登錄頁面,如果不是網頁(如AJAX請求),我們需要在客戶端中判斷返回的字符串中是否包含“SESSION_TIMEOUT_ERROR,如果有的話就做出跳到首頁的處理。


那麼,現在輪到客戶端了,因爲使用的是ExtJS,幾乎所有的請求都是AJAX請求,所以判斷SESSION_TIMEOUT_ERROR是關鍵。那總不能所有的AJAX請求都加上這些判斷吧??OMG,殺了我吧,可憐的碼農……

其實,我們可以寫一個TimeoutControl類,封裝一些我們需要修改和添加的東西,來實現超時跳轉功能!誰叫ExtJS提供了這麼多類功能(繼承,重寫,覆蓋)呢?

我們知道,ExtJS的請求雖然都是AJAX請求,但是卻可以區分爲Store請求和一般的AJAX請求,那麼我們的TimeoutControl類就需要重新構造這些請求方式,並且,以後寫的所有請求都需要使用這個類來完成。

Ext.define('Ext.ux.TimeoutControl', {
	extend : 'Ext.data.Store',
	alias : 'widget.timeoutstore',
	constructor : function(config) {
		Ext.apply(config.proxy, {
			listeners : {
				exception : function(self, response) {
					var responseText = response.responseText;
					if (responseText
							&& responseText.indexOf("SESSION_TIMEOUT_ERROR") > 0) {
						top.location = '../login/loginSystem.do';
					}
				}
			}
		});
		this.callParent([config]);
	},

	statics : {
		request : function(config) {
			var f = config.success;
			config.success = Ext.Function.createInterceptor(f, function(
							response) {
						var txt = response.responseText;
						// alert(txt);
						if (txt && txt.indexOf("SESSION_TIMEOUT_ERROR") > 0) {
							top.location = '../login/loginSystem.do';
							return false;
						}

						return true;
					});
			Ext.Ajax.request(config);
		}
	}
});


這個類中,我們繼承了Ext.data.Store,並且在構造器中動態加入了一個proxy的exception處理函數,也就是說,只要使用此類,無論Store的proxy中寫沒寫exception函數,都會在這裏添加上,而這個函數就是處理超時控制的。然後,這個類還提供了一個靜態方法request,這個request方法會調用Ext.Ajax.request(config),但是在調用之前,我們給配置的success函數添加了一段判斷超時的代碼,使用的是ExtJS的函數攔截方法,效果槓槓的。

最後,只要我們在使用到Store的地方中使用Ext.ux.TimeoutControl類,在使用Ext.Ajax.request的地方中使用Ext.ux.TimeoutControl.request取代,那麼,超時控制就完成了。

使用Store的例子:

		var store = Ext.create('Ext.ux.<span style="font-size:18px; white-space: pre; background-color: rgb(240, 240, 240);">TimeoutControl</span>', {
					model : 'MyDesktop.data.WorkOrderModule',
					remoteSort : true,
					remoteFilter : true,
					sorters : [new Ext.util.Sorter({
								property : 'reportId',
								direction : 'ASC'
							})],
					proxy : {
						type : 'ajax',
						actionMethods : {
							read : 'POST'
						},
						extraParams : {
							projectCode : "44190008",
							orderMonth : 2,
							id : 0
						},
						pageParam : 'pageNo',
						limitParam : 'pageSize',
						url : '../lebang/workOrder/queryWorkorderList.do',
						reader : {
							type : 'json',
							root : 'orders',
							totalProperty : 'totalCount'
						}
					}
				});

使用AJAX請求的例子:

					Ext.ux.TimeoutControl.request({
								url : "../user/logout.do",
								timeout : 60000,
								method : 'POST',
								disableCaching : false,
								params : {},
								success : function(response) {
									window.location = '../login/loginSystem.do';
								},
								failure : function() {
									Ext.Msg.alert("系統提示", "註銷異常,請聯繫管理人員!!");
								}
							});







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章