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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21407840/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 08:32:35  来源:igfitidea点击:

Validation in Spring MVC in Controllers or Service Layer?

javaspringvalidationspring-mvc

提问by AlexLiesenfeld

For quite some time I try to figure out where validation of user input should take place in a Spring MVC application. In many online blogs and tutorials I basically read that a controller should validate the users input and, if invalid, respond to the user by showing a page containing the error message. My current understanding of the Spring and Spring MVC layering system, however, is that a Controller is a only shallow interface between the application logic (service layer) and the "web world", allowing usage of the service layer from the web. Also, as far as I can see, Spring MVC does only provide reasonable tools for validation in a Controller.

在相当长的一段时间里,我试图弄清楚在 Spring MVC 应用程序中应该在哪里验证用户输入。在许多在线博客和教程中,我基本上读到控制器应该验证用户输入,如果无效,则通过显示包含错误消息的页面来响应用户。然而,我目前对 Spring 和 Spring MVC 分层系统的理解是,Controller 是应用程序逻辑(服务层)和“Web 世界”之间唯一的浅层接口,允许从 Web 使用服务层。另外,据我所知,Spring MVC 只提供了合理的工具来在控制器中进行验证。

If now validation takes place in a Controller, if at some later point I want to untie the application logic from the "web world", validation logic must be reimplemented in the new environment (e.g. a desktop application using Swing). In my opinion, the ability to decide which operations are "valid" on domain objects, and what "valid" states such objects may have, is core part of the service layer, and not the concern of some other part of the application (e.g. Controllers).

如果现在验证发生在控制器中,如果稍后我想将应用程序逻辑与“网络世界”分开,则必须在新环境中重新实现验证逻辑(例如,使用 Swing 的桌面应用程序)。在我看来,决定哪些操作对域对象“有效”以及这些对象可能具有哪些“有效”状态的能力是服务层的核心部分,而不是应用程序的其他部分(例如控制器)。

In this context, why is it "good practice" to place input validation logic in the controller layer and not the service layer?

在这种情况下,为什么将输入验证逻辑放在控制器层而不是服务层是“好习惯”?

采纳答案by Nikola Yovchev

A common approach is to do validation on both places. But if you are talking about @Valid, from my experience it is nicer to put on Controllers level.

一种常见的方法是在两个地方都进行验证。但是如果你在谈论@Valid,根据我的经验,把它放在控制器级别会更好。

It also depends what kind of validation logic we are talking about. Let's say you have a bean:

这也取决于我们在谈论什么样的验证逻辑。假设你有一个 bean:

@Data
public class MyBean {
    @NotNull private UUID someId;
    @NotEmpty private String someName; 
}

It would make sense for this bean to be annotated with @Validon the controller level so it doesn't even reach the service. There is no benefit to putting the @Validon the service method, because why would you propagate it further while you can immediately in the controller decide if it is that kind of valid or not.

@Valid在控制器级别对这个 bean 进行注释是有意义的,这样它甚至不会到达服务。将@Valid放在服务方法上没有任何好处,因为为什么要进一步传播它,而您可以立即在控制器中决定它是否有效。

Then there is a second type of validation: business logic validation. Let's say for the same bean that the someId property is a timeUUid and its timestamp needs to be at most 2 days after some event occurred, in other case, the bean should be discarded by the service.

然后是第二种类型的验证:业务逻辑验证。假设对于同一个 bean,someId 属性是一个 timeUUid 并且它的时间戳最多需要在某个事件发生后 2 天,在其他情况下,该 bean 应该被服务丢弃。

That seems like a business logic validation case, because by just looking at the bean, you wouldn't be able to validate it, unless you apply some logic to it.

这似乎是一个业务逻辑验证案例,因为仅查看 bean,您将无法对其进行验证,除非您对其应用一些逻辑。

Since both approaches to validation actually validate different things, it is obvious to see that each of your MVC components - Model, View and Controller, do their own validation and it should be reasonable about what it validates without introducing dependency to the other components.

由于两种验证方法实际上验证了不同的东西,很明显,您的每个 MVC 组件(模型、视图和控制器)都进行自己的验证,并且在不引入对其他组件的依赖的情况下,它验证的内容应该是合理的。

As for showing the error to the user, yes, the Errorsobject is indeed intended to be used for bean validation at controller level, but you can design some filter that catches exceptions on any level and then pretty formats it for the user. There are many approaches to it, and I am not sure if Spring prescribes that any is better than the other.

至于向用户显示错误,是的,Errors对象确实旨在用于控制器级别的 bean 验证,但是您可以设计一些过滤器来捕获任何级别的异常,然后为用户对其进行漂亮的格式化。有很多方法可以解决,我不确定 Spring 是否规定了任何一种比另一种更好

Depending on different resolve mechanism (as in, for example, jstl or Hymanson or something else), you would probably be inclined to deal with validation in a different way. For example, a traditional jstl view resolverwould nicely work with a contraption that uses Errors, while a Hymanson resolverwould probably work nicer with a combination of @ResponseBodyand some filter that catches errors and puts them in a predefined error part of the response object.

根据不同的解析机制(例如,jstl 或 Hymanson 或其他机制),您可能倾向于以不同的方式处理验证。例如,传统的jstl 视图解析器可以很好地与使用错误的装置配合使用,而Hymanson 解析器可能更适合@ResponseBody和一些捕获错误并将它们放入响应对象的预定义错误部分的过滤器的组合.

回答by Tarmo

In one of our previous projects, we had huge forms with very complex logic which meant a lot of validating code. So we used a third kind of solution. For every controller, we autowired a helper class. Example:

在我们之前的一个项目中,我们拥有具有非常复杂逻辑的巨大表单,这意味着需要大量验证代码。所以我们使用了第三种解决方案。对于每个控制器,我们自动装配了一个辅助类。例子:

myview <-> MyController <- MyService <- MyDAO
                 ^
                 |
               MyHelper

Controllershandled the view resolving.
Serviceshandled mapping from dto-s to model objects for view and vice versa,
DAO-shandled database transactions and,
Helpershandled everything else including validation.

Controllers处理视图解析。
Services处理从 dto-s 到模型对象的映射,反之亦然,
DAO-s处理数据库事务,
Helpers处理包括验证在内的所有其他事情。

If now someone would have wanted to change the frontend from web to something else, it would have been a lot easier and at the same time, we didn't over-bloat the service implementation classes.

如果现在有人想要将前端从 web 更改为其他东西,那会容易得多,同时,我们不会过度膨胀服务实现类。