SpringMVC學習記錄(七)--攔截器的使用


SpringMVC的請求如以下這樣的圖所看到的:
此處輸入圖片的描寫敘述

能夠看出全部的請求都要通過Dispatherservlet來接收,然后通過Handlermapping來決定使用哪個控制器,再依據ViewResolver來決定返回哪個視圖.從流程來看,Handlermapping就是我們能夠實現攔截器的第一種方法.另外另一種是實現WebRequestInterceptor接口,或者繼承其子類.


一.實現HandlerInterceptor接口

實現HandlerInterceptor接口或者繼承HandlerInterceptor的子類,比方比方Spring 已經提供的實現了HandlerInterceptor 接口的抽象類HandlerInterceptorAdapter ,以下講實現其接口的寫法,先看一下這個接口的三個方法.
- 方法preHandle: 顧名思義,該方法將在請求處理之前進行調用。SpringMVC 中的Interceptor 是鏈式的調用的,在一個應用中或者說是在一個請求中能夠同一時候存在多個Interceptor 。

每個Interceptor 的調用會依據它的聲明順序依次運行,並且最先運行的都是Interceptor 中的preHandle 方法,所以能夠在這種方法中進行一些前置初始化操作或者是對當前請求的一個預處理。也能夠在這種方法中進行一些推斷來決定請求是否要繼續進行下去。

該方法的返回值是布爾值Boolean 類型的,當它返回為false 時,表示請求結束,興許的Interceptor 和Controller 都不會再運行;當返回值為true 時就會繼續調用下一個Interceptor 的preHandle 方法。假設已經是最后一個Interceptor 的時候就會是調用當前請求的Controller 方法。
- 方法postHandle:由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 方法之后的內容就是反向的。
- 方法afterCompletion:該方法也是須要當前相應的Interceptor 的preHandle 方法的返回值為true 時才會運行。顧名思義。該方法將在整個請求結束之后,也就是在DispatcherServlet 渲染了相應的視圖之后運行。這種方法的主要作用是用於進行資源清理工作的。

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class SpringMVCInterceptor implements HandlerInterceptor {


    /** * preHandle方法是進行處理器攔截用的,顧名思義,該方法將在Controller處理之前進行調用,SpringMVC中的Interceptor攔截器是鏈式的。能夠同一時候存在 * 多個Interceptor。然后SpringMVC會依據聲明的前后順序一個接一個的運行,並且全部的Interceptor中的preHandle方法都會在 * Controller方法調用之前調用。

SpringMVC的這樣的Interceptor鏈式結構也是能夠進行中斷的。這樣的中斷方式是令preHandle的返 * 回值為false。當preHandle的返回值為false的時候整個請求就結束了。

*/ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // TODO Auto-generated method stub return false; } /** * 這種方法僅僅會在當前這個Interceptor的preHandle方法返回值為true的時候才會運行。postHandle是進行處理器攔截用的,它的運行時間是在處理器進行處理之 * 后,也就是在Controller的方法調用之后運行。可是它會在DispatcherServlet進行視圖的渲染之前運行,也就是說在這種方法中你能夠對ModelAndView進行操 * 作。這種方法的鏈式結構跟正常訪問的方向是相反的,也就是說先聲明的Interceptor攔截器該方法反而會后調用。這跟Struts2里面的攔截器的運行過程有點像, * 僅僅是Struts2里面的intercept方法中要手動的調用ActionInvocation的invoke方法,Struts2中調用ActionInvocation的invoke方法就是調用下一個Interceptor * 或者是調用action。然后要在Interceptor之前調用的內容都寫在調用invoke之前,要在Interceptor之后調用的內容都寫在調用invoke方法之后。 */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } /** * 該方法也是須要當前相應的Interceptor的preHandle方法的返回值為true時才會運行。該方法將在整個請求完畢之后,也就是DispatcherServlet渲染了視圖運行, * 這種方法的主要作用是用於清理資源的。當然這種方法也僅僅能在當前這個Interceptor的preHandle方法的返回值為true時才會運行。 */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }


二.實現WebRequestInterceptor接口

WebRequestInterceptor 中也定義了三個方法。我們也是通過這三個方法來實現攔截的。這三個方法都傳遞了同一個參數WebRequest ,那么這個WebRequest 是什么呢?這個WebRequest 是Spring 定義的一個接口,它里面的方法定義都基本跟HttpServletRequest 一樣,在WebRequestInterceptor 中對WebRequest 進行的全部操作都將同步到HttpServletRequest 中,然后在當前請求中一直傳遞。

  • 方法preHandle:方法將在請求處理之前進行調用,也就是說會在Controller 方法調用之前被調用。這種方法跟HandlerInterceptor 中的preHandle 是不同的。主要差別在於該方法的返回值是void 。也就是沒有返回值,所以我們一般主要用它來進行資源的准備工作,比方我們在使用Hibernate 的時候能夠在這種方法中准備一個Hibernate 的Session 對象,然后利用WebRequest 的setAttribute(name, value, scope) 把它放到WebRequest 的屬性中。這里能夠說說這個setAttribute 方法的第三個參數scope ,該參數是一個Integer 類型的。在WebRequest 的父層接口RequestAttributes 中對它定義了三個常量:
    SCOPE_REQUEST :它的值是0 ,代表僅僅有在request 中能夠訪問。
    SCOPE_SESSION :它的值是1 ,假設環境同意的話它代表的是一個局部的隔離的session。否則就代表普通的session。並且在該session范圍內能夠訪問。
    SCOPE_GLOBAL_SESSION :它的值是2 ,假設環境同意的話。它代表的是一個全局共享的session,否則就代表普通的session,並且在該session 范圍內能夠訪問。

  • 方法postHandle:該方法將在請求處理之后。也就是在Controller 方法調用之后被調用,可是會在視圖返回被渲染之前被調用,所以能夠在這種方法里面通過改變數據模型ModelMap 來改變數據的展示。該方法有兩個參數,WebRequest 對象是用於傳遞整個請求數據的,比方在preHandle 中准備的數據都能夠通過WebRequest 來傳遞和訪問。ModelMap 就是Controller 處理之后返回的Model 對象,我們能夠通過改變它的屬性來改變返回的Model 模型。

  • 方法afterCompletion:該方法會在整個請求處理完畢,也就是在視圖返回並被渲染之后運行。所以在該方法中能夠進行資源的釋放操作。

    而WebRequest 參數就能夠把我們在preHandle 中准備的資源傳遞到這里進行釋放。Exception 參數表示的是當前請求的異常對象。假設在Controller 中拋出的異常已經被Spring 的異常處理器給處理了的話,那么這個異常對象就是是null 。

import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.WebRequestInterceptor;

public class AllInterceptor implements WebRequestInterceptor {

    /** * 在請求處理之前運行,該方法主要是用於准備資源數據的,然后能夠把它們當做請求屬性放到WebRequest中 */
    @Override
    public void preHandle(WebRequest request) throws Exception {
        // TODO Auto-generated method stub
        System.out.println("AllInterceptor...............................");
        request.setAttribute("request", "request", WebRequest.SCOPE_REQUEST);//這個是放到request范圍內的,所以僅僅能在當前請求中的request中獲取到
        request.setAttribute("session", "session", WebRequest.SCOPE_SESSION);//這個是放到session范圍內的,假設環境同意的話它僅僅能在局部的隔離的會話中訪問。否則就是在普通的當前會話中能夠訪問
        request.setAttribute("globalSession", "globalSession", WebRequest.SCOPE_GLOBAL_SESSION);//假設環境同意的話。它能在全局共享的會話中訪問。否則就是在普通的當前會話中訪問
    }

    /** * 該方法將在Controller運行之后,返回視圖之前運行。ModelMap表示請求Controller處理之后返回的Model對象,所以能夠在 * 這種方法中改動ModelMap的屬性,從而達到改變返回的模型的效果。 */
    @Override
    public void postHandle(WebRequest request, ModelMap map) throws Exception {
        // TODO Auto-generated method stub
        for (String key:map.keySet())
            System.out.println(key + "-------------------------");;
        map.put("name3", "value3");
        map.put("name1", "name1");
    }

    /** * 該方法將在整個請求完畢之后,也就是說在視圖渲染之后進行調用。主要用於進行一些資源的釋放 */
    @Override
    public void afterCompletion(WebRequest request, Exception exception)
    throws Exception {
        // TODO Auto-generated method stub
        System.out.println(exception + "-=-=--=--=-=-=-=-=-=-=-=-==-=--=-=-=-=");
    }

}

三.攔截器的配置

1.mvc:interceptors標簽來聲明須要增加到SpringMVC攔截器鏈中的攔截器

    <mvc:interceptors>
        <!-- 使用bean定義一個Interceptor。直接定義在mvc:interceptors根以下的Interceptor將攔截全部的請求 -->
        <bean class="com.host.app.web.interceptor.AllInterceptor"/>
        <mvc:interceptor>
            <mvc:mapping path="/test/number.do"/>
            <!-- 定義在mvc:interceptor以下的表示是對特定的請求才進行攔截的 -->
            <bean class="com.host.app.web.interceptor.LoginInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

由上面的演示樣例能夠看出能夠利用mvc:interceptors標簽聲明一系列的攔截器,然后它們就能夠形成一個攔截器鏈。攔截器的運行順序是按聲明的先后順序運行的,先聲明的攔截器中的preHandle方法會先運行,然而它的postHandle方法和afterCompletion方法卻會后運行。
在mvc:interceptors標簽下聲明interceptor主要有兩種方式:
(1)直接定義一個Interceptor實現類的bean對象。使用這樣的方式聲明的Interceptor攔截器將會對全部的請求進行攔截。
(2)使用mvc:interceptor標簽進行聲明。使用這樣的方式進行聲明的Interceptor能夠通過mvc:mapping子標簽來定義須要進行攔截的請求路徑。


經過上述兩步之后。定義的攔截器就會發生作用對特定的請求進行攔截了。


原文鏈接 http://haohaoxuexi.iteye.com/blog/1750680


樣例:

近期正好寫了一個簡單的登錄驗證攔截器:

以下攔截器,推斷session里面是否存在登錄,存在且同意訪問,不存在則跳轉到登錄頁面

package com.aust.interceptor;

import com.aust.model.system.SysUser;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class LoginUserInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        String url = httpServletRequest.getRequestURI();
        if (url.indexOf("system/login")>0){
            return true;
        }
        //推斷session是否已登錄
        HttpSession session = httpServletRequest.getSession();
        SysUser user = (SysUser) session.getAttribute("loginsucess");
        if (user != null){
            return true;
        }
        //運行到這里說明沒有session,須要攔截
        httpServletRequest.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(httpServletRequest,httpServletResponse);
        return false;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {

    }
}

須要在springMVC.xml中配置:

    <!--訪問攔截-->
    <mvc:interceptors>
        <!-- 使用bean定義一個Interceptor,直接定義在mvc:interceptors根以下的Interceptor將攔截全部的請求 -->
        <!--<bean class="com.host.app.web.interceptor.AllInterceptor"/>-->
        <mvc:interceptor>
        <!-- 對system下的請求全部攔截 -->
            <mvc:mapping path="/system/*"/>
            <!-- 定義在mvc:interceptor以下的表示是對特定的請求才進行攔截的 -->
            <bean class="com.aust.interceptor.LoginUserInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

這樣就實現了訪問攔截功能


項目演示樣例能夠參考:
SSM框架整合: https://github.com/nl101531/JavaWEB


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM