Spring中利用攔截器控制登錄及頁面跳轉

一、問題簡要描述:

在做web開發的時候往往會遇到這種情況,用戶在沒登錄的情況下訪問一些需要身份驗證的頁面,系統會自動幫用戶跳轉到登錄頁面,用戶登錄成功後,不會返回一個固定的頁面,系統會跳轉到用戶之前訪問的頁面,用戶可以繼續進行剛纔的操作。或者是session裏面保存的用戶信息過期了,用戶需要重新進行身份驗證(重新登錄),用戶登錄成功後,頁面還是會回到之前訪問的頁面。

二、問題所涉及的知識和技術:

Shiro,Spring,SpringMVC,攔截器,java,Servlet

三、問題解決

這個問題我現在知道的有兩種解決辦法(本人能力有限),一種是利用SpringMVC裏面的攔截器(實現HandlerInterceptor接口),一種是使用Shiro插件(不久我會整理一份《Apache Shiro簡介》和《Spring整合Shiro詳解》,具體可查看我的這兩個博文)

1、實現HandlerInterceptor接口從而實現控制登錄及頁面跳轉

HandlerInterceptor接口中定義了三個方法,我們就是通過這三個方法來對用戶的請求進行攔截處理的。

(1 )preHandle(HttpServletRequest request, HttpServletResponse response, Object handle) 方法,顧名思義,該方法將在請求處理之前進行調用。SpringMVC 中的Interceptor是鏈式的調用的,在一個應用中或者說是在一個請求中可以同時存在多個Interceptor 。每個Interceptor的調用會依據它的聲明順序依次執行,而且最先執行的都是Interceptor 中的preHandle方法,所以可以在這個方法中進行一些前置初始化操作或者是對當前請求的一個預處理,也可以在這個方法中進行一些判斷來決定請求是否要繼續進行下去。該方法的返回值是布爾值Boolean 類型的,當它返回爲false時,表示請求結束,後續的Interceptor 和Controller都不會再執行;當返回值爲true 時就會繼續調用下一個Interceptor 的preHandle 方法,如果已經是最後一個Interceptor 的時候就會是調用當前請求的Controller方法。

   (2 )postHandle (HttpServletRequest request,HttpServletResponse response, Object handle, ModelAndView modelAndView) 方法,由preHandle 方法的解釋我們知道這個方法包括後面要說到的afterCompletion 方法都只能是在當前所屬的Interceptor的preHandle 方法的返回值爲true時才能被調用。postHandle 方法,顧名思義就是在當前請求進行處理之後,也就是Controller 方法調用之後執行,但是它會在DispatcherServlet進行視圖返回渲染之前被調用,所以我們可以在這個方法中對Controller 處理之後的ModelAndView對象進行操作。postHandle 方法被調用的方向跟preHandle是相反的,也就是說先聲明的Interceptor 的postHandle方法反而會後執行,這和Struts2 裏面的Interceptor的執行過程有點類型。Struts2 裏面的Interceptor的執行過程也是鏈式的,只是在Struts2 裏面需要手動調用ActionInvocation的invoke 方法來觸發對下一個Interceptor或者是Action 的調用,然後每一個Interceptor中在invoke 方法調用之前的內容都是按照聲明順序執行的,而invoke 方法之後的內容就是反向的。

   (3 )afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handle, Exception ex) 方法,該方法也是需要當前對應的Interceptor 的preHandle 方法的返回值爲true 時纔會執行。顧名思義,該方法將在整個請求結束之後,也就是在DispatcherServlet 渲染了對應的視圖之後執行。這個方法的主要作用是用於進行資源清理工作的。

下面給出具體的代碼:(具體思路是這樣的,在preHandle這個方法中,獲得請求的地址(具體讀者可以瞭解項目地址,真實地址,帶參地址)然後把它保存在session中,最後在你認證登錄的時候作一個判斷,取出這個session裏面的地址,進行登錄跳轉)

        @Override
	public void afterCompletion(HttpServletRequest arg0,
			HttpServletResponse arg1, Object arg2, Exception arg3)
			throws Exception {
		
		
	}
	@Override
	public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
			Object arg2, ModelAndView arg3) throws Exception {
		
		
	}
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
			Object arg2) throws Exception {
		
		User user = (User) request.getSession().getAttribute("loginUser");
		if(user == null){
			request.getRequestDispatcher("/login.jsp").forward(request, response);  
			HttpSession session = request.getSession(true); 
	    	String uri = request.getRequestURI();//拿到上一個頁面地址
	    	String path = uri.substring(request.getContextPath().length());//去掉項目地址長度的字符(因爲我的默認項目地址是給出的)
	    	String query = request.getQueryString();//得到參數
	    	if(query == null) {
	    		query = "";
	    	}
	    	String realPath = path+"?"+query;
	    	System.out.println(uri+"?"+query);//測試用
	    	System.out.println(realPath);//測試用
	    	session.setAttribute("realPath", realPath);
			return false;
		}
		return true;
	}
}

2、使用Shiro插件實現

如果你的項目裏面集成了Shiro安全框架,那麼恭喜你,你可以很方便的實現控制登錄及頁面跳轉,我也推薦使用這個方法,因爲Shiro實在是太強大了,讀者可以閱讀我的另外兩個博文(即將發出):《Apache Shiro簡介》和《Spring整合Shiro詳解》。先來介紹這個,Shiro裏面有一個方法,可以得到跳轉到登錄頁面之前的頁面的地址SavedRequest savedRequest =WebUtils.getSavedRequest(request);是不是很方便。

具體代碼如下(因爲牽扯的太多,所以只講述這一塊,如果想深入瞭解,可以閱讀我的其他博文,謝謝):

這段是你的項目裏面的認證控制器

        @SysLog(operation="登錄")
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String login(String username, String password, String remember, String captcha, Model model, HttpSession httpSession,HttpServletRequest request) throws IOException {
		httpSession.setAttribute("username", username);
		User user = userService.getByUsername(username);
		httpSession.setAttribute("loginUser", userService.getByUsername(username));
		
		SavedRequest savedRequest = WebUtils.getSavedRequest(request);
		if(savedRequest == null){
			if(user.getUserType() == UserType.admin) {
				return "redirect:/admin/dashboard";
			}
			return "redirect:/user";
		}else {
			String url = savedRequest.getRequestUrl().substring(request.getContextPath().length());
			return "redirect:"+url;
		}
	}

作者聲明:寫這篇文章的初衷旨在不忘記一些工作中需要的知識點和技能,方便以後查閱,也方便有需要的同行拿去參考。以上文字和圖片都不是本人敲打上去的(除了本段),因爲沒那時間和精力,也沒必要。東湊西拼的東西好用就行,也能發揮互聯網共享的理念,我也做一個不辭辛苦的搬運工。以上內容的原文如有,“轉載註明原文出處”,還望見諒沒能實現,早已忘記是從哪裏摘錄。此致!奮鬥在猿類世界的小晨。

發佈了24 篇原創文章 · 獲贊 9 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章