如何在Service層獲取使用者session中儲存的使用者資訊的方法(Filter+ThreadLocal)
*
* Description: 用ThreadLocal提供一個儲存執行緒內變數的地方. <p/>
* 客戶端程式碼可以用靜態方法儲存和獲取執行緒內變數,不需要依賴於HttpSession.
* web層的Controller可通過此處向business層傳入user_id之類的變數
*
*/
@SuppressWarnings("unchecked")
public class UserSession {
/** * 儲存變數的ThreadLocal,保持在同一執行緒中同步資料. */
private static final ThreadLocal SESSION_MAP = new ThreadLocal();
/** * 工具類的protected構造方法. */
protected UserSession() {
}
/**
* 獲得執行緒中儲存的屬性.
*
* @param attribute
* 屬性名稱
* @return 屬性值
*/
public static Object get(String attribute) {
Map map = (Map) SESSION_MAP.get();
System.out.println(map.toString());
System.out.println(map.containsKey("usersession"));
return map.get(attribute);
}
/**
* 獲得執行緒中儲存的屬性,使用指定型別進行轉型.
*
* @param attribute
* 屬性名稱
* @param clazz
* 型別
* @param <T>
* 自動轉型
* @return 屬性值
*/
public static <T> T get(String attribute, Class<T> clazz) {
return (T) get(attribute);
}
/**
* 設定制定屬性名的值.
*
* @param attribute
* 屬性名稱
* @param value
* 屬性值
*/
public static void set(String attribute, Object value) {
Map map = (Map) SESSION_MAP.get();
if (map == null) {
map = new HashMap();
SESSION_MAP.set(map);
}
map.put(attribute, value);
}
}
我在使用者登入的時候 執行:
UserSession.set("User",User);
然後在我需要的service層中執行:
UserSession.get("User");
//UserSession.get("User",User.class);
此時會出現一個bug:這樣第一次取到session中的User物件,後面的請求都取不到了。
解決方法:ThreadLocal 是當前請求(前臺對後臺的每個請求都會被認為是一個獨立的執行緒)的物件。每一次執行緒請求的時候,都需要從session中把session物件取出來。放到ThreadLocal中去(最好的方式是通過filter攔截器實現)。 這樣才能從service中取得到。acegi就是這麼處理的
攔截器程式碼:
public class SessionFilterUtil implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest session_request = (HttpServletRequest) request;
HttpServletResponse session_response = (HttpServletResponse) response;
HttpSession session = session_request.getSession();
User user = (User) session.getAttribute("user");
if (user != null) {
UserSession.set("userSession", session);
chain.doFilter(request, response);
} else {
String uri = session_request.getRequestURI(); // 獲取uri資訊
String ctx = session_request.getContextPath(); // 獲取上下文,如/專案名
if(uri.indexOf("!") != -1){
String method = uri.substring(uri.indexOf("!") + 1, uri.indexOf(".action"));
if(method.equals("bistore_login")){
chain.doFilter(request, response);
}
}
session_response.getWriter().print("<script>location.href='" + ctx + "/adf/login!bistore_login.action'</script>");
}
}
public void init(FilterConfig filterConfig) throws ServletException {
}
}