Servlet规范中所引入的filter令人心动不已,因为它引入了一个功能强大的拦截模式。Filter是这样一种Java对象,它能在request到达servlet的服务方法之前拦截HttpServletRequest对象,而在服务方法转移控制后又能拦截HttpServletResponse对象。你可以使用filter来实现特定的任务,比如验证用户输入,以及压缩web内容。但你拟富有成效地使用过滤器的念头却被你不能改变HttpServletRequest对象的参数的现实扫了兴,因为java.util.Map所包装的HttpServletRequest对象的参数是不可改变的。这极大地缩减了filter的应用范围。至少在一半的时间里,你希望可以改变准备传送给filter的对象。如果在HttpServletRequest对象到达Struts的action servlet之前,我们可以通过一个filter将用户输入的多余空格去掉,而响应的时候将响应内容压缩后在输出,难道不是更美妙吗?这样的话,幸运的是,尽管你不能改变不变对象本身,但你却可以通过使用装饰模式来改变其状态。
现在,让我们来看看,如何编写自己的HttpServletRequest装饰类。
实例:
1、编码过滤以及请求信息中的字符处理:
httpservletRequest 装饰类
package soufun.com;
importjava.io.UnsupportedEncodingException;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletRequestWrapper;
importorg.apache.commons.lang.StringEscapeUtils;
/**
*@author WHD
*data 2015年8月23日
*/
// HttpServletRequestWrapper 类实现了HttpServletRequest这个接口
// 继承这个实现类,进行方法重写来实现对请求信息的修改操作
public class EscapeWrapper extends HttpServletRequestWrapper {
public EscapeWrapper(HttpServletRequest request) {
super(request);
//TODO Auto-generated constructor stub
}
@Override
// 之前我们的过滤器不能对请求参数进行操作,但现在我们可以使用这个装饰模式对请求参数进行操作
// 重写getParameter(String str)方法 来操作请求参数
publicString getParameter(String name){
// 获取请求参数
Stringvalue= getRequest().getParameter("name");
System.out.println("修改前"+value);
try { // 编码设置
byte[]by= value.getBytes("ISO8859-1");
// 编码过滤器,这里的编码是自己定义的编码
value= new String(by,"utf-8");
}catch (UnsupportedEncodingException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
//这里可以对内容进行相应的操作
value=value.replaceAll("a","b");
System.out.println("修改后"+value);
returnvalue;
}
}
过滤器使用装饰类来处理请求参数:
package soufun.com;
importjava.io.IOException;
importjavax.servlet.Filter;
importjavax.servlet.FilterChain;
importjavax.servlet.FilterConfig;
importjavax.servlet.ServletException;
importjavax.servlet.ServletRequest;
importjavax.servlet.ServletResponse;
importjavax.servlet.http.HttpServletRequest;
/**
*@author WHD
*data 2015年8月23日
*/
public class Filter2 implements Filter{
@Override
publicvoid destroy() {
//TODO Auto-generated method stub
}
@Override
publicvoid doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChainchain) throws IOException, ServletException {
// 在这里给FilterChain 传递的参数是传装饰后的request,之后调用的就是EscapeWrapper重写的getParameter(String name )这个方法
// 获取装饰后的Request对象
HttpServletRequest request =newEscapeWrapper((HttpServletRequest)arg0);
// 使用过滤器就是在请求到大server之前,调用service(HttpServletRequest request,HttpServletResponse response)之前将request对象替换为装饰后的request对象
// 只要使用了这个过滤器的请求的reques对象都会被替换为装饰后的request 对象,这样之后调用的getParameter(String str)方法自然就是装饰后的类的方法
chain.doFilter(request, arg1);
}
@Override
publicvoid init(FilterConfig arg0) throws ServletException {
//TODO Auto-generated method stub
}
}
2、响应信息压缩后返回
压缩流的创建:
package soufun.com;
importjava.io.IOException;
importjava.util.zip.GZIPOutputStream;
importjavax.servlet.ServletOutputStream;
/**
*@author WHD
*data 2015年8月23日
*/
// 扩展输出流
public class GZipServletOutputStream extendsServletOutputStream{
// 定义压缩输出流
privateGZIPOutputStream gzipOutputStream;
// 构造函数来创建压缩输出流
public GZipServletOutputStream(ServletOutputStream servletOutputStreams) throwsIOException{
gzipOutputStream= newGZIPOutputStream(servletOutputStreams);
}
@Override
// write 方法重写
public void write(int b) throws IOException {
//TODO Auto-generated method stub
gzipOutputStream.write(b);
}
public GZIPOutputStream getGzipOutputStream() {
returngzipOutputStream;
}
public void setGzipOutputStream(GZIPOutputStream gzipOutputStream) {
this.gzipOutputStream= gzipOutputStream;
}
}
httpservletResponse装饰类
package soufun.com;
importjava.io.IOException;
importjava.io.OutputStreamWriter;
importjava.io.PrintWriter;
importjava.util.zip.GZIPOutputStream;
importjavax.servlet.ServletOutputStream;
importjavax.servlet.http.HttpServletResponse;
importjavax.servlet.http.HttpServletResponseWrapper;
/**
*@author WHD
*data 2015年8月23日
*/
public class CompressionWrapper extends HttpServletResponseWrapper {
privateGZipServletOutputStream gzServletOutputStream;
privatePrintWriter printWriter;
public CompressionWrapper(HttpServletResponse response) {
super(response);
//TODO Auto-generated constructor stub
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if(printWriter!= null) {
thrownew IllegalStateException();
}
if(gzServletOutputStream == null) {
gzServletOutputStream= new GZipServletOutputStream(
getResponse().getOutputStream());
}
returngzServletOutputStream;
}
@Override
// getWrite() 方法重写,实现压缩输出流
public PrintWriter getWriter() throws IOException {
if(gzServletOutputStream!= null) {
thrownew IllegalStateException();
}
if(printWriter == null) {
gzServletOutputStream= new GZipServletOutputStream(
getResponse().getOutputStream());
OutputStreamWriterosw = newOutputStreamWriter(gzServletOutputStream,getResponse().getCharacterEncoding());
printWriter= new PrintWriter(osw);
}
returnprintWriter;
}
@Override
public void setContentLength(int len) {}
publicGZIPOutputStream getGZIPOutputStream() {
if(this.gzServletOutputStream == null) {
returnnull;
}
returnthis.gzServletOutputStream.getGzipOutputStream();
}
}
过滤器使用httpservletResponse 的装饰类
package soufun.com;
importjava.io.IOException;
importjava.util.zip.GZIPOutputStream;
importjavax.servlet.Filter;
importjavax.servlet.FilterChain;
importjavax.servlet.FilterConfig;
importjavax.servlet.ServletException;
importjavax.servlet.ServletRequest;
importjavax.servlet.ServletResponse;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
/**
*@author WHD
*data 2015年8月23日
*/
public class CompressionFilter implements Filter{
@Override
publicvoid destroy() {
//TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChainchain) throws IOException, ServletException {
//TODO Auto-generated method stub
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String encodings = req.getHeader("accept-encoding");
//判断浏览器是否支持gzip输出
if((encodings != null) && (encodings.indexOf("gzip") > -1)){
// 创建装饰后的resposne对象
CompressionWrapper responseWrapper =new CompressionWrapper(res);
responseWrapper.setHeader("content-encoding","gzip");
// 这里传递的是装饰后的Response对象,所以printwrite 使用的是压缩输出
// 使用过滤器就是将所有的响应在到大浏览器之前将原来的Response 替换为装饰后的Response对象
chain.doFilter(request,responseWrapper);
GZIPOutputStreamgzipOutputStream = responseWrapper.getGZIPOutputStream();
if(gzipOutputStream != null) {
gzipOutputStream.finish();
}
}
else{
chain.doFilter(request,response);
}
}
@Override
publicvoid init(FilterConfig arg0) throws ServletException {
//TODO Auto-generated method stub
}
}
总结:
1、Filter的配置和Servlet的配置是一样的
<filter><filter-name>filter2</filter-name>
<filter-class>soufun.com.Filter2</filter-class>
<init-param>
<param-name>utf8</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>filter2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2、继承HttpServletRequestWrapper 和HttpServletResponse 两个类对 getParameter(String str) 和getWrite()两方法进行重写,而方法中实现我们想要的操作
3、使用Filter过滤器,我们知道Filter是在请求到达servlet之前和servlet响应信息到达浏览器之前进行两次拦截,而就在到达server之前我们将FilterChain的doFilter(request,reponse)方法的request参数替换为我们装饰后的request而我们又重写的getParameter(String str)方法,之后调用的就是这个方法,因此也就完成了
请求参数的过滤和修改
4、响应和请求其实是一样的,也是替换了Response对象,从而调用我们重写的方法实。