Spring中的@Valid 和 @Validated注解你用对了吗
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
批注。
分组验证
,就是将字段分组,分别验证,比如我们将用户信息分为两组:BasicInfo
和AdvanceInfo
可以建立两个空接口:
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注解你用对了吗的更多相关文章
- Spring 中的事务操作、注解、以及 XML 配置
事务 事务全称叫数据库事务,是数据库并发控制时的基本单位,它是一个操作集合,这些操作要么不执行,要么都执行,不可分割.例如我们的转账这个业务,就需要进行数据库事务的处理. 转账中至少会涉及到两条 SQ ...
- 在spring中常被忽视的注解 @Primary
在spring 中使用注解,常使用@Autowired, 默认是根据类型Type来自动注入的. 但有些特殊情况,对同一个接口,可能会有几种不同的实现类,而默认只会采取其中一种的情况下 @Primary ...
- Spring中Bean管理的常用注解
在Spring中,主要用于管理bean的注解分为四大类:1.用于创建对象.2.用于给对象的属性注入值.3.用于改变作用的范围.4.用于定义生命周期.这几个在开发中经常接触到,也可以说每天都会遇见.其中 ...
- Spring 中基于 AOP 的 @AspectJ注解实例
@AspectJ 作为通过 Java 5 注释注释的普通的 Java 类,它指的是声明 aspects 的一种风格.通过在你的基于架构的 XML 配置文件中包含以下元素,@AspectJ 支持是可用的 ...
- Spring中声明式事务的注解@Transactional的参数的总结(REQUIRED和REQUIRES_NEW的与主方法的回滚问题)
一.事务的传播行为1.介绍 当事务方法被另一个事务方法调用时,必须指定事务应该如何传播.例如:方法可能继续在现有事务中运行,也可能开启一个新事务,并在自己的事务中运行.2.属性 事务的传播行为可以由传 ...
- 在使用spring中的ContextConfiguration、test注解时出现的错误
错误: 在使用测试注解时出现ContextConfiguration注解和test注解无法正常导包使用的编译异常,如图: 解决办法: 将pom.xml文件中以下依赖管理 中的<scope> ...
- spring中xml配置方式和注解annoation方式(包括@autowired和@resource)的区别
xml文件中配置itemSqlParameterSourceProvider是可以的: <bean id="billDbWriter" class="com.aa. ...
- Spring中的@response和@request注解
@response 标注对象返回的格式为json文本 @requestBody将json对象转换为对应的java类
- spring中使用@PostConstruct和@PreConstruct注解
1.@PostConstruct说明 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器调用一次,类似于Serclet的inti()方法.被@PostCo ...
随机推荐
- flex:align-items和align-content的区别
属性值 align-items的属性值有:baseline.center.flex-end.flex-start.stretch.inherit.initial.unset align-content ...
- 题解-CTS2019 珍珠
题面 CTS2019 珍珠 有 \(n\) 个在 \([1,d]\) 内的整数,求使可以拿出 \(2m\) 个整数凑成 \(m\) 个相等的整数对的方案数. 数据范围:\(0\le m\le 10^9 ...
- 双端口RAM和多模块存储器
目录 双端口RAM 存取周期 双端口RAM 多模块存储器 普通存储器 单体多字存储器 多体并行的存储器 高位交叉编址的多体存储器 低位交叉编址的多提存储器 为什么要这么弄? 高位 低位 流水线(考试常 ...
- oracle ADG启动顺序
一.oracle ADG启动顺序 1.启动主备库监听 [oracle@dgdb1 ~]$ lsnrctl start [oracle@dgdb2 ~]$ lsnrctl start 2.启动备库 ...
- Nacos源码深度解析1-服务注册初始化(客户端)
一.初始化 NamingService naming = NamingFactory.createNamingService(properties); 二.通过反射传入properties生成Naco ...
- spring boot 项目使用idea正常打包后执行总是出现异常,解决办法
众所周知,spring boot 在构建项目时,确实为Java程序员们省了不少力气,打包项目非常容易. 上周在项目中遇到打包后的项目总是无法运行,困扰了我们团队将近两天才找到原因. 图和真相在这里.
- Shell-匹配行及date日期转换
#将指定字符串转化为从1970年1月1日到现在的秒数. date -d '20170506' "+%s" #将1970年1月1日到现在累计的秒数转化为日期 date -d @149 ...
- 简单学习 SQL and NOSql
文章参考链接::https://www.cnblogs.com/xrq730/p/11039384.html 结构化数据.非结构化数据与半结构化数据 文章的开始,聊一下结构化数据.非结构化数据与半结构 ...
- 2020年“感恩杯”台州学院第十三届大学生程序设计竞赛D、H、I题解(后续补充)
D题:小z与他的袜子 描述 小z每天会穿一双新袜子. 开始他的衣柜里有n双袜子,袜子会从1-n进行编号.每天早上他都会从衣柜里拿编号最小的袜子来穿.每天晚上他会把今天穿的袜子扔进篮子里,如果篮子里有n ...
- win7开机登录界面壁纸修改
1.选择一张自己喜欢的图(一定要是jpg格式,亲测png格式不行),分辨率最好和自己电脑的分辨率差不多. 2.将图片改名为"backgroundDefault.jpg": 3.按下 ...