概念:java中的Bean Validation是一个数据验证的规范。
说明:Hibernate Validator是Bean Validation的一个具体实现。
举例:在springMVC中使用Hibernate Validator
1)maven依赖:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>1.1.0.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>5.1.2.Final</version>
</dependency>
2)JavaBean:
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotBlank;
/**
* 在需要进行校验的属性上添加相应的注解:
*
* 1)Bean Validation 提供的 constraint:
* @Null 被注释的元素必须为 null
* @NotNull 被注释的元素必须不为 null
* @AssertTrue 被注释的元素必须为 true
* @AssertFalse 被注释的元素必须为 false
* @Min(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值,可修饰Integer。
* @Max(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值,可修饰Integer。
* @DecimalMin(value) 被注释的元素必须是一个数字,其值必须大于等于指定的最小值
* @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
* @Size(max=, min=) 被注释的元素的大小必须在指定的范围内,修饰字符串长度。不可修饰Integer。
* @Digits (integer, fraction) 被注释的元素必须是一个数字,其值必须在可接受的范围内
* @Past 被注释的元素必须是一个过去的日期
* @Future 被注释的元素必须是一个将来的日期
* @Pattern(regexp=,message=) 被注释的元素必须符合指定的正则表达式
* 举例:@Pattern(regexp="^[\\u4e00-\\u9fa5_a-zA-Z0-9]+$", message="只能由中文、英文、数字、下划线组成")
* 说明:中文:[\u4e00-\u9fa5] 英文:[a-zA-Z] 数字:[0-9]
*
* 2)Hibernate Validator 特有的 constraint:
* @NotBlank(message =) 验证字符串非null,且长度必须大于0
* @NotEmpty 被注释的字符串或集合的必须非空
* @Email 被注释的元素必须符合email的格式
* @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
* @Range(min=,max=,message=) 被注释的元素必须在合适的范围内
*
*/
public class User {
@NotBlank(message = "name is null!")
private String name;
@NotNull(message = "age is null!")
private Integer age;
private String email;
private String address;
// getter and setter ..
}
3)控制器:
方式一:
import javax.validation.Valid;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMethod;
@RestController
@RequestMapping("/sys")
public class UserController {
/**
* 1.给需要校验的参数添加 @Valid注解
* 2.给方法添加一个类型为 BindingResult的参数,用来封装 校验的结果
*/
@RequestMapping(value = "/user/add", method = RequestMethod.POST)
public String addUser(@Valid @RequestBody User req, BindingResult bindingResult) {
if (bindingResult.hasErrors()) {
List<ObjectError> allErrors = bindingResult.getAllErrors();
List<String> msgs = new ArrayList<String>();
for (ObjectError objectError : allErrors) {
String msg = objectError.getDefaultMessage();
msgs.add(msg);
}
String paramErrorMsg = StringUtils.join(msgs, " & ");
return paramErrorMsg;
} else {
System.out.println("do add user.");
return "success!";
}
}
}
方式二:使用@ControllerAdvice + @ExceptionHandler
@RestController
@RequestMapping("/sys")
public class UserController {
@RequestMapping(value = "/user/add", method = RequestMethod.POST)
public String addUser(@Valid @RequestBody User req) {
System.out.println("do add user.");
return "success!";
}
}
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ValidationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleValidationException(HttpServletRequest request, ConstraintViolationException e) {
LOGGER.error("request uri [{}] error, method: [{}]", request.getRequestURI(), request.getMethod(), e);
Set<ConstraintViolation<?>> constraintViolations = e.getConstraintViolations();
List<String> msgList = new ArrayList();
for (ConstraintViolation constraintViolation : constraintViolations) {
String field = constraintViolation.getPropertyPath();
String errorMsg = constraintViolation.getMessage();
msgList.add(field + "-" + errorMsg);
}
String paramErrorMsg = StringUtils.join(msgList, " & ");
return paramErrorMsg;
}
}
4)接口测试:
地址:http://localhost:8081/jxn-web/api/sys/user/add
请求类型:Content-Type: application/json
参数:
{"name":"","age":null} ==> 响应内容:age is null! & name is null!
{"name":"","age":""} ==> 响应内容:age is null! & name is null!
{"name":"jack","age":"17"} ==> 响应内容:success!
常见错误:
报错:javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type: java.lang.Integer.
分析:是由于@NotBlank修饰了Integer、Long等引用类型的属性
eg:
@NotBlank
private Integer age;
修正:应该使用@NotNull来修饰引用类型的属性。
@NotNull
private Integer age;