SiteMesh:更改响应的内容类型

时间:2010-02-23 12:47:27

标签: java servlets sitemesh

我试图说服SiteMesh装饰器改变响应的内容类型,但没有快乐。内容类型总是最终与装饰的JSP相同,而不是装饰器的相同。

例如,假设我有一个带标题的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的内容类型,而不是取自装饰器?

2 个答案:

答案 0 :(得分:1)

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

从我看到的情况来看,ContentBufferingResponse方法是实例化SiteMeshFilter类的唯一位置,因此ContentBufferingResponseobtainContent将成为寻找变通方法的地方。

一种可能的解决方法是覆盖SiteMeshFilter的子类中的obtainContent,并使用多态在运行时调用正确的方法。这只有一个问题:obtainContent被标记为私有,因此多态无效。要调用其他doFilter方法,您必须在过滤器中覆盖比此方法更多的内容,而且我担心这将包含setContentType方法本身。

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

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

第三种(也是丑陋的)解决方法是只是破解SiteMesh的代码并对其进行处理(不确定是否会遇到许可证问题)。

因此,在我看来,除非您愿意采用一些丑陋的解决方法,否则一旦设置完毕,您将无法更改内容类型。

答案 1 :(得分:0)

编写适用于您的页面的servlet过滤器,覆盖setContentType()以不调用super,然后在装饰器中将内容类型设置为您想要的任何内容。

你需要再编写一个servlet过滤器,但它应该非常简单。

相关问题