我正在尝试说服一个SiteMesh装饰者更改响应的内容类型,但没有得到joy的响应。内容类型最终总是与装饰的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 type直接传递给响应。一旦这样做了,再多的哄骗也不会说服对方做其他的事情。
那么有没有解决这个问题的办法呢?是否可以隐藏目标JSP的content-type,而从装饰器中获取?
发布于 2010-04-15 18:04:34
ContentBufferingResponse.setContentType将触发对HttpServletResponseWrapper.setContentType的调用。稍后,使用不能更改状态代码或设置标头的RequestDispatcher.include将装饰器包含在响应中(任何更改的尝试都将被忽略)。所以基本上,一旦你设置了内容类型,它的游戏结束了,你就不能改变它了。
在我看来,SiteMeshFilter.obtainContent方法是ContentBufferingResponse类唯一被实例化的地方,因此SiteMeshFilter和ContentBufferingResponse将是寻找变通方法的地方。
一种可能的解决方法是在SiteMeshFilter的子类中重写obtainContent,并通过使用多态性在运行时调用正确的方法。这样做只有一个问题:obtainContent被标记为私有,所以多态性不起作用。要调用不同的obtainContent方法,您必须在过滤器中重写比此方法多得多的内容,我担心这将包括doFilter方法本身。
另一种解决方法是以某种方式调用另一个版本的setContentType方法,该方法不使用修饰页的mime类型调用super.setContentType。但是您不能更改对另一个方法的调用,因为在obtainContent的代码中,我们使用“ContentBufferingResponse”实例化了一个新实例。
此时,您可以在项目中创建ContentBufferingResponse类的副本(在相同的包声明下),其中setContentType方法使用所需的mime类型调用super.setContentType,而不是来自修饰页面的mime类型。然后,您可以欺骗服务器加载您的类,而不是原来的类,方法是使用类路径并确保您的类在SiteMesh的jar中的类之前加载。如果你有多个装饰器(我确信你有:D),这里的主要问题将是在不同的mime类型之间进行管理。
第三个(也很难看)的解决办法就是破解SiteMesh的代码,然后随心所欲(不确定你是否会遇到许可证的问题)。
因此,在我看来,除非你愿意求助于一些丑陋的变通方法,否则一旦设置了内容类型,你就不能改变它。
发布于 2011-02-22 13:12:29
编写一个应用于页面的servlet过滤器,覆盖setContentType()以不调用super,然后在装饰器中将内容类型设置为您想要的任何类型。
您需要再编写一个servlet筛选器来完成此任务,但它应该非常简单。
https://stackoverflow.com/questions/2318165
复制相似问题