分享

java filter 应用介绍

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

一、批量设置请求编码

Java代码 复制代码
  1. public class EncodingFilter implements Filter {   
  2.   
  3.     private String encoding = null;   
  4.   
  5.     public void destroy() {   
  6.         encoding = null;   
  7.     }   
  8.   
  9.     public void doFilter(ServletRequest request, ServletResponse response,   
  10.             FilterChain chain) throws IOException, ServletException {   
  11.         String encoding = getEncoding();   
  12.         if (encoding == null){   
  13.             encoding = "gb2312";   
  14.         }   
  15.         request.setCharacterEncoding(encoding);// 在请求里设置上指定的编码   
  16.         chain.doFilter(request, response);   
  17.     }   
  18.   
  19.     public void init(FilterConfig filterConfig) throws ServletException {   
  20.         this.encoding = filterConfig.getInitParameter("encoding");   
  21.     }   
  22.   
  23.     private String getEncoding() {   
  24.         return this.encoding;   
  25.     }   
  26.   
  27. }  

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.   
  10. <filter-mapping>  
  11.    <filter-name>EncodingFilter</filter-name>  
  12.    <url-pattern>/*</url-pattern>  
  13. </filter-mapping>  

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

Java代码 复制代码
  1. public void doFilter(ServletRequest request,   
  2.         ServletResponse response,   
  3.         FilterChain chain)   
  4.         throws IOException, ServletException {   
  5.   
  6.     HttpServletRequest req = (HttpServletRequest) request;   
  7.     HttpServletResponse res = (HttpServletResponse) response;   
  8.   
  9.     HttpSession session = req.getSession();   
  10.     if (session.getAttribute("username") != null) {//登录后才能访问   
  11.         chain.doFilter(request, response);   
  12.     } else {   
  13.         res.sendRedirect("../failure.jsp");   
  14.     }   
  15. }  


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 : To use gzip compression you could set the following properties :   
  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.  * This class is used for wrapped response for getting cached data.  
  5.  */    
  6. class CachedResponseWrapper extends HttpServletResponseWrapper {   
  7.   
  8.     /**  
  9.      * Indicate that getOutputStream() or getWriter() is not called yet.  
  10.      */  
  11.     public static final int OUTPUT_NONE = 0;   
  12.   
  13.     /**  
  14.      * Indicate that getWriter() is already called.  
  15.      */  
  16.     public static final int OUTPUT_WRITER = 1;   
  17.   
  18.     /**  
  19.      * Indicate that getOutputStream() is already called.  
  20.      */  
  21.     public static final int OUTPUT_STREAM = 2;   
  22.   
  23.     private int outputType = OUTPUT_NONE;   
  24.   
  25.     private int status = SC_OK;   
  26.   
  27.     private ServletOutputStream output = null;   
  28.   
  29.     private PrintWriter writer = null;   
  30.   
  31.     private ByteArrayOutputStream buffer = null;   
  32.   
  33.     public CachedResponseWrapper(HttpServletResponse resp) throws IOException {   
  34.         super(resp);   
  35.         buffer = new ByteArrayOutputStream();   
  36.     }   
  37.   
  38.     public int getStatus() {   
  39.         return status;   
  40.     }   
  41.   
  42.     public void setStatus(int status) {   
  43.         super.setStatus(status);   
  44.         this.status = status;   
  45.     }   
  46.   
  47.     public void setStatus(int status, String string) {   
  48.         super.setStatus(status, string);   
  49.         this.status = status;   
  50.     }   
  51.   
  52.     public void sendError(int status, String string) throws IOException {   
  53.         super.sendError(status, string);   
  54.         this.status = status;   
  55.     }   
  56.   
  57.     public void sendError(int status) throws IOException {   
  58.         super.sendError(status);   
  59.         this.status = status;   
  60.     }   
  61.   
  62.     public void sendRedirect(String location) throws IOException {   
  63.         super.sendRedirect(location);   
  64.         this.status = SC_MOVED_TEMPORARILY;   
  65.     }   
  66.   
  67.     public PrintWriter getWriter() throws IOException {   
  68.         if (outputType == OUTPUT_STREAM)   
  69.             throw new IllegalStateException();   
  70.         else if (outputType == OUTPUT_WRITER)   
  71.             return writer;   
  72.         else {   
  73.             outputType = OUTPUT_WRITER;   
  74.             writer = new PrintWriter(new OutputStreamWriter(buffer,   
  75.                     getCharacterEncoding()));   
  76.             return writer;   
  77.         }   
  78.     }   
  79.   
  80.     public ServletOutputStream getOutputStream() throws IOException {   
  81.         if (outputType == OUTPUT_WRITER)   
  82.             throw new IllegalStateException();   
  83.         else if (outputType == OUTPUT_STREAM)   
  84.             return output;   
  85.         else {   
  86.             outputType = OUTPUT_STREAM;   
  87.             output = new WrappedOutputStream(buffer);   
  88.             return output;   
  89.         }   
  90.     }   
  91.   
  92.     public void flushBuffer() throws IOException {   
  93.         if (outputType == OUTPUT_WRITER)   
  94.             writer.flush();   
  95.         if (outputType == OUTPUT_STREAM)   
  96.             output.flush();   
  97.     }   
  98.   
  99.     public void reset() {   
  100.         outputType = OUTPUT_NONE;   
  101.         buffer.reset();   
  102.     }   
  103.   
  104.     /**  
  105.      * Call this method to get cached response data.  
  106.      *   
  107.      * @return byte array buffer.  
  108.      * @throws IOException  
  109.      */  
  110.     public byte[] getResponseData() throws IOException {   
  111.         flushBuffer();   
  112.         return buffer.toByteArray();   
  113.     }   
  114.   
  115.     /**  
  116.      * This class is used to wrap a ServletOutputStream and store output stream  
  117.      * in byte[] buffer.  
  118.      */  
  119.     class WrappedOutputStream extends ServletOutputStream {   
  120.   
  121.         private ByteArrayOutputStream buffer;   
  122.   
  123.         public WrappedOutputStream(ByteArrayOutputStream buffer) {   
  124.             this.buffer = buffer;   
  125.         }   
  126.   
  127.         public void write(int b) throws IOException {   
  128.             buffer.write(b);   
  129.         }   
  130.   
  131.         public byte[] toByteArray() {   
  132.             return buffer.toByteArray();   
  133.         }   
  134.     }   
  135.   
  136. }  

(2).GZipFilter类
Java代码 复制代码
  1. public class GZipFilter implements Filter {   
  2.     public void init(FilterConfig arg0) throws ServletException {   
  3.     }   
  4.   
  5.     public void doFilter(ServletRequest request, ServletResponse response,   
  6.             FilterChain chain) throws IOException, ServletException {   
  7.   
  8.         HttpServletResponse httpResponse = (HttpServletResponse) response;   
  9.         CachedResponseWrapper wrapper = new CachedResponseWrapper(httpResponse);   
  10.         // 写入wrapper:   
  11.         chain.doFilter(request, wrapper);   
  12.         // 对响应进行处理,这里是进行GZip压缩:   
  13.         byte[] data = GZipUtil.gzip(wrapper.getResponseData());   
  14.         httpResponse.setHeader("Content-Encoding""gzip");   
  15.         httpResponse.setContentLength(data.length);   
  16.         ServletOutputStream output = response.getOutputStream();   
  17.         output.write(data);   
  18.         output.flush();   
  19.     }   
  20.   
  21.     public void destroy() {   
  22.   
  23.     }   
  24.   
  25. }  

(3).GZipUtil类
Java代码 复制代码
  1. public final class GZipUtil {   
  2.     /** * Do a gzip operation. */  
  3.     public static byte[] gzip(byte[] data) {   
  4.         ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(10240);   
  5.         GZIPOutputStream output = null;   
  6.         try {   
  7.             output = new GZIPOutputStream(byteOutput);   
  8.             output.write(data);   
  9.         } catch (IOException e) {   
  10.             throw new RuntimeException("G-Zip failed.", e);   
  11.         } finally {   
  12.             if (output != null) {   
  13.                 try {   
  14.                     output.close();   
  15.                 } catch (IOException e) {   
  16.                 }   
  17.             }   
  18.         }   
  19.         return byteOutput.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>  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多