Spring portlet MVC 3.1如何确定使用多个控制器呈现哪个带注释的方法?

时间:2012-05-03 13:22:39

标签: spring-mvc portlet spring-portlet-mvc

使用多个控制器类和DefaultAnnotationHandlerMapping时,我们遇到了使用Spring Portlet MVC 3.1的问题。

背景

  • 我们正在使用带有注释的Spring Portlet MVC 3.1 for Render&行动阶段
  • 我们正在使用JBoss EPP 5.1.1

问题

  • 对于带有params的Portlet呈现请求,将在portlet中呈现不正确的页面

原因

  • Spring Portlet MVC对@RenderMapping使用的方法与使用正确注释的预期方法不同

技术分析

  1. 我们所有的控制器都包含@RenderMapping和@ActionMapping注释,并且都有“params”参数,以确保根据我们的portlet URL中的参数集调用预期的方法。对于默认渲染,我们有一个方法,它有一个没有“params”参数的@RenderMapping注释,当请求不包含参数时,我们使用它来渲染空白JSP。

  2. 根据本书第7章和第8章的内容,我们了解到Dispatcher Portlet尝试获取传入请求的相应处理程序映射,并将其发送到配置的控制器bean中的相应方法。我们的假设是我们的默认@RenderMapping注释(没有参数)只有在检查控制器中没有其他方法的注释与特定请求参数匹配后才会被调用。

  3. 但是,我们已经调试,意识到这个假设是不正确的。 DefaultAnnotationHandlerMapping似乎以某种预定义的顺序遍历Controller bean中可用的注释列表。这意味着如果具有默认@RenderMapping注释(没有参数)的控制器bean出现在列表之前,则将调用具有默认@RenderMapping注释(没有参数)的方法,而不是在列表中更下方的正确方法

  4. 表现错误

    我们正在Windows环境中开发并部署到Linux环境。在Windows中,我们看到处理程序按字母顺序循环遍历控制器bean,因此我们最初通过在控制器中添加@RenderMapping带注释的方法来解决我们的问题,其中bean名称最接近'Z'。

    然而,在Linux中,似乎以不同的顺序检测到控制器bean。我已经附上了下面的Spring日志以突出显示该问题。 no params @RenderMapping注释位于YourDetailsController中,正如您在Windows日志中看到的那样,它出现在列表的最后,而在Linux中却没有。这意味着如果我们尝试访问列表中YourDetailsController之后出现的其中一个控制器,我们总是最终在YourDetailsController中找到no params注释。

    问题

    1. 我们的假设不正确吗?
    2. 我们的诊断是否反映了预期的行为?或者它是Spring Portlet MVC的错误?
    3. 是否有不同的方法来扫描注释以形成处理程序映射bean列表?
    4. 使用xml配置(而不是注释)会删除我们的问题吗?
    5. 我们能否定义多个处理程序映射和顺序,以便默认处理程序映射是调度程序portlet使用的最后一个处理程序映射?
    6. 对此问题的任何想法或建议都将不胜感激。

5 个答案:

答案 0 :(得分:1)

麦克。我遇到了完全相同的问题。我正在使用JDK 7,Spring 3.1.1.RELEASE和Hibernate 4.1.3.Final。我正在开发Linux(Fedora)并在Linux上部署(Fedora和SL)。

我被卡住了,因为我确信各个部分(控制器)一次只能工作一个,但是随机忽略了对渲染请求的调用。有时候改变某些东西会使渲染请求中的东西再次起作用,但它们从未一起工作过。

正如Walter建议的那样,当我在其自己的包中隔离仅包含默认渲染请求的控制器时,只留下默认的渲染请求(在我有删除/查看请求之前)并将portlet中的控制器扫描分开两个XML配置与其他人一起扫描默认控制器后,突然一切都像魅力一样。

看看这个bug是否在Spring跟踪器中会很有趣......

答案 1 :(得分:1)

我最近被这个问题所困扰,所以我想根据我发现的内容添加一些额外的信息。

在我的情况下,我的默认控制器(带有空@Controller@ActionMapping注释)总是被调用,即使有更具体的带注释的控制器/操作(例如@Controller(XXXX)@ActionMapping(YYYY))。让我的案例更奇怪的是它在Tomcat / Pluto中运行良好,但在WAS / WebSphere Portal Server中运行不正确。

事实证明,Spring的3.1.x中引入了一个错误,这意味着注释处理程序没有正确排序。请参阅https://jira.springsource.org/browse/SPR-9303https://jira.springsource.org/browse/SPR-9605。显然,这已在3.1.3中修复。

对我而言,最大的谜团是它为什么在Tomcat工作而不是WebSphere?根本原因是Pluto(2.0.3)使用Sun JRE 1.6.0而WebSphere使用IBM JRE 1.5.0。这两个JRE具有不同的Collections.sort()实现,在排序报告它们相等的数组元素(即compareTo()函数的结果)时会产生不同的输出顺序。由于上面的Spring bug(它报告一些处理程序在不应该处理时是相等的),这意味着处理程序的顺序在两个JRE中是不确定的。

因此,就我而言,IBM JRE恰好将默认控制器作为第一个元素,因此每次都会被拾取。我们可以影响“相等”处理程序的排序的一种方式(其中“等于”是由于Spring错误导致的一个狡猾的定义)是改变Spring发现它们的顺序 - 这会影响输入到排序的顺序常规。这就是为什么,根据上述帖子,将控制器从组件扫描移动到在XML配置中明确列出的工作。在我的例子中,将我的默认控制器包作为组件扫描中的最后一个条目就足够了。我不需要将它移动到XML配置。

无论如何,希望这有助于更多地了解正在发生的事情。

答案 2 :(得分:0)

Ashish Sarin的回复:

  

嗨,迈克,

     

虽然我没有测试过您所遵循的完全相同的情况   在你的项目中,但我可以说它看起来不正确   定义控制器的方法。如果你的控制器只能使用   @RenderMapping和@ActionMapping注释,那么它可能是   开发人员很难找到确切的控制器   负责处理传入的portlet请求。我会   建议您在类型级别使用@RequestMapping   将portlet请求映射到特定控制器,并使用请求   参数进一步缩小了对特定方法的请求   在控制器中。

     

如果您仍然遇到此问题的任何问题,请与我们联系。

答案 3 :(得分:0)

迈克,您的描述与我们遇到的问题完全相同。在Windows中,我们实现了相同的解决方法(将控制器与带有Z的默认渲染作为前缀)并解决了它。 Linux环境中的相同代码与您的问题相同。它看起来像是一个时代邮票问题,因为这些方法没有被选中,但没有运气去那条路。

我认为这是一个春天的虫子。

我认为这里的方法还可以 - 我们希望不同的控制器处理不同的功能,但我们需要一个默认的控制器。

我刚刚找到了一个解决方法。我使用默认渲染方法将控制器移动到另一个包,因此它不包含在组件扫描中。

我在组件扫描行之后手动添加该控制器(在portletname-portlet.xml文件中),因此它将其添加为最后一个控制器。

答案 4 :(得分:0)

我们使用context:component-scan(在nnn-portlet.xml中)来划分portlet之间的控制器默认渲染映射。