SiteMesh:更改响应的内容类型

SiteMesh:更改响应的内容类型

问题描述:

我试图说服SiteMesh装饰器更改响应的内容类型,但没有喜悦。内容类型总是与装饰JSP相同,而不是装饰器。SiteMesh:更改响应的内容类型

例如,说我有一个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,它不能更改状态码或设置标题(任何尝试进行更改都将被忽略)。所以基本上,一旦你设置了内容类型,它的游戏结束了,你不能改变它。

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

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

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

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

第三个(也是丑陋的)解决方法是只是破解SiteMesh的代码,并有自己的方式(不知道你是否会遇到与许可证有关的问题)。

因此,在我看来,除非您愿意诉诸一些丑陋的解决方法,否则您将无法在设置内容类型后进行更改。

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

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