springmvc學習筆記(20)-攔截器

springmvc學習筆記(20)-攔截器

標籤: springmvc



本文主要介紹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最終使用該攔截器。

<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="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>

    ...省略

作者@brianway更多文章:個人網站 | CSDN | oschina

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