我想知道对用户输入执行表单验证的最简洁和最好的方法是什么 . 我见过一些开发人员实现org.springframework.validation.Validator . 关于这一点的问题:我看到它验证了一个类 . 是否必须使用用户输入中的值手动填充类,然后传递给验证器?
我对用于验证用户输入的最干净和最好的方法感到困惑 . 我知道使用 request.getParameter()
然后手动检查 nulls
的传统方法,但我不想在我的 Controller
中进行所有验证 . 关于这方面的一些好建议将不胜感激 . 我在这个应用程序中没有使用Hibernate .
6 回答
使用Spring MVC,有3种不同的方法可以执行验证:使用注释,手动或两者兼而有之 . 没有一种独特的“最干净,最好的方法”来验证,但可能更适合您的项目/问题/背景 .
让我们有一个用户:
Method 1 : 如果您要执行Spring 3.x并进行简单验证,请使用
javax.validation.constraints
注释(也称为JSR-303注释) .你的库中需要一个JSR-303提供程序,比如Hibernate Validator谁是参考实现(这个库与数据库和关系映射无关,它只是验证:-) .
然后在你的控制器中你会有类似的东西:
注意@Valid:如果用户恰好有一个空名称,result.hasErrors()将为true .
Method 2 : 如果您有复杂的验证(如大型业务验证逻辑,跨多个字段的条件验证等),或者由于某种原因您无法使用方法1,请使用手动验证 . 将控制器代码与验证逻辑分开是一种很好的做法 . 不要从头创建验证类,Spring提供了一个方便的
org.springframework.validation.Validator
接口(从Spring 2开始) .所以,假设你有
并且你想做一些“复杂”的验证,如:如果用户的年龄低于18岁,则责任用户不能为空且责任人的年龄必须超过21岁 .
你会做这样的事情
然后在您的控制器中,您将拥有:
如果存在验证错误,result.hasErrors()将为true .
注意:您还可以使用“binder.setValidator(...)”在控制器的@InitBinder方法中设置验证器(在这种情况下,无法使用方法1和2的混合使用,因为您替换了默认值验证器) . 或者您可以在控制器的默认构造函数中实例化它 . 或者在控制器中注入一个@Component / @Service UserValidator(@Autowired):非常有用,因为大多数验证器都是单例测试模拟变得更容易验证器可以调用其他Spring组件 .
Method 3 : 为什么不使用这两种方法的组合?使用注释验证简单的东西,比如"name"属性(它很快,简洁,更易读) . 保持验证器的重要验证(如果编写自定义复杂验证注释需要数小时,或者只是在无法使用注释时) . 我是在一个以前的项目中做到这一点,它的工作就像一个魅力,快速和简单 .
Warning : 你不能将 validation handling 误认为 exception handling . Read this post知道何时使用它们 .
参考文献:
A very interesting blog post about bean validation(Original link已死)
Another good blog post about validation
Latest Spring documentation about validation
有两种方法可以验证用户输入:注释和继承Spring的Validator类 . 对于简单的情况,注释很好 . 如果您需要复杂的验证(例如,跨域验证,例如“验证电子邮件地址”字段),或者您的模型在应用程序的多个位置使用不同的规则进行验证,或者您无法修改通过在其上放置注释来构建模型对象,Spring的基于继承的Validator是可行的方法 . 我将展示两者的例子 .
无论您使用哪种类型的验证,实际验证部分都是相同的:
如果您正在使用注释,则
Foo
类可能如下所示:上面的注释是
javax.validation.constraints
注释 . 您也可以使用Hibernate的org.hibernate.validator.constraints
,但它看起来并不像您正在使用Hibernate .或者,如果您实现Spring的Validator,您将创建一个类,如下所示:
如果使用上面的验证器,您还必须将验证器绑定到Spring控制器(如果使用注释,则不需要):
另见Spring docs .
希望有所帮助 .
我想延伸杰罗姆·达尔伯特的好答案 . 我发现很容易用JSR-303方式编写自己的注释验证器 . 您不限于“一个字段”验证 . 您可以在类型级别创建自己的注释,并进行复杂的验证(请参阅下面的示例) . 我更喜欢这种方式,因为我不需要像Jerome那样混合不同类型的验证(Spring和JSR-303) . 此验证器也是“Spring意识”,因此您可以使用@Inject / @Autowire开箱即用 .
Example of custom object validation:
Example of generic fields equality:
如果对于不同的方法处理程序有相同的错误处理逻辑,那么最终会有许多具有以下代码模式的处理程序:
假设您正在创建RESTful服务,并希望为每个验证错误情况返回
400 Bad Request
以及错误消息 . 然后,对于需要验证的每个REST endpoints ,错误处理部分都是相同的 . 在每个处理程序中重复那个相同的逻辑并不是那么 DRY ish!解决此问题的一种方法是在每个To-Be-Validated bean之后删除立即
BindingResult
. 现在,您的处理程序将是这样的:这样,如果绑定的bean无效,Spring将抛出
MethodArgumentNotValidException
. 您可以使用相同的错误处理逻辑定义处理此异常的ControllerAdvice
:您仍然可以使用
MethodArgumentNotValidException
的getBindingResult
方法检查基础BindingResult
.查找Spring Mvc Validation的完整示例
将此bean放在配置类中 .
然后你可以使用
用于手动验证bean . 然后你将获得BindingResult中的所有结果,你可以从那里检索 .