2

我试图说服 SiteMesh 装饰器更改响应的内容类型,但没有任何乐趣。content-type 最终总是与被装饰的 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 的内容类型,并取而代之从装饰器中获取?

4

2 回答 2

1

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

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

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

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

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

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

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

于 2010-04-15T10:04:34.280 回答
0

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

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

于 2011-02-22T05:12:28.570 回答