Servlet--过滤器与封装器
1.过滤器
在容器调用Servlet的service()方法前,Servlet并不知道有请求的到来,在Servlet的service()方法执行后,容器真正对浏览器进行响应之前,浏览器也不知道Servlet真正的响应是什么。过滤器正如其名所示,可以拦截过滤浏览器对Servlet的请求,也可以改变Servlet对浏览器的响应。
要实现过滤器,必须实现Filter接口,并在web.xml中定义过滤器。Filter接口有三个要实现的方法:init(),doFilter(),destroy()。
FilterConfig为web.xml中过滤器的代表对象,如果在定义过滤器时设置了初始参数,可以通过getInitParameter()方法取得初始参数。
当请求来到容器,容器发现在调用Servlet的service()方法之前可以应用某个过滤器时,会调用该过滤器的doFilter()方法。如果调用了FilterChain的doFilter()方法,就会执行下一个过滤器,直至目标Servlet的service()方法。如果因为某些情况(例如未通过用户验证)而没有调用FilterChain的doFilter(),则请求不会继续交给接下来的过滤器或目标Servlet,这既是拦截请求。
在陆续调用玩Filter实例的doFilter()至Servlet的service()之后,流程会以堆栈顺序返回,所以在FilterChain的doFilter()之后,可以针对service()做后续处理。
//service()前置处理
chain.doFilter(request, response);
//service()后置处理
import java.io.*;
import javax.servlet.*;
public class PerformanceFilter implements Filter {
private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
long begin = System.currentTimeMillis();
chain.doFilter(request, response);
filterConfig.getServletContext().log("Request process in " +
(System.currentTimeMillis() - begin) + " milliseconds");
}
public void destroy() {
}
}
在web.xml中设置过滤器时,<filter-mapping>中可以使用<url-pattern>来指定哪些url请求将应用此过滤器,也可以使用<servlet-name>指定哪些Servlet将应用此过滤器。触发过滤器的时机,默认是浏览器直接发出请求。如果是那些通过设置RequestDispatcher的forward()或include()的请求,则可以在web.xml中设置<dispatcher>标签,指定哪些请求转发类型将触发过滤器。如果某个url或者Servlet会应用多个过滤器,则根据<filter-ampping>在web.xml中出现的先后顺序决定过滤器的执行顺序。
2.封装器
对于容器产生的HttpServletRequest对象,我们无法直接修改某些信息,比如请求参数。可以通过继承HttpServletRequestWrapper类,并重写某些方法。对于HttpServletResponse对象,可以继承HttpServletResponseWrapper类。
import java.util.*;
import javax.servlet.http.*;
import javax.servlet.http.HttpServletRequestWrapper;
public class CharacterRequestWrapper extends HttpServletRequestWrapper {
private Map<String, String> escapeMap;
public CharacterRequestWrapper(HttpServletRequest request,
Map<String, String> escapeMap) {
super(request);
this.escapeMap = escapeMap;
}
@Override
public String getParameter(String name) {
return doEscape(this.getRequest().getParameter(name));
}
private String doEscape(String parameter) {
String result = parameter;
Iterator<String> iterator = escapeMap.keySet().iterator();
while (iterator.hasNext()) {
String origin = iterator.next();
String escape = escapeMap.get(origin);
result = result.replaceAll(origin, escape);
}
return result;
}
}
使用这个请求封装器类搭配过滤器,可以进行字符过滤的服务。
import java.io.*;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.*;
import javax.servlet.http.*;
public class CharacterFilter implements Filter {
private Map<String, String> escapeMap;
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<String, String>();
while ((input = reader.readLine()) != null) {
String[] tokens = input.split("\t");
escapeMap.put(tokens[0], tokens[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);
}
}
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest requestWrapper =
new CharacterRequestWrapper(
(HttpServletRequest) request, escapeMap);
chain.doFilter(requestWrapper, response);
}
public void destroy() {
}
}