【问题标题】:Java Spring MVC stateless-to-stateful handoverJava Spring MVC 无状态到有状态的切换
【发布时间】:2010-11-27 09:47:31
【问题描述】:

虽然我已将此标记为 java/spring 问题,但可以轻松地询问任何具有无状态控制器的 mvc 框架。我知道 Rails 使用简单的无状态控制器,所以也许你们知道如何最好地解决这个问题。我可以最好地描述 java/spring mvc 的问题,它是实现 - 请原谅 java 行话。

问题

我们很难想出一种令人满意的方式来在 spring mvc 中执行无状态到有状态的切换。 本质上给出了这样的结构:

型号:Unit 状态:撤回、可用、不可用 以及操作:getOutline()getHelp()

控制器:UnitController 带有操作:displayOutline()displayHelp()

在执行displayOutline()操作之前,我们需要一种方法来检查单元的状态(因为单元本身可能会被撤回,因此用户应该被转发到撤回的页面)。

我们尝试了多种方式来做到这一点,包括:

最简单的方法(任何语言)

控制器中所有需要“可用”状态单元的方法在其实现的第一行调用方法 isAvailable()。显然这里有很多复制,很臭。

AOP 方式(Java 特有)

可以创建一个名为 UnitAccess 的 @Around 通知,它会检查并重新路由控制流(即,不是调用会调用底层方法的proceed(),而是调用控制器上的另一个方法)。这似乎是一种 hack,而不是真正的 AOP,它确实消除了复制,但增加了复杂性并降低了透明度。

拦截器(由 servlet 架构提供,但可能在其他框架中可行)

它检查单元状态并从根本上改变实际的 URL 调用。这似乎也不对。我们不喜欢在到达控制器之前调用模型逻辑的想法。

我们考虑过

命令模式

创建一个命令模式结构,它(使用继承)可以返回一个撤回的视图或有效的 displayOutline 视图。由于 execute 方法将在 super()call 中执行检查以及具体命令中的特定逻辑。即创建一个对象结构,如

DisplayOutlineCommand extends UnitCommand

    public void execute(){
        super();
        // must be ok, perform getOutline()
    }

最后,使用自定义异常

在服务级别对象上调用getAvailableUnit(),它将在返回单元之前检查可用性等。如果该单元被撤回,那么它将抛出一个 UnitWithdrawnException,该异常可以被 servlet 捕获并通过返回适当的视图来处理。还是不服气。我们也不热衷于使用异常进行正常流控制的想法。

我们错过了什么吗?在 spring/另一个无状态控制器框架下有没有简单的方法来做到这一点?

【问题讨论】:

  • 对使用 AOP 的反思:我们认为这不是它的正确位置,因为我们通常认为横切关注点不应该“摆弄”它所使用的类/方法的主要功能。 “日志”或“事务管理”是 AOP 的重要用途,因为它们本质上是在不改变上下文的情况下进行装饰。控制器的主要功能是控制流程,使用 AOP 来处理控制器内部的流程似乎并不正确。

标签: java model-view-controller oop spring


【解决方案1】:

也许我没有抓住重点,但是如果单元被撤回,用户为什么要来控制器?

我认为最好确保通常页面不会链接到要求该单元“正常”的控制器,如果该单元不“正常”。 如果 Unit 的状态在呈现引用页面和实际调用进入控制器之间发生变化(它不再是“OK”),那么使用异常来处理该事件对我来说似乎完全没问题(就像发生乐观锁定错误时出现异常一样)。

【讨论】:

  • 谢谢弗里德,我为你的观点投了你的票,但我不能给你打勾。基本上我得出的结论是有状态的控制器太难了。似乎没有人在现实世界中使用它们。相反,开发人员选择无状态控制器并将状态存储在 httpsession 对象或类似对象中。大公司似乎更喜欢这种方法,它可以让他们更好地扩展。我仍然很想听听其他人关于这个问题的想法,但是它调用了很多东西,我最喜欢的名字是一次性控制器(因为它们的生命周期绑定到请求范围)
  • 仅供参考,在这种情况下,我们最终选择了异常方法。
【解决方案2】:

也许您还没有描述整个问题,但为什么不把检查放在displayOutline() 本身呢?也许路由到displayOutlineOrHelp() 方法,它看起来基本上像

ModelAndView displayOutlineOrHelp(...)  {
    Unit unit = ... //code to get the unit the request refers to

    return unit.isAvailable() ? displayOutline(...) : displayHelp(...);   
}

【讨论】:

  • 感谢您的回答,但有点错过。 displayOutline() 和 displayHelp() 是具有完全不同视图的不同方法。可能是 app/unit/outline 和 /app/unit/help 的示例 url。关键是两者都需要一个处于“正常”状态的单元。我们的 20 种视图方法需要一个单元才能“正常”。我们可以添加一个方法调用(方法 1),但它看起来更像是一个横切关注点(AOP - 方法 2),但它似乎不是正确的解决方案。理想情况下,我们正在寻找一种与标准 oo 隐喻一致且不会增加复杂性的特征。
  • 啊 - 我明白了 - 我误解了这个问题。我会说 AOP 是实现它的方法 - 这当然可以用纯 OOP 实现,但它需要更多的工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-01-08
  • 2015-05-09
  • 2023-03-27
  • 2012-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多