当前位置:首页 >> 计算机软件及应用 >>

10. 尚硅谷_佟刚_JavaWEB_过滤器_图文

Filter(过滤器)简介
? Filter 的基本功能是对 Servlet 容器调用 Servlet 的过程进 行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊 的功能。 ? 在 Servlet API 中定义了三个接口类来开供开发人员编写 Filter 程序:Filter, FilterChain, FilterConfig ? Filter 程序是一个实现了 Filter 接口的 Java 类,与 Servlet 程序相似,它由 Servlet 容器进行调用和执行 ? Filter 程序需要在 web.xml 文件中进行注册和设置它所能 拦截的资源:Filter 程序可以拦截 Jsp, Servlet, 静态图片文 件和静态 html 文件

Filter 的过滤过程

JSP

FilterChain

Filter 的基本工作原理
? 当在 web.xml 中注册了一个 Filter 来对某个 Servlet 程序进行拦截处 理时,这个 Filter 就成了 Servlet 容器与该 Servlet 程序的通信线路 上的一道关卡,该 Filter 可以对 Servlet 容器发送给 Servlet 程序的 请求和 Servlet 程序回送给 Servlet 容器的相应进行拦截,可以决定 是否将请求继续传递给 Servlet 程序,以及对请求和相应信息是否进 行修改 ? 在一个 web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序 都可以对一个或一组 Servlet 程序进行拦截。 ? 若有多个 Filter 程序对某个 Servlet 程序的访问过程进行拦截,当针 对该 Servlet 的访问请求到达时,web 容器将把这多个 Filter 程序组 合成一个 Filter 链(过滤器链)。Filter 链中各个 Filter 的拦截顺序与 它们在应用程序的 web.xml 中映射的顺序一致

Filter 接口
? init(FilterConfig filterConfig)throws ServletException:在 web 应用程 序启动时,web 服务器将根据 web.xml 文件中的配置信息来创建每 个注册的 Filter 实例对象,并将其保存在服务器的内存中。Web容器 创建 Filter 对象实例后,将立即调用该 Filter 对象的 init 方法。Init 方 法在 Filter 生命周期中仅执行一次,web 容器在调用 init 方法时,会 传递一个包含 Filter 的配置和运行环境的 FilterConfig 对象 (FilterConfig的用法和ServletConfig类似)。利用FilterConfig对象可以 得到ServletContext对象,以及部署描述符中配置的过滤器的初始化 参数。在这个方法中,可以抛出ServletException异常,通知容器该 过滤器不能正常工作。

? destroy():在Web容器卸载 Filter 对象之前被调用。该方法在Filter的 生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源
? 与开发Servlet不同的是,Filter接口并没有相应的实现类可供继承, 要开发过滤器,只能直接实现Filter接口。

Filter 接口
? doFilter(ServletRequest request,ServletResponse response, FilterChain chain)throws java.io.IOException,ServletException: doFilter()方法类似于Servlet接口的service()方法。当客户端请求目 标资源的时候,容器就会调用与这个目标资源相关联的过滤器的 doFilter()方法。其中参数 request, response 为 web 容器或 Filter 链的上一个 Filter 传递过来的请求和相应对象;参数 chain 为代表 当前 Filter 链的对象,在特定的操作完成后,可以在当前 Filter 对 象的 doFilter 方法内部需要调用 FilterChain 对象的 chain.doFilter(request,response)方法才能把请求交付给 Filter 链 中的下一个 Filter 或者目标 Servlet 程序去处理,也可以直接向客 户端返回响应信息,或者利用RequestDispatcher的forward()和 include()方法,以及HttpServletResponse的sendRedirect()方法将 请求转向到其他资源。这个方法的请求和响应参数的类型是 ServletRequest和ServletResponse,也就是说,过滤器的使用并 不依赖于具体的协议。

FilterChain接口
? FilterChain接口:代表当前 Filter 链的对象。由容器实现, 容器将其实例作为参数传入过滤器对象的doFilter()方法 中。过滤器对象使用FilterChain对象调用过滤器链中的下 一个过滤器,如果该过滤器是链中最后一个过滤器,那 么将调用目标资源。 ? doFilter(ServletRequest request,ServletResponse response)throws java.io.IOException:调用该方法将使 过滤器链中的下一个过滤器被调用。如果是最后一个过 滤器,会调用目标资源。

FilterConfig 接口
? javax.servlet.FilterConfig接口:该接口类似于ServletConfig 接口,由容器实现。Servlet规范将代表 ServletContext 对象 和 Filter 的配置参数信息都封装在该对象中。Servlet 容器将 其作为参数传入过滤器对象的init()方法中。 ? String getFilterName():得到描述符中指定的过滤器的名字。 ? String getInitParameter(String name): 返回在部署描述中指 定的名字为name的初始化参数的值。如果不存在返回null. ? Enumeration getInitParameterNames():返回过滤器的所有 初始化参数的名字的枚举集合。 ? public ServletContext getServletContext():返回Servlet上下 文对象的引用。

过滤器的部署
? 在实现一个过滤器后,需要在 web.xml 中进行注册 和设置它所能拦截的资源。这可以通过<filter>和 <filter-mapping>元素来完成的。

<filter> 元素(注册Filter)
? <filter>元素用于在Web应用程序中注册一个过滤器。 ? 在<filter>元素内
– <filter-name>用于为过滤器指定一个名字,该元素的内容不 能为空。 – <filter-class>元素用于指定过滤器的完整的限定类名。 – <init-param>元素用于为过滤器指定初始化参数,它的子元素 <param-name>指定参数的名字,<param-value>指定参数的 值。在过滤器中,可以使用FilterConfig接口对象来访问初始 化参数。

<filter> 元素(注册Filter)
Servlet容器对部署描述符中声明的每一个过滤器,只创 建一个实例。与Servlet类似,容器将在同一个过滤器 实例上运行多个线程来同时为多个请求服务,因此, 开发过滤器时,也要注意线程安全的问题。
<filter> <filter-name>testFitler</filter-name> <filter-class>org.test.TestFiter</filter-class> <init-param> <param-name>word_file</param-name> <param-value>/WEB-INF/word.txt</param-value> </init-param> </filter>

直接发 GET 或 POST 请求:REQUEST

test.jsp

直接发 GET 或 POST 请求:REQUEST

dispatcher.jsp

请求转发:FORWARD

test.jsp

映射 Filter
? <filter-mapping>元素用于设置一个 Filter 所负责拦截的资 源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径( url样式)
– <filter-name>子元素用于设置filter的注册名称。该值必须是在 <filter>元素中声明过的过滤器的名字 – <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式) – <servlet-name>指定过滤器所拦截的Servlet名称。

– <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式, 可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认 REQUEST. 可以设置多个<dispatcher> 子元素用来指定 Filter 对资 源的多种调用方式进行拦截

映射 Filter
? <dispatcher> 子元素可以设置的值及其意义:
– REQUEST:当用户直接访问页面时,Web容器将会调用过 滤器。如果目标资源是通过RequestDispatcher的include()或 forward()方法访问时,那么该过滤器就不会被调用。 – INCLUDE:如果目标资源是通过RequestDispatcher的 include()方法访问时,那么该过滤器将被调用。除此之外, 该过滤器不会被调用。 – FORWARD:如果目标资源是通过RequestDispatcher的 forward()方法访问时,那么该过滤器将被调用,除此之外, 该过滤器不会被调用。 – ERROR:如果目标资源是通过声明式异常处理机制调用时, 那么该过滤器将被调用。除此之外,过滤器不会被调用。

映射 Filter
<filter-mapping> <filter-name>testFilter</filter-name> <url-pattern>/test.jsp</url-pattern> </filter-mapping>

<filter-mapping> <filter-name>testFilter</filter-name> <url-pattern>/index.jsp</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher> </filter-mapping>

映射 Filter
? 在同一个 web.xml 文件中可以为同一个 Filter 设置多个 映射。若一个 Filter 链中多次出现了同一个 Filter 程序, 这个 Filter 程序的拦截处理过程将被多次执行

other.jsp other.jsp
request.getRequestDispatcher(“other.jsp”).forward(request, response) response.sendRedirct(“other.jsp”)

FilterChain Filter1 Filter1 Filter2 Filter2 Filter3 Filter3

target.js target.js

chain.doFilter(request, response)

login.jsp

1.

2.
3.

UserNameFilter

PasswordFilter

4.

login.jsp 请求提交到 hello.jsp。 该页面中有两个 text,分别为 username 和 password UserNameFilter、 PasswordFilter 拦截 login.jsp 的 请求页面,即 hello.jsp UserNameFilter: 若 username 不等于 Tom,则将请求转发到 login.jsp,并提示用户: “用户名 错误”,若等于 Tom,则把请求 转给下一个 Filter PasswordFilter:若 passord 不等 于 1234,则将请求转发到 login.jsp,并提示用户: “密码错 误”,若等于 1234,则把请求转 给目标页面

hello.jsp

Username(Tom)需配置为 UserNameFilter 的初始化参数,password (1234)需要配置为当前 WEB 应用的初 始化参数











典型应用1:
? 使浏览器不缓存页面的过滤器:
– 有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页 面,它们在 Servlet 中的示例代码如下:
? response.setDateHeader("Expires",-1); ? response.setHeader("Cache-Control","no-cache"); ? response.setHeader("Pragma","no-cache");

– 并不是所有的浏览器都能完全支持上面的三个响应头, 因此最好是同时使用上面的三个响应头

典型应用2:
? 字符编码的过滤器
– 通过配置参数encoding指明使用何种字符 编码,以处理Html Form请求参数的中文问题

典型应用3:
? 检测用户是否登陆的过滤器:
– 情景:系统中的某些页面只有在正常登陆后才可以使用,用户请求 这些页面时要检查 session 中有无该用户信息,但在所有必要的页 面加上session的判断相当麻烦的事情 – 解决方案:编写一个用于检测用户是否登陆的过滤器,如果用户未 登录,则重定向到指的登录页面 – 要求:需检查的在 Session 中保存的关键字; 如果用户未登录,需 重定向到指定的页面(URL不包括 ContextPath); 不做检查的URL列 表(以分号分开,并且 URL 中不包括 ContextPath)都要采取可配置 的方式

典型应用4:
? 利用Filter限制用户浏览权限

提交表单 调用方法 powerManageServlet 返回对应的 派发页面 user 对象 xml 查询

UserDAO

customers.xml

powermanager.jsp

powermanager.jsp

调用方法

xml 更新

updatePowerServlet
派发页面

UserDAO

customers.xml

logonFilter
检查是否登录

powerFilter
检查是否具备权限

装饰 HttpServletRequest 对象
? 需求:在 HttpServletRequest 对象到达 Servlet 之前把用户 输入的多余空格都去掉 ? 情景:因为 HttpServletRequest 对象里的请求参数都实际 包含在 java.util.Map 对象里,而Map是不允许修改的,所以 包含在 HttpServletRequest 对象里的请求参数不能被修改 ? 解决方案:采取 Decorator(装饰器)模式

Decorator 模式
? 因为继承的关系,当需要改变某个对象的行为时,只须扩 展这个对象所属的类并重写其有关的方法就可以达到目的。 但是,当想要改变其行为的对象是由应用程序里的另一个 子系统(例如:一个对象工厂或是一个Servlet 容器)负责构 造,继承机制将无能为力

Decorator 模式----情景
? 已知:Messager 类的定义(可以从它派生处一个之类); Messager 对象总是来自一个对象工厂(MessagerFactory), 该工厂可以对它创建的每一个 Messager 对象进行初始化---通过调用 getMessage() 方法而获得的 message 属性也 不例外(即不能对 Messager 对象进行初始化) ? 假设:需要使用 Messager 类的 getMessage() 方法。有一 个Util的使用工具类,该类中有如下方法:
public static void broadcast(Message messager){ System.out.println(messager.getMessage()); }

Decorator 模式----需求,方案
? 需求:让 broadcast 方法打印的字母都是大写字母 ? 方案:从 Messager 类派生一个子类,把子类对象传 递给 broadcast 方法。因为只有对象工厂知道如何初 始化 Messager 对象,所以该方案无意义 ? Decorator 模式:
– 从 Messager 类派生一个子类 MessagerDecorator,把子类 对象传递给 broadcast 方法 – 在 MessagerDecorator 类里实现构造器:接受一个 Messager 对象作为输入参数,而这个 Messager 就是想要装 饰的对象:public MessagerDecorator(Messager messager) – 重写 getMessage 方法,让重写的方法用大写字母来返回 message 属性

HttpServletRequestWrapper 类
? Servlet API 中提供了一个 HttpServletRequestWrapper 类来包装原始的 request 对象, HttpServletRequestWrapper 类实现了 HttpServletRequest 接口中的所有方法,这些方法的内部 实现都是仅仅调用了一下所包装的的 request 对象的对应 方法 ? 相类似 Servlet API 也提供了一个 HttpServletResponseWrapper 类来包装原始的 response 对象

典型应用5:为论坛过滤不雅文字和HTML特殊字符
? 开发论坛模块时要解决以下两个问题:
– 1. 用户回复或发帖时可能会输入 HTML 代码(例如:<, >等), 这可能会破坏论坛的正常显示,也可能会带来安全隐患。 – 2. 某些用户在回复时可能会输入不雅子句,这些子句会给论 坛带来不好的影响 – 3. 实现对不雅文字的可配置

? 要求:不雅文字及其替换内容实现可配置。
I shit you! I **** you! I s*h*i*t you!

例子:开发一个留言板程序

例子:开发一个留言板程序

HttpServletRequst:RequestFacade content.jsp ContentFilter

请求

HttpServletRequst 对象 (成员变量)RequestFacade

bbs.jsp


相关文章:
更多相关标签: