java - SiteMesh:更改响应的内容类型

标签 java servlets sitemesh

我试图说服 SiteMesh 装饰器更改响应的内容类型,但我并不高兴。内容类型最终总是与装饰的 JSP 相同,而不是装饰器的类型。

例如,假设我有一个带有 header 的 JSP

<%@ page contentType="application/xhtml+xml" %>

我还有一个 SiteMesh 装饰器 JSP,它定义了这个:

<%@ page contentType="application/vnd.wap.xhtml+xml" %>

我想要的是装饰响应具有装饰器的 MIME 类型(这里使用的实际 MIME 类型并不重要,这只是为了说明问题)。

深入研究 SiteMesh 2.4.1 源代码表明问题出在 ContentBufferingResponse 类,该类负责捕获目标的输出。这会覆盖 setContentType() 方法,记录值供以后使用,但它也会调用 super.setContentType(),有效地直接传递目标 JSP 的内容类型到响应。一旦完成,再多的哄骗也无法说服响应不这样做。

那么有解决办法吗?是否可以抑制目标 JSP 的内容类型,并改为从装饰器中获取?

最佳答案

ContentBufferingResponse.setContentType 将触发对 HttpServletResponseWrapper.setContentType 的调用。稍后,装饰器使用 RequestDispatcher.include 包含在响应中,它不能更改状态代码或设置 header (忽略任何更改尝试)。所以基本上,一旦你设置了内容类型,它就结束了,你不能改变它。

据我所知,SiteMeshFilter.obtainContent 方法是唯一实例化 ContentBufferingResponse 类的地方,所以 SiteMeshFilter ContentBufferingResponse 将是寻找解决方法的地方。

一种可能的解决方法是覆盖 SiteMeshFilter 的子类中的 obtainContent 并使用多态性在运行时调用正确的方法。这只有一个问题:obtainContent 被标记为私有(private),因此多态性将不起作用。要调用不同的 obtainContent 方法,您必须在过滤器中覆盖比此方法更多的内容,而且恐怕会包括 doFilter 方法本身.

另一种解决方法是以某种方式调用另一个版本的 setContentType 方法,该方法不使用装饰页面的 mime 类型调用 super.setContentType。但是您不能更改对另一个方法的调用,因为在 obtainContent 的代码中,我们使用“new”实例化了一个 ContentBufferingResponse 实例。

此时,您可以在项目中创建 ContentBufferingResponse 类的副本(在相同的包声明下),其中 setContentType 方法调用 super .setContentType 使用您想要的 mime 类型,而不是装饰页面中的 mime 类型。然后,您可以通过使用类路径并确保您的类在 SiteMesh 的 jar 中的类之前加载,从而欺骗服务器加载您的类而不是原始类。如果您有多个装饰器(我相信您有 :D),这里的主要问题将是在不同的 MIME 类型之间进行管理。

第三种(也是丑陋的)解决方法是破解 SiteMesh 的代码并按照自己的方式解决(不确定您是否会遇到许可证问题)。

因此,在我看来,除非您愿意诉诸一些丑陋的变通办法,否则您将无法在设置内容类型后更改它。

关于java - SiteMesh:更改响应的内容类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2318165/

相关文章:

java - 当表已经创建时,设置长度在 hibernate 中不起作用

jsp - sitemesh 与 jsp-config (<include-prelude>)

java - 如何将参数传递给自定义适配器?

java - 简单的 Android 许可

java - 可以将子域映射到标准 Java 应用程序服务器中的 Web 应用程序吗?

javascript - 在超链接的点击事件上调用javascript函数

java - Grails 资源插件入门

layout - Sitemesh布局不适用于Grails中的g.include标记

java - 如何运行单一场景

java - 从 servlet 运行 C++ exe