本文主要介紹springmvc中的攔截器,包括攔截器定義和的配置,然后演示了一個鏈式攔截的測試示例,最后通過一個登錄認證的例子展示了攔截器的應用
攔截定義
定義攔截器,實現HandlerInterceptor
接口。接口中提供三個方法。
public class HandlerInterceptor1 implements HandlerInterceptor{ //進入 Handler方法之前執行 //用于身份認證、身份授權 //比如身份認證,如果認證通過表示當前用戶沒有登陸,需要此方法攔截不再向下執行 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //return false表示攔截,不向下執行 //return true表示放行 return false; } //進入Handler方法之后,返回modelAndView之前執行 //應用場景從modelAndView出發:將公用的模型數據(比如菜單導航)在這里傳到視圖,也可以在這里統一指定視圖 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } //執行Handler完成執行此方法 //應用場景:統一異常處理,統一日志處理 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
可以從名稱和參數看出各個接口的順序和作用:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
- 參數最少,只有三個
- 進入 Handler方法之前執行
- 用于身份認證、身份授權。比如身份認證,如果認證通過表示當前用戶沒有登陸,需要此方法攔截不再向下執行
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
- 多了一個modelAndView參數
- 進入Handler方法之后,返回modelAndView之前執行
- 應用場景從modelAndView出發:將公用的模型數據(比如菜單導航)在這里傳到視圖,也可以在這里統一指定視圖
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
- 多了一個Exception的類型的參數
- 執行Handler完成執行此方法
- 應用場景:統一異常處理,統一日志處理
攔截器配置
針對HandlerMapping配置
springmvc攔截器針對HandlerMapping進行攔截設置,如果在某個HandlerMapping中配置攔截,經過該HandlerMapping映射成功的handler最終使用該攔截器。
<beanclass="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"><property name="interceptors"> <list> <ref bean="handlerInterceptor1"/> <ref bean="handlerInterceptor2"/> </list> </property> </bean> <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/> <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>
一般不推薦使用。
類似全局的攔截器
springmvc配置類似全局的攔截器,springmvc框架將配置的類似全局的攔截器注入到每個HandlerMapping中。
<!--攔截器 -->
<mvc:interceptors><!--多個攔截器,順序執行 --><mvc:interceptor><!-- /**表示所有url包括子url路徑 --> <mvc:mapping path="/**"/> <bean class="com.iot.learnssm.firstssm.interceptor.HandlerInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.iot.learnssm.firstssm.interceptor.HandlerInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors>
攔截測試
測試多個攔截器各個方法執行時機
訪問/items/queryItems.action
- 1.兩個攔截器都放行
DEBUG [http-apr-8080-exec-1] - DispatcherServlet with name 'springmvc' processing GET request for [/ssm1/items/queryItems.action]
DEBUG [http-apr-8080-exec-1] - Looking up handler method for path /items/queryItems.action
DEBUG [http-apr-8080-exec-1] - Returning handler method [public org.springframework.web.servlet.ModelAndView com.iot.learnssm.firstssm.controller.ItemsController.queryItems(javax.servlet.http.HttpServletRequest,com.iot.learnssm.firstssm.po.ItemsQueryVo) throws java.lang.Exception]
DEBUG [http-apr-8080-exec-1] - Returning cached instance of singleton bean 'itemsController'
DEBUG [http-apr-8080-exec-1] - Last-Modified value for [/ssm1/items/queryItems.action] is: -1
HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
DEBUG [http-apr-8080-exec-1] - Fetching JDBC Connection from DataSource
DEBUG [http-apr-8080-exec-1] - Registering transaction synchronization for JDBC Connection
DEBUG [http-apr-8080-exec-1] - Returning JDBC Connection to DataSource
HandlerInterceptor2...postHandle
HandlerInterceptor1...postHandle
DEBUG [http-apr-8080-exec-1] - Rendering view [org.springframework.web.servlet.view.JstlView: name 'items/itemsList'; URL [/WEB-INF/jsp/items/itemsList.jsp]] in DispatcherServlet with name 'springmvc'
DEBUG [http-apr-8080-exec-1] - Added model object 'itemtypes' of type [java.util.HashMap] to request in view with name 'items/itemsList'
DEBUG [http-apr-8080-exec-1] - Added model object 'itemsQueryVo' of type [com.iot.learnssm.firstssm.po.ItemsQueryVo] to request in view with name 'items/itemsList'
DEBUG [http-apr-8080-exec-1] - Added model object 'org.springframework.validation.BindingResult.itemsQueryVo' of type [org.springframework.validation.BeanPropertyBindingResult] to request in view with name 'items/itemsList'
DEBUG [http-apr-8080-exec-1] - Added model object 'itemsList' of type [java.util.ArrayList] to request in view with name 'items/itemsList'
DEBUG [http-apr-8080-exec-1] - Forwarding to resource [/WEB-INF/jsp/items/itemsList.jsp] in InternalResourceView 'items/itemsList'
HandlerInterceptor2...afterCompletion
HandlerInterceptor1...afterCompletion
DEBUG [http-apr-8080-exec-1] - Successfully completed request
總結:preHandle方法按順序執行,postHandle和afterCompletion按攔截器配置的逆向順序執行。
2.攔截器1放行,攔截器2不放行
DEBUG [http-apr-8080-exec-8] - DispatcherServlet with name 'springmvc' processing GET request for [/ssm1/items/queryItems.action]
DEBUG [http-apr-8080-exec-8] - Looking up handler method for path /items/queryItems.action
DEBUG [http-apr-8080-exec-8] - Returning handler method [public org.springframework.web.servlet.ModelAndView com.iot.learnssm.firstssm.controller.ItemsController.queryItems(javax.servlet.http.HttpServletRequest,com.iot.learnssm.firstssm.po.ItemsQueryVo) throws java.lang.Exception]
DEBUG [http-apr-8080-exec-8] - Returning cached instance of singleton bean 'itemsController'
DEBUG [http-apr-8080-exec-8] - Last-Modified value for [/ssm1/items/queryItems.action] is: -1
HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
HandlerInterceptor1...afterCompletion
DEBUG [http-apr-8080-exec-8] - Successfully completed request
總結:
- 攔截器1放行,攔截器2 preHandle才會執行。
- 攔截器2 preHandle不放行,攔截器2 postHandle和afterCompletion不會執行。
- 只要有一個攔截器不放行,postHandle不會執行。
3.兩個攔截器都不放
DEBUG [http-apr-8080-exec-9] - DispatcherServlet with name 'springmvc' processing GET request for [/ssm1/items/queryItems.action]
DEBUG [http-apr-8080-exec-9] - Looking up handler method for path /items/queryItems.action
DEBUG [http-apr-8080-exec-9] - Returning handler method [public org.springframework.web.servlet.ModelAndView com.iot.learnssm.firstssm.controller.ItemsController.queryItems(javax.servlet.http.HttpServletRequest,com.iot.learnssm.firstssm.po.ItemsQueryVo) throws java.lang.Exception]
DEBUG [http-apr-8080-exec-9] - Returning cached instance of singleton bean 'itemsController'
DEBUG [http-apr-8080-exec-9] - Last-Modified value for [/ssm1/items/queryItems.action] is: -1
HandlerInterceptor1...preHandle
DEBUG [http-apr-8080-exec-9] - Successfully completed request
總結:
- 攔截器1 preHandle不放行,postHandle和afterCompletion不會執行。
- 攔截器1 preHandle不放行,攔截器2不執行。
4.攔截器1不放行,攔截器2放行
DEBUG [http-apr-8080-exec-8] - DispatcherServlet with name 'springmvc' processing GET request for [/ssm1/items/queryItems.action]
DEBUG [http-apr-8080-exec-8] - Looking up handler method for path /items/queryItems.action
DEBUG [http-apr-8080-exec-8] - Returning handler method [public org.springframework.web.servlet.ModelAndView com.iot.learnssm.firstssm.controller.ItemsController.queryItems(javax.servlet.http.HttpServletRequest,com.iot.learnssm.firstssm.po.ItemsQueryVo) throws java.lang.Exception]
DEBUG [http-apr-8080-exec-8] - Returning cached instance of singleton bean 'itemsController'
DEBUG [http-apr-8080-exec-8] - Last-Modified value for [/ssm1/items/queryItems.action] is: -1
HandlerInterceptor1...preHandle
DEBUG [http-apr-8080-exec-8] - Successfully completed request
和兩個攔截器都不行的結果一致,因為攔截器1先執行,沒放行
- 小結
根據測試結果,對攔截器應用。
比如:統一日志處理攔截器,需要該攔截器preHandle一定要放行,且將它放在攔截器鏈接中第一個位置。
比如:登陸認證攔截器,放在攔截器鏈接中第一個位置。權限校驗攔截器,放在登陸認證攔截器之后。(因為登陸通過后才校驗權限,當然登錄認證攔截器要放在統一日志處理攔截器后面)
攔截器應用(實現登陸認證)
需求
- 1.用戶請求url
- 2.攔截器進行攔截校驗
- 如果請求的url是公開地址(無需登陸即可訪問的url),讓放行
- 如果用戶session 不存在跳轉到登陸頁面
- 如果用戶session存在放行,繼續操作。
登陸controller方法
@Controller
public class LoginController { // 登陸 @RequestMapping("/login") public String login(HttpSession session, String username, String password) throws Exception { // 調用service進行用戶身份驗證 // ... // 在session中保存用戶身份信息 session.setAttribute("username", username); // 重定向到商品列表頁面 return "redirect:/items/queryItems.action"; } // 退出 @RequestMapping("/logout") public String logout(HttpSession session) throws Exception { // 清除session session.invalidate(); // 重定向到商品列表頁面 return "redirect:/items/queryItems.action"; } }
登陸認證攔截實現
- 代碼實現
/*** Created by brian on 2016/3/8.* 登陸認證攔截器*/public class LoginInterceptor implements HandlerInterceptor { //進入 Handler方法之前執行 //用于身份認證、身份授權 //比如身份認證,如果認證通過表示當前用戶沒有登陸,需要此方法攔截不再向下執行 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //獲取請求的url String url = request.getRequestURI(); //判斷url是否是公開 地址(實際使用時將公開 地址配置配置文件中) //這里公開地址是登陸提交的地址 if(url.indexOf("login.action")>=0){ //如果進行登陸提交,放行 return true; } //判斷session HttpSession session = request.getSession(); //從session中取出用戶身份信息 String username = (String) session.getAttribute("username"); if(username != null){ //身份存在,放行 return true; } //執行這里表示用戶身份需要認證,跳轉登陸頁面 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response); //return false表示攔截,不向下執行 //return true表示放行 return false; } //進入Handler方法之后,返回modelAndView之前執行 //應用場景從modelAndView出發:將公用的模型數據(比如菜單導航)在這里傳到視圖,也可以在這里統一指定視圖 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("LoginInterceptor...postHandle"); } //執行Handler完成執行此方法 //應用場景:統一異常處理,統一日志處理 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("LoginInterceptor...afterCompletion"); } }
- 攔截器配置
<!--攔截器 -->
<mvc:interceptors><!--多個攔截器,順序執行 --><!-- 登陸認證攔截器 --><mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.iot.learnssm.firstssm.interceptor.LoginInterceptor"></bean> </mvc:interceptor> ...省略