【问题标题】:MVC design Pattern and Form processing [duplicate]MVC设计模式和表单处理[重复]
【发布时间】:2013-04-22 06:31:01
【问题描述】:

我想知道您将在 MVC 框架中的何处处理表单提交? 您是否有一个模型来处理逻辑或直接在控制器中处理它?

假设这是一个注册表单,最终会在数据库中创建一个用户。

你会如何处理这样的事情?

我的做法是验证控制器中的表单数据,使用数据创建用户模型并将其保存到数据库中。 但是,我已经看到专门处理表单数据的模型(控制器加载了一个表单模型,将 $_POST 数据传递给它),我想知道是否有必要

谢谢

【问题讨论】:

  • 好吧,如果您使用的是 Apple 的 MVC,我会说控制器应该解析表单数据并使用该数据创建模型。如果您使用的是“传统”MVC,我会说模型应该处理这个问题。
  • 你使用的是什么 MVC 框架?
  • 很可能是以下内容的副本:What is the right way to handle $_POST data in MVC?
  • @Carlos。你说的对。该线程几乎涵盖了我的答案。谢谢

标签: oop model-view-controller


【解决方案1】:

以下是Struts 2(最好的 MVC 框架之一)如何处理典型的用户注册。

Registration Page --Submit-->
    Filter Dispatcher (Controller) --Struts-->
        Interceptor --Stack--> Validator --Passed-->
            Action (Model)
                --Invokes--> Service/DAO Layer --Persists--> Database
            Result <--returns-- Action
        JSP (View) (selected based on result)
    Interceptor (any post-processing)
Registration Success HTML

Servlets 不同,您实际上并没有编写任何控制器;您只需使用 Struts.xml 以声明方式配置框架,然后它会按照配置编排整个 MVC 流程。

Controller 通过拦截器执行验证,并将预填充和验证的数据对象传递给模型以持久保存到数据库中。

public class UserRegistrationAction {

    private User user = new User();

    public User getModel() { // Struts Callback
        return user; // automatically gets populated with validated values
    }

    // This will seem incorrect to someone used to Spring's setter injection but
    // Struts injects in reverse; pulls the model onto a ValueStack to inject properties

    public String execute() {
        // already validated; simply persist
        UserRegistrationService.getInstance().persist(getUser());
        return Action.SUCCESS;
    }
    ...
}

所以,是的,您在控制器中实现验证是正确的。

但是,话虽如此,对数据的任何处理都应始终在模型本身中进行。假设您还询问了您的用户是否愿意导入他们的 Facebook 好友列表或 GMail 联系人列表,并且他们同意并提供了必要的详细信息:

public String execute() {
    user.setContactsList(
        thirdPartyService.getInstance(getPartyCode()).fetchContacts(user.getAuthInfo())
    );
    UserRegistrationService.getInstance().persist(getUser());
    return Action.SUCCESS;
}

使用第三方服务进行身份验证和获取其他详细信息以更新您的用户对象(在您持久化之前)的逻辑也将进入您的模型。这是因为这构成了您的业务逻辑,并且应该封装在独立的可重用模型类中,与您用于实现控制器的技术(Servlet、Stuts 或 Spring MVC)无关。

因此,理想情况下,您只需将横切关注点(如验证、身份验证、缓存等)分解到控制器中,并将核心业务逻辑留在模型中。

【讨论】:

  • Xm.... 这在本质上与 Didaxis 的建议完全相反,更符合我一开始的想法。谢谢。也会感谢其他人的更多投入。然而非常简洁的解释
  • @Thomas 更新以更好地解释getModel()。请使用javajava-ee 标记您的问题以获得更多回复。
  • 嗨拉维。基本上,我是一个 PHP 人。但我相信无论语言如何,设计模式的原则都是相同的。所以让我们让它与语言无关
【解决方案2】:

关注点分离是这里的关键。话虽如此,您的控制器不应该知道表单数据。事实上,Controller 根本不需要任何 html 表单的概念。

您的模型应该封装您打算通过某种形式提供的值。您的控制器对模型执行操作(例如,将数据从模型加载到数据库)。

每个 MVC 框架在使用的约定上会略有不同,但一般来说,我上面所说的应该适用于任何 MVC 框架。

更新(回应您的评论):

不,恰恰相反。您的表单数据应该由传递给控制器​​的模型/视图模型封装,控制器插入/更新您的底层数据存储(即您的数据库)。将 MVC 视为高速公路系统。您的模型是沿着路径行驶的汽车,控制器指挥交通。模型通常是包含数据字段的简单对象,控制器使用该数据执行操作。模型/视图模型与您的数据库数据是分开的;模型是您愿意呈现给视图(表示层)的内容。尽管您的控制器负责将模型转换为您的底层数据库,但您的数据库是独立于视图/模型/控制器的层/层。

【讨论】:

  • 那么Controller将数据传递给Form Model,由Form Model完成所有处理并创建User权限?
  • 查看我的答案的更新,无法将所有内容放入评论中。
  • 以上不是MVC。我什至不确定它是 MVVM。控制器在数据库中不插入/更新任何内容。这就是模型的持久层的用途。