ServletResponse和HttpServletResponseWrapper之间的区别?

2022-09-03 09:39:35

我是servlet的新手,正在阅读一些关于过滤器和包装器的文本。我可以理解过滤器,但对包装器感到困惑。在书中,作者举了一个例子:

如果没有包装器:

public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {

        String name = request.getParameter("name").trim();

        try {
            chain.doFilter(request, response);
            PrintWriter out = response.getWriter();
            if (name.length() == 0) {
                out.println("Some message");
                out.println("</body>");
                out.println("</html>");
                out.close();
            }
        } catch (Throwable t) {
        }
    }

在包装器的情况下:

 public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {

        String name = request.getParameter("name").trim();

        HttpServletResponse httpRes = (HttpServletResponse) response;
        HttpServletResponseWrapper resWrapper = new HttpServletResponseWrapper(httpRes);
        try {
            chain.doFilter(request, response);

            PrintWriter out = resWrapper.getWriter(); // why dont we just use response.getWriter();
            if (name.length() == 0) {
                out.println("<h3>Some message");
                out.println("</body>");
                out.println("</html>");
                out.close();
            }
        } catch (Throwable t) {
        }
    }

为什么我们需要,而我们可以在案例1中做同样的事情?任何人都可以给我一个我们必须使用的明确例子来代替?我试图谷歌,但没有找到运气。HttpServletResponseWrapperServletResponseHttpServletResponseWrapperServletResponse


答案 1

BalusC的答案很好,但如果你刚刚开始,它可能会有点压倒性。

简而言之:SerlvetResponse及其扩展,HttpServletResponse,是告诉你哪些方法可以调用来做你需要的事情的接口。在使用 Filters、Servlets 等的正常过程中,您将经常使用 HttpServletResponse 来告诉您的应用程序如何响应请求。

HttpServletResponseWrapper是HttpServletResponse的一个特殊实现,它为您提供了一种方便的方法,可以用您自己的一些逻辑包装现有响应,而无需编写接口的全新实现。它有很多方法,所以这真的很好。举一个简单的例子,假设你想禁止调用responser.flushBuffer()。这段代码,使用HttpServletResponseWrapper,将做到这一点:

class DisallowFlushResponseWrapper extends HttpServletResponseWrapper {
    public DisallowFlushResponseWrapper(HttpServletResponse response) {
        super(response);
    }

    @Override
    public void flushBuffer() {
        throw new UnsupportedOperationException("Don't call this!");
    }
}

使用这种包装器的典型方法是创建一个这样的过滤器:

class DisallowFlushFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) {
        if (response instanceof HttpServletResponse) {
            HttpServletResponse newResponse =
                new DisallowFlushResponseWrapper((HttpServletResponse) response);
            chain.doFilter(request, newResponse);
        }
        ...
    }
    ...
}

请注意,我们使用自己的包装器实例包装进入筛选器的响应。然后,我们将包装器交给过滤器链中的下一个项目。因此,如果此筛选器之后的任何内容调用 flushBuffer() 都会得到一个异常,因为它将在我们的包装器上调用它。由于其默认行为,包装器将任何其他调用委托给包装的响应,这是真正的响应,因此除了对该方法的调用之外,所有内容都将正常工作。


答案 2

这实际上是一个愚蠢的例子,它没有显示请求/响应包装器的好处。实际上,整个过滤器示例很差。发布HTML应该由JSP完成,或者最高由servlet完成(但这仍然很差)。浏览我们的过滤器wiki页面,以获取有关过滤器可用于哪些用途的一些想法。

如果要修改响应的行为,或者只想在请求-响应链中使用响应时收集有关响应的信息则响应包装器非常有用。每当某些 servlet 或 JSP 在响应上调用某个方法时,就会发生修改后的行为。如果在包装类中重写了它,则将改为调用此类。您可以在那里改变行为或收集信息。

在Stackoverflow上,您可以找到一些有用的实现的具体示例。HttpServletResponseWrapper


推荐