重温java web过滤器filter

1、Filter是什么?

Filter 技术是servlet 2.3 新增加的功能。Filter翻译过来的意思就是过滤器,能对客户端的消息进行预处理,然后将请求转发给其它的web组件,可以对ServletHttpRequest和ServletHttpResponse进行修改和检查。例如:在Filter中可以检查用户是否登录,对未登录的用户跳转到登陆界面。

2、过滤器快速入门

要定义一个过滤器,则需要实现javax.servlet.Filter接口,一个过滤器中包含了三个与生命周期相关的方法:

void init(FilterConfig  config)  过滤器初始化时执行,FilterConfig 可以用来获取过滤器的初始化参数。

void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

过滤器过滤请求时执行,包含了request和response,chain用来是否执行下一步请求。

destroy()   web容器(tomcat)停止时执行

    第一步:创建DemoFilter.java

packagecn.zq.filter;importjava.io.IOException;

importjavax.servlet.Filter;

importjavax.servlet.FilterChain;

importjavax.servlet.FilterConfig;

importjavax.servlet.ServletException;

importjavax.servlet.ServletRequest;

importjavax.servlet.ServletResponse;

publicclassDemoServletimplementsFilter{

publicvoidinit(FilterConfig config)throwsServletException{System.out.println("DemoServlet.init...");}publicvoiddoFilter(ServletRequest req, ServletResponse resp, FilterChain chain)throwsIOException, ServletException{

System.out.println("DemoServlet.doFilter...");                System.out.println("this = "+this);        }publicvoiddestroy(){System.out.println("DemoServlet.destroy...");}}

第二步:在web.xml文件中添加如下配置:

democn.zq.filter.DemoServletdemo/*

url-pattern配置为/*,表示过滤所有请求。

启动tomcat,可以看到如下输出:

说明Filter的init方法在web容器启动的时候执行,读者可以自行验证destroy()方法会在web容器停止时执行,访问主页:

在访问主页的时候浏览器是一片空白的,控制台输出上面的消息,Filter只会实例化一次,为什么我们访问不到我们要访问的内容呢?只需要在doFilter方法中加入如下的语句就可以了:

chain.doFilter(req, resp);

FilterChain(过滤器链)是用来干什么的呢?这个对象只包含一个void doFilter(ServletRequest request, ServletResponse response)方法,Filter调用此方法去调用下一个web组件(Filter,Servlet等),如果不调用此方法,那么下一个web组件不会被执行。

再放行之前,我们可以在Filter中设置响应头信息,如下:

resp.setContentType("text/html;charset=UTF-8");        chain.doFilter(req, resp);

过滤器的过滤过程如下:

过滤器中的各项配置:

配置初始化参数:

democn.zq.filter.DemoServletencodingUTF-8nameRiccioZhangdemo/*

然后在init方法中获取:

publicvoidinit(FilterConfig config)throwsServletException{System.out.println("DemoServlet.init...");String encoding = config.getInitParameter("encoding");String name = config.getInitParameter("name");System.out.println("encoding="+encoding);System.out.println("name="+name);}

<!-- filter的名字 -->demo<!-- 类名 -->cn.zq.filter.DemoServlet<!-- 可以有多个 --><!-- 对哪个filter进行配置 -->demo<!--    配置过滤的url,不能是/   其他与servlet配置类似   -->/*<!--

  根据名字配置对哪个servlet进行过滤

  -->DemoServlet<!--

  ERROR: <error-page>过来的请求

  FORWARD: 对转发过来的请求进行过滤,也就是对request.getRequestDispatcher(path).forward(request, response)

  INCLUDE:对request.getRequestDispatcher(path).include(request, response)过来的请求进行过滤

  REQUEST(默认): 对客户端的请求进行拦截

  可以配置多个

  -->ERROR

3、Filter的应用

为了便于编写Filter,本节的所有应用中提供了一个通过的Filter的实现:

packagecn.zq.filter;

importjava.io.IOException;

importjava.io.Serializable;

importjava.util.Enumeration;

importjavax.servlet.Filter;

importjavax.servlet.FilterChain;

importjavax.servlet.FilterConfig;

importjavax.servlet.ServletContext;

importjavax.servlet.ServletException;

importjavax.servlet.ServletRequest;

importjavax.servlet.ServletResponse;

/** * 通用的Filter的实现 *

@authorzq

*

*/

publicabstractclassGenericFilterimplementsFilter,FilterConfig,Serializable{privatestaticfinallongserialVersionUID =5497978960987185665L;

       privateFilterConfig filterConfig;/**

* 需要初始化,应该覆盖整个方法

*/publicvoidinit(){}publicvoidinit(FilterConfig filterConfig)throwsServletException{this.filterConfig = filterConfig;init();}

abstractpublicvoiddoFilter(ServletRequest request, ServletResponse response,

FilterChain chain)throwsIOException, ServletException;publicvoiddestroy(){}

publicStringgetFilterName(){returngetFilterConfig().getFilterName();}

publicStringgetInitParameter(String name){

returngetFilterConfig().getInitParameter(name);}

publicEnumerationgetInitParameterNames(){

returngetFilterConfig().getInitParameterNames();}

publicServletContextgetServletContext(){returngetFilterConfig().getServletContext();}publicFilterConfiggetFilterConfig(){returnfilterConfig;}}

packagecn.zq.filter;

importjava.io.IOException;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.ServletRequest;

importjavax.servlet.ServletResponse;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicabstractclassHttpFilterextendsGenericFilter{

privatestaticfinallongserialVersionUID =1029993995265394412L;

publicvoiddoFilter(ServletRequest request, ServletResponse response, FilterChain chain)throwsIOException, ServletException{HttpServletRequest req = (HttpServletRequest) request;HttpServletResponse resp = (HttpServletResponse) response;doFilter(req, resp, chain);}protectedabstractvoiddoFilter(HttpServletRequest request, HttpServletResponse response,

FilterChain chain)throwsIOException, ServletException;}

3.1、解决GET和POST获取参数的乱码问题

第一步:创建Filter

packagecn.zq.filter;

importjava.io.IOException;

importjava.io.UnsupportedEncodingException;

importjava.util.Iterator;

importjava.util.Map;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletRequestWrapper;

importjavax.servlet.http.HttpServletResponse;

/**

* 处理字符编码的Filter

*@authorzq

*

*/

publicclassCharacterEncodingFilterextendsHttpFilter{

       privatestaticfinallongserialVersionUID = -4329981031091311164L;privateString characterEncoding ="UTF-8";publicvoidinit(){String ce = getInitParameter("characterEncoding");if(ce !=null&& !ce.equals("")){characterEncoding = ce.toUpperCase();}}publicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{request.setCharacterEncoding(characterEncoding);response.setContentType("text/html;charset="+characterEncoding);//优化:只对GET请求的request进行包装if(request.getMethod().equals("GET")){request =newParameterHandlerRequest(request);}chain.doFilter(request, response);}privateclassParameterHandlerRequestextendsHttpServletRequestWrapper{publicParameterHandlerRequest(HttpServletRequest request){super(request);}publicStringgetParameter(String name){String value =super.getParameter(name);returngetString(value);}privateStringgetString(String value){if(value !=null){try{value =newString( value.getBytes("ISO-8859-1"), getRequest().getCharacterEncoding() );}catch(UnsupportedEncodingException e) {e.printStackTrace();}}returnvalue;}publicString[] getParameterValues(String name) {String[] values =super.getParameterValues(name);if(null!= values){for(inti =0; i < values.length; i++){values[i] = getString(values[i]);}}returnvalues;}publicMap getParameterMap() {Map paramMap =super.getParameterMap();Iterator it = paramMap.values().iterator();while(it.hasNext()){String[] values = it.next();if(null!= values){for(inti =0; i < values.length; i++){values[i] = getString(values[i]);}}}returnparamMap;}}}

第二步:编写配置文件

CharacterEncodingFiltercn.zq.filter.CharacterEncodingFilterCharacterEncodingFilter/*

这个过滤器应该配置在所有过滤器的前面

第三步:测试

packagecn.zq.servlet;

importjava.io.IOException;

importjava.util.Iterator;

importjava.util.Map;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassDemoServletextendsHttpServlet{privatestaticfinallongserialVersionUID = -4363281555738840730L;publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{        doPost(request, response);    }publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{        System.out.println("--------"+request.getMethod()+"--------");        System.out.println("request = "+ request);        System.out.println("name = "+ request.getParameter("name"));                String[] names = request.getParameterValues("name");if(names !=null&& names.length >0){            System.out.println("names[0] = "+ names[0]);        }        Map parameterMap = request.getParameterMap();for(Iterator it = parameterMap.keySet().iterator();                it.hasNext();){            String key = it.next();            String[] values = parameterMap.get(key);            System.out.println(key+"="+values[0] );        }    }}

DemoServletcn.zq.servlet.DemoServletDemoServlet/servlet/DemoServlet

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">My JSP 'index.jsp' starting page<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->Click

访问并测试:

这个过滤器应该被配置在所有过滤器的前面,就能解决全站的乱码了,这样就不用重复的编写解决乱码问题的代码了。

3.2、设置所有的jsp页面不缓存

因为jsp页面的有些内容是动态生成的,所有混成jsp页面的意义不大,我们通常会设置这些jsp页面不缓存。

第一步:开发Filter

packagecn.zq.filter;

importjava.io.IOException;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassDynamicPageCacheFilterextendsHttpFilter{/** * */privatestaticfinallongserialVersionUID = -5449451659530735173L;publicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{//设置3个响应头response.setHeader("pragma","no-cache");response.setHeader("cache-control","no-cache");response.setDateHeader("expires",0);chain.doFilter(request, response);}}

第二步:配置web.xml

DynamicPageCacheFiltercn.zq.filter.DynamicPageCacheFilterDynamicPageCacheFilter*.jspREQUESTFORWARDINCLUDE

第三步:打开ie,清空所有的缓存,cookie,访问本项目的jsp文件看是否有缓存文件,将Filter拿到,再访问看是否有缓存文件。

控制是否缓存,也可以在jsp页面中加入这几个头

3.3、控制静态页面缓存(如html,图片)

第一步:编写Filter

packagecn.zq.filter;

importjava.io.IOException;

importjava.util.Calendar;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassStaticContentCacheFilterextendsHttpFilter{/** * */privatestaticfinallongserialVersionUID =7660878144738222823L;@OverridepublicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{/*

*让图片缓存一个月,html文件缓存一个星期 ,

*具体的相关信息可以通过配置文件来配置。

*/String requestURI = request.getRequestURI();longtime =0;intday =0;if(requestURI.endsWith(".jpg")){day =30;}elseif(requestURI.endsWith(".html")){day =7;}Calendar calendar = Calendar.getInstance();calendar.add(Calendar.DATE, day);time = calendar.getTimeInMillis();response.setDateHeader("expires", time);chain.doFilter(request, response);}}

第二步:配置

StaticContentCacheFiltercn.zq.filter.StaticContentCacheFilterStaticContentCacheFilter*.html*.jpg

第三步:测试

请求资源,再次请求。查看状态码为304,及缓存文件的日期为N天以后。这是返回的状态码:HTTP/1.1 304 Not Modified

3.4 验证用户是否登录

第一步:开发filter

packagecn.zq.filter;

importjava.io.IOException;

importjava.io.PrintWriter;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpSession;

/**

* 验证用户是否登录的过滤器

*@authorRiccio Zhang

*

*/

publicclassLoginFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID = -6363929637537263967L;

protectedvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{HttpSession session = request.getSession();Object user = session.getAttribute("user");//没有找到user,则说明用户没有登录,转到登录页面让用户登录if(user ==null){PrintWriter out = response.getWriter();out.print("<script>"+"alert('您还未登录!');"+"window.location.href='"+request.getContextPath()+"/login.jsp'"+"</script>");return;}chain.doFilter(request, response);}}

第二步:开发登录功能,配置web.xml

packagecn.zq.servlet;

importjava.io.IOException;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassLoginServletextendsHttpServlet{

privatestaticfinallongserialVersionUID =3059445154848670189L;publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{//让用户退出登录request.getSession().invalidate();response.sendRedirect(request.getContextPath() +"/login.jsp");}

publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{/*

* 让用户登录成功

*/String username = request.getParameter("username");if(username ==null|| username.length() ==0){request.setAttribute("msg","用户名不能为空!");request.getRequestDispatcher("/login.jsp").forward(request, response);return;}request.getSession().setAttribute("user", username);//重定向到主页response.sendRedirect(request.getContextPath() +"/page/index.jsp");}}

登录页面:/login.jsp

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">My JSP 'login.jsp' starting page${requestScope.msg }username :

登录成功跳转页面:/page/index.jsp

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">My JSP 'index.jsp' starting page<!--

<link rel="stylesheet" type="text/css" href="styles.css">

-->欢迎你,
退出

<!-- 对/page/*进行过滤 -->LoginFiltercn.zq.filter.LoginFilterLoginFilter/page/*DemoServlet/servlet/DemoServletLoginServlet/login

第三步:测试,

在访问/page/index.jsp页面时,未登录是否会跳转到登录页面。登录时显示用户的名字。

3.5、自动登录

自动登录是为了让用户下次访问时,不用输入用户名和密码。将用户的信息保存到cookie中,下次直接从cookie中取。

第一步:开发登录页面

<%@pagelanguage="java"import="java.util.*"pageEncoding="UTF-8"%><%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%><%Stringpath=request.getContextPath();StringbasePath=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">My JSP 'login.jsp' starting page${requestScope.msg }username :
自动登录不自动登录
1天
一个星期
一个月
欢迎您,
退出

第二步:开发登录servlet

packagecn.zq.servlet;

importjava.io.IOException;

importjava.net.URLEncoder;

importjavax.servlet.ServletException;

importjavax.servlet.http.Cookie;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

publicclassLoginServletextendsHttpServlet{/** * */privatestaticfinallongserialVersionUID =3059445154848670189L;

       publicvoiddoGet(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{//让用户退出登录request.getSession().invalidate();//删除cookieCookie cookie =newCookie("autoLogin","");/**

* 0表示删除文件和缓存

* -1表示删除文件,但是还有缓存

*/cookie.setMaxAge(0);cookie.setPath("/");response.addCookie(cookie);response.sendRedirect(request.getContextPath() +"/login.jsp");}

publicvoiddoPost(HttpServletRequest request, HttpServletResponse response)throwsServletException, IOException{/*

* 让用户登录成功

*/String username = request.getParameter("username");if(username ==null|| username.length() ==0){request.setAttribute("msg","用户名不能为空!");request.getRequestDispatcher("/login.jsp").forward(request, response);return;}intday =0;String auto = request.getParameter("day");try{day = Integer.parseInt(auto);}catch(Exception e) {}//对中文要进行编码Cookie cookie =newCookie("autoLogin", URLEncoder.encode(username, request.getCharacterEncoding()));cookie.setMaxAge(day*24*3600);cookie.setPath("/");response.addCookie(cookie);request.getSession().setAttribute("user", username);response.sendRedirect(request.getContextPath() +"/page/index.jsp");}}

DemoServlet/servlet/DemoServletLoginServlet/login

第三步:开发自动登录过滤器

packagecn.zq.filter;

importjava.io.IOException;

importjava.net.URLDecoder;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.Cookie;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpSession;

publicclassAutoLoginFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID =5891858915933022714L;

@OverridepublicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{/*

* 优化:当用户手动登录或退出时,就不需要自动登录,

* 并且用户已经登录,也不需要自动登录,自动登录的代码是

* 多此一举

*/HttpSession session = request.getSession();String requestURI = request.getRequestURI();Object user = session.getAttribute("user");if(!requestURI.contains("/login") && user ==null){//获取cookieCookie[] cookies = request.getCookies();if(cookies !=null){for(Cookie c : cookies){if("autoLogin".equals(c.getName())){String username = c.getValue();username = URLDecoder.decode(username, request.getCharacterEncoding());session.setAttribute("user", username);break;}}}}chain.doFilter(request, response);}}

AutoLoginFiltercn.zq.filter.AutoLoginFilterAutoLoginFilter/*

3.6、过滤非法语句(脏话)

在过滤器中,包装HttpServletRequest,修改getParameter方法

packagecn.zq.filter;

importjava.io.IOException;

importjava.util.Arrays;

importjava.util.List;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletRequestWrapper;

importjavax.servlet.http.HttpServletResponse;

publicclassDirtyWordsFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID = -5025789414017693051L;

publicvoiddoFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{request =newMyHttpServletRequest(request);chain.doFilter(request, response);}}

class

MyHttpServletRequestextendsHttpServletRequestWrapper{List dirtyWords = Arrays.asList(newString[]{"SB","sb","傻B","2B"});publicMyHttpServletRequest(HttpServletRequest request){

           super(request);}publicStringgetParameter(String name){String value =super.getParameter(name);if(value !=null&& value.length() >0){for(String dw : dirtyWords){value = value.replaceAll(dw,"***");}}returnvalue;}}

3.7、全站压缩

实现对输出流的压缩:

在tomcat将数据输出到浏览器前,进行压缩,可以减少传送过去的数据,节约成本。如果在流量很少的情况下查看相同的内容和乐而不为呢?

思路:

在调用request.getOutputStream()或request.getWriter()时获取自己的输出流,将数据写到事先准备的缓冲中。

在输出完成后获取我们自己的缓冲数据

然后在对缓冲的数据进行压缩,在过滤器中将数据传输给浏览器

第一步:编写压缩数据的过滤器

packagecn.zq.filter;

importjava.io.ByteArrayOutputStream;

importjava.io.IOException;

importjava.io.OutputStreamWriter;

importjava.io.PrintWriter;

importjava.util.zip.GZIPOutputStream;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.ServletOutputStream;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpServletResponseWrapper;

publicclassGzipFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID =3410826595861585118L;publicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{String ac = request.getHeader("Accept-Encoding");//支持gzip压缩if(ac !=null&& ac.toLowerCase().indexOf("gzip") != -1){BufferedHttpServletResponse bRes =newBufferedHttpServletResponse(response);chain.doFilter(request, bRes);byte[] data = bRes.getData();System.out.println("->压缩前数据大小:"+ data.length);ByteArrayOutputStream bos =newByteArrayOutputStream();GZIPOutputStream gout =newGZIPOutputStream(bos);gout.write(data);gout.close();byte[] compressedData = bos.toByteArray();System.out.println("->压缩后的数据大小:"+compressedData.length);//设置头信息response.setContentLength(compressedData.length);response.setHeader("Content-Encoding","gzip");ServletOutputStream out = response.getOutputStream();out.write(compressedData);}else{chain.doFilter(request, response);}}}

classBufferedHttpServletResponseextendsHttpServletResponseWrapper{privateByteArrayOutputStream buf =newByteArrayOutputStream();

       privatePrintWriter pw;

publicBufferedHttpServletResponse(HttpServletResponse response){

super(response);}publicPrintWritergetWriter()throwsIOException{    pw =newPrintWriter(newOutputStreamWriter(buf, getResponse().getCharacterEncoding()));returnpw;}

publicServletOutputStreamgetOutputStream()throwsIOException{ServletOutputStream sos =newServletOutputStream() {publicvoidwrite(intb)throwsIOException{buf.write(b);}};returnsos;}

publicbyte[] getData(){if(pw !=null){pw.close();}returnbuf.toByteArray();}}

第二步:配置对所有的jsp进行压缩

GzipFiltercn.zq.filter.GzipFilterGzipFilterDemoServlet*.jsp

第三步:测试压缩过滤器

使用压缩过滤器应该注意:应该只用这个压缩过滤器对文本进行压缩,例如jsp,html,css,js等进行压缩,对视频和图片的压缩率很低,不要用来压缩视频和图片,如果是下载,那也不应该用来压缩,这样不但压缩率很低,而且还有可能让服务器奔溃。

关于压缩过滤器的优化:

在doFilter方法中先将数据拿出来,然后放到GzipOutputStream中进行压缩,然后得到压缩后的字节再输出给客户端,这样2次都得到了字节,假如数据量较大,这2次都会占用较多的内存,能不能从包装的response拿出来时直接就是压缩过后的数据呢?改造后的代码如下:

packagecn.zq.filter;

importjava.io.ByteArrayOutputStream;

importjava.io.IOException;

importjava.io.OutputStreamWriter;

importjava.io.PrintWriter;

importjava.util.zip.GZIPOutputStream;

importjavax.servlet.FilterChain;

importjavax.servlet.ServletException;

importjavax.servlet.ServletOutputStream;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.servlet.http.HttpServletResponseWrapper;

publicclassGzipFilterextendsHttpFilter{

privatestaticfinallongserialVersionUID =3410826595861585118L;publicvoiddoFilter(HttpServletRequest request,

HttpServletResponse response, FilterChain chain)throwsIOException, ServletException{String ac = request.getHeader("Accept-Encoding");//支持gzip压缩if(ac !=null&& ac.toLowerCase().indexOf("gzip") != -1){BufferedHttpServletResponse bRes =newBufferedHttpServletResponse(response);chain.doFilter(request, bRes);byte[] compressedData = bRes.getData();//设置头信息response.setContentLength(compressedData.length);response.setHeader("Content-Encoding","gzip");ServletOutputStream out = response.getOutputStream();out.write(compressedData);}else{chain.doFilter(request, response);}}}

classBufferedHttpServletResponseextendsHttpServletResponseWrapper{privateByteArrayOutputStream buf =newByteArrayOutputStream();

       privateGZIPOutputStream gout;

privatePrintWriter pw;

publicBufferedHttpServletResponse(HttpServletResponse response)throwsIOException{super(response);gout =newGZIPOutputStream(buf);}publicPrintWritergetWriter()throwsIOException{    pw =newPrintWriter(newOutputStreamWriter(gout, getResponse().getCharacterEncoding()));returnpw;}

publicServletOutputStreamgetOutputStream()throwsIOException{ServletOutputStream sos =newServletOutputStream() {publicvoidwrite(intb)throwsIOException{gout.write(b);}};returnsos;}

publicbyte[] getData()throwsIOException{if(pw !=null){pw.close();}gout.close();returnbuf.toByteArray();}}

4.总结

利用Filter能对请求和响应进行预处理,在到达目标组件之前,对强求进行处理,诸如:对请求头和响应头进行处理。充分的利用了包装器设计模式,对request或response进行包装,对其方法进行增强。假如我们拒绝某个请求,就可以写一个过滤器对不希望的请求不放行,即不执行chain.doFilter(request, response)方法,过滤器能帮助我们干很多的事情。

作者:RiccioZhang

出处:https://blog.csdn.net/ricciozhang/article/details/43833401

源网络,版权归原创者所有。如有侵权烦请告知,我们会立即删除并表示歉意。


更多技术,欢迎关注下方公众号

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容