本文转自喻志强的博客
原文地址:https://yuzhiqiang.blog.csdn.net/article/details/81288912
JavaWeb之过滤器(Filter)
今天学习JavaWeb的过滤器时,发现了一篇关于JavaWeb的过滤器的博客很好,对像我这样IT小白很有用!
首先解释一下什么是过滤器?
过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理
通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理
应用场景为:
- 登录过滤
- 字符编码设置
创建一个Filter
在Servlet中我们一般都会对request和response中的字符集编码进行配置,如果Servlet过多字符集编码发生变化时修改起码会很麻烦,这些通用的字符集编码配置等工作我们可以放到Filter中来实现。
下面我们来创建一个处理字符集编码的Filter。
右键包名—>new ---->Filter
输入过滤器名称,跟创建Servlet一样,这里我们直接使用 @WebFilter 注解,不再去web,xml中进行配置了。
创建完成后默认代码,可以看到,CharsetFilter实现了Filter接口,实现了3个方法。3个方法的作用已经在注释中写清楚了。
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "CharsetFilter")
public class CharsetFilter implements Filter {
public void destroy() {
/*销毁时调用*/
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
/*过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理*/
chain.doFilter(req, resp);//交给下一个过滤器或servlet处理
}
public void init(FilterConfig config) throws ServletException {
/*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/
}
}
配置Filter
可以配置这些
常用配置项
urlPatterns
配置要拦截的资源
1.以指定资源匹配。例如"/index.jsp"
2.以目录匹配。例如"/servlet/"
3.以后缀名匹配,例如".jsp"
4.通配符,拦截所有web资源。"/*"
**initParams **
配置初始化参数,跟Servlet配置一样
例如
initParams = {
@WebInitParam(name = "key",value = "value")
}
dispatcherTypes **
配置拦截的类型,可配置多个。默认为DispatcherType.REQUEST**
例如
dispatcherTypes = {DispatcherType.ASYNC,DispatcherType.ERROR}
其中DispatcherType是个枚举类型,有下面几个值
FORWARD,//转发的
INCLUDE,//包含在页面的
REQUEST,//请求的
ASYNC,//异步的
ERROR;//出错的
下面我们来对CharsetFilter 代码进行一下修改
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebInitParam;
import java.io.IOException;
@WebFilter(filterName = "CharsetFilter",
urlPatterns = "/*",/*通配符(*)表示对所有的web资源进行拦截*/
initParams = {
@WebInitParam(name = "charset", value = "utf-8")/*这里可以放一些初始化的参数*/
})
public class CharsetFilter implements Filter {
private String filterName;
private String charset;
public void destroy() {
/*销毁时调用*/
System.out.println(filterName + "销毁");
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
/*过滤方法 主要是对request和response进行一些处理,然后交给下一个过滤器或Servlet处理*/
System.out.println(filterName + "doFilter()");
req.setCharacterEncoding(charset);
resp.setCharacterEncoding(charset);
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
/*初始化方法 接收一个FilterConfig类型的参数 该参数是对Filter的一些配置*/
filterName = config.getFilterName();
charset = config.getInitParameter("charset");
System.out.println("过滤器名称:" + filterName);
System.out.println("字符集编码:" + charset);
}
}
这样一个简单的字符集编码处理的过滤器就完成了
我们看看执行打印的结果
需要注意的是
过滤器是在服务器启动时就会创建的,只会创建一个实例,常驻内存,也就是说服务器一启动就会执行Filter的init(FilterConfig config)方法.
当Filter被移除或服务器正常关闭时,会执行destroy方法
多个Filter的执行顺序
在我们的请求到达Servle之间是可以经过多个Filter的,一般来说,建议Filter之间不要有关联,各自处理各自的逻辑即可。这样,我们也无需关心执行顺序问题。
如果一定要确保执行顺序,就要对配置进行修改了,执行顺序如下
1.在web.xml中,filter执行顺序跟<filter-mapping>的顺序有关,先声明的先执行
2.使用注解配置的话,filter的执行顺序跟名称的字母顺序有关,例如AFilter会比BFilter先执行
3.如果既有在web.xml中声明的Filter,也有通过注解配置的Filter,那么会优先执行web.xml中配置的Filter
我们写个小例子看一下
新建3个Filter,加上之前的CharsetFilter一共四个
其中CharsetFilter和ABFilter是通过注解声明的
CharsetFilter注解配置
@WebFilter(filterName = "CharsetFilter",
urlPatterns = "/*",/*通配符(*)表示对所有的web资源进行拦截*/
initParams = {
@WebInitParam(name = "charset", value = "utf-8")/*这里可以放一些初始化的参数*/
})
ABFilter
@WebFilter(filterName = "ABFilter",urlPatterns = "/*")
AFilter和BFilter是在web.xml配置的。
执行顺序跟filter的顺序无关
filter-mapping的顺序才决定执行顺序
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>AFilter</filter-name>
<filter-class>filter.AFilter</filter-class>
</filter>
<filter>
<filter-name>BFilter</filter-name>
<filter-class>filter.BFilter</filter-class>
</filter>
<!--这里BFilter在AFilter之前-->
<filter-mapping>
<filter-name>BFilter</filter-name>
<url-pattern>/filter.jsp</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>AFilter</filter-name>
<url-pattern>/filter.jsp</url-pattern>
</filter-mapping>
</web-app>
每个Filter添加了打印语句,如下
以ABFilter为例
package filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(filterName = "ABFilter",urlPatterns = "/*")
public class ABFilter implements Filter {
private String filterName;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println(filterName + " doFilter()");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
filterName= config.getFilterName();
System.out.println("过滤器名称:" + filterName +" init");
}
}
打印结果
可以看到,执行结果符合预期。
BFilter和AFilter是在web.xml中声明的,且BFilter的filter-mapping在前,故BFilter在AFilter之前执行。
ABFilter和CharsetFilter是通过注解声明的,故他俩在BFilter和AFilter之后执行,但是ABFilter的名称以A开头,故在CharsetFilter之前执行