萬字長文帶你徹底學會攔截器與過濾器

一隻胡說八道的猴子發表於2021-01-30

SpringMVC攔截器介紹

什麼是攔截器

Spring MVC中的攔截器(Interceptor)類似於Servlet中的過濾器(Filter),它主要用於攔截使用者請求並作相應的處理。例如通過攔截器可以進行許可權驗證、記錄請求資訊的日誌、判斷使用者是否登入等。

攔截器快速入門

1.建立攔截器實現HandlerInterceptor介面
2.配置攔截器
3.測試攔截器的攔截效果

1.建立攔截器實現HandlerInterceptor介面

package com.pjh.HandleInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
    /*目標方法執行前執行*/
    /*false代表不放行,true代表放行*/
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("第一個:preHandle");
        return false;
    }
     /*目標方法執行之後,檢視返回之前執行*/
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("第一個:postHandle");
    }
    /*全部流程執行完畢後執行*/
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("第一個:afterCompletion");
    }
}

方法介紹

  • preHandle() 方法:該方法會在控制器方法前執行,其返回值表示是否中斷後續操作。當其返回值為true時,表示繼續向下執行;
    當其返回值為false時,會中斷後續的所有操作(包括呼叫下一個攔截器和控制器類中的方法執行等)。

  • postHandle()方法:該方法會在控制器方法呼叫之後,且解析檢視之前執行。可以通過此方法對請求域中的模型和檢視做出進一步的修改。

  • afterCompletion()方法:該方法會在整個請求完成,即檢視渲染結束之後執行。可以通過此方法實現一些資源清理、記錄日誌資訊等工作。

2.配置攔截器

開發攔截器就像開發servlet或者filter一樣,都需要在配置檔案進行配置,配置程式碼如下:

<mvc:interceptors>
     <mvc:interceptor>
         <!--配置攔截器作用路徑-->
         <mvc:mapping path="/**"/>
         <!--定義在<mvc:interceptor>下面的表示匹配指定路徑的請求才進行攔截-->
         <!--這裡是對所有目標方法都進行攔截-->
         <bean class="com.pjh.HandleInterceptor.MyInterceptor"/>
     </mvc:interceptor>
 </mvc:interceptors>

上面的程式碼中,mvc:interceptors元素用於配置一組攔截器,基子元素中定義的是全域性攔截器,它會攔截所有的請求;而mvc:interceptor元素中定義的是指定路徑的攔截器,它會對指定路徑下的請求生效。mvc:interceptor元素的子元素mvc:mapping用於配置攔截器作用的路徑,該路徑在其屬性path 中定義。如上述程式碼中 path 的屬性值“/**” 表示攔截所有路徑,“/hello” 表示攔截所有以 “/hello” 結尾的路徑。如果在請求路徑中包含不需要攔截的內容,還可以通過mvc:exclude-mapping元素進行配置。
注意:mvc:interceptor中的子元素必須按照上述程式碼中的配置順序進行編寫,即mvc:mapping mvc:exclude-mapping ,否則檔案會報錯。

攔截器的執行流程

單個攔截器

在執行程式時,攔截器的執行是有一定順序的,該順序與配置檔案中所定義的攔截器的順序相關。
單個攔截器,在程式中的執行流程如下圖所示:

在這裡插入圖片描述

1.程式先執行preHandle()方法,如果該方法的返回值為true,則程式會繼續向下執行處理器中的方法,否則將不再向下執行。

2.在業務處理器(即控制器Controller類)處理完請求後,會執行postHandle()方法,然後會通過DispatcherServlet向客戶端返回響應。

3.在DispatcherServlet處理完請求後,才會執行afterCompletion()方法。

測試案例

定義一個攔截器,訪問資源後觀察控制檯輸出

package com.pjh.HandleInterceptor;

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

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

public class MyInterceptor implements HandlerInterceptor {
    /*目標方法執行前執行*/
    /*false代表不放行,true代表放行*/
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("第一個:preHandle");
        return false;
    }
     /*目標方法執行之後,檢視返回之前執行*/
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("第一個:postHandle");
    }
    /*全部流程執行完畢後執行*/
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("第一個:afterCompletion");
    }
}

在這裡插入圖片描述

配置多個攔截器的執行流程

多個攔截器(假設有兩個攔截器Interceptor1和Interceptor2,並且在配置檔案中, Interceptor1攔截器配置在前),在程式中的執行流程如下圖所示:

在這裡插入圖片描述

從圖可以看出,當有多個攔截器同時工作時,它們的preHandle()方法會按照配置檔案中攔截器的配置順序執行,而它們的postHandle()方法和afterCompletion()方法則會按照配置順序的反序執行。

測試案例

mvc配置檔案中的資料

 <!--配置攔截器-->
 <mvc:interceptors>
     <!--第一個攔截器-->
     <mvc:interceptor>
         <!--配置攔截器作用路徑-->
         <mvc:mapping path="/**"/>
         <!--定義在<mvc:interceptor>下面的表示匹配指定路徑的請求才進行攔截-->
         <!--這裡是對所有目標方法都進行攔截-->
         <bean class="com.pjh.HandleInterceptor.MyInterceptor"/>
     </mvc:interceptor>
     <!--第二個攔截器-->
     <mvc:interceptor>
         <mvc:mapping path="/**"/>
         <bean class="com.pjh.HandleInterceptor.MyInterceptor2"/>
     </mvc:interceptor>
 </mvc:interceptors>

第一個攔截器中的程式碼

/*目標方法執行前執行*/
    /*false代表不放行,true代表放行*/
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("第一個:preHandle");
        return true;
    }
     /*目標方法執行之後,檢視返回之前執行*/
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("第一個:postHandle");
    }
    /*全部流程執行完畢後執行*/
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("第一個:afterCompletion");
    }

**
**
**
第二個攔截器中的程式碼

package com.pjh.HandleInterceptor;

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

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

public class MyInterceptor2  implements HandlerInterceptor {
    /*目標方法執行前執行*/
    /*false代表不放行,true代表放行*/
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("第二個:preHandle");
        return true;
    }
    /*目標方法執行之後,檢視返回之前執行*/
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("第二個:postHandle");
    }
    /*全部流程執行完畢後執行*/
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("第二個:afterCompletion");
    }
}

訪問資源後的控制檯輸出
在這裡插入圖片描述

攔截器案例1

攔截器通過判斷get方法中的引數來判斷是否跳轉到頁面的案例

攔截器程式碼配置

package com.pjh.HandleInterceptor;

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

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

public class MyInterceptor implements HandlerInterceptor {
    /*目標方法執行前執行*/
    /*false代表不放行,true代表放行*/
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("第一個:preHandle");
        String param = request.getParameter("param");
        /*如果引數為false返回success頁面*/
        /*如果引數不為false返回error頁面*/
        if ("yes".equals(param)){
            return true;
        }else {
            request.getRequestDispatcher("error.jsp").forward(request,response);
            return false;
        }
    }
     /*目標方法執行之後,檢視返回之前執行*/
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("第一個:postHandle");
    }
    /*全部流程執行完畢後執行*/
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("第一個:afterCompletion");
    }
}

當get方法所帶引數為yes時

在這裡插入圖片描述

當get方法所帶引數不為yes時
在這裡插入圖片描述

攔截器案例2判斷使用者有沒有登入

專案背景:

以訪問一個後臺管理系統為例,如果使用者登入了則讓其可以訪問後臺管理系統,如果使用者沒有登入則在使用者點選任意選單時都跳轉到登入頁面

點選側邊欄的任何一個按鈕均跳轉到登入頁面
在這裡插入圖片描述

在這裡插入圖片描述

攔截器的配置

<!--配置攔截器-->
    <mvc:interceptors>
        <mvc:interceptor>
            <!--配置攔截路徑,對哪些方法進行攔截操作-->
            <mvc:mapping path="/**"/>
           <!--配置攔截路徑對哪些方法不進行攔截操作,應該將login函式放行,不然就一直卡在登入頁面-->
            <mvc:exclude-mapping path="/user/login"/>
            <!--配置攔截器類的所在位置-->
            <bean class="com.pjh.Interceptor.PrivilegeInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>

攔截器程式碼實現

package com.pjh.Interceptor;
import com.pjh.domain.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.print.DocFlavor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class PrivilegeInterceptor implements HandlerInterceptor {

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /*如果session域中的user物件為空則跳轉到登入頁面說明使用者沒有登入或則登入失敗*/
        HttpSession session = request.getSession();
        User user = (User) session.getAttribute("user");
        System.out.println("攔截器:"+user);
        if (user==null){
            response.sendRedirect(request.getContextPath()+"/login.jsp");
            return false;
        }
        /*使用者存在放行*/
        return true;
    }

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

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion");
    }

}

Controller層/login程式碼

呼叫Service層函式判斷是否存在該使用者

 @Autowired
    private UserService userService;
   @RequestMapping("/login")
   public String login(String username, String password, HttpSession session){
       System.out.println(username);
       System.out.println(password);
     User user =userService.login(username,password);
     if (user!=null){
         session.setAttribute("user",user);
         System.out.println(user);
         return "redirect:/index.jsp";
     }else {
         return "redirect:/login.jsp";
     }
   }

Service層login函式程式碼

public User login(String username, String password) {
        User user=userDao.findPasswordAndUsername(username,password);
       return user;
    }

Dao層查詢使用者是否存在程式碼

注意這裡要捕獲異常否則當查詢到使用者為空的時候會丟擲異常

 public User findPasswordAndUsername(String username, String password) {
       try{
       User user = jdbcTemplate.queryForObject("select * from sys_user where username=? and password=?", new BeanPropertyRowMapper<User>(User.class), username, password);
       System.out.println(user);
       return user;
   }catch (EmptyResultDataAccessException e){
       return null;
    }
}

經過以上設定只有使用者輸入正確的使用者名稱及其密碼之後才可以進入後臺管理頁面

過濾器的介紹及其使用

啥是過濾器

顧名思義即過濾掉一些東西,比如我們經歷的高考中考都是過濾器,他過濾掉一些在學習這一方面不是很好的人,而那些成績好的人則升入高中,大學。
在這裡插入圖片描述

但是java中的過濾器與生活中的過濾器的作用是相差無幾的,即按照制定的一些規則來控制一些物件

Filer的作用:

過濾器是出於客戶端與伺服器端之間的一道過濾網,在訪問資源之前,通過一系列的過濾器對請求進行修改,判斷等。把不符合規則的請求在中途攔截或修改,攔截或修改響應
在這裡插入圖片描述

應用場景

自動登入
統一設定編碼格式
訪問許可權控制
敏感字元過濾等

過濾器快速入門

需要匯入的jar座標

<dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>servlet-api</artifactId>
        <version>6.0.29</version>
    </dependency>
    <dependency>
        <groupId>org.mortbay.jetty</groupId>
        <artifactId>servlet-api-2.5</artifactId>
        <version>6.1.7</version>
    </dependency>

1. 步驟:

  1. 定義一個類,實現介面Filter
  2. 複寫方法
    3.1註解配置
    3.2web.xml配置

3.1註解配置

Filter類程式碼如下
**

package com.pjh;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*在執行所有資源之前都會執行該過濾器*/
@WebFilter("/*")
public class MyFilter1 implements Filter {
    /*在伺服器啟動後,會建立Filter物件,然後呼叫init方法。只執行一次。用於載入資源*/
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化");
    }
   /*:每一次請求被攔截資源時,會執行。執行多次*/
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("執行過濾器操作");
          /*放行操作*/
        filterChain.doFilter(servletRequest, servletResponse);
    }
  /*在伺服器關閉後,Filter物件被銷燬。如果伺服器是正常關閉,則會執行destroy方法。只執行一次。用於釋放資源*/
    public void destroy() {
        System.out.println("過濾器銷燬操作");
    }
}

3.2web.xml配置

 <filter>
       <filter-name>MyFilter1</filter-name>
       <!--過濾器所在的類的路徑-->
       <filter-class>com.pjh.MyFilter1</filter-class>
   </filter>
    <filter-mapping>
        <!--攔截路徑配置-->
        <filter-name>MyFilter1</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

1. 過濾器執行流程

  1. 執行過濾器
  2. 執行放行後的資源
  3. 回來執行過濾器放行程式碼下邊的程式碼

2. 過濾器生命週期方法

1. init:

在伺服器啟動後,會建立Filter物件,然後呼叫init方法。只執行一次。用 於載入資源
**

2. doFilter:

每一次請求被攔截資源時,會執行。執行多次

3. destroy:

在伺服器關閉後,Filter物件被銷燬。如果伺服器是正常關閉,則會執 行destroy方法。只執行一次。用於釋放資源

4. 過濾器配置詳解

* 攔截路徑配置:

** 1. 具體資源路徑:**
/index.jsp 只有訪問index.jsp資源時,過濾器才會被執行

2. 攔截目錄:
/user/* 訪問/user下的所有資源時,過濾器都會被執行

3. 字尾名攔截:
*.jsp 訪問所有字尾名為jsp資源時,過濾器都會被執行

4. 攔截所有資源:
/* 訪問所有資源時,過濾器都會被執行

* 攔截方式配置:資源被訪問的方式

*** 註解配置:**
* 設定dispatcherTypes屬性
	1. REQUEST:預設值。瀏覽器直接請求資源
	2. FORWARD:轉發訪問資源
	3. INCLUDE:包含訪問資源
	4. ERROR:錯誤跳轉資源
	5. ASYNC:非同步訪問資源

package com.pjh;

import javax.print.DocFlavor;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/*在執行所有資源之前,而且是直接訪問該資源的時候才會執行該過濾器*/
@WebFilter(value = "/*",dispatcherTypes =DispatcherType.REQUEST )
public class MyFilter1 implements Filter {
    /*在伺服器啟動後,會建立Filter物件,然後呼叫init方法。只執行一次。用於載入資源*/
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化");
    }
   /*:每一次請求被攔截資源時,會執行。執行多次*/
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {

        System.out.println("執行過濾器操作");
        /*放行操作*/
        filterChain.doFilter(servletRequest, servletResponse);
    }
  /*在伺服器關閉後,Filter物件被銷燬。如果伺服器是正常關閉,則會執行destroy方法。只執行一次。用於釋放資源*/
    public void destroy() {
        System.out.println("過濾器銷燬操作");
    }
}

* web.xml配置

* 設定<dispatcher></dispatcher>標籤即可

<filter>
       <filter-name>MyFilter1</filter-name>
       <!--過濾器所在的類的路徑-->
       <filter-class>com.pjh.MyFilter1</filter-class>
   </filter>
    <filter-mapping>
        <!--攔截路徑配置-->
        <filter-name>MyFilter1</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>

5. 過濾器鏈(配置多個過濾器)

* 執行順序:如果有兩個過濾器:過濾器1和過濾器2

看圖就行,很好理解
在這裡插入圖片描述

1. 過濾器1
2. 過濾器2
3. 資源執行
4. 過濾器2
5. 過濾器1  

* 過濾器先後順序問題:

  1. 註解配置:按照類名的字串比較規則比較,值小的先執行
    如: AFilter 和 BFilter,AFilter就先執行了

  2. web.xml配置: 誰定義在上邊,誰先執行

案例一:過濾器之-使用者登入案例

專案背景:

以訪問一個後臺管理系統為例,如果使用者登入了則讓其可以訪問後臺管理系統,如果使用者沒有登入則不能訪問任何的該網站頁面,並且自動跳轉到登入頁面,在登入後才可以訪問其他頁面

點選側邊欄的任何一個按鈕均跳轉到登入頁面
在這裡插入圖片描述

在這裡插入圖片描述

過濾器程式碼實現

package com.pjh.Filter;
import com.pjh.domain.User;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;
public class LoginFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("過濾啟動");
    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("過濾器執行");
        System.out.println(servletRequest);
        /*強制轉換*/
        HttpServletRequest request=  (HttpServletRequest)servletRequest;
        /*獲取請求資源的路徑*/
        String  uri = request.getRequestURI();
        /*判斷是否是包含登入資源的相關路徑要注意排除掉 css/js/圖片/驗證碼等資源*/
        if (uri.contains("/login") ||uri.contains("/login.jsp")|| uri.contains("/loginServlet") || uri.contains("/css/") || uri.contains("/js/") || uri.contains("/fonts/") || uri.contains("/checkCodeServlet") ||uri.contains("/img/")){
            /*是訪問登入相關的路徑,放行*/
            filterChain.doFilter(servletRequest,servletResponse);
        }else{
            /*不是登入的相關路徑,看看使用者有沒有登入*/
            HttpSession session = request.getSession();
            /*從session域中獲取user,看看有沒有登入*/
            User user = (User)session.getAttribute("user");
            System.out.println(user);
            if (user==null){
                /*未登入跳轉到登入頁面*/
                request.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
            }else{
                /*已經登入放行*/
                filterChain.doFilter(servletRequest, servletResponse);
            }
        }
    }

    public void destroy() {
        System.out.println("過濾器銷燬");
    }
}

在web.xml中對過濾器的配置

 <filter>
       <filter-name>filter1</filter-name>
       <!--過濾器所在的位置-->
       <filter-class>com.pjh.Filter.LoginFilter</filter-class>
   </filter>
  <filter-mapping>
      <filter-name>filter1</filter-name>
      <!--過濾器對所有資源生效-->
      <url-pattern>/*</url-pattern>
   </filter-mapping>

經過以上配置使用者只有在登入之後才可以對資源進行訪問了

案例二 過濾器之敏感詞彙的過濾

應用場景:

比如在王者榮耀當中經常有低素質的人在裡面狂噴別人,滿嘴汙穢詞彙,這個時候為了營造良好的遊戲氛圍,就要使用到敏感詞彙過濾的技術,將罵人的詞彙變成“****”

基本原理:

這時候我們就要使用過濾器了,在過濾器中對這些敏感詞彙進行等一系列操作

下面通過一張圖來講解
**
比如我們的敏感詞彙為“壞蛋”,如果我們輸入“你是壞蛋”那麼過濾後的內容就為“你是**”,在過濾器中由於reqest物件沒有setParemeter操作,所以我們只能對request物件的getParameter方法進行增強,並且產生一個新的Parameter物件,並在新的request物件中加入過濾後的詞彙,供其他方法呼叫

在這裡插入圖片描述

Filter中是使用動態代理的方式來對敏感詞彙進行過濾的

需求對以下敏感詞彙進行過濾,並將敏感詞彙替換為“*

笨蛋
傻瓜

**
**
分析:
1.對request物件進行增強,增強獲取引數的相關方法
2.放行,傳遞代理物件

Filter函式程式碼如下

package com.pjh.Filter;

import com.sun.org.apache.bcel.internal.generic.IF_ACMPEQ;

import javax.servlet.*;
import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

public class SensitiveWordFilter implements Filter {
    /*建立敏感詞彙集合*/
    private List<String> list = new ArrayList<String>();
    public void init(FilterConfig filterConfig) throws ServletException {
       /*讀取相關的敏感詞彙檔案並存入對應的集合中*/
        try{
            /*獲取檔案的真實路徑*/
            ServletContext servletContext = filterConfig.getServletContext();
            InputStream path = this.getClass().getResourceAsStream("/SensitiveWord.txt");
            /*讀取檔案*/
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(path,"UTF-8"));
            /*將檔案的每一行資料新增到list集合中*/
            String line=null;
            while ((line=bufferedReader.readLine())!=null){
                list.add(line);
            }
            bufferedReader.close();
           // System.out.println(list);

        }catch (Exception e){
            System.out.println(e);
        }

    }

    public void doFilter(final ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filter1:"+servletRequest);
        ServletRequest proxy_req= (ServletRequest) Proxy.newProxyInstance(servletRequest.getClass().getClassLoader(), servletRequest.getClass().getInterfaces(), new InvocationHandler() {
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
              /*1.判斷是否是getParameter方法
                2. 增強getParameter方法             */
                if (method.getName().equals("getParameter")){
                    /*增強返回值*/
                    /*獲取返回值*/
                   String value= (String)method.invoke(servletRequest,args);
                   /*遍歷集合判斷字串中是否存在敏感詞彙*/
                   if (value!=null){
                       for (String s : list) {
                           if (value.contains(value)){
                               value=value.replace(s,"***");
                           }
                       }
                   }
                   return value;
                }

                return method.invoke(servletRequest,args);
            }
        });
        System.out.println("list集合資料:"+list);
        System.out.println("filter2proxy_req:"+proxy_req);
        /*放行*/
        filterChain.doFilter(proxy_req,servletResponse);
    }

    public void destroy() {
        System.out.println("銷燬方法");
    }
}

在web.xml中設定攔截路徑

<!--設定敏感詞彙過濾器-->
    <filter>
        <filter-name>filter2</filter-name>
        <filter-class>com.pjh.Filter.SensitiveWordFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>filter2</filter-name>
        <url-pattern>/filter/*</url-pattern>
    </filter-mapping>

Controller類程式碼

package com.pjh.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.UnsupportedEncodingException;
/*設定編碼格式*/
@Controller
@RequestMapping(value = "/filter",produces = "text/html;charset=utf-8")
public class TestFilterController {
    @RequestMapping("/test1")
    @ResponseBody
    public String test1(ServletRequest request, ServletResponse response) throws UnsupportedEncodingException {
        System.out.println("test1:"+request);
        String id = request.getParameter("id");
        System.out.println("test1ID:"+id);
        return "你的id是"+id;
    }
}

未設定過濾器前
**
在這裡插入圖片描述

設定過濾器後
**

在這裡插入圖片描述

過濾器與攔截器的區別以及過濾器的基本:

過濾器與攔截器的區別

1.過濾器:

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

2.攔截器:

依賴於web框架,在SpringMVC中就是依賴於SpringMVC框架。在實現上基於Java的反射機制,屬於面向切面程式設計(AOP)的一種運用。由於攔截器是基於web框架的呼叫,因此可以使用Spring的依賴注入(DI)進行一些業務操作,同時一個攔截器例項在一個controller生命週期之內可以多次呼叫。但是缺點是隻能對controller請求進行攔截,對其他的一些比如直接訪問靜態資源的請求則沒辦法進行攔截處理
3.過濾器和攔截器的區別:
①攔截器是基於java的反射機制的,而過濾器是基於函式回撥。
②攔截器不依賴與servlet容器,過濾器依賴與servlet容器。
③攔截器只能對action請求起作用,而過濾器則可以對幾乎所有的請求起作用。
④攔截器可以訪問action上下文、值棧裡的物件,而過濾器不能訪問。
⑤在action的生命週期中,攔截器可以多次被呼叫,而過濾器只能在容器初始化時被呼叫一次。
⑥攔截器可以獲取IOC容器中的各個bean,而過濾器就不行,這點很重要,在攔截器裡注入一個service,可以呼叫業務邏輯。

在這裡插入圖片描述

過濾器


@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException {
        System.out.println("before...");
        chain.doFilter(request, response);
        System.out.println("after...");
    }

chain.doFilter(request, response);這個方法的呼叫作為分水嶺。事實上呼叫Servlet的doService()方法是在chain.doFilter(request, response);這個方法中進行的。
**
在這裡插入圖片描述

在這裡插入圖片描述

相關文章