欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

深入解析Java的Servlet過(guò)濾器的原理及其應(yīng)用

 更新時(shí)間:2016年01月06日 08:54:06   作者:zhangjunhd  
這篇文章主要介紹了深入解析Java的Servlet過(guò)濾器的原理及應(yīng)用,Java編寫的Servlet通常是一個(gè)與網(wǎng)頁(yè)一起作用于瀏覽器客戶端的程序,需要的朋友可以參考下

1.Servlet過(guò)濾器
1.1 什么是過(guò)濾器
過(guò)濾器是一個(gè)程序,它先于與之相關(guān)的servlet或JSP頁(yè)面運(yùn)行在服務(wù)器上。過(guò)濾器可附加到一個(gè)或多個(gè)servlet或JSP頁(yè)面上,并且可以檢查進(jìn)入這些資源的請(qǐng)求信息。在這之后,過(guò)濾器可以作如下的選擇:
①以常規(guī)的方式調(diào)用資源(即,調(diào)用servlet或JSP頁(yè)面)。
②利用修改過(guò)的請(qǐng)求信息調(diào)用資源。
③調(diào)用資源,但在發(fā)送響應(yīng)到客戶機(jī)前對(duì)其進(jìn)行修改。
④阻止該資源調(diào)用,代之以轉(zhuǎn)到其他的資源,返回一個(gè)特定的狀態(tài)代碼或生成替換輸出。
 
1.2 Servlet過(guò)濾器的基本原理
在Servlet作為過(guò)濾器使用時(shí),它可以對(duì)客戶的請(qǐng)求進(jìn)行處理。處理完成后,它會(huì)交給下一個(gè)過(guò)濾器處理,這樣,客戶的請(qǐng)求在過(guò)濾鏈里逐個(gè)處理,直到請(qǐng)求發(fā)送到目標(biāo)為止。例如,某網(wǎng)站里有提交“修改的注冊(cè)信息”的網(wǎng)頁(yè),當(dāng)用戶填寫完修改信息并提交后,服務(wù)器在進(jìn)行處理時(shí)需要做兩項(xiàng)工作:判斷客戶端的會(huì)話是否有效;對(duì)提交的數(shù)據(jù)進(jìn)行統(tǒng)一編碼。這兩項(xiàng)工作可以在由兩個(gè)過(guò)濾器組成的過(guò)濾鏈里進(jìn)行處理。當(dāng)過(guò)濾器處理成功后,把提交的數(shù)據(jù)發(fā)送到最終目標(biāo);如果過(guò)濾器處理不成功,將把視圖派發(fā)到指定的錯(cuò)誤頁(yè)面。


2.Servlet過(guò)濾器開發(fā)步驟
開發(fā)Servlet過(guò)濾器的步驟如下:
①編寫實(shí)現(xiàn)Filter接口的Servlet類。
②在web.xml中配置Filter。
開發(fā)一個(gè)過(guò)濾器需要實(shí)現(xiàn)Filter接口,F(xiàn)ilter接口定義了以下方法:
①destory()由Web容器調(diào)用,初始化此Filter。
②init(FilterConfig filterConfig)由Web容器調(diào)用,初始化此Filter。
③doFilter(ServletRequest request,ServletResponse response,FilterChain chain)具體過(guò)濾處理代碼。


3.一個(gè)過(guò)濾器框架實(shí)例
SimpleFilter1.java

package com.zj.sample;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
 
public class SimpleFilter1 implements Filter {
  @SuppressWarnings("unused")
  private FilterConfig filterConfig;
 
  public void init(FilterConfig config) throws ServletException {
    this.filterConfig = config;
  }
 
  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) {
    try {
      System.out.println("Within SimpleFilter1:Filtering the Request...");
      chain.doFilter(request, response);// 把處理發(fā)送到下一個(gè)過(guò)濾器
      System.out .println("Within SimpleFilter1:Filtering the Response...");
    } catch (IOException ioe) {
      ioe.printStackTrace();
    } catch (ServletException se) {
      se.printStackTrace();
    }
  }
 
  public void destroy() {
    this.filterConfig = null;
  }
}

 
SimpleFilter2.java

package com.zj.sample;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
 
public class SimpleFilter2 implements Filter {
  @SuppressWarnings("unused")
  private FilterConfig filterConfig;
 
  public void init(FilterConfig config) throws ServletException {
    this.filterConfig = config;
  }
 
  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) {
    try {
      System.out.println("Within SimpleFilter2:Filtering the Request...");
      chain.doFilter(request, response); // 把處理發(fā)送到下一個(gè)過(guò)濾器
      System.out.println("Within SimpleFilter2:Filtering the Response...");
    } catch (IOException ioe) {
      ioe.printStackTrace();
    } catch (ServletException se) {
      se.printStackTrace();
    }
  }
 
  public void destroy() {
    this.filterConfig = null;
  }
}

 
web.xml

<filter>
  <filter-name>filter1</filter-name>
  <filter-class>com.zj.sample.SimpleFilter1</filter-class>
</filter>
<filter-mapping>
  <filter-name>filter1</filter-name>
  <url-pattern>/*</url-pattern>//為所有的訪問(wèn)做過(guò)濾
</filter-mapping>
 
<filter>
  <filter-name>filter2</filter-name>
  <filter-class>com.zj.sample.SimpleFilter2</filter-class>
</filter>
<filter-mapping>
  <filter-name>filter2</filter-name>
  <url-pattern>/*</url-pattern>//為所有的訪問(wèn)做過(guò)濾
</filter-mapping>

 
打開web容器中任意頁(yè)面輸出結(jié)果:(注意過(guò)濾器執(zhí)行的請(qǐng)求/響應(yīng)順序)

Within SimpleFilter1:Filtering the Request...
Within SimpleFilter2:Filtering the Request...
Within SimpleFilter2:Filtering the Response...
Within SimpleFilter1:Filtering the Response...

4.報(bào)告過(guò)濾器
我們來(lái)試驗(yàn)一個(gè)簡(jiǎn)單的過(guò)濾器,只要調(diào)用相關(guān)的servlet或JSP頁(yè)面,它就打印一條消息到標(biāo)準(zhǔn)輸出。為實(shí)現(xiàn)此功能,在doFilter方法中執(zhí)行過(guò)濾行為。每當(dāng)調(diào)用與這個(gè)過(guò)濾器相關(guān)的servlet或JSP頁(yè)面時(shí),doFilter方法就生成一個(gè)打印輸出,此輸出列出請(qǐng)求主機(jī)和調(diào)用的URL。因?yàn)間etRequestURL方法位于HttpServletRequest而不是ServletRequest中,所以把ServletRequest對(duì)象構(gòu)造為HttpServletRequest類型。我們改動(dòng)一下章節(jié)3的SimpleFilter1.java。
SimpleFilter1.java

package com.zj.sample;
import java.io.IOException;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
 
public class SimpleFilter1 implements Filter {
  @SuppressWarnings("unused")
  private FilterConfig filterConfig;
 
  public void init(FilterConfig config) throws ServletException {
    this.filterConfig = config;
  }
 
  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) {
    try {
      System.out.println("Within SimpleFilter1:Filtering the Request...");
      HttpServletRequest req = (HttpServletRequest) request;
      System.out.println(req.getRemoteHost() + " tried to access "
         + req.getRequestURL() + " on " + new Date() + ".");
      chain.doFilter(request, response);
      System.out.println("Within SimpleFilter1:Filtering the Response...");
    } catch (IOException ioe) {
      ioe.printStackTrace();
    } catch (ServletException se) {
      se.printStackTrace();
    }
  }
 
  public void destroy() {
    this.filterConfig = null;
  }
}

 
web.xml設(shè)置不變,同章節(jié)3。
 
測(cè)試:
輸入[url]http://localhost:8080/Test4Jsp/login.jsp[/url]
 
結(jié)果:

Within SimpleFilter1:Filtering the Request...
0:0:0:0:0:0:0:1 tried to access [url]http://localhost:8080/Test4Jsp/login.jsp[/url] on Sun Mar 04 17:01:37 CST 2007.
Within SimpleFilter2:Filtering the Request...
Within SimpleFilter2:Filtering the Response...
Within SimpleFilter1:Filtering the Response...

5.訪問(wèn)時(shí)的過(guò)濾器(在過(guò)濾器中使用servlet初始化參數(shù))
下面利用init設(shè)定一個(gè)正常訪問(wèn)時(shí)間范圍,對(duì)那些不在此時(shí)間段的訪問(wèn)作出記錄。我們改動(dòng)一下章節(jié)3的SimpleFilter2.java。
SimpleFilter2.java。

package com.zj.sample;
import java.io.IOException;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
 
public class SimpleFilter2 implements Filter {
  @SuppressWarnings("unused")
  private FilterConfig config;
  private ServletContext context;
  private int startTime, endTime;
  private DateFormat formatter;
 
  public void init(FilterConfig config) throws ServletException {
    this.config = config;
    context = config.getServletContext();
    formatter = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,
       DateFormat.MEDIUM);
    try {
      startTime = Integer.parseInt(config.getInitParameter("startTime"));// web.xml
      endTime = Integer.parseInt(config.getInitParameter("endTime"));// web.xml
    } catch (NumberFormatException nfe) { // Malformed or null
      // Default: access at or after 10 p.m. but before 6 a.m. is
      // considered unusual.
      startTime = 22; // 10:00 p.m.
      endTime = 6; // 6:00 a.m.
    }
  }
 
  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) {
    try {
      System.out.println("Within SimpleFilter2:Filtering the Request...");
      HttpServletRequest req = (HttpServletRequest) request;
      GregorianCalendar calendar = new GregorianCalendar();
      int currentTime = calendar.get(Calendar.HOUR_OF_DAY);
      if (isUnusualTime(currentTime, startTime, endTime)) {
       context.log("WARNING: " + req.getRemoteHost() + " accessed "
           + req.getRequestURL() + " on "
           + formatter.format(calendar.getTime()));
       // The log file is under <CATALINA_HOME>/logs.One log per day.
      }
      chain.doFilter(request, response);
      System.out
         .println("Within SimpleFilter2:Filtering the Response...");
    } catch (IOException ioe) {
      ioe.printStackTrace();
    } catch (ServletException se) {
      se.printStackTrace();
    }
  }
 
  public void destroy() {}
 
  // Is the current time between the start and end
  // times that are marked as abnormal access times?
  private boolean isUnusualTime(int currentTime, int startTime, int endTime) {
    // If the start time is less than the end time (i.e.,
    // they are two times on the same day), then the
    // current time is considered unusual if it is
    // between the start and end times.
    if (startTime < endTime) {
      return ((currentTime >= startTime) && (currentTime < endTime));
    }
    // If the start time is greater than or equal to the
    // end time (i.e., the start time is on one day and
    // the end time is on the next day), then the current
    // time is considered unusual if it is NOT between
    // the end and start times.
    else {
      return (!isUnusualTime(currentTime, endTime, startTime));
    }
  }
}

 
web.xml設(shè)置不變。
關(guān)于Tomcat日志處理,這里補(bǔ)充介紹一下。config.getServletContext().log("log message")會(huì)將日志信息寫入<CATALINA_HOME>/logs文件夾下,文件名應(yīng)該為localhost_log.2007-03-04.txt這樣的形式(按日期每天產(chǎn)生一個(gè),第二天可以看見(jiàn))。要得到這樣一個(gè)日志文件,應(yīng)該在server.xml中有:
<Logger className="org.apache.catalina.logger.FileLogger" prefix="catalina_log." suffix=".txt" timestamp="true"/>

6.禁止站點(diǎn)過(guò)濾器
如果你希望在你的過(guò)濾器檢測(cè)到不正常的異常而中途中斷后面的過(guò)濾過(guò)程時(shí),可這樣做:

public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws ServletException, IOException {
  HttpServletRequest req = (HttpServletRequest) request;
  HttpServletResponse res = (HttpServletResponse) response;
  if (isUnusualCondition(req)) {
    res.sendRedirect("http://www.somesite.com");
  } else {
    chain.doFilter(req, res);
  }
}

下例是一個(gè)禁止站點(diǎn)過(guò)濾器,如果不希望某些站點(diǎn)訪問(wèn)你的網(wǎng)站,你可以在web.xml的param-value中列出它的站點(diǎn),然后應(yīng)用上面的原理跳出常規(guī)過(guò)濾,給出禁止訪問(wèn)的頁(yè)面。
BannedAccessFilter.java

package com.zj.sample;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.StringTokenizer;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
 
public class BannedAccessFilter implements Filter {
  private HashSet<String> bannedSiteTable;
 
/**
* Deny access if the request comes from a banned site or is referred here
* by a banned site.
 */
  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws ServletException, IOException {
    System.out.println("Within BannedAccessFilter:Filtering the Request...");
    HttpServletRequest req = (HttpServletRequest) request;
    String requestingHost = req.getRemoteHost();
    String referringHost = getReferringHost(req.getHeader("Referer"));
    String bannedSite = null;
    boolean isBanned = false;
    if (bannedSiteTable.contains(requestingHost)) {
      bannedSite = requestingHost;
      isBanned = true;
    } else if (bannedSiteTable.contains(referringHost)) {
      bannedSite = referringHost;
      isBanned = true;
    }
    if (isBanned) {
      showWarning(response, bannedSite);
    } else {
      chain.doFilter(request, response);
    }
    System.out.println("Within BannedAccessFilter:Filtering the Response...");
  }
 
/**
* Create a table of banned sites based on initialization parameters.
* Remember that version 2.3 of the servlet API mandates the use of the
* Java 2 Platform. Thus, it is safe to use HashSet (which determines
* whether a given key exists) rather than the clumsier Hashtable
* (which has a value for each key).
*/
 
  public void init(FilterConfig config) throws ServletException {
    bannedSiteTable = new HashSet<String>();
    String bannedSites = config.getInitParameter("bannedSites");
    // Default token set: white space.
    StringTokenizer tok = new StringTokenizer(bannedSites);
    while (tok.hasMoreTokens()) {
      String bannedSite = tok.nextToken();
      bannedSiteTable.add(bannedSite);
      System.out.println("Banned " + bannedSite);
    }
  }
 
  public void destroy() {}
 
  private String getReferringHost(String refererringURLString) {
    try {
      URL referringURL = new URL(refererringURLString);
      return (referringURL.getHost());
    } catch (MalformedURLException mue) { // Malformed or null
      return (null);
    }
  }
 
  // Replacement response that is returned to users
  // who are from or referred here by a banned site.
  private void showWarning(ServletResponse response, String bannedSite)
      throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    String docType = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 "
       + "Transitional//EN\">\n";
    out.println(docType + "<HTML>\n"
       + "<HEAD><TITLE>Access Prohibited</TITLE></HEAD>\n"
       + "<BODY BGCOLOR=\"WHITE\">\n" + "<H1>Access Prohibited</H1>\n"
       + "Sorry, access from or via " + bannedSite + "\n"
       + "is not allowed.\n" + "</BODY></HTML>");
  }
}

 
web.xml

<filter>
  <filter-name>BannedAccessFilter</filter-name>
  <filter-class>com.zj.sample.BannedAccessFilter</filter-class>
  <init-param>
    <param-name>bannedSites</param-name>
    <param-value>
      [url]www.competingsite.com[/url] [url]www.bettersite.com[/url]
      [url]www.moreservlets.com[/url] 127.0.0.1//我們測(cè)試這個(gè)
    </param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>BannedAccessFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>

 
測(cè)試:

[url]http://localhost:8080/Test4Jsp/[/url]

 
結(jié)果:

20161685230203.jpg (664×253)

7.替換過(guò)濾器
7.1修改響應(yīng)
過(guò)濾器能夠阻止對(duì)資源的訪問(wèn)或者阻止激活它們。但如果過(guò)濾器想更改資源所生成的響應(yīng)。怎么辦呢?似乎沒(méi)有辦法能夠?qū)σ粋€(gè)資源所生成的響應(yīng)進(jìn)行訪問(wèn)。DoFilter的第二個(gè)參數(shù)(ServletResponse)給過(guò)濾器提供了一種發(fā)送新輸出到客戶機(jī)的辦法,但沒(méi)有給過(guò)濾器提供對(duì)servlet或JSP頁(yè)面輸出進(jìn)行訪問(wèn)的辦法。為什么會(huì)這樣呢?因?yàn)樵诘谝淮握{(diào)用doFilter方法時(shí),servlet或JSP頁(yè)面甚至還沒(méi)有執(zhí)行。一旦調(diào)用了FilterChain對(duì)象中的doFilter方法,要修改響應(yīng)似乎就太遲了,這是數(shù)據(jù)已經(jīng)發(fā)送到客戶機(jī)。
不過(guò),辦法是有的,那就是修改傳遞給FilterChain對(duì)象的doFilter方法的響應(yīng)對(duì)象。一般,建立緩存servlet或JSP頁(yè)面生成的所有輸出的版本。Servlet API 2.3版為此提供了一種有用的資源,即,HttpServletResponseWrapper類。這個(gè)類的使用包括以下五個(gè)步驟:
1)建立一個(gè)響應(yīng)包裝器。擴(kuò)展javax.servlet.http.HttpServletResponseWrapper。
2)提供一個(gè)緩存輸出的PrintWriter。重載getWriter方法,返回一個(gè)保存發(fā)送給它的所有東西的PrintWriter,并把結(jié)果存進(jìn)一個(gè)可以稍后訪問(wèn)的字段中。
3)傳遞該包裝器給doFilter。此調(diào)用是合法的,因?yàn)镠ttpServletResponseWrapper實(shí)現(xiàn)HttpServletResponse。
4)提取和修改輸出。在調(diào)用FilterChain的doFilter方法后,原資源的輸出只要利用步驟2中提供的機(jī)制就可以得到。只要對(duì)你的應(yīng)用適合,就可以修改或替換它。
5)發(fā)送修改過(guò)的輸出到客戶機(jī)。因?yàn)樵Y源不再發(fā)送輸出到客戶機(jī)(這些輸出已經(jīng)存放到你的響應(yīng)包裝器中了),所以必須發(fā)送這些輸出。這樣,你的過(guò)濾器需要從原響應(yīng)對(duì)象中獲得PrintWriter或OutputStream,并傳遞修改過(guò)的輸出到該流中。
 
7.2一個(gè)可重用的響應(yīng)包裝器
下例程序給出了一個(gè)包裝器,它可用于希望過(guò)濾器修改資源的輸出的大多數(shù)應(yīng)用中。CharArrayWrapper類重載getWriter方法以返回一個(gè)PrintWriter,它累積一個(gè)大字符數(shù)組中的所有東西。開發(fā)人員可利用toCharArray(原始char[])或toString(從char[]得出的一個(gè)String)方法得到這個(gè)結(jié)果。
CharArrayWrapper.java

package com.zj.sample;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
 
/**
 * A response wrapper that takes everything the client would normally
 * output and saves it in one big character array.
 */
public class CharArrayWrapper extends HttpServletResponseWrapper {
  private CharArrayWriter charWriter;
 
  /**
   * Initializes wrapper.
   * <P>
   * First, this constructor calls the parent constructor. That call
   *is crucial so that the response is stored and thus setHeader, *setStatus, addCookie, and so forth work normally.
   * <P>
   * Second, this constructor creates a CharArrayWriter that will
* be used to accumulate the response.
   */
  public CharArrayWrapper(HttpServletResponse response) {
    super(response);
    charWriter = new CharArrayWriter();
  }
 
  /**
   * When servlets or JSP pages ask for the Writer, don't give them
* the real one. Instead, give them a version that writes into
* the character array.
   * The filter needs to send the contents of the array to the
* client (perhaps after modifying it).
   */
  public PrintWriter getWriter() {
    return (new PrintWriter(charWriter));
  }
 
  /**
   * Get a String representation of the entire buffer.
   * <P>
   * Be sure <B>not</B> to call this method multiple times on the same
   * wrapper. The API for CharArrayWriter does not guarantee that it
   * "remembers" the previous value, so the call is likely to make
* a new String every time.
   */
  public String toString() {
    return (charWriter.toString());
  }
 
  /** Get the underlying character array. */
  public char[] toCharArray() {
    return (charWriter.toCharArray());
  }
}

 
7.3 替換過(guò)濾器
這里展示前一節(jié)中給出的CharArrayWrapper的一個(gè)常見(jiàn)的應(yīng)用:更改一個(gè)多次出現(xiàn)的目標(biāo)串為某個(gè)替代串的過(guò)濾器。
 
7.3.1通用替換過(guò)濾器
ReplaceFilter.java給出一個(gè)過(guò)濾器,它在CharArraryWrapper中包裝響應(yīng),傳遞該包裝器到FilterChain對(duì)象的doFilter方法中,提取一個(gè)給出所有資源的輸出的String型值,用一個(gè)替代串替換某個(gè)目標(biāo)串的所有出現(xiàn),并發(fā)送此修改過(guò)的結(jié)果到客戶機(jī)。
關(guān)于這個(gè)過(guò)濾器,有兩件事情需要注意。首先,它是一個(gè)抽象類。要使用它,必須建立一個(gè)提供getTargetString和getReplacementString方法的實(shí)現(xiàn)的子類。下一小節(jié)中給出了這種處理的一個(gè)例子。其次,它利用一個(gè)較小的實(shí)用類(見(jiàn)FilterUtils.java)來(lái)進(jìn)行實(shí)際的串替換。你可使用新的常規(guī)表達(dá)式包而不是使用String和StringTokenizer中低級(jí)的和繁瑣的方法。
ReplaceFilter.java

package com.zj.sample;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
 
/**
 * Filter that replaces all occurrences of a given string with a
* replacement.
 * This is an abstract class: you <I>must</I> override the getTargetString
* and getReplacementString methods in a subclass.
* The first of these methods specifies the string in the response
* that should be replaced. The second of these specifies the string
* that should replace each occurrence of the target string.
 */
public abstract class ReplaceFilter implements Filter {
  private FilterConfig config;
 
  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws ServletException, IOException {
    CharArrayWrapper responseWrapper = new CharArrayWrapper(
       (HttpServletResponse) response);
    // Invoke resource, accumulating output in the wrapper.
    chain.doFilter(request, responseWrapper);
    // Turn entire output into one big String.
    String responseString = responseWrapper.toString();
    // In output, replace all occurrences of target string with replacement
    // string.
    responseString = FilterUtils.replace(responseString, getTargetString(),
       getReplacementString());
    // Update the Content-Length header.
    updateHeaders(response, responseString);
    PrintWriter out = response.getWriter();
    out.write(responseString);
  }
 
  /**
   * Store the FilterConfig object in case subclasses want it.
   */
  public void init(FilterConfig config) throws ServletException {
    this.config = config;
  }
 
  protected FilterConfig getFilterConfig() {
    return (config);
  }
 
  public void destroy() {
  }
 
  /**
   * The string that needs replacement.
*Override this method in your subclass.
   */
  public abstract String getTargetString();
 
  /**
   * The string that replaces the target. Override this method in
   * your subclass.
   */
  public abstract String getReplacementString();
 
  /**
   * Updates the response headers. This simple version just sets
*the Content-Length header, assuming that we are using a
*character set that uses 1 byte per character.
* For other character sets, override this method to use
* different logic or to give up on persistent HTTP connections.
* In this latter case, have this method set the Connection header
* to "close".
   */
  public void updateHeaders(ServletResponse response, String responseString) {
    response.setContentLength(responseString.length());
  }
}

 
FilterUtils.java

package com.zj.sample;
 
/**
 * Small utility to assist with response wrappers that return strings.
 */
public class FilterUtils {
  /**
   * Change all occurrences of orig in mainString to replacement.
   */
  public static String replace(String mainString, String orig,
      String replacement) {
    String result = "";
    int oldIndex = 0;
    int index = 0;
    int origLength = orig.length();
    while ((index = mainString.indexOf(orig, oldIndex)) != -1) {
      result = result + mainString.substring(oldIndex, index)
         + replacement;
      oldIndex = index + origLength;
    }
    result = result + mainString.substring(oldIndex);
    return (result);
  }
}
 
7.3.2實(shí)現(xiàn)一個(gè)字符替換過(guò)濾器
假設(shè)百度收購(gòu)了google(只是假設(shè)),現(xiàn)在所有的頁(yè)面上凡是出現(xiàn)google字樣的文字都必須替換為百度!ReplaceSiteNameFilter.java繼承上文ReplaceFilter.java來(lái)實(shí)現(xiàn)這一功能。
ReplaceSiteNameFilter.java
package com.zj.sample;
 
public class ReplaceSiteNameFilter extends ReplaceFilter {
  public String getTargetString() {
    return ("google.com.cn");
  }
 
  public String getReplacementString() {
    return ("baidu.com");
  }
}

 
web.xml

<filter>
  <filter-name>ReplaceSiteNameFilter</filter-name>
  <filter-class>com.zj.sample.ReplaceSiteNameFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>ReplaceSiteNameFilter</filter-name>
  <url-pattern>/login.jsp</url-pattern>
</filter-mapping>

 
測(cè)試結(jié)果:
過(guò)濾前

20161685344662.jpg (400×269)

過(guò)濾后

20161685400382.jpg (420×282)

8.壓縮過(guò)濾器
有幾個(gè)最新的瀏覽器可處理壓縮的內(nèi)容,自動(dòng)解開以gzip作為Content-Encoding響應(yīng)頭值的壓縮文件,然后就像對(duì)原文檔那樣處理結(jié)果。發(fā)送這樣的壓縮內(nèi)容可以節(jié)省很多時(shí)間,因?yàn)樵诜?wù)器上壓縮文檔,然后在客戶機(jī)上解開文檔所需的時(shí)間與下載文件的時(shí)間相比是微不足道的。程序LongServlet.java給出了一個(gè)具有很長(zhǎng)的、重復(fù)的純文本輸出的servlet,這是一個(gè)可供壓縮使用的成熟的servlet。如果使用gzip,它可以把輸出結(jié)果壓縮到1/300!
在瀏覽器支持這個(gè)壓縮能力時(shí),壓縮過(guò)濾器可利用章節(jié)7介紹的CharArrayWrapper來(lái)壓縮內(nèi)容,完成此任務(wù)需要下列內(nèi)容:
1)實(shí)現(xiàn)Filter接口的類。這個(gè)類名為CompressionFIlter。init方法存放FilterConfig對(duì)象在一個(gè)字段中,以防子類需要訪問(wèn)servlet環(huán)境或過(guò)濾器名。destory方法體為空。
2)包裝的響應(yīng)對(duì)象。DoFilter方法將ServletResponse對(duì)象包裝在一個(gè)CharArrayWrapper中,并傳遞此包裝器到FilterChain對(duì)象的doFilter方法上。在此調(diào)用完成后,所有其他過(guò)濾器和最終資源都已執(zhí)行,且輸出結(jié)果位于包裝器之內(nèi)。這樣,原doFilter提取一個(gè)代表所有資源的輸出的字符數(shù)組。如果客戶機(jī)指出它支持壓縮(即,以gzip作為Accept-Encoding頭的一個(gè)值),則過(guò)濾器附加一個(gè)GZIPOutputStream到ByteArrayOutputStream上,將字符數(shù)組復(fù)制到此流中,并設(shè)置Content-Encoding響應(yīng)頭為gzip。如果客戶機(jī)不支持gzip,則將未修改過(guò)的字符數(shù)組復(fù)制到ByteArrayOutputStream。最后,doFilter通過(guò)將整個(gè)字符數(shù)組(可能是壓縮過(guò)的)寫到與original響應(yīng)相關(guān)的OutputStream中,發(fā)送結(jié)果到客戶機(jī)。
3)對(duì)LongServlet進(jìn)行注冊(cè)。
CompressionFilter.java

package com.zj.sample;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.zip.GZIPOutputStream;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * Filter that compresses output with gzip (assuming that browser supports
 * gzip).
 */
public class CompressionFilter implements Filter {
 
  private FilterConfig config;
 
  /**
   * If browser does not support gzip, invoke resource normally. If browser
   * <I>does</I> support gzip, set the Content-Encoding response header and
   * invoke resource with a wrapped response that collects all the output.
   * Extract the output and write it into a gzipped byte array. Finally, write
   * that array to the client's output stream.
   */
  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws ServletException, IOException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse res = (HttpServletResponse) response;
    if (!isGzipSupported(req)) {
      // Invoke resource normally.
      chain.doFilter(req, res);
    } else {
      // Tell browser we are sending it gzipped data.
      res.setHeader("Content-Encoding", "gzip");
      // Invoke resource, accumulating output in the wrapper.
      CharArrayWrapper responseWrapper = new CharArrayWrapper(res);
      chain.doFilter(req, responseWrapper);
      // Get character array representing output.
      char[] responseChars = responseWrapper.toCharArray();
      // Make a writer that compresses data and puts it into a byte array.
      ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
      GZIPOutputStream zipOut = new GZIPOutputStream(byteStream);
      OutputStreamWriter tempOut = new OutputStreamWriter(zipOut);
      // Compress original output and put it into byte array.
      tempOut.write(responseChars);
      // Gzip streams must be explicitly closed.
      tempOut.close();
      // Update the Content-Length header.
      res.setContentLength(byteStream.size());
      // Send compressed result to client.
      OutputStream realOut = res.getOutputStream();
      byteStream.writeTo(realOut);
    }
  }
 
  /**
   * Store the FilterConfig object in case subclasses want it.
   */
  public void init(FilterConfig config) throws ServletException {
    this.config = config;
  }
 
  protected FilterConfig getFilterConfig() {
    return (config);
  }
 
  public void destroy() {}
 
  private boolean isGzipSupported(HttpServletRequest req) {
    String browserEncodings = req.getHeader("Accept-Encoding");
    return ((browserEncodings != null) && (browserEncodings.indexOf("gzip") != -1));
  }
}
 
LongServlet.java
package com.zj.sample;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
/**
 * Servlet with <B>long</B> output. Used to test the effect of the compression
 * filter of Chapter 9.
 */
 
public class LongServlet extends HttpServlet {
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    String docType = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 "
       + "Transitional//EN\">\n";
    String title = "Long Page";
    out.println(docType + "<HTML>\n" + "<HEAD><TITLE>" + title
       + "</TITLE></HEAD>\n" + "<BODY BGCOLOR=\"#FDF5E6\">\n"
       + "<H1 ALIGN=\"CENTER\">" + title + "</H1>\n");
    String line = "Blah, blah, blah, blah, blah. "
       + "Yadda, yadda, yadda, yadda.";
    for (int i = 0; i < 10000; i++) {
      out.println(line);
    }
    out.println("</BODY></HTML>");
  }
}

 
web.xml

<filter>
  <filter-name>CompressionFilter</filter-name>
  <filter-class>com.zj.sample.CompressionFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>CompressionFilter</filter-name>
  <servlet-name>LongServlet</servlet-name>
</filter-mapping>
 
<servlet>
  <servlet-name>LongServlet</servlet-name>
  <servlet-class>com.zj.sample.LongServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>LongServlet</servlet-name>
  <url-pattern>/LongServlet</url-pattern>
</servlet-mapping>

相關(guān)文章

  • Java中用戶向系統(tǒng)傳遞參數(shù)的三種基本方式實(shí)例分享

    Java中用戶向系統(tǒng)傳遞參數(shù)的三種基本方式實(shí)例分享

    這篇文章主要介紹了Java中用戶向系統(tǒng)傳遞參數(shù)的三種基本方式實(shí)例,有需要的朋友可以參考一下
    2014-01-01
  • Spring boot隨機(jī)端口你都不會(huì)還怎么動(dòng)態(tài)擴(kuò)容

    Spring boot隨機(jī)端口你都不會(huì)還怎么動(dòng)態(tài)擴(kuò)容

    這篇文章主要介紹了Spring boot隨機(jī)端口你都不會(huì)還怎么動(dòng)態(tài)擴(kuò)容,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • java微信公眾號(hào)支付開發(fā)之現(xiàn)金紅包

    java微信公眾號(hào)支付開發(fā)之現(xiàn)金紅包

    這篇文章主要為大家詳細(xì)介紹了java微信公眾號(hào)支付開發(fā)之現(xiàn)金紅包,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • 如何使用Comparator比較接口實(shí)現(xiàn)ArrayList集合排序

    如何使用Comparator比較接口實(shí)現(xiàn)ArrayList集合排序

    這篇文章主要介紹了如何使用Comparator比較接口實(shí)現(xiàn)ArrayList集合排序問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • 教你bat腳本一鍵配置java開發(fā)環(huán)境

    教你bat腳本一鍵配置java開發(fā)環(huán)境

    公司新入職一名員工,項(xiàng)目經(jīng)理讓我安排新人工作,首先需要對(duì)java開發(fā)相關(guān)環(huán)境進(jìn)行配置安裝,但時(shí)常會(huì)因?yàn)榘惭b配置不到位或者操作錯(cuò)誤導(dǎo)致時(shí)間的浪費(fèi),所以在空余時(shí)間收集了一系列軟件的免安裝版本,感興趣的朋友一起看看吧
    2021-12-12
  • 關(guān)于idea引入spring boot <parent></parent>父依賴標(biāo)紅問(wèn)題

    關(guān)于idea引入spring boot <parent></parent>父依賴標(biāo)紅問(wèn)題

    這篇文章主要介紹了idea引入spring boot <parent></parent>父依賴標(biāo)紅問(wèn)題,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10
  • 帶你快速搞定Mysql優(yōu)化

    帶你快速搞定Mysql優(yōu)化

    大部分的游戲數(shù)據(jù)庫(kù)都是使用mysql ,所以今天今天大概聊一下對(duì)數(shù)據(jù)庫(kù)的優(yōu)化原則問(wèn)題,都是基于InnoDB 引擎,希望你能在遇到同樣的問(wèn)題時(shí)能解決問(wèn)題
    2021-07-07
  • java對(duì)于JSON的解析方法舉例詳解

    java對(duì)于JSON的解析方法舉例詳解

    在編寫應(yīng)用時(shí),我們經(jīng)常要解析JSON,下面這篇文章主要給大家介紹了關(guān)于java對(duì)于JSON的解析方法,文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2023-09-09
  • springMVC傳遞list對(duì)象的三種使用方式

    springMVC傳遞list對(duì)象的三種使用方式

    這篇文章主要介紹了springMVC傳遞list對(duì)象的三種使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • SpringBoot項(xiàng)目集成Flyway詳細(xì)過(guò)程

    SpringBoot項(xiàng)目集成Flyway詳細(xì)過(guò)程

    今天帶大家學(xué)習(xí)SpringBoot項(xiàng)目集成Flyway詳細(xì)過(guò)程,文中有非常詳細(xì)的介紹及代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05

最新評(píng)論