一、什么是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 错误。实际业务中,输出

【感谢】

慕课网Fcming 讲师

[Java] JSP笔记 - Filter 过滤器的更多相关文章

  1. Java 中的 Filter 过滤器详解

    Filter简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件 ...

  2. Java中的Filter过滤器

    Filter简介 Filter也称之为过滤器,它是Servlet技术中最实用的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, 静态图片文件 ...

  3. j2ee学习笔记 Filter过滤器

    作用:过滤response和request对象的内容 使用: Filter是J2EE的一个接口,自定义Filter需要实现该接口,并重写所有的方法. Filter提供的方法: init() doFil ...

  4. Java精选笔记_Filter(过滤器)

    Filter(过滤器) Filter入门 什么是Filter Filter被称作过滤器或者拦截器,其基本功能就是对Servlet容器调用Servlet的过程进行拦截,从而在Servlet进行响应处理前 ...

  5. Java Web进阶——Filter过滤器

    一.过滤器的介绍: 在Servlet规范2.3中定义了过滤器,它是一个服务器端的组件,可以截取用户端的请求与响应信息,并且对这些信息进行过滤. Servlet过滤器本身并不生成请求和响应对象,只是提供 ...

  6. JAVA JSP笔记

    一.jsp加载项目中资源图片 如果直接将静态页面写的代码copy到jsp中,你会发现图片都无法加载. 获取代码: String path = request.getContextPath(); Str ...

  7. [Java] JSP笔记 - 自定义标签

    自定义标签的创建步骤: 自定义标签的四大功能: 自定义标签的类结构: 在 1.0 中呢, 可以将 <body-content> 的值设置为 JSP, 2.0中则不允许在自定义标签体中出现j ...

  8. [Java] JSP笔记 - Listener 监听器

    Java Web 开发时,可以使用 Listener 来监听来监听一些事件,从而实现一些功能.实际上这个监听器,原理就是 Delphi 中大家常用的各种事件. 1. 那么,监听器的主要用途用哪些呢: ...

  9. [Java] JSP笔记 - EL、JSTL 常用标签

    一. 什么是 EL 语言 表达式语言(EL)是 JSP 2.0 引入的一种计算和输出 Java 对象的简单语言. 二.EL 语言的作用 为了使JSP写起来更加简单.表达式语言的灵感来自于 ECMASc ...

随机推荐

  1. WereWolf项目 Postmortem

    WereWolf项目 Postmortem (博客园的MarkDown编辑器好像有些问题,编号都显示1..) 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描 ...

  2. 基于ARM处理器的反汇编器软件简单设计及实现

    写在前面 2012年写的毕业设计,仅供参考 反汇编的目的 缺乏某些必要的说明资料的情况下, 想获得某些软件系统的源代码.设计思想及理念, 以便复制, 改造.移植和发展: 从源码上对软件的可靠性和安全性 ...

  3. Oracle分区索引

    索引与表类似,也可以分区: 分区索引分为两类: Locally partitioned index(局部分区索引) Globally partitioned index(全局分区索引) 下面就来详细解 ...

  4. python教程与资料

    网上有个人写的python快速教程,非常好.比看书好多了.猛击下面的链接地址 http://www.douban.com/group/topic/30008503/ python文档资料收集 pyth ...

  5. My first win32 application program

    #include<afxwin.h>#include<afx.h>#define _AFXDLLclass CHelloApp :public CWinApp{public:  ...

  6. Java程序设计之链表结构

    唉,说点废话,昨天偶尔看到一年前自己用C解约瑟夫环问题的循环链表,唏嘘不已,想想自己一年前嵌入式的梦呢,这两天发生了许多,而有些人不在了就真的不在了,心情不好,不多说了,直接上代码,只是些链表的基本操 ...

  7. mac下搭建redis环境

    一.redis简介 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合)和zset(有 ...

  8. js 批量设置css样式

    在js中更换样式比较常见,但是批量设置比较少遇见: 但是在做就是插件时,不想额外的添加css文件(需要导入,还可能引起冲突),能批量设置就比较方便了. 以下代码是来自网上的三种方法,使用第二种最方便了 ...

  9. 基于GPU的高分一号影像正射校正的设计与实现

    一 RPC正射校正的原理 影像正射校正的方法有很多,主要包含两大类:一类是严格的几何纠正模型,另一类是近似几何纠正模型.当遥感影像的成像模型和有关参数已知时,可以根据严格的成像模型来校正图像,这种方法 ...

  10. tensorflow学习笔记二:入门基础

    TensorFlow用张量这种数据结构来表示所有的数据.用一阶张量来表示向量,如:v = [1.2, 2.3, 3.5] ,如二阶张量表示矩阵,如:m = [[1, 2, 3], [4, 5, 6], ...