过滤器Filter

过滤器

过滤器, Filter , 也被称作拦截器。 Servlet, Session, Filter 是 Java网站开发的三个最基础的机制。

过滤器的作用:对请求进行过滤处理

过滤器处理的结果:

   1 通过,可以访问目标URL

   2 拒绝,不可以访问目标URL

目标URL可以是一个Servlet,或是一个静态文件 。

  • Filter 是一个interface 。和 Servlet一样, Filter 也是单例的,所有 Filter会在Web 应用启动时初始化。

init()  初始化 

destroy()  退出

doFilter()   在此可以‘拒绝’用户的访问

例  登录才能查看机密文件

package my;

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.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

@WebFilter("/index.html")
public class MyFilter implements Filter
{
	public void init(FilterConfig fConfig) throws ServletException
	{
		// 加载应用时调用 (注:Filter也是单例)
		System.out.println("*** Filter init() ..");
	}

	public void destroy()
	{
		// 应用退出时调用
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException
	{
		HttpServletRequest req=(HttpServletRequest) request;
		HttpServletResponse resp=(HttpServletResponse) response;
		
		User u=null;
		HttpSession ss=req.getSession();
		u=(User) ss.getAttribute("user");
		if(u==null)
		{
			resp.sendError(403, "登录才能查看机密文件!");
			return; //在作出应答后应该return
		}
		
		//已登录用户放行
		chain.doFilter(request, response);
	}
}

过滤器的配置

  • Filter的URL匹配,和 Servlet的匹配规则一样,有3种

全路径匹配  /data/sample/1234.html

路径匹配   /data/sample/*

后缀名匹配  *.html

注意:路径不包含ContextPath

  • 常见的URL Pattern 设置错误

@WebFilter("abc.html")    应为 "/abc.html"  ,路径配置时,注意要前面要加 /

@WebFilter("data/sample/1234.html") 应为 "/data/sample/1234.html"

@WebFilter("/data/sample/*.html") 不支持这种。要么前缀,要么后缀。有特殊需求的,可以先匹配 /data/sample/* ,然后自己再作进一步处理。

@WebFilter("/data/sample*")  这样不能匹配 "/data/sample/1234.html" , 如果表示路径,末尾必须要横线, "/data/sample/*。

  • Filter的声明:注解方式 , web.xml方式

1.注解方式的声明

传入一个String参数, /abc.html

@WebFilter("/abc.html")

@WebFilter(filterName = "filter3",urlPatterns = "/abc.html")

传入一个String[] 参数,三种URL都匹配

@WebFilter({"/a.html", "/b.html", "/c.html"} )

@WebFilter(filterName = "filter3",urlPatterns = {"/a.html","/b.html", "/c.html"} )

如未配置 filterName,则fitlerName默认为类名全称,如 com.example.MyFilter。

2.XML方式的声明

<filter>
    <filter-name>MyFilter3</filter-name>
    <filter-class>my.MyFilter3</filter-class>
</filter>
<filter-mapping>
    <filter-name>MyFilter3</filter-name>
    <url-pattern> /a.html </url-pattern>
    <url-pattern> /b.html </url-pattern>
    <url-pattern> /c.html </url-pattern>
</filter-mapping>

其中,filter-class表示类的路径,如 my.MyFilter5。url-pattern 表示过滤的URL格式,如 /abc.html。

  • Filter的初始化参数

在web.xml 里,还可以添加一些Filter的配置参数。

<filter>
    <filter-name>MyFilter5</filter-name>
    <filter-class>my.MyFilter5</filter-class>
    <init-param>
        <param-name> enableLog </param-name>
        <param-value> yes </param-value>
    </init-param>
    <init-param>
        <param-name> interval </param-name>
        <param-value> 30</param-value>
    </init-param>
</filter>

这里,<init-param> 表示配置参数。这里设置了两个初始化参数。

enableLog: yes

interval : 30

在过滤器的init() 方法里,可以读取这些参数。例如,

public class MyFilter5 implements Filter
{
    public void init(FilterConfig filterCfg) throws ServletException
    {
        String enableLog = filterCfg.getInitParameter("enableLog");
        String interval = filterCfg.getInitParameter("interval");
        ...
    }
    ...
}

多重过滤

一个URL请求,被多个过滤器拦截

比如,有一个高考成绩查询的接口 http://127.0.0.1:8080/demo/score/query.do

添加了2个过滤器:

ScoreFilter1  匹配  *.do

ScoreFilter2  匹配  /score/*

当有多重过滤时,每一重过滤都有否决权 。若过通过,则调用    chain.doFilter(request, response) 继续后续的处理。其中的 FilterChain,就表示这种有多个 Filter 串在一起的链式结构。

//查询成绩接口
@WebServlet("/score/query.do")
public class ScoreQuery extends HttpServlet
{
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		response.setCharacterEncoding("UTF-8");
		response.setContentType("text/plain");
		response.getWriter().print("你好,你的高考成绩为726分!");
	}
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
	{
		doGet(request, response);
	}
}
@WebFilter("*.do")
public class ScoreFilter1 implements Filter
{
	public void init(FilterConfig fConfig) throws ServletException
	{
		System.out.println("ScoreFilter1: init()");
	}

	public void destroy()
	{
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException
	{
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse)response;
		System.out.println("ScoreFilter 1: " + req.getServletPath());
		chain.doFilter(request, response);
	}
}
@WebFilter("/score/*")
public class ScoreFilter2 implements Filter
{
	public void init(FilterConfig fConfig) throws ServletException
	{
		System.out.println("ScoreFilter2: init()");
	}

	public void destroy()
	{
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException
	{
		HttpServletRequest req = (HttpServletRequest) request;
		HttpServletResponse resp = (HttpServletResponse)response;
		System.out.println("ScoreFilter 2: " + req.getServletPath());
        // 调用 chain.doFilter()表示 '通过'
		chain.doFilter(request, response);
	}
}

当 FilterChain 上有多个过滤器时,执行顺序:

1 优先加载web.xml 里的 Filter ,如果有多个 Filter,按照在 web.xml 里出现的从上到下出现的顺序 。

2 然后加载注释声明的 Filter  ,如果有多个 Filter, 则按类的全路径名称排序 。如   先my.score.ScoreFilter1  后my.score.ScoreFilter2。

注意:经实测验证,并不是按 filterName 排序 ,而是按类路径名排序的。


版权声明:本文为qq_17699069原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。