本文主要介紹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
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception
springmvc攔截器針對HandlerMapping進行攔截設置,如果在某個HandlerMapping中配置攔截,經過該HandlerMapping映射成功的handler最終使用該攔截器。
<code class="language-xml hljs "><bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="interceptors"> <list> <ref bean="handlerInterceptor1"> <ref bean="handlerInterceptor2"> </ref></ref></list> </property> </bean> <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"> <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"></bean></bean></code>
一般不推薦使用。
springmvc配置類似全局的攔截器,springmvc框架將配置的類似全局的攔截器注入到每個HandlerMapping中。
測試多個攔截器各個方法執行時機
訪問/items/queryItems.action
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一定要放行,且將它放在攔截器鏈接中第一個位置。
比如:登陸認證攔截器,放在攔截器鏈接中第一個位置。權限校驗攔截器,放在登陸認證攔截器之後。(因為登陸通過後才校驗權限,當然登錄認證攔截器要放在統一日志處理攔截器後面)
@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");
}
}
攔截器配置
...省略