[10] 过滤器 Filter
1、过滤器的基本概念和作用
在网站的页面访问时,我们往往需要做一些控制,如普通用户无法访问VIP用户的页面。如果在每一个需要访问控制的文件中都加上判断代码,那么代码将会很冗余,一旦需要统一修改时也极其繁琐。
过滤器就可以解决这样的问题,配置完成的过滤器,会强制让指定的页面在访问之前先从过滤器走一趟。
2、过滤器相关的API
Servlet API中,与过滤器有关的API共有三个接口,分别是:
- Filter
- FilterChain (在Filter中init方法作为参数)
- FilterConfig (在Filter中doFilter方法作为参数)
Filter接口
Filter接口是我们自定义的过滤器类必须要实现的接口,该接口有三个方法:
- init(FilterConfig filterConfig)
- 该方法是对Filter对象进行初始化的方法,仅在容器初始化Filter对象结束后被调用一次,其中FilterConfig可以获取初始化参数
- doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
- 该方法是Filter进行过滤操作的方法,是最重要的方法。我们自定义的过滤器类都要实现该方法。
- 方法体中可以对请求和响应进行预处理,FilterChain则可以将处理后的请求响应传递到过滤链上的下一个资源
- destroy()
- 该方法在容器销毁过滤器对象之前被调用
可以看到,其他两个接口是分别作为参数在Filter接口的方法中进行使用。它们的作用在于:
FilterConfig接口
该接口类型作为Filter接口中init方法的参数使用,这个接口有一个常用方法:
- getInitParameter(String name)
- 该方法用来获取过滤器的初始化参数,这个初始化参数在web.xml中进行配置,方式和Servlet初始化参数类似
FilterChain接口
该接口类型作为Filter接口中doFilter方法的参数使用,这个接口有一个方法:
- doFilter(ServletRequest request, ServletResponse response)
- 该方法可以将当前请求和相应传递到过滤链上的下一个资源,可能是下个过滤器,也可能是目标资源
3、示例:过滤器限制页面访问时间
实现这样的功能,某个页面,在规定的时间内才能访问,否则跳转到通知页面,告知未到开放时间,暂时无法访问。
可以通过修改系统的时间,来完成过滤器的效果测试:
3.1 创建jsp页面
创建四个jsp页面:index、login、home和notice,文件放置目录结构如下:
3.2 自定义过滤器
自定义过滤器,读取初始参数配置,并判断是否符合要求,根据需要进行页面跳转:
public class TimeFilter implements Filter {
private int start = 0;
private int end = 24;
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("TimeFilter初始化,开始抓取初始化参数");
start = Integer.parseInt(filterConfig.getInitParameter("start"));
end = Integer.parseInt(filterConfig.getInitParameter("end"));
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("TimeFilter过滤");
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
int curHour = calendar.get(Calendar.HOUR_OF_DAY);
if (curHour >= end || curHour < start) {
request.setAttribute("start", start);
request.setAttribute("end", end);
request.getRequestDispatcher("/WEB-INF/notice.jsp").forward(request, response);
}
chain.doFilter(request, response);
}
public void destroy() {
System.out.println("TimeFilter爆炸");
}
}
x
1
public class TimeFilter implements Filter {
2
private int start = 0;
3
private int end = 24;
4
5
public void init(FilterConfig filterConfig) throws ServletException {
6
System.out.println("TimeFilter初始化,开始抓取初始化参数");
7
start = Integer.parseInt(filterConfig.getInitParameter("start"));
8
end = Integer.parseInt(filterConfig.getInitParameter("end"));
9
}
10
11
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
12
System.out.println("TimeFilter过滤");
13
Calendar calendar = Calendar.getInstance();
14
calendar.setTime(new Date());
15
int curHour = calendar.get(Calendar.HOUR_OF_DAY);
16
if (curHour >= end || curHour < start) {
17
request.setAttribute("start", start);
18
request.setAttribute("end", end);
19
request.getRequestDispatcher("/WEB-INF/notice.jsp").forward(request, response);
20
}
21
22
chain.doFilter(request, response);
23
}
24
25
public void destroy() {
26
System.out.println("TimeFilter爆炸");
27
}
28
}
3.3 配置web.xml和初始化参数
在web.xml中配置过滤器的具体类,以及过滤的资源和过滤器初始化的参数:
<filter>
<filter-name>timeFilter</filter-name>
<filter-class>com.zker.TimeFilter</filter-class>
<init-param>
<param-name>start</param-name>
<param-value>15</param-value>
</init-param>
<init-param>
<param-name>end</param-name>
<param-value>22</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>timeFilter</filter-name>
<url-pattern>/limit/*</url-pattern>
</filter-mapping>
16
1
<filter>
2
<filter-name>timeFilter</filter-name>
3
<filter-class>com.zker.TimeFilter</filter-class>
4
<init-param>
5
<param-name>start</param-name>
6
<param-value>15</param-value>
7
</init-param>
8
<init-param>
9
<param-name>end</param-name>
10
<param-value>22</param-value>
11
</init-param>
12
</filter>
13
<filter-mapping>
14
<filter-name>timeFilter</filter-name>
15
<url-pattern>/limit/*</url-pattern>
16
</filter-mapping>
4、Filter使用总结和配置说明
- 首先要实现Filter接口
- 自定义的过滤方法写在doFilter方法体中,最后并通过形参 FilterChain 的 doFilter(request, response) 方法传递请求和响应
- 然后要在web.xml中进行配置,包括过滤器的具体类,过滤文件,初始参数等
关于配置文件的部分说明:
- <filter> 定义Filter的具体类
- <init-param> 定义初始化参数
- <filter-mapping> 定义过滤器的限制目录
在<filter-mapping>中实际上还可以通过 <dispatcher> 配置请求方式的过滤:
<filter-mapping>
<filter-name>timeFilter</filter-name>
<url-pattern>/limit/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
1
<filter-mapping>
2
<filter-name>timeFilter</filter-name>
3
<url-pattern>/limit/*</url-pattern>
4
<dispatcher>REQUEST</dispatcher>
5
<dispatcher>FORWARD</dispatcher>
6
<dispatcher>INCLUDE</dispatcher>
7
<dispatcher>ERROR</dispatcher>
8
</filter-mapping>
<dispatcher>配置表示哪些请求传递方式到如上的/limit/*时需要被过滤,默认不写的话为REQUEST
(假如我只写了REQUEST,而没写FORWARD,那么通过转发方式到达的/limit/*的资源,就不会被过滤)