1六、SpringMVC攔截器

攔截定義

定義攔截器,實現HandlerInterceptor接口。接口中提供三個方法。java

public class HandlerInterceptor1 implements HandlerInterceptor{

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //return false表示攔截,不向下執行
        //return true表示放行
        return false;
    }

    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 {
    }
}

能夠從名稱和參數看出各個接口的順序和做用:web

  • 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最終使用該攔截器。spring

<bean
	class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
	<property name="interceptors">
		<list>
			<ref bean="handlerInterceptor1"/>
			<ref bean="handlerInterceptor2"/>
		</list>
	</property>
</bean>
<bean id="handlerInterceptor1" class="com.tianlang.intercapter.HandlerInterceptor1"/>
<bean id="handlerInterceptor2" class="com.tianlang.intercapter.HandlerInterceptor2"/>

通常不推薦使用。session

相似全局的攔截器

springmvc配置相似全局的攔截器,springmvc框架將配置的相似全局的攔截器注入到每一個HandlerMapping中。mvc

<!--攔截器 -->
<mvc:interceptors>
    <!--多個攔截器,順序執行 -->
    <mvc:interceptor>
        <!-- /**表示全部url包括子url路徑 -->
        <mvc:mapping path="/**"/>
        <bean class="com.tianlang.interceptor.HandlerInterceptor1"></bean>
    </mvc:interceptor>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <bean class="com.tianlang.interceptor.HandlerInterceptor2"></bean>
    </mvc:interceptor>
</mvc:interceptors>

攔截測試

測試多個攔截器各個方法執行時機app

訪問/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按攔截器配置的逆向順序執行。jsp

2.攔截器1放行,攔截器2不放行post

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方法

@Controller
public class LoginController {
    // 登錄
    @RequestMapping("/login")
    public String login(HttpSession session, String username, String password)
            throws Exception {
        // 在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";
    }
}

登錄認證攔截實現

  • 代碼實現
/**
 * 登錄認證攔截器
 */
public class LoginInterceptor implements HandlerInterceptor {

    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;
    }

    public void postHandle(HttpServletRequest request,
                           HttpServletResponse response, Object handler,
                           ModelAndView modelAndView) throws Exception {
        System.out.println("LoginInterceptor...postHandle");
    }

    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.tianlang.interceptor.LoginInterceptor"></bean>
	</mvc:interceptor>  
</mvc:interceptors>
相關文章
相關標籤/搜索