4

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

背景

  • 我们使用 Spring Portlet MVC 3.1 和 Render & Action 阶段的注释
  • 我们正在使用 JBoss EPP 5.1.1

问题

  • 对于带有参数的 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 注释(没有参数)的方法,而不是列表下方的正确方法.

显示的错误

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

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

问题

  1. 我们的假设不正确吗?
  2. 我们的诊断是否反映了预期的行为?还是 Spring Portlet MVC 的错误?
  3. 是否有其他方法可以扫描注释以形成处理程序映射 bean 列表?
  4. 使用 xml 配置(而不是注释)会解决我们的问题吗?
  5. 我们能否定义多个处理程序映射和顺序,以便默认处理程序映射是调度程序 portlet 使用的最后一个处理程序映射?

您对此问题的任何想法或建议将不胜感激。

4

5 回答 5

1

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

我被卡住了,因为我确定各个部分(控制器)一次都在工作,但是对渲染请求的调用被随机忽略了。有时改变一些东西会使事情在渲染请求上再次工作,但他们从来没有一起工作过。

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

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

于 2012-07-11T13:46:42.467 回答
1

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

在我的情况下,我的默认控制器(带有空@Controller@ActionMapping注释)总是被调用,即使有更具体的注释控制器/动作(例如@Controller(XXXX)or @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 错误(它报告一些处理程序不应该相等),这意味着处理程序的顺序在两个 JRE 之间是不确定的。

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

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

于 2012-07-31T23:03:53.103 回答
0

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

于 2013-09-19T09:34:20.880 回答
0

迈克,您的描述与我们遇到的问题完全相同。在 Windows 中,我们实现了相同的解决方法(在控制器前面加上 Z 的默认渲染)并解决了这个问题。Linux 环境中的相同代码与您的问题相同。看起来这是一个时间戳问题排序,因为没有被选中的方法,但走这条路没有运气。

我认为这是一个弹簧错误。

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

我现在只是找到了一种解决方法。我将具有默认渲染方法的控制器移动到不同的包中,因此它不包含在组件扫描中。

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

于 2012-05-07T15:30:00.577 回答
0

从 Ashish Sarin 收到的回复:

嗨迈克,

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

如果您仍然遇到这种方法的任何问题,请告诉我。

于 2012-05-04T09:30:28.960 回答