[Java] JSP笔记 - Filter 过滤器
一、什么是Web过滤器
Servlet API 很久以前就已成为企业应用开发的基石,而 Servlet 过滤器则是对 J2EE 家族的相对较新的补充。
Servlet 过滤器是可插入的 Web 组件,它允许我们实现 Web 应用程序中的预处理和后期处理逻辑。过滤器支持 servlet 和 JSP 页面的基本请求处理功能,比如日志记录、性能、安全、会话处理、XSLT 转换,等等。 过滤器最初是随 Java Servlet 2.3 规范发布的。
Servlet 过滤器是什么?
Servlet 过滤器是小型的 Web
组件,它们拦截请求和响应,以便查看、提取或以某种方式操作正在客户机和服务器之间交换的数据。过滤器是通常封装了一些功能的 Web
组件,这些功能虽然很重要,但是对于处理客户机请求或发送响应来说不是决定性的。典型的例子包括记录关于请求和响应的数据、处理安全协议、管理会话属性,
等等。过滤器提供一种面向对象的模块化机制,用以将公共任务封装到可插入的组件中,这些组件通过一个配置文件来声明,并动态地处理。
Servlet 过滤器中结合了许多元素,从而使得过滤器成为独特、强大和模块化的 Web 组件。也就是说,Servlet 过滤器是:
声明式的:过滤器通过 Web 部署描述符(web.xml)中的 XML 标签来声明。这样允许添加和删除过滤器,而无需改动任何应用程序代码或 JSP 页面。
动态的:过滤器在运行时由 Servlet 容器调用来拦截和处理请求和响应。
灵活的:过滤器在 Web
处理环境中的应用很广泛,涵盖诸如日志记录和安全等许多最公共的辅助任务。过滤器还是灵活的,因为它们可用于对来自客户机的直接调用执行预处理和后期处
理,以及处理在防火墙之后的 Web 组件之间调度的请求。最后,可以将过滤器链接起来以提供必需的功能。
模块化的:通过把应用程序处理逻辑封装到单个类文件中,过滤器从而定义了可容易地从请求/响应链中添加或删除的模块化单元。
可移植的:与 Java 平台的其他许多方面一样,Servlet 过滤器是跨平台和跨容器可移植的,从而进一步支持了 Servler 过滤器的模块化和可重用本质。
可重用的:归功于过滤器实现类的模块化设计,以及声明式的过滤器配置方式,过滤器可以容易地跨越不同的项目和应用程序使用。
透明的:在请求/响应链中包括过滤器,这种设计是为了补充(而不是以任何方式替代)servlet 或 JSP 页面提供的核心处理。因而,过滤器可以根据需要添加或删除,而不会破坏 servlet 或 JSP 页面。
所以 Servlet
过滤器是通过一个配置文件来灵活声明的模块化可重用组件。过滤器动态地处理传入的请求和传出的响应,并且无需修改应用程序代码就可以透明地添加或删除它们。最后,过滤器独立于任何平台或者 Servlet 容器,从而允许将它们容易地部署到任何相容的 J2EE 环境中。
二、第一个过滤器
package com.po; import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; public class FirstFilter implements Filter { @Override
public void destroy() {
System.out.println("destroy");
} @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("doFilter: " + request.toString());
chain.doFilter(request, response);
} @Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init: " + filterConfig.toString());
}
}
过滤器需要实现 Filter 接口:
init():这个方法在容器实例化过滤器时被调用,它主要设计用于使过滤器为处理做准备。该方法接受一个 FilterConfig 类型的对象作为输入。
doFilter():
与 servlet 拥有一个 service() 方法(这个方法又调用 doPost() 或者
doGet())来处理请求一样,过滤器拥有单个用于处理请求和响应的方法——doFilter()。这个方法接受三个输入参数:一个
ServletRequest、response 和一个 FilterChain 对象。
destroy():正如您想像的那样,这个方法执行任何清理操作,这些操作可能需要在自动垃圾收集之前进行。展示了一个非常简单的过滤器,它跟踪满足一个客户机的 Web 请求所花的大致时间。
三、配置 web.xml ,启用过滤器
先来看下这个图:

现在,我们在 web.xml 中,添加这些 xml 内容:
<!-- 过滤器配置 -->
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>com.po.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
filter 标签用来声明一个过滤器,每个过滤器只能有一个filter标签。
filter-mapping 标签用来指定过滤器的作用对象。上面的示例中 url-pattern 设定为了 "/*", 代表对所有jsp请求有效。
更改为 web.xml 后,需要重启 tomcat 服务器。
在重启服务器时,我们可以在控制台日志中看到我们的过滤器 init() 被调用了。
在浏览器 中访问一个页面,doFilter 会被执行。
四、 常见问题
1. 过滤器是否能够改变用户请求的WEB资源呢? 也就是能否改变用户请求的路径?
回答: 能。比如检测到用户没有登录,可以请WEB资源指向到登录页面。
2. 过滤器能否直接返回数据,能不能直接处理用户请求?
回答: 不能。因为过滤器不是一样标准的 Servlet ,它不能直接返回数据。它要是么指向一个WEB资源,要么是重定向到其它的WEB资源。
五、多个过滤器
WEB服务程序是可以支持多个过滤器的。
假如一个URL和多个过滤器指定的URL相符时,会生成一个过滤器链。

服务器会按照web.xml中过滤器定义的先后顺序组装成过滤器链。
过滤器链的执行过程:

六、过滤器的分类

过滤器默认是 Request 类型。
FORWARD 过滤器:
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>com.po.FirstFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<url-pattern>/index.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
INCLUDE 过滤器和 FORWARD 声明类似,将dispatcher改为INCLUDE就可以了。
错误过滤器:
<!-- 错误过滤器 -->
<error-page>
<error-code>404</error-code>
<location>/error.jsp</location>
</error-page> <filter>
<filter-name>ErrorFilter</filter-name>
<filter-class>com.po.ErrorFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ErrorFilter</filter-name>
<url-pattern>/error.jsp</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
在 Servlet 3.0 及之后的版本中,增加了异步支持。还增加使用注解的方式来定义过滤器(也就是说不需要我们修改 web.xml)了。
七、 @WebFilter 注解定义过滤器
我们先来看看 @WebFilter的常用属性。

示例: (错误过滤器)
package com.po; import java.io.IOException; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter; @WebFilter(
filterName="ErrorFilter",
value={"/error.jsp"},
dispatcherTypes={javax.servlet.DispatcherType.ERROR})
public class ErrorFilter implements Filter { @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("doFilter start.");
chain.doFilter(request, response);
System.out.println("doFilter end.");
} }
上面的代码,使用注解来定义过滤器。
下面是异步过滤的示例:
首先是新建一个Servlet,这个Servlet用来处理复杂的异步事务。
package servlet; import java.io.IOException;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; @WebServlet(name="AsyncServlet",asyncSupported=true,urlPatterns={"/servlet/AsyncServlet"},description="异步过滤器示例Servlet")
public class AsyncServlet extends HttpServlet {
private static final long serialVersionUID = 1L; @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("业务请求开始.");
AsyncContext context = req.startAsync();
// 开启异步线程
new Thread(new Executor(context)).start();
// req.getRequestDispatcher("/index.jsp").forward(req, resp);
// resp.getWriter().close();
System.out.println("业务请求结束.");
} public class Executor implements Runnable {
private AsyncContext context; public Executor(AsyncContext context) {
this.context = context;
} @Override
public void run() {
try {
// 复杂业务处理
System.out.println(context.getRequest().getScheme());
Thread.sleep(10 * 1000);
System.out.println("业务执行完成.");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} }
接下来,建立一个异步过滤器。
package servlet; import java.io.IOException; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter; @WebFilter(filterName="AsyncFilter",
urlPatterns={"/servlet/AsyncServlet"},
asyncSupported=true,
dispatcherTypes={javax.servlet.DispatcherType.ASYNC}
)
public class AsyncFilter implements Filter { @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
} }
异步过滤器的特性就是能很快的响应用户请求,复杂的业务处理过程放到新的线程中执行。
当然了,在我们上面的示例代码中, AsyncServlet.onGet里面只是启动一个业务处理线程,并没写响应的代码,所以会导致客户端出现一个 500 错误。实际业务中,输出
【感谢】
[Java] JSP笔记 - Filter 过滤器的更多相关文章
- Java 中的 Filter 过滤器详解
Filter简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件 ...
- Java中的Filter过滤器
Filter简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件 ...
- j2ee学习笔记 Filter过滤器
作用:过滤response和request对象的内容 使用: Filter是J2EE的一个接口,自定义Filter需要实现该接口,并重写所有的方法. Filter提供的方法: init() doFil ...
- Java精选笔记_Filter(过滤器)
Filter(过滤器) Filter入门 什么是Filter Filter被称作过滤器或者拦截器,其基本功能就是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet进行响应处理前 ...
- Java Web进阶——Filter过滤器
一.过滤器的介绍: 在Servlet规范2.3中定义了过滤器,它是一个服务器端的组件,可以截取用户端的请求与响应信息,并且对这些信息进行过滤. Servlet过滤器本身并不生成请求和响应对象,只是提供 ...
- JAVA JSP笔记
一.jsp加载项目中资源图片 如果直接将静态页面写的代码copy到jsp中,你会发现图片都无法加载. 获取代码: String path = request.getContextPath(); Str ...
- [Java] JSP笔记 - 自定义标签
自定义标签的创建步骤: 自定义标签的四大功能: 自定义标签的类结构: 在 1.0 中呢, 可以将 <body-content> 的值设置为 JSP, 2.0中则不允许在自定义标签体中出现j ...
- [Java] JSP笔记 - Listener 监听器
Java Web 开发时,可以使用 Listener 来监听来监听一些事件,从而实现一些功能.实际上这个监听器,原理就是 Delphi 中大家常用的各种事件. 1. 那么,监听器的主要用途用哪些呢: ...
- [Java] JSP笔记 - EL、JSTL 常用标签
一. 什么是 EL 语言 表达式语言(EL)是 JSP 2.0 引入的一种计算和输出 Java 对象的简单语言. 二.EL 语言的作用 为了使JSP写起来更加简单.表达式语言的灵感来自于 ECMASc ...
随机推荐
- 步步深入:MySQL架构总览->查询执行流程->SQL解析顺序
前言: 一直是想知道一条SQL语句是怎么被执行的,它执行的顺序是怎样的,然后查看总结各方资料,就有了下面这一篇博文了. 本文将从MySQL总体架构--->查询执行流程--->语句执行顺序来 ...
- DependencyResolver.Current
描述: 获取依赖关系解析程序的实现. 命名空间: System.Web.Mvc 程序集: System.Web.Mvc(在 System.Web.Mvc.dll 中) 用例: IRecLockServ ...
- 不同数据库,查询前n条数据的SQL语句
不同的数据库,支持的SQL语法略有不同,以下是不同数据库查询前n条数据的SQl语句 SQL Server(MSSQL) SELECT TOP n * FROM table_name ORACLE SE ...
- JMM(java内存模型)
What is a memory model, anyway? In multiprocessorsystems, processors generally have one or more laye ...
- USACO . Greedy Gift Givers
Greedy Gift Givers A group of NP (2 ≤ NP ≤ 10) uniquely named friends has decided to exchange gifts ...
- 初识NodeJS
1.JavaScript 模块化规范 浏览器环境 AMD Asynchronous Module Definition RequireJS CMD Common Module Definition S ...
- JSONP是如何工作的
我对这个问题的探究来源于一个需求: 当访问某个页面的时候,需要向另外一个网站报告一下这次访问的信息. 其实发一个跨域的请求就能大致实现这个需求.我们发跨域的例子其实很常见,例如请求一个第三方的图片.引 ...
- Javascript的this用法及jQuery中$this和$(this)的区别
this是Javascript语言的一个关键字. 它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用.比如, function test(){ this.x = 1; } 1.this就是全 ...
- 【WPF】 Timer与 dispatcherTimer 在wpf中你应该用哪个?
源:Roboby 1.timer或重复生成timer事件,dispatchertimer是集成到队列中的一个时钟.2.dispatchertimer更适合在wpf中访问UI线程上的元素 3.Dispa ...
- RabbitMQ操作
注意:在rabbitmq中,可以存在多个exchange,exchange只是负责接收消息,然后消息必须发送到给queue中,如果没有queue,消息就丢失了,exchange就相当于交换机,不负责存 ...