• [Java] JSP笔记


    一、什么是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 讲师

  • 相关阅读:
    ios8 xcode6 下的启动界面设置和图标设置
    写一些有关android的东西吧,那时候玩android时候的一些笔记
    使用sqlite3 有关tableview删除cell的问题
    iOS 使用CLGeocoder获取地理位置
    ios 解决有关火星坐标的问题
    iOS 火星坐标相关整理及解决方案汇总(转)
    IOS开发UI篇之──自定义UIActionSheet
    python中新式类和经典类的区别
    python中几个常用的算术函数
    多线程
  • 原文地址:https://www.cnblogs.com/yangyxd/p/5624145.html
Copyright © 2020-2023  润新知