学习目标:
1、了解Filter的概念
2、掌握Filter的定义和使用
3、根据业务需要灵活定义Filter
学习过程:
一、什么是过滤器filter
与Servlet相似,可以绑定到一个Web应用程序中。但是与其他Web应用程序组件不同的是,过滤器是“链”在容器的处理过程中的。这就意味着它们会在servlet处理器之前访问一个进入的请求,并且在外发的响应信息返回到客户前访问这些响应信息。这种访问使得过滤器可以检查并修改请求和响应的内容。 通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件或静态 html 文件等进行拦截。
过滤器放在Web资源之前,可以在请求抵达它所应用的Web资源(可以是一个servlet、一个JSP页面)之前截获进入的请求,并且在它返回到客户之前也会截获输出请求。也就说过滤器会在请求前后都会经过这个过滤器。
在Servlet作为过滤器使用时,它可以对客户的请求进行处理。 处理完成后,它会交给下一个过滤器处理,这样,客户的请求在过滤链里逐个处理,直到请求发送到目标为止.
filter在很多地方都可以使用,你可以把servlet中的一些共用代码抽象到filter中,比如对提交的数据进行统一编码,也可以把登录拦截放到filter中进行,也可以把发送给客户端的静态页面先进行压缩后再发送,还可以实现过滤敏感词汇、等等等功能。
二、定义过滤器filter
Servlet API中提供了一个Filter接口,开发web应用时,如果编写的Java类实现了这个接口,则把这个java类称之为过滤器Filter
1、实现过滤器。
新建一个普通类FirstFilter,然后实现Filter接口。并实现其三个方法
public class FirstFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("FirstFilter初始化了。");
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//进入过滤器
//System.out.println("FirstFilter进入下一步之前 前 前");
//进入下一步
chain.doFilter(request, response);
//System.out.println("FirstFilter进入下一步之后 后 后");
}
public void destroy() {
System.out.println("FirstFilter销毁了。");
}
}
2、过滤器的配置。
上面我们定义了一个过滤器,因为过滤器的生命周期有web容器管理,和servlet一样,我们需要在web.xml中配置这个过滤器,这样web容器启动的时候就会初始化这个过滤器。打开web.xml,添加一下代码:
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>com.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
和servlet差不多的一个配置,其中url-pattern是需要过滤的路径,我们可以直接写一个url路径,同时它也支持通配符(*)的使用,比如“/*”就表示过滤所有的信息,“/admin/*”就表示过滤所有的在admin访问路径下的所有的信息,这里我们先拦截的是“/userServlet”这个路径。
3、过滤器的生命周期
这个时候你就可以启动tomcat服务器了,注意filter是在服务器启动的时候就会初始化了,并且在服务器关闭的时候才会销毁,所以filter整个生命周期由服务器维护。
重点是doFilter方法,这个方法在每一次拦截的时候都会执行。在这个方法里面有三个参数其中有两个我们非常属性的request和response对象,还有就是FilterChain对象,这个对象一般会调用doFilter方法,表示把交给下一个链操作,可能是servlet,也可能是下一个过滤器。
现在你可以打开浏览器输入访问/userServlet这个网址。
http://localhost:8080/userdemo/userServlet。
查看控制台的输入,会先输出:
FirstFilter访问业务核心前执行
执行了核心的逻辑servlet
FirstFilter访问业务核心后执行
4、过滤器的先后顺序
注意过滤器在web.xml的定义顺序是会影响其拦截的先后顺序的,如果两个过滤器都会拦截同一个路径,那么先定义的就会先拦截。比如我们再定义一个过滤器:
public class SecondFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//System.out.println("SecondFilter进入下一步之前 前 前");
chain.doFilter(request, response);
//System.out.println("SecondFilter进入下一步之后 后 后");
}
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
public void destroy() {
// TODO Auto-generated method stub
}
}
在web.xml中配置时,是在第一个过滤器的后面定义的,也是一样拦截同一个路径;
<filter>
<filter-name>firstFilter</filter-name>
<filter-class>com.filter.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>firstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>secondFiter</filter-name>
<filter-class>com.filter.SecondFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>secondFiter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这是时候我们在访问/userServlet这个网址。
http://localhost:8080/userdemo/userServlet。
结果输出如下:
FirstFilter访问业务核心前执行
SecondFilter访问业务核心前执行
执行了核心的逻辑servlet
SecondFilter访问业务核心后执行
FirstFilter访问业务核心后执行
先拦截的过滤器,与返回给客户端的顺序相反,也就是和栈的结构是一样的,先进后出。当然这个也是很容易理解的。
三、过滤器的应用
1、编码过滤器
下面我们可以讲两个简单的应用,因为每一个servlet都需要设置编码,代码如下:
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
所以我们放到filter中配置,先进一个编码过滤器:
//编码拦截器
public class ChaFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response);
}
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
public void destroy() {
// TODO Auto-generated method stub
}
}
我们可以把这个拦截器放到最前面。在web.xml配置如下;
<filter>
<filter-name>chaFilter</filter-name>
<filter-class>com.filter.ChaFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>chaFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
好,这样就不要在每个servlet都写上编码的代码了。
2、登录拦截器
要做这个登录拦截器,我们必须先做好规划,比如需要登录才能访问的路径,我们一律都是放在admin的访问路径之下的。这样我们就只需要拦截这个路径就可以了,凡是没有登录的就去登录页面,登录就去下一个操作就行了。实现代码如下:
public class LoginFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)res;
// 先判断用户是否已经登录了。
HttpSession session = request.getSession();
User userss = (User) session.getAttribute("user");
if (userss == null) {
response.sendRedirect("/userdem/index.jsp");
return;
}
chain.doFilter(request, response);
}
public void destroy() {
// TODO Auto-generated method stub
}
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
web.xml配置文件如下;
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>com.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
</filter-mapping>