1.概述

本文我们将重点介绍Spring中 @Valid@Validated注解的区别 。

验证用户输入是否正确是我们应用程序中的常见功能。Spring提供了@Valid和@Validated两个注解来实现验证功能,下面我们来详细介绍它们。

2. @Valid和@Validate注解

在Spring中,我们使用@Valid 注解进行方法级别验证,同时还能用它来标记成员属性以进行验证。

但是,此注释不支持分组验证。@Validated则支持分组验证。

3.例子

让我们考虑一个使用Spring Boot开发的简单用户注册表单。首先,我们只有名称密码属性:

public class UserAccount {

    @NotNull
@Size(min = 4, max = 15)
private String password; @NotBlank
private String name; // standard constructors / setters / getters / toString }

接下来,让我们看一下控制器。在这里,我们将使用带有@Valid批注的saveBasicInfo方法来验证用户输入:

@RequestMapping(value = "/saveBasicInfo", method = RequestMethod.POST)
public String saveBasicInfo(
@Valid @ModelAttribute("useraccount") UserAccount useraccount,
BindingResult result,
ModelMap model) {
if (result.hasErrors()) {
return "error";
}
return "success";
}

现在让我们测试一下这个方法:

@Test
public void givenSaveBasicInfo_whenCorrectInput`thenSuccess() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/saveBasicInfo")
.accept(MediaType.TEXT_HTML)
.param("name", "test123")
.param("password", "pass"))
.andExpect(view().name("success"))
.andExpect(status().isOk())
.andDo(print());
}

在确认测试成功运行之后,现在让我们扩展功能。下一步的逻辑步骤是将其转换为多步骤注册表格,就像大多数向导一样。第一步,名称密码保持不变。在第二步中,我们将获取其他信息,例如age 和 phone。因此,我们将使用以下其他字段更新域对象:

public class UserAccount {

    @NotNull
@Size(min = 4, max = 15)
private String password; @NotBlank
private String name; @Min(value = 18, message = "Age should not be less than 18")
private int age; @NotBlank
private String phone; // standard constructors / setters / getters / toString }

但是,这一次,我们将注意到先前的测试失败。这是因为我们没有传递年龄电话字段。

为了支持此行为,我们引入支持分组验证的@Validated批注。

分组验证,就是将字段分组,分别验证,比如我们将用户信息分为两组:BasicInfoAdvanceInfo

可以建立两个空接口:

public interface BasicInfo {
}
public interface AdvanceInfo {
}

第一步将具有BasicInfo接口,第二步 将具有AdvanceInfo  。此外,我们将更新UserAccount类以使用这些标记接口,如下所示:

public class UserAccount {

    @NotNull(groups = BasicInfo.class)
@Size(min = 4, max = 15, groups = BasicInfo.class)
private String password; @NotBlank(groups = BasicInfo.class)
private String name; @Min(value = 18, message = "Age should not be less than 18", groups = AdvanceInfo.class)
private int age; @NotBlank(groups = AdvanceInfo.class)
private String phone; // standard constructors / setters / getters / toString }

另外,我们现在将更新控制器以使用@Validated注释而不是@Valid

@RequestMapping(value = "/saveBasicInfoStep1", method = RequestMethod.POST)
public String saveBasicInfoStep1(
@Validated(BasicInfo.class)
@ModelAttribute("useraccount") UserAccount useraccount,
BindingResult result, ModelMap model) {
if (result.hasErrors()) {
return "error";
}
return "success";
}

更新后,再次执行测试,现在可以成功运行。现在,我们还要测试这个新方法:

@Test
public void givenSaveBasicInfoStep1`whenCorrectInput`thenSuccess() throws Exception {
this.mockMvc.perform(MockMvcRequestBuilders.post("/saveBasicInfoStep1")
.accept(MediaType.TEXT_HTML)
.param("name", "test123")
.param("password", "pass"))
.andExpect(view().name("success"))
.andExpect(status().isOk())
.andDo(print());
}

也成功运行!

接下来,让我们看看@Valid对于触发嵌套属性验证是必不可少的。

4.使用@Valid批注标记嵌套对象

@Valid 可以用于嵌套对象。例如,在我们当前的场景中,让我们创建一个 UserAddress 对象:

public class UserAddress {

    @NotBlank
private String countryCode; // standard constructors / setters / getters / toString
}

为了确保验证此嵌套对象,我们将使用@Valid批注装饰属性:

public class UserAccount {

    //...

    @Valid
@NotNull(groups = AdvanceInfo.class)
private UserAddress useraddress; // standard constructors / setters / getters / toString
}

5. 总结

@Valid保证了整个对象的验证, 但是它是对整个对象进行验证,当仅需要部分验证的时候就会出现问题。 这时候,可以使用@Validated 进行分组验证。

参考


作者:Jadepeng

出处:jqpeng的技术记事本--http://www.cnblogs.com/xiaoqi

您的支持是对博主最大的鼓励,感谢您的认真阅读。

本文版权归作者所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

Spring中的@Valid 和 @Validated注解你用对了吗的更多相关文章

  1. Spring 中的事务操作、注解、以及 XML 配置

    事务 事务全称叫数据库事务,是数据库并发控制时的基本单位,它是一个操作集合,这些操作要么不执行,要么都执行,不可分割.例如我们的转账这个业务,就需要进行数据库事务的处理. 转账中至少会涉及到两条 SQ ...

  2. 在spring中常被忽视的注解 @Primary

    在spring 中使用注解,常使用@Autowired, 默认是根据类型Type来自动注入的. 但有些特殊情况,对同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下 @Primary ...

  3. Spring中Bean管理的常用注解

    在Spring中,主要用于管理bean的注解分为四大类:1.用于创建对象.2.用于给对象的属性注入值.3.用于改变作用的范围.4.用于定义生命周期.这几个在开发中经常接触到,也可以说每天都会遇见.其中 ...

  4. Spring 中基于 AOP 的 @AspectJ注解实例

    @AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格.通过在你的基于架构的 XML 配置文件中包含以下元素,@AspectJ 支持是可用的 ...

  5. Spring中声明式事务的注解@Transactional的参数的总结(REQUIRED和REQUIRES_NEW的与主方法的回滚问题)

    一.事务的传播行为1.介绍 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播.例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行.2.属性 事务的传播行为可以由传 ...

  6. 在使用spring中的ContextConfiguration、test注解时出现的错误

    错误: 在使用测试注解时出现ContextConfiguration注解和test注解无法正常导包使用的编译异常,如图: 解决办法: 将pom.xml文件中以下依赖管理 中的<scope> ...

  7. spring中xml配置方式和注解annoation方式(包括@autowired和@resource)的区别

    xml文件中配置itemSqlParameterSourceProvider是可以的: <bean id="billDbWriter" class="com.aa. ...

  8. Spring中的@response和@request注解

    @response 标注对象返回的格式为json文本 @requestBody将json对象转换为对应的java类

  9. spring中使用@PostConstruct和@PreConstruct注解

    1.@PostConstruct说明 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法.被@PostCo ...

随机推荐

  1. Object.prototype.toString.call()和typeof()区别

    js中判断数据类型都知道用tyoeof(),但是他只能判断object,boolean,function,string,number,undefined还有symbol(es6新增)这几种初步类型,比 ...

  2. 串口数据监视-Bus Hound

    Bus Hound使用说明 一.打开该工具,会看到最上面的六个图标:1.Capture(捕捉按钮):按下它选择捕捉数据界面2.Save(保存按钮):按下它选择保存数据界面3.Setting(设置按钮) ...

  3. proxySQL with SemiSync

    环境信息 hostname IP port role comm ms81 192.168.188.81 3399 master ms82 192.168.188.82 3399 slave ms83 ...

  4. django 取出数据库的时间与当前时间相加减

    1 转换时区utc比北京时间慢八个小时 from datetime import tzinfo, timedelta, datetime ZERO = timedelta(0) class UTC(t ...

  5. Elastic Search 学习之路(三)—— tutorial demo

    一.ElasticSearch tutorial demo example 1. 单机.local.CRUD操作 实现方式: SpringBoot + ElasticSearch 拷贝的小demo,原 ...

  6. ERROR 1071 (42000): Specified key was too long; max key length is 1000 bytes

    这个错误是我在安装ambari平台时,准备为ambari指定mysql数据库时,执行建表语句时遇到的. ERROR 1071 (42000): Specified key was too long; ...

  7. 登录linux时 shell执行顺序

    # .bash_history,.bash_logout,.bash_profile,.bashrc/etc/profile 全局.bash_history 记录当前登录用户历史操作的命令.bash_ ...

  8. js 获取某月第一天和最后一天

    1.获取某月第一天和最后一天日期 function getDateByMonth (timeStamp) { let inDate = new Date(timeStamp) let year = i ...

  9. rest framework Serializer fields

    串行领域 在表单类中的每个字段不仅负责验证数据,同时也为"清洁" - 它以标准化格式一致. - Django文档 串行字段手柄的原始值和内部数据类型之间的转换.他们还应对验证输入值 ...

  10. 爱普生 L4160 Serveies 网络打印机配置(问题解决)

    一.爱普生网络打印机固定IP地址 用网络打印机过程中,偶尔会出现打印机脱机的状况,大多数原因是打印机的IP地址在路由器重启过后重新分配了IP地址导致的.此时,为了减少不必要的麻烦就需要固定打印机的IP ...