JavaWeb 学习笔记 7:Filter

JavaWeb 学习笔记 7:Filter

1.快速开始

使用过滤器的方式与 Servlet 类似,要实现一个Filter接口:

@WebFilter("/*")
public class FirstFilter implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("pre chain.doFilter");
        // 放行请求
        chain.doFilter(request, response);
        System.out.println("after chain.doFilter");
    }

    public void destroy() {

    }
}

这里 @WebFilter 指定的是过滤器拦截的路径规则,/*是对所有请求进行拦截。

Fitler接口有三个方法:

  • init,过滤器初始化时执行
  • doFilter,拦截请求
  • destroy,过滤器销毁时执行

doFilter方法中,通常需要执行chain.doFilter()方法放行请求,否则请求就不会正常被 Servlet 进行处理,直接被 Filter 阻断。

添加一个 JSP 以观察 Filter 的执行过程:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    Title


Hello World!

<% System.out.println("hello.jsp..."); %>

请求这个 JSP 会看到如下输出:

pre chain.doFilter
hello.jsp...
after chain.doFilter

整个过程可以用下图表示:

JavaWeb 学习笔记 7:Filter_第1张图片

2.Filter 拦截路径

Filter 可以拦截以下几种路径:

  • 具体路径,比如/jsp/hello.jsp,只有访问这个 JSP 的请求会被拦截。
  • 目录,比如/jsp/*,访问/jsp这个目录下的所有资源路径都会被拦截。
  • 后缀名拦截,比如*.jsp,左右访问后缀名为.jsp的资源都会被拦截。
  • 拦截全部,/*,访问任意资源都会被拦截。

3.过滤器链

一个 Web 应用可以配置多个过滤器,这些过滤器合称“过滤器链”。

下面看实际演示。

在应用中设置两个过滤器:

@WebFilter("/*")
public class Filter1 implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("before filter1 chain.doFilter");
        chain.doFilter(request, response);
        System.out.println("after filter1 chain.doFilter");
    }

    public void destroy() {

    }
}

@WebFilter("/*")
public class Filter2 implements Filter {
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("before filter2 chain.doFilter");
        chain.doFilter(request, response);
        System.out.println("after filter2 chain.doFilter");
    }

    public void destroy() {

    }
}

请求 JSP 页面可以看到如下输出:

before filter1 chain.doFilter
before filter2 chain.doFilter
hello.jsp...
after filter2 chain.doFilter
after filter1 chain.doFilter

如果使用注解配置过滤器,过滤器在过滤器链上的先后顺序由过滤器类名做字典排序决定。

4.案例:登录验证

使用过滤器可以对一些需要在多个 Servlet 中进行的统一处理进行简化。比如每个 Servlet 都需要的请求内容乱码处理或者响应报文添加统一的报文头等等。

这里展示如何使用过滤器实现登录验证功能。

@WebFilter("/*")
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 对登录相关请求和静态资源进行放行
        String[] paths = new String[]{
                "/user/login",
                "/user/registry",
                "/user/check_code",
                "/css/",
                "/imgs/",
                "/index.jsp"
        };
        if (!(request instanceof HttpServletRequest &&
                response instanceof HttpServletResponse)){
            throw new RuntimeException("This is not web Application.");
        }
        HttpServletRequest hRequest = (HttpServletRequest) request;
        HttpServletResponse hResponse = (HttpServletResponse) response;
        String url = hRequest.getRequestURL().toString();
        String prefix = "http://"+hRequest.getHeader("host")+hRequest.getContextPath();
        for (String path: paths){
            if (url.indexOf(prefix+path) == 0){
                // 符合规则,放行
                System.out.println("放行"+url);
                chain.doFilter(hRequest, hResponse);
                return;
            }
        }
        // 检查是否登录,如果没有登录,重定向到登录页面
        Object username = hRequest.getSession().getAttribute("username");
        if (username == null){
            hResponse.sendRedirect("/login-demo/user/login");
            return;
        }
        // 已经登录,放行
        chain.doFilter(hRequest, hResponse);

    }

    @Override
    public void destroy() {

    }
}

需要注意的是,这里除了需要通过 Session 判断是否登录状态,没有登录的让重定向到登录页面以外,还需要对于特殊路径进行放行,否则有些页面就无法正常显示。在我们这个示例中,需要非登录状态就可以访问的资源有:

  • CSS
  • 图片
  • 登录相关的 Servlet
  • 注册相关的 Servlet
  • 返回验证码的 Servlet
  • 首页(用于重定向到登录页)

对于这些特殊资源,这里简单地用字符串匹配的方式判断和处理。

5.Listener

Listener、Filter 和 Servlet 是 JavaWeb 的三大组件。

Listener 的用途是监听 Application\Session\Request 三个对象的创建、销毁或属性的修改和删除。

具体包含以下监听器:

JavaWeb 学习笔记 7:Filter_第2张图片

利用 ServletContext监听器,我们可以在 Servlet 容器创建后执行一些应用的初始化代码:

@WebListener
public class ApplicationRunner implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // 这里执行一些应用的初始化工作
        System.out.println("Web Application is already run...");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // 这里执行应用退出时的清理工作
    }
}

使用监听器很容易,只要实现相应的接口,并使用@WebListener注解标记类即可。

本文的完整示例可以从这里获取。

6.参考资料

  • 黑马程序员JavaWeb基础教程

你可能感兴趣的:(JAVA,学习,笔记,java)