还想看更多文章的朋友可以访问我的个人博客
Hibernate Validator 校验 (简单校验)
Validator 规范对约束的定义包括两部分,一是约束注解, @NotBlank
就是约束注解;二是约束验证器,每一个约束注解都存在对应的约束验证器,约束验证器用来验证具体的对象是否满足该约束注解声明的条件。
声明需要校验的字段
以User
实体为例,其中username
字段使用注解:@NotBlank
,该注解声明username
字段不能为空(虽该注解也要求字段不能为null
,但与@NotNull
有本质区别,后面会列举常见校验注解的区别)。
@Entity // This tells Hibernate to make a table out of this class
public class User {
@NotBlank
private String username;
...
}
测试用例,模拟发出增添用户的 Post 请求(username
字段为""
)。
@Test
public void testValidUser() throws Exception {
String content = "{\"username\":\"\",\"password\": \"password\",\"birthday\":" + new Date().getTime() + "}";
mockMvc.perform(post("/user").contentType(MediaType.APPLICATION_JSON_UTF8)
.content(content))
.andExpect(status().isOk());
}
执行后结果如下:
很明显,我们预想的校验并没有生效。那如何让我们添加的字段校验生效呢?
Mapping
方法参数声明需要校验的参数实例
Controller 层需要对传入参数添加@Valid
注解,使得校验生效,如下:
@RestController
public class UserController {
@PostMapping
public User addUser(@RequestBody @Valid User user) {
return userService.addUser(user);
}
}
执行之前的测试用例,测试结果:
可以看出,我们执行形同的的测试用例,这次的测试请求却是失败的,也就是说我们对User
实体中username
字段的校验生效了。
但是,如果发生错误时我们只是向用户提醒请求错误时不够的。怎样才能自己处理想管的校验错误呢?
收集错误信息、发生错误时进入方法体。
只需要在Controller 层传入(注入)封装了错误信息的参数BandingResult
类型的实例,如下修改Mapping
方法:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public User addUser(@RequestBody @Valid User user, BindingResult result) {
// 输出错误信息
if (result.hasErrors()) {
result.getAllErrors().forEach(err -> System.out.println(err.getDefaultMessage()));
}
return userService.addUser(user);
}
}
测试结果如下:
终于,模拟发出的用户添加请求返回的 HTTP 状态码为
200
,并且在Controller层也成功输出了错误信息:must not be blank
。
如此,借助 Hibernate Validator 支持的注解,即可为实体字段添加简单的校验,并在 Controller 层对校验的错误信息做相应处理(比如返回给前端)。
获得具体的校验错误信息
BindingResult
的getAllErrors()
方法返回值为List<ObjectError>
,将ObjectError
的实力强转为FieldError
即可获得字段名称等信息。只需修改 Controller 层代码如下:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public User addUser(@RequestBody @Valid User user, BindingResult result) {
// 输出字段名称与校验错误信息
if (result.hasErrors()) {
result.getAllErrors().forEach(err -> {
if (err instanceof FieldError) {
FieldError error = (FieldError) err;
System.out.println(error.getField() + " " + error.getDefaultMessage());
}
});
}
return userService.addUser(user);
}
}
测试结果如下:
这样一来,就可以为前端提供较为具体的响应信息。
尽管如此,那如何为需要校验的校验项自定义错误消息呢?
自定义校验错误消息
其实,Hibernate Validator 提供的索引校验注解都有共同的一个属性——message
,通过声明该属性,即可为校验项自定义错误消息,修改实体User
校验字段@NotBlank
注解如下:
@Entity
public class User {
@NotBlank(message = "用户名不能为空")
private String username;
...
}
Controller 层与测试用例无需修改,测试结果如下:
当然,此时很明显我们没有必要再输出字段名了,所以应该修改Controller层处的错误处理代码,但这里就不一一列举了。
Hibernate Validator 提供的校验注解
这里列举一些常用的 Hibernate Validator 提供的校验注解,利用这些注解可以完成开发中绝大多数的校验逻辑。
注解 | 描述 |
---|---|
@NotNull | 值不能为 null |
@NotBlank | 字符串必须包含字符 |
@NotEmpty | 字符串不为 null,集合必须有元素 |
@Null | 值必须为空 |
@Pattern(regex=) | 字符串必须满足于正则 |
@Size(min=,max=) | 集合的元素数必须在 min 到 max 之间 |
@CreditCardNumber(ignoreNonDightCharacters=) | 字符串必须是信用卡号(美国标准如何自定义信用卡校验) |
字符串必须是Email | |
@Length(min=,max=) | 校验字符串的长度 |
@Range(min=,max=) | min <= 数字 <= max |
@SafeHtml | 字符串是安全的 HTML |
@URL | 字符串是合法的URL |
@AssertFalse | 布尔值为 false |
@AssertTrue | 布尔值为 true |
@DecimalMax(value=,inclusive=) | 值必须小于等于(inclusive=true)/小于(inclusive=false)指定的value值。可注解在字符串值上 |
@DecimalMin(value=,inclusive=) | 值必须大于等于(inclusive=true)/大于(inclusive=false)指定的value值。可注解在字符串值上 |
@Digits(integer=,fraction=) | 数字格式校验。integer指定整数部分长度,fraction指定小数部分长度 |
@Future | 值必须是未来的日期 |
@Past | 值必须是过去的日期 |
@Max | 值必须小于等于value值。不可注解在字符串值上 |
@Min | 值必须大于等于value值。不可注解在字符串值上 |