过滤器
过滤器, 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 排序 ,而是按类路径名排序的。