J2EE进阶之过滤器Filter 二十一

过滤器Filter

一、过滤器是什么?有什么用?

过滤器是什么?

  过滤器是一个可以对请求相应进行拦截的程序。

作用:

  拦截一些信息,比如请求参数有相关不符合请求的。。。

二、过滤器的编码步骤

新建类,实现filter接口,会有三个为实现的方法,destroy,init,doFilter。在doFilter中编写逻辑。之后利用chain.doFilter(request,response)方法放行。
xml中配置过滤器。

写个demo测试下:

Filter

public class FilterDemo1 implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("初始化了");
    }
    //针对过滤范围内的资源的每次访问都会执行该方法,由服务器调用
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("FilterDemo1执行前");
        chain.doFilter(request, response);//放行。让下一个执行
        System.out.println("FilterDemo1执行后");
    }

    public void destroy() {
        System.out.println("销毁了");
    }

}

再写一个Servlet

public class ServletDemo1 extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        System.out.println("ServletDemo1执行了");
    }

配置xml文件

  <filter>
    <filter-name>FilterDemo1</filter-name>
    <filter-class>wsj.filter1.FilterDemo1</filter-class>
  </filter>
  <filter-mapping>
  <!-- 过滤器过滤资源 -->
    <filter-name>FilterDemo1</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

打印输出:

总结:
你会发现在运行Servlet之前走了一遍过滤器,然后Servlet之后再次走了一遍过滤器。。注意:再次走过滤器是走了chain.doFilter(request, response);之后的代码。

三、过滤器的执行过程(生命周期)

生命周期

诞生:应用加载时(服务器开启时)就完成实例化,并由服务器调用init初始化方法。

走的Filter的init方法

活着:应用活着他就活着
死亡:应用被卸载时,就死亡,并由服务器调用destory方法。
走Destory方法:

在控制台输入指令:

然后代码就会走销毁方法:

四、串联过滤器

串联过滤器是指多个过滤器多个过滤器多某些资源进行过滤。编写多个过滤器,在xml文件中配置多个过滤器。执行顺序是先配置的过滤器先执行

写个demo2

public class FilterDemo2 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        System.out.println("FilterDemo2执行前");
        chain.doFilter(request, response);//放行。让下一个执行
        System.out.println("FilterDemo2执行后");

    }

整个过程:

五、过滤器的简单案例:

1解决全站中文乱码问题。除了GET请求方式

public class SetCharacterEncodingFilter 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 {
        //参数不存在,返回null
        String encoding = filterConfig.getInitParameter("encoding");
        //给出默认编码
        if(encoding == null){
            encoding = "UTF-8";
        }

        request.setCharacterEncoding(encoding);//解决POST请求参数的中文编码
        response.setCharacterEncoding(encoding);//更改输出字符流的编码
        response.setContentType("text/html;charset="+encoding);//告知客户端使用字符编码
        chain.doFilter(request, response);
    }

    public void destroy() {

    }

}

xml配置

  <filter>
    <!--  POST请求和响应的编码过滤器 -->
    <filter-name>SetCharacterEncodingFilter</filter-name>
    <filter-class>com.itheima.filter.SetCharacterEncodingFilter</filter-class>
    <!-- 过滤器参数配置 -->
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>SetCharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

分别控制html、css、js的静态资源的缓存时间

public class StaticResourcesNeedCacheFilter implements Filter {

    private FilterConfig filterConfig;

    public void init(FilterConfig filterConfig) throws ServletException {
        this.filterConfig = filterConfig;
    }

    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }
        long time = 0;//缓存时间的偏移量

        //根据用户访问的资源,获取参数的值,从而设置缓存的时间
        String uri = request.getRequestURI();//   
        String resourceType = uri.substring(uri.lastIndexOf(".")+1);//   html

//      if("html".equals(resourceType)){
//          String value = filterConfig.getInitParameter("html");//得到配置的html的缓存时间,单位是小时
//          time = Long.parseLong(value)*60*60*1000;
//      }
//      
//      if("css".equals(resourceType)){
//          String value = filterConfig.getInitParameter("css");//得到配置的html的缓存时间,单位是小时
//          time = Long.parseLong(value)*60*60*1000;
//      }
//      if("js".equals(resourceType)){
//          String value = filterConfig.getInitParameter("js");//得到配置的html的缓存时间,单位是小时
//          time = Long.parseLong(value)*60*60*1000;
//      }

        String value = filterConfig.getInitParameter(resourceType);
        if(value!=null){
            time = Long.parseLong(value)*60*60*1000;
        }

        response.setDateHeader("Expires", System.currentTimeMillis()+time);
        chain.doFilter(request, response);
    }

    public void destroy() {

    }

}

xml配置

  <!-- 控制静态资源的缓存时间 -->
  <filter>
    <filter-name>StaticResourcesNeedCacheFilter</filter-name>
    <filter-class>com.itheima.filter.StaticResourcesNeedCacheFilter</filter-class>
    <init-param>
        <param-name>html</param-name>
        <param-value>1</param-value><!-- 单位是小时 -->
    </init-param>
    <init-param>
        <param-name>css</param-name>
        <param-value>2</param-value><!-- 单位是小时 -->
    </init-param>
    <init-param>
        <param-name>js</param-name>
        <param-value>3</param-value><!-- 单位是小时 -->
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>StaticResourcesNeedCacheFilter</filter-name>
    <url-pattern>*.html</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>StaticResourcesNeedCacheFilter</filter-name>
    <url-pattern>*.js</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>StaticResourcesNeedCacheFilter</filter-name>
    <url-pattern>*.css</url-pattern>
  </filter-mapping>

不缓存

public class DynamicResourcesNoCacheFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request;
        HttpServletResponse response;
        try{
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)resp;
        }catch(Exception e){
            throw new RuntimeException("non-http request or response");
        }

        response.setHeader("Expires", "-1");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Pragma", "no-cache");
        chain.doFilter(request, response);
    }

    public void destroy() {

    }

}

xml配置

  <!-- 控制动态资源不要缓存 -->
  <filter>
    <filter-name>DynamicResourcesNoCacheFilter</filter-name>
    <filter-class>com.itheima.filter.DynamicResourcesNoCacheFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>DynamicResourcesNoCacheFilter</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>DynamicResourcesNoCacheFilter</filter-name>
    <url-pattern>/servlet/*</url-pattern>
  </filter-mapping>

六、过滤器的高级配置

REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。

INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。

FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。

ERROR:

以上都会出现不会过滤的情况

设置方式:

  <filter-mapping>
    <filter-name>FilterDemo1</filter-name>
    <url-pattern>/*</url-pattern>
    <!-- 如果一个dispatcher都不写:默认是REQUEST -->
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
  </filter-mapping>

Gzip压缩

  1 import java.io.ByteArrayOutputStream;
  2 import java.io.IOException;
  3 import java.io.OutputStreamWriter;
  4 import java.io.PrintWriter;
  5 import java.util.zip.GZIPOutputStream;
  6 
  7 import javax.servlet.Filter;
  8 import javax.servlet.FilterChain;
  9 import javax.servlet.FilterConfig;
 10 import javax.servlet.ServletException;
 11 import javax.servlet.ServletOutputStream;
 12 import javax.servlet.ServletRequest;
 13 import javax.servlet.ServletResponse;
 14 import javax.servlet.http.HttpServletRequest;
 15 import javax.servlet.http.HttpServletResponse;
 16 import javax.servlet.http.HttpServletResponseWrapper;
 17 
 18 public class GzipFilter implements Filter {
 19 
 20     public void init(FilterConfig filterConfig) throws ServletException {
 21 
 22     }
 23 
 24     public void doFilter(ServletRequest req, ServletResponse resp,
 25             FilterChain chain) throws IOException, ServletException {
 26         HttpServletRequest request;
 27         HttpServletResponse response;
 28 
 29         try {
 30             request = (HttpServletRequest) req;
 31             response = (HttpServletResponse) resp;
 32         } catch (ClassCastException e) {
 33             throw new ServletException("non-HTTP request or response");
 34         }
 35 
 36         GzipHttpServletResponse mresponse = new GzipHttpServletResponse(response);
 37         chain.doFilter(request, mresponse);
 38         //在此处完成压缩
 39         byte b[] =mresponse.getBytes();//得到原来要输出的数据是关键
 40         System.out.println("数据原来大小:"+b.length);
 41         
 42         ByteArrayOutputStream baos = new ByteArrayOutputStream();// 带有缓存的字节内存输出流
 43         GZIPOutputStream gout = new GZIPOutputStream(baos);
 44         gout.write(b);
 45         gout.close();//数据用gzip压缩到了baos中
 46         
 47         b = baos.toByteArray();//取出的压缩后的字节
 48         System.out.println("数据压缩后的大小:"+b.length);
 49         
 50         //告知客户端编码方式
 51         response.setHeader("Content-Encoding", "gzip");
 52         response.setContentLength(b.length);//告知正文的长度
 53         
 54         ServletOutputStream sos = response.getOutputStream();
 55         sos.write(b);
 56         
 57     }
 58 
 59     public void destroy() {
 60 
 61     }
 62 
 63 }
 64 class GzipHttpServletResponse extends HttpServletResponseWrapper{
 65     private ByteArrayOutputStream baos = new ByteArrayOutputStream();//临时仓库,存放截获的原始数据
 66     private PrintWriter pw;
 67     public GzipHttpServletResponse(HttpServletResponse response){
 68         super(response);
 69     }
 70     //截获原来的数据:字节流
 71     public ServletOutputStream getOutputStream() throws IOException {
 72         return new MyServletOutputStream(baos);
 73     }
 74     //截获原来的数据:字符流
 75     public PrintWriter getWriter() throws IOException {
 76         pw = new PrintWriter(new OutputStreamWriter(baos, super.getCharacterEncoding()));//字符流--->字节流:查码表。
 77         return pw;
 78     }
 79     //返回原始的数据
 80     public byte[] getBytes(){
 81         try {
 82             if(pw!=null){
 83                 pw.close();
 84             }
 85             baos.flush();
 86         } catch (IOException e) {
 87             e.printStackTrace();
 88         }
 89         return baos.toByteArray();
 90     }
 91 }
 92 class MyServletOutputStream extends ServletOutputStream{
 93     private ByteArrayOutputStream baos;
 94     public MyServletOutputStream(ByteArrayOutputStream baos){
 95         this.baos = baos;
 96     }
 97     public void write(int b) throws IOException {
 98         baos.write(b);
 99     }
100     
101 }

压缩结果:

猜你喜欢

转载自blog.csdn.net/onceing/article/details/77754572