`
thecloud
  • 浏览: 871977 次
文章分类
社区版块
存档分类
最新评论

filter结合gzip 解决web应用中网络传输数据量大的问题

 
阅读更多

过滤器Filter也具有生命周期:init()->doFilter()->destroy(),由部署文件中的filter元素驱动。在servlet2.4中,过滤器同样可以用于请求分派器,但须在web.xml中声明,<dispatcher>INCLUDE或FORWARD或REQUEST或ERROR</dispatcher>该元素位于filter-mapping中。

一、批量设置请求编码

Java代码
  1. publicclassEncodingFilterimplementsFilter{
  2. privateStringencoding=null;
  3. publicvoiddestroy(){
  4. encoding=null;
  5. }
  6. publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
  7. FilterChainchain)throwsIOException,ServletException{
  8. Stringencoding=getEncoding();
  9. if(encoding==null){
  10. encoding="gb2312";
  11. }
  12. request.setCharacterEncoding(encoding);//在请求里设置上指定的编码
  13. chain.doFilter(request,response);
  14. }
  15. publicvoidinit(FilterConfigfilterConfig)throwsServletException{
  16. this.encoding=filterConfig.getInitParameter("encoding");
  17. }
  18. privateStringgetEncoding(){
  19. returnthis.encoding;
  20. }
  21. }

Xml代码
  1. <filter>
  2. <filter-name>EncodingFilter</filter-name>
  3. <filter-class>com.logcd.filter.EncodingFilter</filter-class>
  4. <init-param>
  5. <param-name>encoding</param-name>
  6. <param-value>gb2312</param-value>
  7. </init-param>
  8. </filter>
  9. <filter-mapping>
  10. <filter-name>EncodingFilter</filter-name>
  11. <url-pattern>/*</url-pattern>
  12. </filter-mapping>

二、用filter控制用户访问权限

Java代码
  1. publicvoiddoFilter(ServletRequestrequest,
  2. ServletResponseresponse,
  3. FilterChainchain)
  4. throwsIOException,ServletException{
  5. HttpServletRequestreq=(HttpServletRequest)request;
  6. HttpServletResponseres=(HttpServletResponse)response;
  7. HttpSessionsession=req.getSession();
  8. if(session.getAttribute("username")!=null){//登录后才能访问
  9. chain.doFilter(request,response);
  10. }else{
  11. res.sendRedirect("../failure.jsp");
  12. }
  13. }


Xml代码
  1. <filter>
  2. <filter-name>SecurityFilter</filter-name>
  3. <filter-class>com.logcd.filter.SecurityFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>SecurityFilter</filter-name>
  7. <url-pattern>/admin/*</url-pattern>
  8. </filter-mapping>

三、过滤链

两个过滤器,EncodingFilter负责设置编码,SecurityFilter负责控制权限,服务器会按照web.xml中过滤器定义的先后循序组装成一条链,然后一次执行其中的doFilter()方法。执行的顺序就如上图所示,执行第一个过滤器的chain.doFilter()之前的代码,第二个过滤器的chain.doFilter()之前的代码,请求的资源,第二个过滤器的chain.doFilter()之后的代码,第一个过滤器的chain.doFilter()之后的代码,最后返回响应。
执行的代码顺序是:

  1. 执行EncodingFilter.doFilter()中chain.doFilter()之前的部分:request.setCharacterEncoding("gb2312");
  2. 执行SecurityFilter.doFilter()中chain.doFilter()之前的部分:判断用户是否已登录。
  3. 如果用户已登录,则访问请求的资源:/admin/index.jsp。
  4. 如果用户未登录,则页面重定向到:/failure.jsp。
  5. 执行SecurityFilter.doFilter()中chain.doFilter()之后的部分:这里没有代码。
  6. 执行EncodingFilter.doFilter()中chain.doFilter()之后的部分:这里也没有代码。

过滤链的好处是,执行过程中任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容。而在实际使用时,就要特别注意过滤链的执行顺序问题,像EncodingFilter就一定要放在所有Filter之前,这样才能确保在使用请求中的数据前设置正确的编码。

四、使用filter,结合gzip 压缩技术,解决web应用中网络传输数据量大的问题
gzip是http协议中使用的一种加密算法,客户端向web服务器端发出了请求后,通常情况下服务器端会将页面文件和其他资源,返回到客户端,客户端加载后渲染呈现,这种情况文件一般都比较大,如果开启Gzip ,那么服务器端响应后,会将页面,JS,CSS等文本文件或者其他文件通过高压缩算法将其压缩,然后传输到客户端,由客户端的浏览器负责解压缩与呈现。通常能节省40%以上的流量(一般都有60%左右),一些PHP,JSP文件也能够进行压缩。
1.Tomcat 直接开启Gzip
打开Tomcat 目录下的conf下的server.xml,并找到如下信息:
Xml代码
  1. <!--Note:Tousegzipcompressionyoucouldsetthefollowingproperties:
  2. compression="on"
  3. compressionMinSize="2048"
  4. noCompressionUserAgents="gozilla,traviata"
  5. compressableMimeType="text/html,text/xml"
  6. -->

把它们加入到你配置的<Connector port="80" .../>中去。如果要压缩css 和 js,加入compressableMimeType="text/html,text/xml,text/css,text/javascript"。还要压缩图片,加入compressableMimeType="text/html,text/xml,text/css,text/javascript,image/gif,image/jpg"。
开启后重启Tomcat ,通过浏览器查看headers信息就能看到是否开启。

2.使用filter,在代码级别完成web应用的gzip压缩的开启。

(1).CachedResponseWrapper类
实现定制输出的关键是对HttpServletResponse 进行包装,截获所有的输出,等到过滤器链处理完毕后,再对截获的输出进行处理,并写入到真正的HttpServletResponse 对象中。JavaEE 框架已经定义了一个HttpServletResponseWrapper 类使得包装HttpServletResponse 更加容易。我们扩展这个HttpServletResponseWrapper,截获所有的输出,并保存到ByteArrayOutputStream 中。
定制的包装响应能方便地从帮助类 HttpServletResponseWrapper 中导出。这一类粗略地执行许多方法,允许我们简单地覆盖 getOutputStream() 方法以及 getWriter() 方法,提供了定制输出流的实例。
HttpServletResponseWrapper这个类的使用包括以下五个步骤:
1)建立一个响应包装器。扩展javax.servlet.http.HttpServletResponseWrapper。
2)提供一个缓存输出的PrintWriter。重载getWriter方法,返回一个保存发送给它的所有东西的PrintWriter,并把结果存进一个可以稍后访问的字段中。
3)传递该包装器给doFilter。此调用是合法的,因为HttpServletResponseWrapper实现HttpServletResponse。
4)提取和修改输出。在调用FilterChain的doFilter方法后,原资源的输出只要利用步骤2中提供的机制就可以得到。只要对你的应用适合,就可以修改或替换它。
5)发送修改过的输出到客户机。因为原资源不再发送输出到客户机(这些输出已经存放到你的响应包装器中了),所以必须发送这些输出。这样,你的过滤器需要从原响应对象中获得PrintWriter或OutputStream,并传递修改过的输出到该流中。
Java代码
  1. /**
  2. *Wrapper:在内存中开辟一个ByteOutputStream,然后将拦截的响应写入byte[],
  3. *写入完毕后,再将wrapper的byte[]写入真正的response对象
  4. *Thisclassisusedforwrappedresponseforgettingcacheddata.
  5. */
  6. classCachedResponseWrapperextendsHttpServletResponseWrapper{
  7. /**
  8. *IndicatethatgetOutputStream()orgetWriter()isnotcalledyet.
  9. */
  10. publicstaticfinalintOUTPUT_NONE=0;
  11. /**
  12. *IndicatethatgetWriter()isalreadycalled.
  13. */
  14. publicstaticfinalintOUTPUT_WRITER=1;
  15. /**
  16. *IndicatethatgetOutputStream()isalreadycalled.
  17. */
  18. publicstaticfinalintOUTPUT_STREAM=2;
  19. privateintoutputType=OUTPUT_NONE;
  20. privateintstatus=SC_OK;
  21. privateServletOutputStreamoutput=null;
  22. privatePrintWriterwriter=null;
  23. privateByteArrayOutputStreambuffer=null;
  24. publicCachedResponseWrapper(HttpServletResponseresp)throwsIOException{
  25. super(resp);
  26. buffer=newByteArrayOutputStream();
  27. }
  28. publicintgetStatus(){
  29. returnstatus;
  30. }
  31. publicvoidsetStatus(intstatus){
  32. super.setStatus(status);
  33. this.status=status;
  34. }
  35. publicvoidsetStatus(intstatus,Stringstring){
  36. super.setStatus(status,string);
  37. this.status=status;
  38. }
  39. publicvoidsendError(intstatus,Stringstring)throwsIOException{
  40. super.sendError(status,string);
  41. this.status=status;
  42. }
  43. publicvoidsendError(intstatus)throwsIOException{
  44. super.sendError(status);
  45. this.status=status;
  46. }
  47. publicvoidsendRedirect(Stringlocation)throwsIOException{
  48. super.sendRedirect(location);
  49. this.status=SC_MOVED_TEMPORARILY;
  50. }
  51. publicPrintWritergetWriter()throwsIOException{
  52. if(outputType==OUTPUT_STREAM)
  53. thrownewIllegalStateException();
  54. elseif(outputType==OUTPUT_WRITER)
  55. returnwriter;
  56. else{
  57. outputType=OUTPUT_WRITER;
  58. writer=newPrintWriter(newOutputStreamWriter(buffer,
  59. getCharacterEncoding()));
  60. returnwriter;
  61. }
  62. }
  63. publicServletOutputStreamgetOutputStream()throwsIOException{
  64. if(outputType==OUTPUT_WRITER)
  65. thrownewIllegalStateException();
  66. elseif(outputType==OUTPUT_STREAM)
  67. returnoutput;
  68. else{
  69. outputType=OUTPUT_STREAM;
  70. output=newWrappedOutputStream(buffer);
  71. returnoutput;
  72. }
  73. }
  74. publicvoidflushBuffer()throwsIOException{
  75. if(outputType==OUTPUT_WRITER)
  76. writer.flush();
  77. if(outputType==OUTPUT_STREAM)
  78. output.flush();
  79. }
  80. publicvoidreset(){
  81. outputType=OUTPUT_NONE;
  82. buffer.reset();
  83. }
  84. /**
  85. *Callthismethodtogetcachedresponsedata.
  86. *
  87. *@returnbytearraybuffer.
  88. *@throwsIOException
  89. */
  90. publicbyte[]getResponseData()throwsIOException{
  91. flushBuffer();
  92. returnbuffer.toByteArray();
  93. }
  94. /**
  95. *ThisclassisusedtowrapaServletOutputStreamandstoreoutputstream
  96. *inbyte[]buffer.
  97. */
  98. classWrappedOutputStreamextendsServletOutputStream{
  99. privateByteArrayOutputStreambuffer;
  100. publicWrappedOutputStream(ByteArrayOutputStreambuffer){
  101. this.buffer=buffer;
  102. }
  103. publicvoidwrite(intb)throwsIOException{
  104. buffer.write(b);
  105. }
  106. publicbyte[]toByteArray(){
  107. returnbuffer.toByteArray();
  108. }
  109. }
  110. }

(2).GZipFilter类
Java代码
  1. publicclassGZipFilterimplementsFilter{
  2. publicvoidinit(FilterConfigarg0)throwsServletException{
  3. }
  4. publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,
  5. FilterChainchain)throwsIOException,ServletException{
  6. HttpServletResponsehttpResponse=(HttpServletResponse)response;
  7. CachedResponseWrapperwrapper=newCachedResponseWrapper(httpResponse);
  8. //写入wrapper:
  9. chain.doFilter(request,wrapper);
  10. //对响应进行处理,这里是进行GZip压缩:
  11. byte[]data=GZipUtil.gzip(wrapper.getResponseData());
  12. httpResponse.setHeader("Content-Encoding","gzip");
  13. httpResponse.setContentLength(data.length);
  14. ServletOutputStreamoutput=response.getOutputStream();
  15. output.write(data);
  16. output.flush();
  17. }
  18. publicvoiddestroy(){
  19. }
  20. }

(3).GZipUtil类
Java代码
  1. publicfinalclassGZipUtil{
  2. /***Doagzipoperation.*/
  3. publicstaticbyte[]gzip(byte[]data){
  4. ByteArrayOutputStreambyteOutput=newByteArrayOutputStream(10240);
  5. GZIPOutputStreamoutput=null;
  6. try{
  7. output=newGZIPOutputStream(byteOutput);
  8. output.write(data);
  9. }catch(IOExceptione){
  10. thrownewRuntimeException("G-Zipfailed.",e);
  11. }finally{
  12. if(output!=null){
  13. try{
  14. output.close();
  15. }catch(IOExceptione){
  16. }
  17. }
  18. }
  19. returnbyteOutput.toByteArray();
  20. }
  21. }

(4).在web.xml中配置 GZipFilter
Xml代码
  1. <filter>
  2. <filter-name>GZipFilter</filter-name>
  3. <filter-class>com.logcd.filter.GZipFilter</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>GZipFilter</filter-name>
  7. <url-pattern>*.html</url-pattern>
  8. </filter-mapping>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics