输入验证在 MVC 应用程序中属于哪里?

Posted

技术标签:

【中文标题】输入验证在 MVC 应用程序中属于哪里?【英文标题】:Where does input validation belong in an MVC application? 【发布时间】:2011-01-05 08:00:06 【问题描述】:

我有一个从表单接收输入的 MVC 应用程序。 这是一个登录表单,因此唯一需要的验证是检查输入是否为非空。 现在,在我将它传递给模型之前,我在控制器中对其进行验证。 这是否是最佳实践?是否属于模型?

【问题讨论】:

简单回答:put it where it’s needed. 【参考方案1】:

我认为没有官方的最佳实践将验证限制在 MVC 模式的任何单个部分。例如,您的视图可以(并且应该)使用 javascript 进行一些预先验证。您的控制器还应该提供相同类型的验证,以及更多与业务逻辑相关的验证。该模型还可以提供验证形式,即不允许空值的设置器。

有一个关于这个at joelonsoftware的有趣讨论。

【讨论】:

我认为应用程序的某处有一些 Javascript?除非这是一个老式的 Web 1.0 风格的 Web 应用程序或框架。 有但我不会触摸/编码/处理它,除非我真的很想这样做:) 在这个框架中,视图只创建和初始化小部件并将它们附加到根小部件。不过,它可以具有验证功能。那么视图是验证数据是否为空的地方,而模型是验证输入的用户名和密码是否正确的地方? 视图也应该调用模型函数吗?这将它们结合在一起,它失去了全部意义。所以这就是控制器现在正在做的事情:验证非空值并将其传递给模型。我是否应该让视图调用将调用模型身份验证方法的控制器,然后将答案返回给将在视图中返回答案的控制器?这听起来像是一项重大开销。【参考方案2】:

我一直在考虑这个问题并尝试在控制器和模型中进行验证之后......最后我得出的结论是,对于我的许多应用程序......验证属于模型而不是在控制器中。为什么?因为相同的模型将来可能被各种其他控制器调用或 API 使用......然后我将不得不一遍又一遍地重复验证过程。这将违反 DRY 并导致许多错误。再加上哲学上它与数据库(或其他持久存储)交互的模型,因此无论如何都是“最后一次喝酒”的地方。

所以我在控制器中进行 get/post 转换,然后将原始数据发送到模型进行验证和处理。当然,我经常做 php/mysql web 应用程序,如果你在做其他事情,结果可能会有所不同。我希望这对某人有所帮助。

【讨论】:

【参考方案3】:

验证必须在模型中

只有模型知道业务的“细节”。只有模型知道哪些数据可以接受,哪些数据不能接受。控制器只知道如何“使用”模型。

例如:假设我们需要向我们的系统注册新用户的功能。

模型:

 public function registerUser(User $user)
    //pseudo code
       //primitive validation
       if(!isInt($user->age))
           //log the invalid input error
           return "age"; 
       
       if(!isString($user->name))
           //log the invalid input error
           return "name";
       
       //business logic validation

        //our buisnees only accept grown peoples
        if($user->age < 18)
            //log the error
            return "age";
        
        //our buisness accepts only users with good physique
        if($user->weight > 100)
            //log the error
            return "weight";
        
        //ervery thing is ok ? then insert the user
        //data base query (insert into user (,,,) valeues (?,?,?,?))
        return true;

现在控制器的工作是“使用”模型 registerUser() 函数,而不知道模型将如何进行验证,甚至不知道什么被认为是“有效”!

控制器:

$user = new User();
$user->age = isset($_POST['age']) ?  $_POST['age'] : null;
$user->name = isset($_POST['name']) ?  $_POST['name'] : null;
$user->age = isset($_POST['weight']) ?  $_POST['weight'] : null;
$result = $theModel->registerUser($user);// <- the controller uses the model
if($result === true)
//build the view(page/template) with success message and die

$msg = "";
//use the return value from the function or you can check the error logs
switch ($result)
    case"age" :
        $msg = "Sorry, you must be over 18";
        break;
    case "name":
        $msg = "name field is not correct";
        break;
    case "weight":
        $msg = "Sorry, you must have a good physique";
        break;

//build the view(page/template) with error messages and die

班级用户

class User  
    public $age;
    public $name;
    public $weight;

拥有这样的架构将使控制器完全从业务逻辑的细节中“解放”出来——这是一件好事——。

假设我们想在网站的其他地方进行另一种形式的用户注册(我们将为它分配另一个控制器)。现在另一个控制器将使用与模型registerUser()相同的方法。

但是,如果我们在控制器和模型之间分配验证逻辑,它们将不会被分离——这对 MVC 不利——这意味着每次你需要创建新视图和控制器来注册新用户时,你必须使用相同的旧控制器和模型在一起。此外,如果业务逻辑发生变化(我们现在在体育俱乐部接受青少年),您只需更改模型 registerUser() 函数中的代码。控制器代码还是一样的。

【讨论】:

【参考方案4】:

它的业务逻辑,所以不,它不属于模型。

【讨论】:

下面的答案另有说明。请详细说明并解释您为什么这么认为。 我可能会走下面概述的路线。在这种情况下,它将进入您的服务层。基本上,这样想;不允许空字符串是模型对您施加的约束吗?它不是用户界面问题。所以这一定是一个商业问题;用户无法使用空用户名登录。 呃。如果您在模型中正确执行 MVC 业务逻辑,而不是视图或控制器。应用逻辑属于控制器,视图就是视图。可以说验证不是业务逻辑而是应用程序逻辑,但那是一种分裂。【参考方案5】:

在控制器中,您有 ModelState 属性,您可以向其中添加验证错误。

见this example on the MSDN。

【讨论】:

【参考方案6】:

假设您的应用程序结构如下:

模型-视图-控制器 服务 坚持 型号

用户输入将到达您的控制器,您将使用服务层中的服务来验证它。

【讨论】:

更多层?什么是服务层?没有数据库,因此本身没有持久性,所有数据都来自另一个进程,所有数据都从 UI 或进程中更改。【参考方案7】:
Business Logic  -> Controller
Data Validation -> Model

【讨论】:

上面的答案说它是业务逻辑,所以它不属于模型。你说这样做对吗?我糊涂了。请详细说明并解释您为什么这么认为。 我不同意。我会说:业务逻辑 -> 领域;用户界面逻辑 -> 控制器;验证 -> 域 + UI(可选) @the_drow:我是说业务逻辑属于Model,它属于Controller。 @Martinho: @unknown 和 @Kaleb 似乎同意我的观点。 让我澄清一下:我所说的域是指所谓的域模型、域层或有时是业务逻辑层 (martinfowler.com/eaaCatalog/domainModel.html)。 UI 是用户界面。 MVC 是一种用户界面架构 (martinfowler.com/eaaDev/uiArchs.html)。我上面说的是业务逻辑不属于用户界面,而是属于领域层。验证应该在领域层,但也可以用在其他层,比如 UI(可能在 Controller 或 Js 中的 View),以向用户提供快速反馈。

以上是关于输入验证在 MVC 应用程序中属于哪里?的主要内容,如果未能解决你的问题,请参考以下文章

控制器或服务层中的 Spring MVC 验证?

MVC 模式与三层 - 逻辑属于哪里?

在 MVC 中将视图状态之类的选择放在哪里?

MVC3 中基于 AD 角色的授权

干净的架构——在哪里放置输入验证逻辑? [关闭]

Spring MVC 验证错误代码在哪里解决?