还想看更多文章的朋友可以访问我的个人博客
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值。不可注解在字符串值上 |