前言:在工作中,遇到需要记录日志的情况,不知道该选择过滤器还是拦截器,故总结了一下。
servlet 过滤器
定义
Java过滤器能够对目标资源的请求和响应进行截取。过滤器的工作方式分为四种
应用场景
可以通过 doFilter 方法的 request、response 提前过滤一些不想要的信息,统一设置一些参数、统一设置字符集、控制权限是否登录等。
配置
<!-- 定义Filter -->
<filter>
<!-- Filter的名字 -->
<filter-name>loginFilter</filter-name>
<!-- Filter的实现类 -->
<filter-class>com.yule.common.filters.LoginFilter</filter-class>
</filter>
<!-- 定义Filter拦截的URL地址 -->
<filter-mapping>
<!-- Filter的名字 -->
<filter-name>loginFilter</filter-name>
<!-- Filter负责拦截的URL 全部以/的请求,如果/*,将会所有的请求-->
<url-pattern>/*</url-pattern>
</filter-mapping>
过滤器的4种工作方式
<filter-mapping>
<filter-name>myFilter</filter-name>
<servlet-name>目标资源</servlet-name>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
四中工作方式通过配置 <dispatcher> 标签来决定
1.request 过滤器:不配 <dispatcher> 标签,或者配置为 <dispatcher>REQUEST</dispatcher> 。说明只有直接访问该目标资源时该过滤器才会起作用,对转发到该目标资源的请求将忽略不处理。
2.forward 过滤器:配置为 <dispatcher>FORWARD</dispatcher> 。表示对转发到目标资源的请求过滤,如果直接访问目标资源,过滤器则不起作用。
3.include 过滤器:配置为 <dispatcher>INCLUDE</dispatcher> 。表示对包含了目标资源的请求过滤,如果直接访问目标资源,则此过滤器将不起作用
include 包含以下语句:
在 JSP 页面中的动作:<jsp:include page=.......
在 Java 代码中的 request.getRequestDispatcher("....").include
注意:如果目标资源一通过 <%@ include file="目标资源二"%> 指令包含,这时此过滤器不工作,因为这个是指令,在JSP 编译时插入一个包含文本或代码的文件,这个包含的过程是静态的。
4.error 过滤器:配置为
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/error.jsp</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page>
当我们访问一个web目标资源时,如果服务器没有找到该目标资源,那么服务器就会给出一个404错误代码。如果我们给404错误代码定义一个页面,那么当404发生时就会调用该页面。
当我们访问一个不存在的文件时,就会访问error.jsp,但是配置了过滤器对错误页面进行过滤,所以过滤器先接受到请求,然后再转发给error.jsp。
如果我们访问一个已经存在的页面,会不会调用error.jsp呢?如果这个页面中有response.sendError(404,"出错了!");那么该错误页面仍然会被调用,过滤器也会工作。
执行顺序
根据 web.xml 的代码顺序来决定过滤器的执行顺序。Filter 链: 一个Web应用中,可以编写多个Filter,这些 Filter 组合起来称之为一个Filter链。
当第一个 Filter 的 doFilter 方法被调用时,web 服务器会创建一个代表 Filter 链的 FilterChain 对象传递给该方法。在 doFilter 方法中,如果调用了 FilterChain 对象的 doFilter 方法,则 web 服务器会检 FilterChain 对象中是否还有 filter ,如果有,则调用第下一个 filter,如果没有,则调用目标资源。
init() 方法和 destroy() 方法随着项目的启动和关闭才会被调用,且仅一次。
举个栗子
web.xml 中
<!-- 定义Filter -->
<filter>
<!-- Filter的名字 -->
<filter-name>demoFilter</filter-name>
<!-- Filter的实现类 -->
<filter-class>com.yule.common.filters.DemoFilter</filter-class>
</filter>
<!-- 定义Filter拦截的URL地址 -->
<filter-mapping>
<!-- Filter的名字 -->
<filter-name>demoFilter</filter-name>
<!-- Filter负责拦截的URL 全部以/的请求,如果/*,将会所有的请求-->
<url-pattern>/*</url-pattern>
</filter-mapping>
Java 代码
package com.yule.common.filters;
import javax.servlet.*;
import java.io.IOException;