Java Web開發(fā)中的過濾器(Filter)

1监嗜、Filter介紹

Filter技術(shù)是servlet 2.3新增加的功能呜投。servlet2.3是sun公司于2000年10月發(fā)布的青自,它的開發(fā)者包括許多個人和公司團(tuán)體崖瞭,充分體現(xiàn)了sun公司所倡導(dǎo)的代碼開放性原則统屈。在眾多參與者的共同努力下胚吁,servlet2.3比以往功能都強大了許多,而且性能也有了大幅提高鸿吆。
通過Filter功能囤采,用戶可以改變一個request和修改一個response。Filter不是一個servlet惩淳,它不能產(chǎn)生一個response蕉毯,但是,它能夠在一個request到達(dá)servlet之前預(yù)處理request思犁,也可以在response離開servlet時處理response代虾。
這樣,F(xiàn)ilter可以對所有的發(fā)往Java服務(wù)器的請求(包括對html激蹲,js棉磨,圖片等靜態(tài)資源的請求)做攔截,從而實現(xiàn)一些特殊的功能学辱,如URL級別的權(quán)限訪問控制乘瓤、過濾敏感詞匯、壓縮響應(yīng)信息等策泣。

2衙傀、Filter執(zhí)行機(jī)制

Servlet API中提供了一個Filter接口,開發(fā)web應(yīng)用時萨咕,如果編寫的Java類實現(xiàn)了這個接口,則把這個java類稱之為過濾器Filter危队。通過Filter類聪建,可以實現(xiàn)用戶在訪問某個目標(biāo)資源之前,對訪問的請求和響應(yīng)進(jìn)行攔截茫陆。
Filter接口中有方法void doFilter(ServletRequest req,ServletResponse res,FilterChain chain)用來執(zhí)行filter的工作金麸。每一個filter從doFilter()方法中得到當(dāng)前的request及response對象。在這個方法里盅弛,可以進(jìn)行任何的針對request及response的操作钱骂,包括收集數(shù)據(jù)叔锐,包裝數(shù)據(jù)等。filter調(diào)用chain.doFilter()方法將請求從該filter中放行见秽。之后愉烙,有可能請求到了要訪問的資源對象,也有可能把控制權(quán)交給了下一個filter解取。
當(dāng)我們編寫好Filter步责,并配置對哪個web資源進(jìn)行攔截后,WEB服務(wù)器每次在調(diào)用web資源的service方法之前禀苦,都會先調(diào)用一下filter的doFilter方法蔓肯,因此,在該方法內(nèi)編寫代碼可達(dá)到如下目的:

  • 調(diào)用目標(biāo)資源之前振乏,讓一段代碼執(zhí)行蔗包。
  • 是否調(diào)用目標(biāo)資源(即是否讓用戶訪問web資源)。
  • 調(diào)用目標(biāo)資源之后慧邮,讓一段代碼執(zhí)行调限。

web服務(wù)器在調(diào)用doFilter方法時,會傳遞一個filterChain對象進(jìn)來误澳,filterChain對象是filter接口中最重要的一個對象耻矮,它也提供了一個doFilter方法,開發(fā)人員可以根據(jù)需求決定是否調(diào)用此方法忆谓,調(diào)用該方法裆装,則web服務(wù)器就會調(diào)用web資源的service方法,即web資源就會被訪問倡缠,否則web資源不會被訪問哨免。

3、Filter入門示意

這里我們編寫一個簡單的Filter示意代碼昙沦。
首先铁瞒,新建一個Filter類,實現(xiàn)javax.servlet.Filter接口桅滋。
com.lfqy.web.filter.FilterTrial01

package com.lfqy.web.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * Created by chengxia on 2019/11/4.
 * filter的三種典型應(yīng)用:
 1、可以在filter中根據(jù)條件決定是否調(diào)用chain.doFilter(request, response)方法身辨,即是否讓目標(biāo)資源執(zhí)行
 2丐谋、在讓目標(biāo)資源執(zhí)行之前,可以對request\response作預(yù)處理煌珊,再讓目標(biāo)資源執(zhí)行
 3号俐、在目標(biāo)資源執(zhí)行之后,可以捕獲目標(biāo)資源的執(zhí)行結(jié)果定庵,從而實現(xiàn)一些特殊的功能
 */
public class FilterTrial01 implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("The filter is initializing...");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //設(shè)置request和response的編碼格式
        servletRequest.setCharacterEncoding("UTF-8");
        servletResponse.setCharacterEncoding("UTF-8");
        //設(shè)置請求的contenttype
        servletResponse.setContentType("text/html;charset=UTF-8");

        System.out.println("Before the request is handled...");
        System.out.println("url: " + ((HttpServletRequest)servletRequest).getRequestURL());
        //讓目標(biāo)資源執(zhí)行吏饿,放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("After the request is handled...");
    }

    @Override
    public void destroy() {
        System.out.println("The filter is destroying...");
    }
}

在這個filter的實現(xiàn)類中踪危,在請求的執(zhí)行前后,分別輸出提示信息和請求的url到控制臺猪落。
然后贞远,在配置文件中,添加這個filter的定義笨忌。
WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>FilterTrial01</filter-name>
        <filter-class>com.lfqy.web.filter.FilterTrial01</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterTrial01</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
</web-app>

從這個配置文件的內(nèi)容蓝仲,可以看出,filter的配置分為兩部分:一部分是定義filter的名稱和filter實現(xiàn)類的關(guān)聯(lián)關(guān)系官疲,另外一部分是定義filter所攔截請求的過濾規(guī)則袱结。這里我們配置了兩個請求url的攔截規(guī)則,也就是攔截所有對jsp和html頁面的請求(前面已經(jīng)說明filter可以攔截對靜態(tài)資源的請求)途凫。前一部分我們稱為注冊Filter垢夹,后一部分我們稱為映射Filter。
這里需要注意urlpattern的配置規(guī)則:

  • /開頭和以/*結(jié)尾的是用來做路徑映射的维费。
  • 以前綴*.開頭的是用來做擴(kuò)展映射的果元。
  • /是用來定義default servlet映射的。
  • 剩下的都是用來定義詳細(xì)映射的掩完。比如: /aa/bb/cc.jsp

所以噪漾,如果urlpattern配置成/*.jsp會報錯,因為它既屬于路徑映射且蓬,又屬于后綴映射欣硼,應(yīng)用服務(wù)器會困惑。

最后恶阴,編寫兩個測試頁面诈胜。
index.jsp

<%--
  Created by IntelliJ IDEA.
  User: chengxia
  Date: 2019/11/4
  Time: 7:47 AM
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>Trial Page for Filter</title>
  </head>
  <body>
  <h3>This is a filter page.</h3>
  </body>
</html>

test.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Gogogo</title>
</head>
<body>
<h1>gogogo</h1>
</body>
</html>

這樣,啟動服務(wù)器之后冯事,分別訪問http://localhost:8080/test.htmlhttp://localhost:8080/index.jsp焦匈,可以看到控制臺輸出如下:

Before the request is handled...
url: http://localhost:8080/test.html
After the request is handled...
Before the request is handled...
url: http://localhost:8080/index.jsp
After the request is handled...

4、Filter其它說明

4.1 Filter鏈

在一個web應(yīng)用中昵仅,可以開發(fā)編寫多個Filter缓熟,這些Filter組合起來稱之為一個Filter鏈。
web服務(wù)器根據(jù)Filter在web.xml文件中的注冊順序摔笤,決定先調(diào)用哪個Filter够滑,當(dāng)?shù)谝粋€Filter的doFilter方法被調(diào)用時,web服務(wù)器會創(chuàng)建一個代表Filter鏈的FilterChain對象傳遞給該方法吕世。在doFilter方法中彰触,開發(fā)人員如果調(diào)用了FilterChain對象的doFilter方法,則web服務(wù)器會檢查FilterChain對象中是否還有filter命辖,如果有况毅,則調(diào)用第2個filter分蓖,如果沒有,則調(diào)用目標(biāo)資源尔许。

4.2 Filter生命周期

4.2.1 創(chuàng)建

Filter的創(chuàng)建和銷毀由應(yīng)用服務(wù)器負(fù)責(zé)么鹤。 web應(yīng)用啟動時,應(yīng)用服務(wù)器將創(chuàng)建Filter的實例對象母债,并調(diào)用其init方法午磁,完成對象的初始化功能,從而為后續(xù)的用戶請求作好攔截的準(zhǔn)備工作毡们,filter對象只會創(chuàng)建一次迅皇,init方法也只會執(zhí)行一次。通過init方法的參數(shù)衙熔,可獲得代表當(dāng)前filter配置信息的FilterConfig對象登颓。

4.2.2 銷毀

Web容器調(diào)用destroy方法銷毀Filter。destroy方法在Filter的生命周期中僅執(zhí)行一次红氯。在destroy方法中框咙,可以釋放過濾器使用的資源。

4.2.3 FilterConfig接口

用戶在配置filter時痢甘,可以使用<init-param>為filter配置一些初始化參數(shù)喇嘱,當(dāng)web容器實例化Filter對象,調(diào)用其init方法時塞栅,會把封裝了filter初始化參數(shù)的filterConfig對象傳遞進(jìn)來者铜。因此開發(fā)人員在編寫filter時,通過filterConfig對象的方法放椰,就可獲得:

  • String getFilterName():得到filter的名稱作烟。
  • String getInitParameter(String name): 返回在部署描述中指定名稱的初始化參數(shù)的值。如果不存在返回null.
  • Enumeration getInitParameterNames():返回過濾器的所有初始化參數(shù)的名字的枚舉集合砾医。
  • public ServletContext getServletContext():返回Servlet上下文對象的引用拿撩。

如下是一個帶參數(shù)的filter的例子。
com.lfqy.web.filter.FilterInitParamTrial

package com.lfqy.web.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * Created by chengxia on 2019/11/4.
 * filter的三種典型應(yīng)用:
 1如蚜、可以在filter中根據(jù)條件決定是否調(diào)用chain.doFilter(request, response)方法压恒,即是否讓目標(biāo)資源執(zhí)行
 2、在讓目標(biāo)資源執(zhí)行之前错邦,可以對request\response作預(yù)處理涎显,再讓目標(biāo)資源執(zhí)行
 3、在目標(biāo)資源執(zhí)行之后兴猩,可以捕獲目標(biāo)資源的執(zhí)行結(jié)果,從而實現(xiàn)一些特殊的功能
 */
public class FilterInitParamTrial implements Filter {
    private String filterName;
    private String filterFunc;
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("The filter is initializing...");
        filterName = filterConfig.getInitParameter("FilterName");
        filterFunc = filterConfig.getInitParameter("Function");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //設(shè)置request和response的編碼格式
        servletRequest.setCharacterEncoding("UTF-8");
        servletResponse.setCharacterEncoding("UTF-8");
        //設(shè)置請求的contenttype
        servletResponse.setContentType("text/html;charset=UTF-8");

        System.out.println(filterName + " for function " + filterFunc + "executing. Before the request is handled...");
        System.out.println("url: " + ((HttpServletRequest)servletRequest).getRequestURL());
        //讓目標(biāo)資源執(zhí)行早歇,放行
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println(filterName + " for function " + filterFunc + "executing. After the request is handled...");
    }

    @Override
    public void destroy() {
        System.out.println("The filter is destroying...");
    }
}

WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>FilterTrial01</filter-name>
        <filter-class>com.lfqy.web.filter.FilterTrial01</filter-class>
    </filter>
    <filter>
        <filter-name>FilterInitParamTrial</filter-name>
        <filter-class>com.lfqy.web.filter.FilterInitParamTrial</filter-class>
        <init-param>
            <description>測試Filter配置參數(shù)01</description>
            <param-name>FilterName</param-name>
            <param-value>PaopaoFilter</param-value>
        </init-param>
        <init-param>
            <description>測試Filter配置參數(shù)02</description>
            <param-name>Function</param-name>
            <param-value>Test filter init param...</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>FilterTrial01</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>FilterInitParamTrial</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
</web-app>

重啟tomcat服務(wù)器倾芝,配置生效之后讨勤,訪問http://localhost:8080/test.html,控制臺輸出如下:

PaopaoFilter for function Test filter init param...executing. Before the request is handled...
url: http://localhost:8080/test.html
PaopaoFilter for function Test filter init param...executing. After the request is handled...

可見晨另,過濾器中配置的初始參數(shù)已經(jīng)被拿到潭千。

4.3 映射Filter時的dispatcher屬性

<dispatcher>指定過濾器所攔截的資源被 Servlet 容器調(diào)用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一借尿,默認(rèn)REQUEST刨晴。用戶可以設(shè)置多個<dispatcher> 子元素用來指定 Filter 對資源的多種調(diào)用方式進(jìn)行攔截。如下:

<filter-name>filterName</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>REQUEST</dispatcher>
   <dispatcher>FORWARD</dispatcher>
</filter-mapping>

<dispatcher>子元素可以設(shè)置的值及其意義:

  • REQUEST:當(dāng)用戶直接訪問頁面時路翻,Web容器將會調(diào)用過濾器狈癞。如果目標(biāo)資源是通過RequestDispatcher的include()forward()方法訪問時,那么該過濾器就不會被調(diào)用茂契。
  • INCLUDE:如果目標(biāo)資源是通過RequestDispatcher的include()方法訪問時蝶桶,那么該過濾器將被調(diào)用。除此之外掉冶,該過濾器不會被調(diào)用真竖。
  • FORWARD:如果目標(biāo)資源是通過RequestDispatcher的forward()方法訪問時,那么該過濾器將被調(diào)用厌小,除此之外恢共,該過濾器不會被調(diào)用。
  • ERROR:如果目標(biāo)資源是通過聲明式異常處理機(jī)制調(diào)用時璧亚,那么該過濾器將被調(diào)用讨韭。除此之外,過濾器不會被調(diào)用涨岁。

5拐袜、Filter使用場景示例

5.1 裝飾器模式

5.1.1 定義

裝飾器模式,又名包裝(Wrapper)模式梢薪。裝飾模式以對客戶端透明的方式擴(kuò)展對象的功能蹬铺,是繼承關(guān)系的一個替代方案。裝飾模式是在不必改變原類文件和使用繼承的情況下秉撇,動態(tài)的擴(kuò)展一個對象的功能甜攀。在裝飾器模式中,會創(chuàng)建一個包裝對象琐馆,用來裝飾包裹真實的對象规阀。

5.1.2 使用場景說明

當(dāng)某個對象的方法不適應(yīng)業(yè)務(wù)需求時,通常有2種方式可以對方法進(jìn)行增強:

  • 編寫子類瘦麸,覆蓋需增強的方法谁撼。
  • 使用裝飾器設(shè)計模式對方法進(jìn)行增強。

在實際應(yīng)用中遇到需增強對象的方法時滋饲,到底選用哪種方式比較好呢厉碟?這個沒有具體的定式喊巍,只能是根據(jù)具體的需求來采用具體的方式,不過有一種情況下箍鼓,必須使用Decorator設(shè)計模式:即被增強的對象崭参,開發(fā)人員只能得到它的對象,無法得到它的class文件款咖。比如request何暮、response對象,開發(fā)人員之所以在servlet中能通過sun公司定義的HttpServletRequest\response接口去操作這些對象铐殃,是因為Tomcat服務(wù)器廠商編寫了request海洼、response接口的實現(xiàn)類。web服務(wù)器在調(diào)用servlet時背稼,會用這些接口的實現(xiàn)類創(chuàng)建出對象贰军,然后傳遞給servlet程序。此種情況下蟹肘,由于開發(fā)人員根本不知道服務(wù)器廠商編寫的request词疼、response接口的實現(xiàn)類是哪個?在程序中只能拿到服務(wù)器廠商提供的對象帘腹,因此就只能采用Decorator設(shè)計模式對這些對象進(jìn)行增強贰盗。

5.1.3 裝飾器模式的實現(xiàn)

在實現(xiàn)裝飾器模式時铛漓,首先看需要被增強對象繼承了什么接口或父類儒飒,編寫一個類也去繼承這些接口或父類。然后驮宴,在類中定義一個變量球化,變量類型即需增強對象的類型秽晚,同時,在類中定義一個構(gòu)造函數(shù)筒愚,構(gòu)造函數(shù)的參數(shù)是需增強的對象赴蝇。最后,覆蓋需增強的方法巢掺,編寫增強的代碼句伶。
這里需要注意,裝飾器模式中陆淀,必須重新編寫接口或者父類的所有方法考余。對于其中,根本不需要增強的方法轧苫,只需要簡單調(diào)用被增強對象(裝飾器類中的成員變量)的同名方法即可楚堤。

5.2 Servlet API中對于請求對象和響應(yīng)對象的默認(rèn)裝飾器實現(xiàn)

Servlet API中提供了一個request對象的Decorator設(shè)計模式的默認(rèn)實現(xiàn)類HttpServletRequestWrapper,HttpServletRequestWrapper類實現(xiàn)了request接口中的所有方法,但這些方法的內(nèi)部實現(xiàn)都是僅僅調(diào)用了一下所包裝的的 request對象的對應(yīng)方法身冬,以避免用戶在對request對象進(jìn)行增強時需要實現(xiàn)request接口中的所有方法鳄袍。
Servlet API中也提供了response對象的Decorator設(shè)計模式的默認(rèn)實現(xiàn)類HttpServletResponseWrapper,HttpServletResponseWrapper類實現(xiàn)了response接口中的所有方法吏恭,但這些方法的內(nèi)部實現(xiàn)都是僅僅調(diào)用了一下所包裝的的 response對象的對應(yīng)方法,以避免用戶在對response對象進(jìn)行增強時需要實現(xiàn)response接口中的所有方法重罪。
這兩個現(xiàn)成的裝飾器類中樱哼,都定義了各自的包裝對象,實現(xiàn)了request對象和reponse對象對應(yīng)接口的方法剿配。只不過在方法的實現(xiàn)中搅幅,都是簡單調(diào)用對應(yīng)包裝對象的方法。這樣的好處是呼胚,當(dāng)我們自己實現(xiàn)裝飾器類的時候茄唐,只需要繼承這兩個線程的裝飾器類,然后蝇更,重寫我們想擴(kuò)展功能的方法即可沪编。

5.2.1 使用Decorator模式包裝request對象解決get請求中的中文參數(shù)亂碼問題

5.2.1.1 問題原因

Tomcat 7之前的版本,對于URL中字符的編碼都是使用iso8859-1年扩。對于Get請求來說蚁廓,參數(shù)是放在URL中的,所以厨幻,對于GET請求相嵌,在獲得請求參數(shù)的時候,如果沒有進(jìn)行合適的轉(zhuǎn)碼操作况脆,取出的參數(shù)值就可能是亂碼饭宾。Tomcat 8以后默認(rèn)的URL編碼格式是utf-8。
在Tomcat配置文件conf/server.xml中設(shè)置URIEncoding的值為UTF-8:

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           URIEncoding="utf-8"/>

但是不建議這么做格了。因為這樣相當(dāng)于應(yīng)用層的代碼依賴于Tomcat的設(shè)置看铆,有損可移植性。
這里用的是Tomcat 8笆搓,為了說明這個例子性湿,這里將Tomcat默認(rèn)的URL編碼方式改成了``

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443"
           URIEncoding="iso-8859-1"/>

5.2.1.2 代碼示例

首先,寫一個解決編碼問題的filter實現(xiàn)類满败,它的作用就是攔截請求肤频,然后,將請求做一個轉(zhuǎn)碼包裝算墨,然后放行宵荒。
com.lfqy.web.filter.CharacterEncodingFilter

package com.lfqy.web.filter;

import com.lfqy.web.wrapper.CharacterEncodingRequest;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by chengxia on 2019/11/13.
 */
public class CharacterEncodingFilter implements Filter {

    private FilterConfig filterConfig = null;
    //設(shè)置默認(rèn)的字符編碼
    private String defaultCharset = "UTF-8";

    public void init(FilterConfig filterConfig){
        //在初始化時,得到過濾器的配置信息
        this.filterConfig = filterConfig;
    }
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //得到在web.xml中配置的字符編碼
        String charset = filterConfig.getInitParameter("charset");
        if(charset==null){
            charset = defaultCharset;
        }
        request.setCharacterEncoding(charset);
        response.setCharacterEncoding(charset);
        response.setContentType("text/html;charset="+charset);

        CharacterEncodingRequest requestWrapper = new CharacterEncodingRequest(request);
        chain.doFilter(requestWrapper, response);
    }

    public void destroy(){
        //do nothing in destory.
    }
}

寫一個請求對象的包裝類,在包裝類中报咳,重寫獲取請求參數(shù)的getParameter方法侠讯,如果是get請求,就轉(zhuǎn)碼之后暑刃,再返回值厢漩。
com.lfqy.web.wrapper.CharacterEncodingRequest

package com.lfqy.web.wrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * Created by chengxia on 2019/11/11.
 */
public class CharacterEncodingRequest extends HttpServletRequestWrapper {
    //定義一個成員變量,該對象就是被增強對象
    private HttpServletRequest req;
    //定義一個構(gòu)造函數(shù)岩臣,其參數(shù)是被增強對象
    public CharacterEncodingRequest(HttpServletRequest req){
        super(req);
        this.req = req;
    }

    @Override
    public String getParameter(String name){
        try{
            //獲取參數(shù)的值
            String value= this.req.getParameter(name);
            if(value==null){
                return null;
            }
            //如果不是以get方式提交數(shù)據(jù)的溜嗜,就直接返回獲取到的值
            if(!this.req.getMethod().equalsIgnoreCase("get")) {
                return value;
            }else{
                //如果是以get方式提交數(shù)據(jù)的,就對獲取到的值進(jìn)行轉(zhuǎn)碼處理
                value = new String(value.getBytes("ISO8859-1"),this.req.getCharacterEncoding());
                return value;
            }
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

接下來寫一個jsp頁面架谎,用來分別發(fā)送GET請求和POST請求:
EncodingFilterTest.jsp

<%--
  Created by IntelliJ IDEA.
  User: chengxia
  Date: 2019/11/13
  Time: 7:53 AM
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--引入jstl標(biāo)簽庫 --%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
    <title>Encoding Filter Test</title>
</head>
<body>
<%--使用c:url標(biāo)簽構(gòu)建url炸宵,構(gòu)建好的url存儲在reqGetUrl變量中--%>
<c:url value="/EncodingTestServlet" scope="page" var="reqGetUrl">
    <%--構(gòu)建的url的附帶的中文參數(shù) ,參數(shù)名是:petname谷扣,值是:于泡泡--%>
    <c:param name="petname" value="于泡泡"></c:param>
</c:url>
<%--使用get的方式訪問 --%>
<a href="${reqGetUrl}">超鏈接(get方式請求)</a>
<hr/>
<%--使用post方式提交表單 --%>
<form action="${pageContext.request.contextPath}/EncodingTestServlet" method="post">
    用戶名:<input type="text" name="petname" value="于泡泡" />
    <input type="submit" value="post方式提交">
</form>

</body>
</html>

為了接收前面的POST請求土全,需要再寫一個Servlet。
com.lfqy.web.servlet.EncodingTestServlet

package com.lfqy.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * Created by chengxia on 2019/11/13.
 */
public class EncodingTestServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //接收參數(shù)
        String petname = request.getParameter("petname");
        //獲取請求方式
        String method = request.getMethod();
        //獲取輸出流
        PrintWriter out = response.getWriter();
        out.write("請求的方式:"+method);
        out.write("<br/>");
        out.write("接收到的參數(shù):"+petname);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

最后看下配置文件WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>FilterTrial01</filter-name>
        <filter-class>com.lfqy.web.filter.FilterTrial01</filter-class>
    </filter>
    <filter>
        <filter-name>FilterInitParamTrial</filter-name>
        <filter-class>com.lfqy.web.filter.FilterInitParamTrial</filter-class>
        <init-param>
            <description>測試Filter配置參數(shù)01</description>
            <param-name>FilterName</param-name>
            <param-value>PaopaoFilter</param-value>
        </init-param>
        <init-param>
            <description>測試Filter配置參數(shù)02</description>
            <param-name>Function</param-name>
            <param-value>Test filter init param...</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.lfqy.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <description>設(shè)置編碼信息</description>
            <param-name>charset</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>FilterTrial01</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>FilterInitParamTrial</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>EncodingTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.EncodingTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EncodingTestServlet</servlet-name>
        <url-pattern>/EncodingTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.PostUrlParamTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <url-pattern>/PostUrlParamTestServlet</url-pattern>
    </servlet-mapping>
</web-app>

啟動項目在Tomcat服務(wù)器上運行会涎,然后訪問http://localhost:8080/EncodingFilterTest.jsp裹匙,效果如下:

測試頁面

這樣,無論點擊鏈接還是點擊按鈕在塔,都會能夠得到正確的請求參數(shù)并回顯幻件。
GET請求

POST請求

5.2.2 使用Decorator模式包裝request對象實現(xiàn)HTML字符的轉(zhuǎn)義

用戶在瀏覽器頁面輸入的內(nèi)容,如果其中含有HTML的中需要轉(zhuǎn)義的字符蛔溃,需要進(jìn)行轉(zhuǎn)義之后才能夠正常顯示绰沥。這里就介紹如何通過裝飾器實現(xiàn)該功能。
首先贺待,新建一個裝飾器類徽曲,用于實現(xiàn)請求內(nèi)容中參數(shù)值的轉(zhuǎn)義。
com.lfqy.web.wrapper.HTMLCharacterEscapeRequest

package com.lfqy.web.wrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * Created by chengxia on 2019/11/11.
 */
public class HTMLCharacterEscapeRequest extends HttpServletRequestWrapper {
    //定義一個成員變量麸塞,該對象就是被增強對象
    private HttpServletRequest req;
    //定義一個構(gòu)造函數(shù)秃臣,其參數(shù)是被增強對象
    public HTMLCharacterEscapeRequest(HttpServletRequest req){
        super(req);
        this.req = req;
    }

    @Override
    public String getParameter(String name){

        //獲取參數(shù)的值
        String value= this.req.getParameter(name);
        if(value==null || value.length() ==0 ){
            return value;
        }
        return filter(value);
    }

    private String filter(String msg){
        if (msg == null){
            return null;
        }
        char content[] = new char[msg.length()];
        msg.getChars(0, msg.length(), content, 0);
        StringBuffer result = new StringBuffer(content.length + 50);
        for (int i = 0; i < content.length; i++) {
            switch (content[i]) {
                case '<':
                    result.append("&lt;");
                    break;
                case '>':
                    result.append("&gt;");
                    break;
                case '&':
                    result.append("&amp;");
                    break;
                case '"':
                    result.append("&quot;");
                    break;
                default:
                    result.append(content[I]);
            }
        }
        return result.toString();
    }
}

新建一個filter實現(xiàn)類。
com.lfqy.web.filter.HTMLCharacterEscapeFilter

package com.lfqy.web.filter;

import com.lfqy.web.wrapper.CharacterEncodingRequest;
import com.lfqy.web.wrapper.HTMLCharacterEscapeRequest;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by chengxia on 2019/11/13.
 */
public class HTMLCharacterEscapeFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //do nothing
    }

    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;

        HTMLCharacterEscapeRequest requestWrapper = new HTMLCharacterEscapeRequest(request);
        chain.doFilter(requestWrapper, response);
    }

    public void destroy(){
        //do nothing in destory.
    }
}

寫一個jsp頁面哪工,用來測試奥此。
HTMLCharacterEscapeTest.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
    <title>Html Character Escape Test</title>
</head>

<body>
<form action="${pageContext.request.contextPath}/HTMLCharacterEscapeTestServlet" method="post">
    留言:
    <textarea rows="8" cols="70" name="message">
        <script type="text/javascript">
            alert("This is my house.")
        </script>
        <a >An Unknown Website</a>
    </textarea>
    <input type="submit" value="發(fā)表">
</form>
</body>
</html>

寫一個Servlet,用于接收測試頁面發(fā)送的請求雁比。
com.lfqy.web.servlet.HTMLCharacterEscapeTestServlet

package com.lfqy.web.servlet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * Created by chengxia on 2019/11/13.
 */
public class HTMLCharacterEscapeTestServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //接收參數(shù)
        String msg = request.getParameter("message");
        //獲取輸出流
        PrintWriter out = response.getWriter();
        out.write("message got:"+"<br/>"+msg);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }
}

最后稚虎,在配置文件中,配置Servlet和過濾器偎捎。
WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>FilterTrial01</filter-name>
        <filter-class>com.lfqy.web.filter.FilterTrial01</filter-class>
    </filter>
    <filter>
        <filter-name>FilterInitParamTrial</filter-name>
        <filter-class>com.lfqy.web.filter.FilterInitParamTrial</filter-class>
        <init-param>
            <description>測試Filter配置參數(shù)01</description>
            <param-name>FilterName</param-name>
            <param-value>PaopaoFilter</param-value>
        </init-param>
        <init-param>
            <description>測試Filter配置參數(shù)02</description>
            <param-name>Function</param-name>
            <param-value>Test filter init param...</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.lfqy.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <description>設(shè)置編碼信息</description>
            <param-name>charset</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>HTMLCharacterEscapeFilter</filter-name>
        <filter-class>com.lfqy.web.filter.HTMLCharacterEscapeFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterTrial01</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>FilterInitParamTrial</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>HTMLCharacterEscapeFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>EncodingTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.EncodingTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EncodingTestServlet</servlet-name>
        <url-pattern>/EncodingTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.PostUrlParamTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <url-pattern>/PostUrlParamTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>HTMLCharacterEscapeTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.HTMLCharacterEscapeTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HTMLCharacterEscapeTestServlet</servlet-name>
        <url-pattern>/HTMLCharacterEscapeTestServlet</url-pattern>
    </servlet-mapping>
</web-app>

啟動服務(wù)器之后蠢终,訪問http://localhost:8080/HTMLCharacterEscapeTest.jsp序攘,效果如下:

留言測試頁面

點擊頁面上的發(fā)表,效果如下寻拂。
留言測試結(jié)果頁面

可以看到程奠,前面的留言內(nèi)容中的字符都已經(jīng)被轉(zhuǎn)義了。

5.2.3 使用Decorator模式包裝request對象實現(xiàn)敏感字符過濾

首先祭钉,新建一個filter實現(xiàn)類瞄沙,在初始化方法中,讀取敏感詞列表慌核,加載到內(nèi)存帕识。同時,實現(xiàn)一個內(nèi)部類遂铡,包裝request類,重新實現(xiàn)獲取參數(shù)值的方法晶姊。
com.lfqy.web.filter.DirtyWordsFilter

package com.lfqy.web.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by chengxia on 2019/11/13.
 */
public class DirtyWordsFilter implements Filter {

    private FilterConfig config = null;
    private List<String> dirtyWords;

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.config = filterConfig;
        dirtyWords = getDirtyWords();
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        DirtyWordsRequest dirtyRequest = new DirtyWordsRequest(request);

        chain.doFilter(dirtyRequest, response);
    }

    @Override
    public void destroy() {

    }

    /**
     * @Method: getDirtyWords
     * @Description: 獲取敏感字符
     * @Anthor:SpaceCatt
     *
     * @return
     */
    private List<String> getDirtyWords(){
        List<String> dirtyWords = new ArrayList<String>();
        String dirtyWordPath = config.getInitParameter("DirtyWordsFilePath");
        InputStream inputStream = config.getServletContext().getResourceAsStream(dirtyWordPath);
        InputStreamReader is = null;
        try {
            is = new InputStreamReader(inputStream,"UTF-8");
        } catch (UnsupportedEncodingException e2) {
            e2.printStackTrace();
        }
        BufferedReader reader = new BufferedReader(is);
        String line;
        try {
            while ((line = reader.readLine())!= null) {//如果 line為空說明讀完了
                dirtyWords.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dirtyWords;
    }

    /**
     * @ClassName: DirtyWordsRequest
     * @Description: 使用Decorator模式包裝request對象扒接,實現(xiàn)敏感字符過濾功能
     * @author: spacecat
     * @date: 2019-12-6 上午08:56:35
     *
     */
    class DirtyWordsRequest extends HttpServletRequestWrapper {
        private HttpServletRequest request;
        public DirtyWordsRequest(HttpServletRequest request) {
            super(request);
            this.request = request;
        }
        /* 重寫getParameter方法,實現(xiàn)對敏感字符的過濾
         * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String)
         */
        @Override
        public String getParameter(String name) {

            String value = this.request.getParameter(name);
            if(value==null){
                return null;
            }

            for(String dirtyWord : dirtyWords){
                if(value.contains(dirtyWord)){
                    System.out.println("內(nèi)容中包含敏感詞:"+dirtyWord+"们衙,將會被替換成****");
                    //替換敏感字符
                    value = value.replace(dirtyWord, "****");
                }
            }
            return value;
        }
    }
}

然后钾怔,寫一個測試頁面,提交帶敏感詞的表單內(nèi)容蒙挑。
DirtyWordsFilterTest.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML>
<html>
<head>
    <title>Html Character Escape Test</title>
</head>

<body>
<form action="${pageContext.request.contextPath}/HTMLCharacterEscapeTestServlet" method="post">
    留言:
    <textarea rows="8" cols="70" name="message">
        這是我的留言宗侦,包含敏感詞1,敏感詞2等敏感詞忆蚀。哈哈
    </textarea>
    <input type="submit" value="發(fā)表">
</form>
</body>
</html>

這里表單的數(shù)據(jù)直接提交到com.lfqy.web.servlet.HTMLCharacterEscapeTestServlet即可矾利,無需新寫。
最后修改配置文件馋袜。
WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>FilterTrial01</filter-name>
        <filter-class>com.lfqy.web.filter.FilterTrial01</filter-class>
    </filter>
    <filter>
        <filter-name>FilterInitParamTrial</filter-name>
        <filter-class>com.lfqy.web.filter.FilterInitParamTrial</filter-class>
        <init-param>
            <description>測試Filter配置參數(shù)01</description>
            <param-name>FilterName</param-name>
            <param-value>PaopaoFilter</param-value>
        </init-param>
        <init-param>
            <description>測試Filter配置參數(shù)02</description>
            <param-name>Function</param-name>
            <param-value>Test filter init param...</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.lfqy.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <description>設(shè)置編碼信息</description>
            <param-name>charset</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>DirtyWordsFilter</filter-name>
        <filter-class>com.lfqy.web.filter.DirtyWordsFilter</filter-class>
        <init-param>
            <description>設(shè)置包含敏感詞的配置文件路徑</description>
            <param-name>DirtyWordsFilePath</param-name>
            <param-value>/WEB-INF/DirtyWords.txt</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>HTMLCharacterEscapeFilter</filter-name>
        <filter-class>com.lfqy.web.filter.HTMLCharacterEscapeFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterTrial01</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>FilterInitParamTrial</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>HTMLCharacterEscapeFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>DirtyWordsFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>EncodingTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.EncodingTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EncodingTestServlet</servlet-name>
        <url-pattern>/EncodingTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.PostUrlParamTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <url-pattern>/PostUrlParamTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>HTMLCharacterEscapeTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.HTMLCharacterEscapeTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HTMLCharacterEscapeTestServlet</servlet-name>
        <url-pattern>/HTMLCharacterEscapeTestServlet</url-pattern>
    </servlet-mapping>
</web-app>

啟動tomcat之后男旗,訪問http://localhost:8080/DirtyWordsFilterTest.jsp,效果如下:

留言敏感詞測試頁面

點擊發(fā)表欣鳖,可以看到關(guān)鍵詞已經(jīng)都被替換:
留言敏感詞測試結(jié)果頁面

在實際中察皇,我們經(jīng)常將上面的三個過濾器合并成一個。如下:
com.lfqy.web.filter.TripleInOneFilter

package com.lfqy.web.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by chengxia on 2019/11/13.
 */
public class TripleInOneFilter implements Filter {

    private FilterConfig config = null;
    private List<String> dirtyWords;
    //設(shè)置默認(rèn)的字符編碼
    private String defaultCharset = "UTF-8";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.config = filterConfig;
        dirtyWords = getDirtyWords();
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //得到在web.xml中配置的字符編碼
        String charset = config.getInitParameter("charset");
        if(charset==null){
            charset = defaultCharset;
        }
        request.setCharacterEncoding(charset);
        response.setCharacterEncoding(charset);
        response.setContentType("text/html;charset="+charset);

        TripleInOneRequest filteredRequest = new TripleInOneRequest(request);

        chain.doFilter(filteredRequest, response);
    }

    @Override
    public void destroy() {

    }

    /**
     * @Method: getDirtyWords
     * @Description: 獲取敏感字符
     * @Anthor:SpaceCat
     *
     * @return
     */
    private List<String> getDirtyWords(){
        List<String> dirtyWords = new ArrayList<String>();
        String dirtyWordPath = config.getInitParameter("DirtyWordsFilePath");
        InputStream inputStream = config.getServletContext().getResourceAsStream(dirtyWordPath);
        InputStreamReader is = null;
        try {
            is = new InputStreamReader(inputStream,"UTF-8");
        } catch (UnsupportedEncodingException e2) {
            e2.printStackTrace();
        }
        BufferedReader reader = new BufferedReader(is);
        String line;
        try {
            while ((line = reader.readLine())!= null) {//如果 line為空說明讀完了
                dirtyWords.add(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dirtyWords;
    }

    /**
     * @ClassName: TripleInOneRequest
     * @Description: 使用Decorator模式包裝request對象泽台,實現(xiàn)敏感字符過濾功能
     * @author: spacecat
     * @date: 2019-12-6 上午08:56:35
     *
     */
    class TripleInOneRequest extends HttpServletRequestWrapper {
        private HttpServletRequest request;
        public TripleInOneRequest(HttpServletRequest request) {
            super(request);
            this.request = request;
        }
        /* 重寫getParameter方法什荣,實現(xiàn)對敏感字符的過濾
         * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String)
         */
        @Override
        public String getParameter(String name) {

            //獲取參數(shù)的值
            String value= this.request.getParameter(name);
            if(value==null){
                return null;
            }

            //如果不是以get方式提交數(shù)據(jù)的,就直接返回獲取到的值怀酷;如果是get方法稻爬,就需要進(jìn)行編碼轉(zhuǎn)換
            if(!this.request.getMethod().equalsIgnoreCase("get")) {
                return value;
            }else{
                try {
                    //如果是以get方式提交數(shù)據(jù)的,就對獲取到的值進(jìn)行轉(zhuǎn)碼處理
                    value = new String(value.getBytes("ISO8859-1"),this.request.getCharacterEncoding());
                }catch (Exception e){
                    e.printStackTrace();
                }
            }

            //html字符轉(zhuǎn)義
            value = filter(value);

            //敏感詞過濾
            for(String dirtyWord : dirtyWords){
                if(value.contains(dirtyWord)){
                    System.out.println("內(nèi)容中包含敏感詞:"+dirtyWord+"胰坟,將會被替換成****");
                    //替換敏感字符
                    value = value.replace(dirtyWord, "****");
                }
            }
            return value;
        }

        public String filter(String value) {
            if (value == null){
                return null;
            }
            char content[] = new char[value.length()];
            value.getChars(0, value.length(), content, 0);
            StringBuffer result = new StringBuffer(content.length + 50);
            for (int i = 0; i < content.length; i++) {
                switch (content[i]) {
                    case '<':
                        result.append("&lt;");
                        break;
                    case '>':
                        result.append("&gt;");
                        break;
                    case '&':
                        result.append("&amp;");
                        break;
                    case '"':
                        result.append("&quot;");
                        break;
                    default:
                        result.append(content[I]);
                }
            }
            return (result.toString());
        }
    }
}

在配置文件中添加的配置信息如下:
WEB-INF/web.xml

<filter>
    <filter-name>DirtyWordsFilter</filter-name>
    <filter-class>com.lfqy.web.filter.DirtyWordsFilter</filter-class>
    <init-param>
        <description>設(shè)置編碼信息</description>
        <param-name>charset</param-name>
        <param-value>utf-8</param-value>
    </init-param>
    <init-param>
        <description>設(shè)置包含敏感詞的配置文件路徑</description>
        <param-name>DirtyWordsFilePath</param-name>
        <param-value>/WEB-INF/DirtyWords.txt</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>TripleInOneFilter</filter-name>
    <!-- "/*"表示攔截所有的請求 -->
    <url-pattern>/*</url-pattern>
</filter-mapping>

5.2.4 使用Decorator設(shè)計模式包裝response對象實現(xiàn)壓縮響應(yīng)正文內(nèi)容

通過filter向目標(biāo)頁面?zhèn)鬟f一個自定義的response對象因篇。在自定義的response對象中泞辐,重寫getOutputStream方法和getWriter方法,使目標(biāo)資源調(diào)用此方法輸出頁面內(nèi)容時竞滓,獲得的是我們自定義的ServletOutputStream對象咐吼。在我們自定義的ServletOuputStream對象中,重寫write方法商佑,使寫出的數(shù)據(jù)寫出到一個buffer中(這里實際上是寫到了java.io.ByteArrayOutputStream中锯茄,這個流自帶一個自動增長的buffer,所有到輸出到該流的數(shù)據(jù)都會先到buffer)茶没。當(dāng)頁面完成輸出后肌幽,通過調(diào)用自定義response對象的getBuffer()方法,在filter中就可得到頁面寫出的數(shù)據(jù)抓半,從而我們可以調(diào)用GzipOuputStream對數(shù)據(jù)進(jìn)行壓縮后再寫出給瀏覽器喂急,以此完成響應(yīng)正文件壓縮功能。
首先笛求,實現(xiàn)一個自定義的過濾器類廊移。
com.lfqy.web.filter.GzipFilter

package com.lfqy.web.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPOutputStream;

/**
 * Created by chengxia on 2019/11/13.
 */
public class GzipFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        BufferedResponse bufResp = new BufferedResponse(response);
        chain.doFilter(request, bufResp);
        //拿出緩存中的數(shù)據(jù),壓縮后再打給瀏覽器
        byte out[] = bufResp.getBuffer();
        System.out.println("原始大小:" + out.length);

        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        //壓縮輸出流中的數(shù)據(jù)
        GZIPOutputStream gout = new GZIPOutputStream(bout);
        gout.write(out);
        gout.close();

        byte gzip[] = bout.toByteArray();
        System.out.println("壓縮后的大小:" + gzip.length);

        response.setHeader("content-encoding", "gzip");
        response.setContentLength(gzip.length);
        response.getOutputStream().write(gzip);
    }

    @Override
    public void destroy() {

    }

    /**
     * @ClassName: BufferedResponse
     * @Description:
     * 使用Decorator模式包裝response對象探入,輸出到帶緩存的ByteArrayOutputStream功能
     * 同時狡孔,實現(xiàn)了getBuffer方法,使能夠拿到緩沖區(qū)的內(nèi)容
     * @author: spacecat
     * @date: 2019-12-6 上午08:56:35
     *
     */
    class BufferedResponse extends HttpServletResponseWrapper {

        private ByteArrayOutputStream bout = new ByteArrayOutputStream();
        private PrintWriter pw;
        private HttpServletResponse response;
        public BufferedResponse(HttpServletResponse response) {
            super(response);
            this.response = response;
        }
        /**
         * 這個方法是我們壓縮之后蜂嗽,再向瀏覽器寫數(shù)據(jù)的時候苗膝,要調(diào)用的。
         * */
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return new MyServletOutputStream(bout);
        }
        /**
         * 這個方法是框架輸出到response對象時調(diào)用的
         * */
        @Override
        public PrintWriter getWriter() throws IOException {
            pw = new PrintWriter(new OutputStreamWriter(bout,this.response.getCharacterEncoding()));
            return pw;
        }

        public byte[] getBuffer(){
            try{
                if(pw!=null){
                    pw.close();
                }
                if(bout!=null){
                    bout.flush();
                    return bout.toByteArray();
                }


                return null;
            }catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    class MyServletOutputStream extends ServletOutputStream{

        private ByteArrayOutputStream bout;
        public MyServletOutputStream(ByteArrayOutputStream bout){
            this.bout = bout;
        }

        @Override
        public void write(int b) throws IOException {
            this.bout.write(b);
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {
        }
    }
}

修改配置文件植旧,說明那些需要壓縮辱揭。
WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>FilterTrial01</filter-name>
        <filter-class>com.lfqy.web.filter.FilterTrial01</filter-class>
    </filter>
    <filter>
        <filter-name>FilterInitParamTrial</filter-name>
        <filter-class>com.lfqy.web.filter.FilterInitParamTrial</filter-class>
        <init-param>
            <description>測試Filter配置參數(shù)01</description>
            <param-name>FilterName</param-name>
            <param-value>PaopaoFilter</param-value>
        </init-param>
        <init-param>
            <description>測試Filter配置參數(shù)02</description>
            <param-name>Function</param-name>
            <param-value>Test filter init param...</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.lfqy.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <description>設(shè)置編碼信息</description>
            <param-name>charset</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>DirtyWordsFilter</filter-name>
        <filter-class>com.lfqy.web.filter.DirtyWordsFilter</filter-class>
        <init-param>
            <description>設(shè)置編碼信息</description>
            <param-name>charset</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <description>設(shè)置包含敏感詞的配置文件路徑</description>
            <param-name>DirtyWordsFilePath</param-name>
            <param-value>/WEB-INF/DirtyWords.txt</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>TripleInOneFilter</filter-name>
        <filter-class>com.lfqy.web.filter.TripleInOneFilter</filter-class>
        <init-param>
            <description>設(shè)置包含敏感詞的配置文件路徑</description>
            <param-name>DirtyWordsFilePath</param-name>
            <param-value>/WEB-INF/DirtyWords.txt</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>GzipFilter</filter-name>
        <filter-class>com.lfqy.web.filter.GzipFilter</filter-class>
    </filter>
    <filter>
        <filter-name>HTMLCharacterEscapeFilter</filter-name>
        <filter-class>com.lfqy.web.filter.HTMLCharacterEscapeFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterTrial01</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>FilterInitParamTrial</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>HTMLCharacterEscapeFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>DirtyWordsFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>TripleInOneFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--jsp文件的輸出的內(nèi)容都經(jīng)過壓縮過濾器壓縮后才輸出 -->
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
        <!-- 配置過濾器的攔截方式-->
        <!-- 對于在Servlet中通過
            request.getRequestDispatcher("jsp頁面路徑").forward(request, response)
        方式訪問的Jsp頁面的要進(jìn)行攔截 -->
        <dispatcher>FORWARD</dispatcher>
        <!--對于直接以URL方式訪問的jsp頁面進(jìn)行攔截,過濾器的攔截方式默認(rèn)就是 REQUEST-->
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    <!--js文件的輸出的內(nèi)容都經(jīng)過壓縮過濾器壓縮后才輸出 -->
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.js</url-pattern>
    </filter-mapping>
    <!--css文件的輸出的內(nèi)容都經(jīng)過壓縮過濾器壓縮后才輸出 -->
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.css</url-pattern>
    </filter-mapping>
    <!--html文件的輸出的內(nèi)容都經(jīng)過壓縮過濾器壓縮后才輸出 -->
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.html</url-pattern>
    </filter-mapping>

    <servlet>
        <servlet-name>EncodingTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.EncodingTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EncodingTestServlet</servlet-name>
        <url-pattern>/EncodingTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.PostUrlParamTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <url-pattern>/PostUrlParamTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>HTMLCharacterEscapeTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.HTMLCharacterEscapeTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HTMLCharacterEscapeTestServlet</servlet-name>
        <url-pattern>/HTMLCharacterEscapeTestServlet</url-pattern>
    </servlet-mapping>
</web-app>

這樣病附,啟動tomcat服務(wù)器之后界阁,訪問http://localhost:8080/DirtyWordsFilterTest.jsp,頁面正常顯示胖喳,服務(wù)器控制臺輸出如下:

Before the request is handled...
url: http://localhost:8080/DirtyWordsFilterTest.jsp
原始大小:376
壓縮后的大小:300
After the request is handled...

5.2.5 使用Decorator設(shè)計模式包裝response對象實現(xiàn)緩存數(shù)據(jù)到內(nèi)存

對于頁面中很少更新的數(shù)據(jù)泡躯,例如商品分類,為避免每次都要從數(shù)據(jù)庫查詢分類數(shù)據(jù)丽焊,因此可把分類數(shù)據(jù)緩存在內(nèi)存或文件中较剃,以此來減輕數(shù)據(jù)庫或者磁盤的壓力,提高系統(tǒng)響應(yīng)速度技健。
原理上写穴,這里也是用自定義的Response對象將輸出先放到緩存,然后雌贱,緩存的數(shù)據(jù)放到一個映射結(jié)構(gòu)中啊送。這樣偿短,后續(xù)如果在內(nèi)存中命中,就不用重新查詢數(shù)據(jù)庫或者訪問磁盤了馋没。
首先寫一個自定義過濾器實現(xiàn)類昔逗。
com.lfqy.web.filter.WebResourceCachedFilter

package com.lfqy.web.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.GZIPOutputStream;

/**
 * Created by chengxia on 2019/11/13.
 */
public class WebResourceCachedFilter implements Filter {

    //用一個map結(jié)構(gòu)緩存web資源
    private Map<String,byte[]> map = new HashMap<String,byte[]>();

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse resp,
                         FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //1.得到用戶請求的uri
        String uri = request.getRequestURI();
        //2.看緩存中有沒有uri對應(yīng)的數(shù)據(jù)
        byte b[] = map.get(uri);
        //3.如果緩存中有,直接拿緩存的數(shù)據(jù)打給瀏覽器篷朵,程序返回
        if(b!=null){
            //根據(jù)字節(jié)數(shù)組和指定的字符編碼構(gòu)建字符串
            String webResourceHtmlStr = new String(b,response.getCharacterEncoding());
            System.out.println(webResourceHtmlStr);
            response.getOutputStream().write(b);
            return;
        }
        //4.如果緩存沒有勾怒,讓目標(biāo)資源執(zhí)行,并捕獲目標(biāo)資源的輸出
        BufferedResponse myresponse = new BufferedResponse(response);
        chain.doFilter(request, myresponse);
        //獲取緩沖流中的內(nèi)容的字節(jié)數(shù)組
        byte out[] = myresponse.getBuffer();
        //5.把資源的數(shù)據(jù)以用戶請求的uri為關(guān)鍵字保存到緩存中
        map.put(uri, out);
        //6.把數(shù)據(jù)打給瀏覽器
        response.getOutputStream().write(out);
    }

    @Override
    public void destroy() {

    }

    /**
     * @ClassName: BufferedResponse
     * @Description:
     * 使用Decorator模式包裝response對象声旺,輸出到帶緩存的ByteArrayOutputStream功能
     * 同時笔链,實現(xiàn)了getBuffer方法,使能夠拿到緩沖區(qū)的內(nèi)容
     * @author: spacecat
     * @date: 2019-12-6 上午08:56:35
     *
     */
    class BufferedResponse extends HttpServletResponseWrapper {

        private ByteArrayOutputStream bout = new ByteArrayOutputStream();
        private PrintWriter pw;
        private HttpServletResponse response;
        public BufferedResponse(HttpServletResponse response) {
            super(response);
            this.response = response;
        }
        /**
         * 這個方法是我們壓縮之后腮猖,再向瀏覽器寫數(shù)據(jù)的時候鉴扫,要調(diào)用的。
         * */
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return new MyServletOutputStream(bout);
        }
        /**
         * 這個方法是框架輸出到response對象時調(diào)用的
         * */
        @Override
        public PrintWriter getWriter() throws IOException {
            pw = new PrintWriter(new OutputStreamWriter(bout,this.response.getCharacterEncoding()));
            return pw;
        }

        public byte[] getBuffer(){
            try{
                if(pw!=null){
                    pw.close();
                }
                if(bout!=null){
                    bout.flush();
                    return bout.toByteArray();
                }


                return null;
            }catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    class MyServletOutputStream extends ServletOutputStream{

        private ByteArrayOutputStream bout;
        public MyServletOutputStream(ByteArrayOutputStream bout){
            this.bout = bout;
        }

        @Override
        public void write(int b) throws IOException {
            this.bout.write(b);
        }

        @Override
        public boolean isReady() {
            return false;
        }

        @Override
        public void setWriteListener(WriteListener writeListener) {
        }
    }
}

修改配置文件澈缺,指定緩存那些頁面幔妨。
WEB-INF/web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <filter>
        <filter-name>FilterTrial01</filter-name>
        <filter-class>com.lfqy.web.filter.FilterTrial01</filter-class>
    </filter>
    <filter>
        <filter-name>FilterInitParamTrial</filter-name>
        <filter-class>com.lfqy.web.filter.FilterInitParamTrial</filter-class>
        <init-param>
            <description>測試Filter配置參數(shù)01</description>
            <param-name>FilterName</param-name>
            <param-value>PaopaoFilter</param-value>
        </init-param>
        <init-param>
            <description>測試Filter配置參數(shù)02</description>
            <param-name>Function</param-name>
            <param-value>Test filter init param...</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>com.lfqy.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <description>設(shè)置編碼信息</description>
            <param-name>charset</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>DirtyWordsFilter</filter-name>
        <filter-class>com.lfqy.web.filter.DirtyWordsFilter</filter-class>
        <init-param>
            <description>設(shè)置編碼信息</description>
            <param-name>charset</param-name>
            <param-value>utf-8</param-value>
        </init-param>
        <init-param>
            <description>設(shè)置包含敏感詞的配置文件路徑</description>
            <param-name>DirtyWordsFilePath</param-name>
            <param-value>/WEB-INF/DirtyWords.txt</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>TripleInOneFilter</filter-name>
        <filter-class>com.lfqy.web.filter.TripleInOneFilter</filter-class>
        <init-param>
            <description>設(shè)置包含敏感詞的配置文件路徑</description>
            <param-name>DirtyWordsFilePath</param-name>
            <param-value>/WEB-INF/DirtyWords.txt</param-value>
        </init-param>
    </filter>
    <filter>
        <filter-name>GzipFilter</filter-name>
        <filter-class>com.lfqy.web.filter.GzipFilter</filter-class>
    </filter>
    <filter>
        <filter-name>WebResourceCachedFilter</filter-name>
        <filter-class>com.lfqy.web.filter.WebResourceCachedFilter</filter-class>
    </filter>
    <filter>
        <filter-name>HTMLCharacterEscapeFilter</filter-name>
        <filter-class>com.lfqy.web.filter.HTMLCharacterEscapeFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterTrial01</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>FilterInitParamTrial</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>HTMLCharacterEscapeFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>DirtyWordsFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>TripleInOneFilter</filter-name>
        <!-- "/*"表示攔截所有的請求 -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!--jsp文件的輸出的內(nèi)容都經(jīng)過壓縮過濾器壓縮后才輸出 -->
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.jsp</url-pattern>
        <!-- 配置過濾器的攔截方式-->
        <!-- 對于在Servlet中通過
            request.getRequestDispatcher("jsp頁面路徑").forward(request, response)
        方式訪問的Jsp頁面的要進(jìn)行攔截 -->
        <dispatcher>FORWARD</dispatcher>
        <!--對于直接以URL方式訪問的jsp頁面進(jìn)行攔截,過濾器的攔截方式默認(rèn)就是 REQUEST-->
        <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    <!--js文件的輸出的內(nèi)容都經(jīng)過壓縮過濾器壓縮后才輸出 -->
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.js</url-pattern>
    </filter-mapping>
    <!--css文件的輸出的內(nèi)容都經(jīng)過壓縮過濾器壓縮后才輸出 -->
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.css</url-pattern>
    </filter-mapping>
    <!--html文件的輸出的內(nèi)容都經(jīng)過壓縮過濾器壓縮后才輸出 -->
    <filter-mapping>
        <filter-name>GzipFilter</filter-name>
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
    
    <filter-mapping>
        <filter-name>WebResourceCachedFilter</filter-name>
        <!-- 映射需要緩存輸出的JSP頁面谍椅,這幾個頁面都只是單純作為輸入UI,不會有太多的變化古话,因此可以緩存輸出 -->
        <url-pattern>/DirtyWordsFilterTest.jsp</url-pattern>
        <url-pattern>/test.jsp</url-pattern>
        <url-pattern>/test2.jsp</url-pattern>
    </filter-mapping>
    
    <servlet>
        <servlet-name>EncodingTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.EncodingTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>EncodingTestServlet</servlet-name>
        <url-pattern>/EncodingTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.PostUrlParamTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>PostUrlParamTestServlet</servlet-name>
        <url-pattern>/PostUrlParamTestServlet</url-pattern>
    </servlet-mapping>

    <servlet>
        <servlet-name>HTMLCharacterEscapeTestServlet</servlet-name>
        <servlet-class>com.lfqy.web.servlet.HTMLCharacterEscapeTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HTMLCharacterEscapeTestServlet</servlet-name>
        <url-pattern>/HTMLCharacterEscapeTestServlet</url-pattern>
    </servlet-mapping>
</web-app>

啟動服務(wù)器之后雏吭,第二次訪問http://localhost:8080/DirtyWordsFilterTest.jsp,服務(wù)器控制臺輸出如下:

Before the request is handled...
url: http://localhost:8080/DirtyWordsFilterTest.jsp

<!DOCTYPE HTML>
<html>
<head>
    <title>Html Character Escape Test</title>
</head>

<body>
<form action="/HTMLCharacterEscapeTestServlet" method="post">
    留言:
    <textarea rows="8" cols="70" name="message">
        這是我的留言陪踩,包含敏感詞1杖们,敏感詞2等敏感詞。哈哈
    </textarea>
    <input type="submit" value="發(fā)表">
</form>
</body>
</html>
原始大小:376
壓縮后的大小:300
After the request is handled...

注意肩狂,在最后的兩個例子中摘完,并沒有調(diào)用chain.doFilter(filteredRequest, response);,也就是說傻谁,請求經(jīng)過這兩個filter處理之后孝治,就不會繼續(xù)往別的過濾器傳遞了。這里需要特別注意审磁。

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钾恢,隨后出現(xiàn)的幾起案子闻察,更是在濱河造成了極大的恐慌,老刑警劉巖陈辱,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異式塌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門慧域,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲤竹,“玉大人,你說我怎么就攤上這事昔榴⌒猎澹” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵互订,是天一觀的道長吱肌。 經(jīng)常有香客問我,道長仰禽,這世上最難降的妖魔是什么氮墨? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮坟瓢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘犹撒。我一直安慰自己折联,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布识颊。 她就那樣靜靜地躺著诚镰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪祥款。 梳的紋絲不亂的頭發(fā)上清笨,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天,我揣著相機(jī)與錄音刃跛,去河邊找鬼抠艾。 笑死,一個胖子當(dāng)著我的面吹牛桨昙,可吹牛的內(nèi)容都是我干的检号。 我是一名探鬼主播腌歉,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼齐苛!你這毒婦竟也來了翘盖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤凹蜂,失蹤者是張志新(化名)和其女友劉穎馍驯,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體玛痊,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡汰瘫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了卿啡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吟吝。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颈娜,靈堂內(nèi)的尸體忽然破棺而出剑逃,到底是詐尸還是另有隱情,我是刑警寧澤官辽,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布蛹磺,位于F島的核電站,受9級特大地震影響同仆,放射性物質(zhì)發(fā)生泄漏萤捆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一俗批、第九天 我趴在偏房一處隱蔽的房頂上張望俗或。 院中可真熱鬧,春花似錦岁忘、人聲如沸辛慰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽帅腌。三九已至,卻和暖如春麻汰,著一層夾襖步出監(jiān)牢的瞬間速客,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工五鲫, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留溺职,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像辅愿,于是被迫代替她去往敵國和親智亮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容