SpringMVC的攔截器和過濾器的區別


一 簡介

(1)過濾器:

依賴於servlet容器。在實現上基於函數回調,可以對幾乎所有請求進行過濾,但是缺點是一個過濾器實例只能在容器初始化時調用一次。使用過濾器的目的是用來做一些過濾操作,獲取我們想要獲取的數據,比如:在過濾器中修改字符編碼;在過濾器中修改HttpServletRequest的一些參數,包括:過濾低俗文字、危險字符等

關於過濾器的一些用法可以參考我寫過的這些文章

  • 繼承HttpServletRequestWrapper以實現在Filter中修改HttpServletRequest的參數:https://www.zifangsky.cn/677.html

  • 在SpringMVC中使用過濾器(Filter)過濾容易引發XSS的危險字符:https://www.zifangsky.cn/683.html

(2)攔截器:

依賴於web框架,在SpringMVC中就是依賴於SpringMVC框架。在實現上基於Java的反射機制,屬於面向切面編程(AOP)的一種運用。由於攔截器是基於web框架的調用,因此可以使用Spring的依賴注入(DI)進行一些業務操作,同時一個攔截器實例在一個controller生命周期之內可以多次調用。但是缺點是只能對controller請求進行攔截,對其他的一些比如直接訪問靜態資源的請求則沒辦法進行攔截處理

關於過濾器的一些用法可以參考我寫過的這些文章:

  • 在SpringMVC中使用攔截器(interceptor)攔截CSRF攻擊(修):https://www.zifangsky.cn/671.html

  • SpringMVC中使用Interceptor+cookie實現在一定天數之內自動登錄:https://www.zifangsky.cn/700.html

二 多個過濾器與攔截器的代碼執行順序

如果在一個項目中僅僅只有一個攔截器或者過濾器,那么我相信相對來說理解起來是比較容易的。但是我們是否思考過:如果一個項目中有多個攔截器或者過濾器,那么它們的執行順序應該是什么樣的?或者再復雜點,一個項目中既有多個攔截器,又有多個過濾器,這時它們的執行順序又是什么樣的呢?

下面我將用簡單的代碼來測試說明:

(1)先定義兩個過濾器:

i)過濾器1:

package cn.zifangsky.filter;
 
import java.io.IOException;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.filter.OncePerRequestFilter;
 
public class TestFilter1 extends OncePerRequestFilter {
 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        //在DispatcherServlet之前執行
        system.out.println("############TestFilter1 doFilterInternal executed############");
        filterChain.doFilter(request, response);
        //在視圖頁面返回給客戶端之前執行,但是執行順序在Interceptor之后
        System.out.println("############TestFilter1 doFilter after############");
//        try {
//            Thread.sleep(10000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
    }
 
}

ii)過濾器2:

package cn.zifangsky.filter;
 
import java.io.IOException;
 
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.filter.OncePerRequestFilter;
 
public class TestFilter2 extends OncePerRequestFilter {
 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        System.out.println("############TestFilter2 doFilterInternal executed############");
        filterChain.doFilter(request, response);
        System.out.println("############TestFilter2 doFilter after############");
 
    }
 
}

2)再定義兩個攔截器:

i)攔截器1,基本攔截器:

package cn.zifangsky.interceptor;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
public class BaseInterceptor implements HandlerInterceptor{
    
    /**
     * 在DispatcherServlet之前執行
     * */
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("************BaseInterceptor preHandle executed**********");
        return true;
    }
 
    /**
     * 在controller執行之后的DispatcherServlet之后執行
     * */
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        System.out.println("************BaseInterceptor postHandle executed**********");
    }
    
    /**
     * 在頁面渲染完成返回給客戶端之前執行
     * */
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("************BaseInterceptor afterCompletion executed**********");
//        Thread.sleep(10000);
    }
 
}

ii)指定controller請求的攔截器:

package cn.zifangsky.interceptor;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
public class TestInterceptor implements HandlerInterceptor {
 
    public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
        System.out.println("************TestInterceptor preHandle executed**********");
        return true;
    }
 
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
        System.out.println("************TestInterceptor postHandle executed**********");
    }
 
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
        System.out.println("************TestInterceptor afterCompletion executed**********");
    }
}

iii)在SpringMVC的配置文件中注冊這兩個攔截器:

<!-- 攔截器 -->
     <mvc:interceptors>
        <!-- 對所有請求都攔截,公共攔截器可以有多個 -->
        <bean name="baseInterceptor" class="cn.zifangsky.interceptor.BaseInterceptor" />
        <!-- <bean name="testInterceptor" class="cn.zifangsky.interceptor.TestInterceptor" /> -->
        <mvc:interceptor>        
            <!-- 對/test.html進行攔截 -->
            <mvc:mapping path="/test.html"/>
            <!-- 特定請求的攔截器只能有一個 -->
            <bean class="cn.zifangsky.interceptor.TestInterceptor" />
        </mvc:interceptor>
    </mvc:interceptors>

(3)定義一個測試使用的controller:

package cn.zifangsky.controller;
 
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
@Controller
public class TestController {
    
    @RequestMapping("/test.html")
    public ModelAndView handleRequest(){
        System.out.println("---------TestController executed--------");
        return new ModelAndView("test");
    }
}

4)視圖頁面test.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>    
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<base href="http://983836259.blog.51cto.com/7311475/">
<title>FilterDemo</title>
</head>
<body>
    <%
        System.out.println("test.jsp is loading");
    %>
    <div align="center">
        This is test page
    </div>
</body>
</html>


免責聲明!

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



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