Spring MVC 应该由哪一层来决定显示下一个视图?

Which layer should decide to display the next view in Spring MVC?

我正在使用 Spring MVC 框架构建应用程序,但存在一个我无法明确解决的架构问题。我的问题是我不完全理解应用程序的哪一部分(层)应该负责控制流(通过流控制我的意思是连续视图的显示 - 页面)。

Spring MVC 中的控制器是视图和应用程序之间的某种适配器。另一方面,服务是基于业务逻辑实现的。

假设我们有一个控制器支持某个端点:

@GetMapping("/goToPageBasedOnLogic")
public ModelAndView passParametersWithModelAndView() {

    ModelAndView modelAndView = null; 
   
    // business logic calculates some stuff...
    if(fooService.bar()) { 
       modelAndView = new ModelAndView("viewPageHello");
       modelAndView.addObject("message", "hello");
    }
    else {
       modelAndView = new ModelAndView("viewPageGoodbye");
       modelAndView.addObject("message", "goodbye");
    }

    return modelAndView;
}

在上面的例子中,控制器根据fooService的结果决定显示哪个视图,从而管理控制流。如果有很多条件,可能会导致控制器中的代码难看。

让我们考虑下一个例子:

@GetMapping("/goToPageBasedOnLogic")
public ModelAndView passParametersWithModelAndView() {

    ModelAndView modelAndView = null; 
    
    session.fooBarResult = fooService.bar(); // logic calculates some stuff and saves in session
    State newState = stateMachine.sendEvent(PAGE_FINISHED_JOB); 
   
    if(newState == State.PAGE_HELLO) { 
       modelAndView = new ModelAndView("viewPageHello");
       modelAndView.addObject("message", "hello");
    }
    else {
       modelAndView = new ModelAndView("viewPageGoodbye");
       modelAndView.addObject("message", "goodbye");
    }

    return modelAndView;
}

在此示例中,显示哪个视图的决定是根据服务和业务逻辑做出的。状态机接收事件,然后根据会话和编码条件,决定 select 下一个视图。然后控制器根据新状态准备正确的视图并 returns 它。控制器对控制流逻辑一无所知。

决定是否显示下一个视图(页面)的解决方案哪种更好?还有其他更有趣的解决方案吗?

我的经验法则是:

  • 服务层应该不知道 UI 的存在。它不应该对 ui 有任何了解,这样服务 class 就会与 ui 解耦,并且可以很容易地在其他上下文中重用(例如将其公开为 API ,另一个新的 ui 在未来等等)所以如果你发现有服务 classes 需要依赖于来自 spring-mvc 或 servlet 等的一些 classes,应该出问题了。

  • ui相关的逻辑,比如下一个画面是什么,应该放在controller层

  • 控制器层应该保持薄。尝试将尽可能多的业务逻辑代码推送到服务层。

所以控制器层应该决定下一个要显示的视图。放在服务层没有意义。否则服务层将耦合到UI(见我的观点1)