Java Servlet 过滤器与 SpringMVC 拦截器的区别?

前言:在工作中,遇到需要记录日志的情况,不知道该选择过滤器还是拦截器,故总结了一下。

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;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/893166aeea1e25d7761addd2482f5202.html