过滤器简介

但这还不是全部。您真的不认为 servlet 有那么简单,是吗?

除了我们已经分析过的 servlet 之外,还有所谓的“实用 servlet”——过滤器。它们与 servlet 非常相似,但它们的主要工作是帮助 servlet 处理请求。

过滤器就像秘书,而 servlet 就像导演。在文件到达主任办公桌之前,它会通过秘书的手。在主管签字后,它会再次交给秘书,例如已经作为外发信函。

这样的秘书可以拒绝对主管的某些请求(例如,垃圾邮件)。或者对他已知的问题给出标准答案(“导演不在位”)。等等。而且,可以有多个这样的秘书:一个可以一次性为所有董事过滤垃圾邮件,另一个可以在不同董事之间传递请求,等等。

过滤器的工作方式相同。

实用程序 servlet”

类 Filter、FilterChain、FilterConfig

过滤器与 servlet 非常相似,但有一些细微差别。要编写自己的过滤器,您需要继承自javax.servlet.Filter.

过滤器也有方法init()destroy()service()过滤器没有方法,而是有一个doFilter(). 甚至有自己的类 FilterConfig。过滤器也被添加到 web.xml 文件中的 servlet 或通过 @WebFilter 注释。

方法列表:

方法 描述
1个 init(FilterConfig config) 过滤器初始化
2个 destroy() 过滤卸料
3个 doFilter(ServletRequest , ServletResponse, FilterChain) 请求处理(过滤)

servlet 和过滤器有什么区别?

可以有多个过滤器,它们按顺序处理请求(和响应)。它们被组合成一个所谓的链 - 甚至有一个特殊的类FilterChain

在方法中处理完请求后,doFilter()需要调用doFilter()链中下一个过滤器的方法。例子:

public class MyFilter implements Filter {

  public void init(FilterConfig arg0) throws ServletException {
  }

  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws Exception {

      PrintWriter out = resp.getWriter();
      out.print("Adding something before the body of the response");

      chain.doFilter(req, resp); // call the next filter in the chain

      out.print("Adding something after the body of the response");
    }

  public void destroy() {
  }
}

实际上,您不能那样添加响应主体。形式上,过滤器和 servlet 是相互独立的,可以独立更改。它们可以由不同的开发人员在不同的时间编写。过滤器功能只是一个服务功能,例如:

  • 记录所有传入的请求(和响应)
  • 数据压缩
  • 数据的加密(和解密)
  • 请求数据验证
  • 添加/删除所需的标题
  • 重定向请求
  • 访问控制(检查用户是否登录)

RequestDispatcher类

doFilter() 有时可能需要在方法中运行过滤器时调用另一个 servlet 。为此,容器有一个特殊的对象RequestDispatcher

您可以通过两种方式获得它:

  • 在对象HttpServletRequest
  • 在对象ServletContext

该对象可用于将现有请求重定向到另一个 servlet。例如,原来用户没有被授权,我们想给他看一个有授权的页面。好吧,或者服务器出现错误,我们想向用户显示一个错误页面:)

public class HelloServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response)  throws Exception {
           String path = "/error.html";
           ServletContext servletContext = this.getServletContext();
           RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher(path);
           requestDispatcher.forward(request, response);
    }
}

您也可以RequestDispatcher从过滤器调用。

public class MyFilter implements Filter {

  public void init(FilterConfig arg0) throws ServletException {
  }

  public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws Exception {
           String path = "/error.html";
           ServletContext servletContext = req.getServletContext();
           RequestDispatcher requestDispatcher = servletContext.getRequestDispatcher(path);
           requestDispatcher.forward(req, resp);
    }

  public void destroy() {
  }
}

注意请求会在方法中处理,使用后forward()不需要再调用。doFilter()RequestDispatcher

重定向和转发的比较

还有一点很重要。如果你想将用户重定向到你的 servlet 中的另一个 URI,那么你可以通过两种方式做到这一点:

  • redirect
  • forward

我们已经对它们进行了分析,但为了方便我再说一遍。

当您通过调用重定向response.sendRedirect("link")时,服务器会向浏览器(客户端)发回响应302和您指定的链接。浏览器在分析服务器响应后,会下载您传递的链接。即,浏览器中的链接更改为新链接。

如果您通过 call转发requestDispatcher.forward(),则会在容器内发出一个新请求,并且您的 servlet 会将其响应发送给浏览器(客户端)作为您的 servlet 的响应。在这种情况下,浏览器收到来自新 servlet 的响应,但浏览器中的链接没有改变。