4.0过滤器和监听器——filter和filter链

本文深入讲解Java Web中的Filter机制,包括Filter的基本概念、工作原理、配置方法及多种应用场景。介绍了如何通过Filter实现请求预处理与后处理,以及如何配置Filter链来对多个Filter进行有序调用。

JAVAWEB学习文章索引点这里
1.Filter介绍
Filter被称作过滤器或拦截器,其基本功能就是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet进行响应处理前后实现一些特殊功能。
filter拦截过程
Filter接口中的方法

init(FilterConfig filterConfig)用于初始化过滤器,由服务器开启时自动调用一次。如果要使用filterConfig对象就该在本方法中使用。
doFilter(ServletRequest request, ServletResponse response, FilterChain chain)request和response是web服务器或上一个filter传过来的请求和响应对象。chain代表当前filter链的对象,它可以调用doFilter(),把请求交给下一个filter或目标程序
destoro()该方法在web服务器卸载filter对象之前被调用,该方法用于释放被filter对象打开的资源,如关闭数据库或者io流

下面演示一下filter
servlet:

package com.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/MyServlet")
public class MyServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("正在访问servlet");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

filter:

package com.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter("/MyServlet")
public class MyFilter implements Filter {

    public void destroy() {
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("正在访问filter");
        //chain.doFilter(request, response);
    }
    public void init(FilterConfig fConfig) throws ServletException {
    }
}

然后打开浏览器,输入servlet的访问路径,控制台的内容为”正在访问filter”,因为使用注解配置的filter和servlet的虚拟路径是相同的,所以在访问后被过滤器拦截住了。如果要放行就使用chain.doFilter(request, response)方法就会继续执行,访问到servlet。

使用配置文件配置filter
在可以使用注解之前,一般在要使用filter的时候都需要在web.xml中进行配置。

  <filter>
    <filter-name>myfilter</filter-name>
    <filter-class>com.filter.MyFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>myfilter</filter-name>
    <url-pattern>/MyServlet</url-pattern>
  </filter-mapping>

配置方式和道理和servlet相似,不同的地方在于,这里的url地方填的是需要被过滤的servlet的虚拟路径,而不是访问filter的路径。当我们直接访问servlet的时候,就会被拦截住。
映射路径的模糊配置
上面我们使用的配置方式是一种准确的配置方式,直接指定了需要过滤的路径。
不过可以过滤的也不只是servlet,也可是是html文件。
如果要配置很多路径的话就可以使用模糊配置:

<url-pattern>/*</url-pattern>:拦截所有的内容
<url-pattern>/test/*</url-pattern>:拦截test路径下的所有内容
<url-pattern>*.do</url-pattern>:拦截所有的以.do结尾的路径

特别注意!!!用.do,.action的时候前面别加/,匹配不会成功,并且高版本tomcat还会启动报错!

拦截不同访问方式的访问访问请求
有四种方式,默认为REQUEST
REQUEST:直接访问页面的时候,会被过滤。如果是通过RequestDispatcher的include()或forward()方法访问的时,过滤器不会被调用。
INCLUDE:通过RequestDispatcher的include()时,可以过滤。其他方式不会
FORWARD:通过RequestDispatcher的forward()访问时,可以过滤,其他方式不会。
ERROR:如果目标资源是通过声明式异常处理机制调用的时候,过滤器会被调用,其他的方式不会。
下面,以REQUEST和FORWARD举例,编写以下页面
1,test.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
test1.jsp
</body>
</html>

2,它的过滤器

package com.filter;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;

@WebFilter(urlPatterns="/test1.jsp")
public class TestFilter1 implements Filter {

    public void destroy() {
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("被拦截了");
        //chain.doFilter(request, response);
    }
    public void init(FilterConfig fConfig) throws ServletException {
    }

}

3,一个进行转发的servelt

package com.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/TestServlet1")
public class TestServlet1 extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //转发到test1.jsp
        request.getRequestDispatcher("/test1.jsp").forward(request, response);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

然后我们直接访问servlet,其将转发到test1.jsp。显示结果为”test1.jsp”,也就是说拦截器没有被调用。
然后我们修改过滤器的注解如下(将访问方式改为FORWARD)

@WebFilter(urlPatterns="/test1.jsp",dispatcherTypes= {DispatcherType.FORWARD})

然后在访问servlet,最后页面结果是“被拦截了”。

filter链
filter链
不同的过滤器可以作用于同一个servlet。它们的作用顺序按照它们在servlet中的配置顺序,先配置的优先进行过滤。
这里我们采用注解的方式访问:
filter

package com.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter(filterName="b",urlPatterns="/MyServlet")
public class MyFilter implements Filter {
    public void destroy() {
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("正在访问filter:before");
        chain.doFilter(request, response);
        System.out.println("正在访问filter:after");
    }
    public void init(FilterConfig fConfig) throws ServletException {
    }
}

filter2

package com.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter(filterName="a",urlPatterns="/MyServlet")
public class MyFilter2 implements Filter {

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("正在访问filter2:before");
        chain.doFilter(request, response);
        System.out.println("正在访问filter2:after");
    }

    public void init(FilterConfig fConfig) throws ServletException {

    }

}

filter3

package com.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

@WebFilter(filterName="c",urlPatterns="/MyServlet")
public class AMyFilter implements Filter {

    public void destroy() {
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("正在访问filter3:before");
        chain.doFilter(request, response);
        System.out.println("正在访问filter3:after");
    }
    public void init(FilterConfig fConfig) throws ServletException {
    }

}

然后打开浏览器,访问前面介绍到的MyServlet这个Servlet。结果如下
正在访问filter3:before
正在访问filter:before
正在访问filter2:before
正在访问servlet
正在访问filter2:after
正在访问filter:after
正在访问filter3:after
在注解中,我分别将filter的名字设置为a、b、c可以看到名字并没有影响到filter的访问顺序,影响到访问顺序的是它们类名(AMyFilter、MyFilter、MyFilter2)
并且,请求和响应都以chain.doFilter(request, response)来进行分隔,该方法以前的内容在请求的时候执行,该方法以后的内容在响应的时候执行。
FilterConfig
FilterConfig主要用于获取配置信息,示例如下。这里使用注解进行配置。

package com.filter;

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;

@WebFilter(filterName="FilterConfigTest", urlPatterns="/test2.jsp",
            initParams={@WebInitParam(name="a",value="1"),
                        @WebInitParam(name="b",value="2")
                        })
public class FilterConfigTest implements Filter {
    FilterConfig fc = null;
    public void destroy() {
    }
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //输出过滤器名称
        System.out.println(fc.getFilterName());
        //输出上下文路径
        System.out.println(fc.getServletContext().getContextPath());
        //获取初始化参数a的值
        System.out.println(fc.getInitParameter("a"));
        chain.doFilter(request, response);
    }
    public void init(FilterConfig fConfig) throws ServletException {
        fc = fConfig;
    }

}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值