過濾器可以在執行Servlet的service()方法前後,進行前置和後置處理。但是有些信息無法更改,例如請求參數。使用請求封裝器及相應封裝器,將容器產生的請求與相應對象加以封裝,可以針對某個請求信息或響應進行加工處理。
HttpServletRequestWrapper實現了HttpServletRequest接口,以下范例通過繼承HttpServletRequestWrapper實現了一個請求封裝器,可以請請求參數中的角括號替換為替代字符。
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class CharacterRequestWrapper extends HttpServletRequestWrapper{
private Map escapeMap;
public CharacterRequestWrapper(HttpServletRequest request,
Map escapeMap) {
super(request); //封裝傳入的請求對象
this.escapeMap = escapeMap;
}
@Override
public String getParameter(String name) { //重寫getParameter()方法
return doEscape(this.getRequest().getParameter(name));
}
private String doEscape(String parameter) {
if (parameter == null) {
return null;
}
String result = parameter;
Iterator it = escapeMap.keySet().iterator();
while(it.hasNext()) {
String origin = it.next();
String escape = escapeMap.get(origin);
result = result.replaceAll(origin, escape);
}
return result;
}
}
可以使用這個請求封裝器搭配過濾器,以進行字符過濾的服務。例如:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
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 CharacterFilter implements Filter {
private Map escapeMap;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
BufferedReader reader = null;
try {
String escapeListFile = filterConfig.getInitParameter("ESCAPE_LIST");
reader = new BufferedReader(new InputStreamReader(
filterConfig.getServletContext().getResourceAsStream(escapeListFile)));
String input = null;
escapeMap = new HashMap();
while ((input = reader.readLine()) != null) {
String[] token = input.split("\t");
escapeMap.put(token[0], token[1]);
}
} catch (IOException ex) {
Logger.getLogger(CharacterFilter.class.getName())
.log(Level.SEVERE, null, ex);
} finally {
try {
reader.close();
} catch (IOException ex) {
Logger.getLogger(CharacterFilter.class.getName())
.log(Level.SEVERE, null, ex);
}
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//將原請求對象封裝到CharacterRequestWrapper中
HttpServletRequest requestWrapper =
new CharacterRequestWrapper((HttpServletRequest)request, escapeMap);
//將CharacterRequestWrapper對象當做請求參數傳入doFilter()
chain.doFilter(requestWrapper, response);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
如果想要對響應的內容進行壓縮處理等,可以在響應封裝器部分繼承HttpServletResponseWrapper類來對HttpServletResponse對象進行封裝。
如要對浏覽器進行輸出響應,必須通過getWriter()取得PrintWriter,或是通過getOutputStream()取得ServletOutputStream。所以針對壓縮輸出的請求,主要就是繼承HttpServletResponseWrapper之後,通過重寫這兩個方法來達成的。
在這裡壓縮功能將采用GZIP格式,這是浏覽器可以接受的壓縮格式,可以使用GZIPOutputStream類來實現。由於getWriter()的PrintWriter在創建時也是必須要用到ServletOutputStream,所以這裡首先擴展ServletOutputStream類,讓它具有壓縮功能。
GzipServletOutputStream.java:
package club.chuxing;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
public class GZipServletOutputStream extends ServletOutputStream{
private GZIPOutputStream gzipOutputStream;
public GZipServletOutputStream(ServletOutputStream servletOutputStream)
throws IOException {
this.gzipOutputStream = new GZIPOutputStream(servletOutputStream);
}
public void write(int b) throws IOException {
//輸出時通過GZIPOutputSteam的write()壓縮輸出
gzipOutputStream.write(b);
}
public GZIPOutputStream getGzipOutputStream() {
return gzipOutputStream;
}
@Override
public boolean isReady() {
// TODO Auto-generated method stub
return false;
}
@Override
public void setWriteListener(WriteListener listener) {
// TODO Auto-generated method stub
}
}
CompressionResponseWrapper.java:
package club.chuxing;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class CompressionResponseWrapper extends HttpServletResponseWrapper {
private GZipServletOutputStream gzServletOutputStream;
private PrintWriter printWriter;
public CompressionResponseWrapper(HttpServletResponse resp) {
super(resp);
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (printWriter != null) {
throw new IllegalStateException();
}
if (gzServletOutputStream == null) {
gzServletOutputStream = new GZipServletOutputStream(
getResponse().getOutputStream());
}
return gzServletOutputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
if (gzServletOutputStream != null) {
throw new IllegalStateException();
}
if (printWriter == null) {
gzServletOutputStream = new GZipServletOutputStream(
getResponse().getOutputStream());
OutputStreamWriter osw = new OutputStreamWriter(
gzServletOutputStream, getResponse().getCharacterEncoding());
printWriter = new PrintWriter(osw);
}
return printWriter;
}
@Override
public void setContentLength(int len) {
}
public GZIPOutputStream getGZIPOutputStream() {
if (this.gzServletOutputStream == null) {
return null;
}
return this.gzServletOutputStream.getGzipOutputStream();
}
}
CompressionFilter.java(壓縮過濾器):
package club.chuxing;
import java.io.IOException;
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;
public class CompressionFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse res = (HttpServletResponse)response;
String encodings = req.getHeader("accept-encoding");
if ((encodings != null) && encodings.indexOf("gzip") > -1) {
//建立響應封裝
CompressionResponseWrapper responseWrapper =
new CompressionResponseWrapper(res);
//設置響應內容編碼為gzip格式
responseWrapper.setHeader("content-encoding", "gzip");
chain.doFilter(request, responseWrapper);
GZIPOutputStream gzipOutputStream = responseWrapper.getGZIPOutputStream();
if (gzipOutputStream != null) {
//調用GZIPOutputStream的finish()方法完成壓縮輸出
gzipOutputStream.finish();
}
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
最後,將過濾器設置在web.xml中,響應就會是壓縮過後的內容。