Java Web 基础 - 过滤器

  • 过滤器是一种服务端组件,可以截取客户端请求和响应信息,对信息进行过滤,包括过滤源 -> 过滤规则 -> 过滤结果;
  • 过滤器可以改变用户请求的 Web 资源(用户请求路径),但不能直接返回数据、处理用户请求(不是标准的 Servlet);
  • 常见使用场景:对请求进行统一认证、编码转换、对发送的数据进行过滤替换、转换图形格式、对响应内容压缩等。

工作原理与生命周期

Web 容器启动使过滤器即启动,接收到用户请求后判断是否符合规则,过滤器把符合规则的请求发送至 Web 资源,处理完成后再经过滤器返回响应给用户。

生命周期:

  1. 实例化(Web 容器启动时加载 web.xml,只实例化一次 );
  2. 初始化(init() 方法);
  3. 对每个请求过滤方法(doFilter() 方法);
  4. 销毁(Web 容器关闭时执行 destroy() 方法销毁)

实现一个过滤器

web.xml

        
    FirstFilter          
    com.ywh.filter.FirstFilter
    
        name               
        ywh
    


    FirstFilter          
    /index.jsp
    FORWARD                

FirstFilter.java

public class FirstFilter implements Filter {

    @Override
    public void destroy() {
        System.out.println("destroy---FirstFilter");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("start----doFilter--FirstFilter");
//      chain.doFilter(request, response);
        HttpServletRequest req =(HttpServletRequest) request;
        HttpServletResponse response2 =(HttpServletResponse) response;
        response2.sendRedirect(req.getContextPath() + "/main.jsp");
//      req.getRequestDispatcher("main.jsp").forward(request, response);
//      req.getRequestDispatcher("main.jsp").include(request, response);
        System.out.println("end------doFilter--FirstFilter");
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init----FirstFilter");
    }
}

过滤器链

对于同一个 URL 可以设置多个过滤器按指定顺序执行。


过滤器链的执行逻辑

    FirstFilter          
    com.ywh.filter.FirstFilter
    
        name               
        zhangsan
    


    FirstFilter          
    /index.jsp


    SecondFilter
    com.ywh.filter.SecondFilter


    SecondFilter
    /index.jsp

过滤器分类

在 Servlet 2.5 中过滤器有四种:

  • REQUEST:用户直接访问页面时调用(重定向、转发);
  • FORWARD:目标资源是通过 RequestDispatcher 的 forward 访问时调用;
  • INCLUDE:目标资源是通过 RequestDispatcher 的 incluer 方法调用时调用;
  • ERROR:目标资源是通过声明式异常处理机制调用时调用。

在 Servlet 3.0 中加入了 ASYNC 支持异步处理。

过滤器注解

使用 @WebFilter 注解将一个类生命为过滤器(在部署时被容器处理,容器将根据具体的属性配置将类部署为过滤器),代替 web.xml 配置过滤器类

@WebFilter(servletNames = {"SimpleServlet"}, filterName="SimpleFilter", value={"/index.jsp"}, dispatcherTypes={DispatcherType.Async})
public class TestFilter implements Filter {
    // ...
}
@WebFilter 常用属性

实例:测试异步过滤器

web.xml



    
    
        This is the description of my J2EE component
        This is the display name of my J2EE component
        AsynServlet
        com.ywh.servlet.AsynServlet
        true
    

    
        AsynServlet
        /servlet/AsynServlet
    
    
        index.jsp
    

AsynServlet.java

public class AsynServlet extends HttpServlet {

    public AsynServlet() {super(); }

    public void destroy() { super.destroy(); }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        System.out.println("Servletִ 执行开始时间:" + new Date());
        AsyncContext context = request.startAsync();
        new Thread(new Executor(context)).start();
        System.out.println("Servletִ 执行结束时间:" + new Date());
    }

    public class Executor implements Runnable {
        private AsyncContext context;

        public Executor(AsyncContext context) { this.context = context; }

        @Override
        public void run() {
            try {
                Thread.sleep(1000 * 10);
                System.out.println("业务执行完成时间:" + new Date());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html");
        PrintWriter out = response.getWriter();
        out.println("");
        out.println("");
        out.println("  A Servlet");
        out.println("  ");
        out.print("    This is ");
        out.print(this.getClass());
        out.println(", using the POST method");
        out.println("  ");
        out.println("");
        out.flush();
        out.close();
    }

    public void init() throws ServletException { }
}

AsynFilter.java

@WebFilter(
    filterName = "AsynFilter", 
    asyncSupported = true, 
    value = {"/servlet/AsynServlet"}, 
    dispatcherTypes = {DispatcherType.REQUEST, DispatcherType.ASYNC}
    )
public class AsynFilter implements Filter {

    @Override
    public void destroy() {}

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
        System.out.println("start.....AsynFilter");
        arg2.doFilter(arg0, arg1);
        System.out.println("end.....AsynFilter");
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException {}
}

实例:对用户请求进行统一认证

login.jsp


    
用户名: 密码:

LoginServlet.java

public class LoginServlet extends HttpServlet {

    public LoginServlet() { super(); }

    public void destroy() { super.destroy(); }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        System.out.println(username);

        if ("admin".equals(username) && "admin".equals(password)) {
            // 校验通过
            HttpSession session = request.getSession();
            session.setAttribute("username", username);
            response.sendRedirect(request.getContextPath() + "/sucess.jsp");
        } else {
            // 校验失败
            response.sendRedirect(request.getContextPath() + "/fail.jsp");
        }
    }

    public void init() throws ServletException { }
}

LoginFilter.java

public class LoginFilter implements Filter {

    private FilterConfig config;

    @Override
    public void destroy() { }

    @Override
    public void doFilter(ServletRequest arg0, ServletResponse arg1, FilterChain arg2) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) arg0;
        HttpServletResponse response = (HttpServletResponse) arg1;
        HttpSession session = request.getSession();

        String noLoginPaths = config.getInitParameter("noLoginPaths");

        String charset = config.getInitParameter("charset");
        if (charset == null) {
            charset = "UTF-8";
        }
        request.setCharacterEncoding(charset);

        if (noLoginPaths != null) {
            String[] strArray = noLoginPaths.split(";");
            // 获取不需要重定向的页面,符合条件则放行(如对于 login.jsp 不再执行重定向)
            for (int i = 0; i < strArray.length; i++) {
                if (strArray[i] == null || "".equals(strArray[i])) 
                    continue;
                if (request.getRequestURI().indexOf(strArray[i]) != -1) {
                    arg2.doFilter(arg0, arg1);
                    return;
                }
            }
        }
        if (session.getAttribute("username") != null) {
            arg2.doFilter(arg0, arg1);
        } else {
            response.sendRedirect("login.jsp");
        }
    }

    @Override
    public void init(FilterConfig arg0) throws ServletException { config = arg0; }

web.xml



    
    
        This is the description of my J2EE component
        This is the display name of my J2EE component
        LoginServlet
        com.ywh.serlvet.LoginServlet
    
    
        LoginServlet
        /servlet/LoginServlet
    
    
        index.jsp
    
    
        LoginFilter
        com.ywh.filter.LoginFilter
        
            noLoginPaths    
            login.jsp;fail.jsp;LoginServlet
        
        
            charset
            UTF-8
        
    
    
        LoginFilter
        /*
    

你可能感兴趣的:(Java Web 基础 - 过滤器)