说明
实际是使用的hibernate-validator的功能
官网:https://hibernate.org/validator/
使用
加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.5.14</version>
</dependency>
创建要校验的类
@Data
public class UserInfoVo {
@NotBlank(message = "名字不能为空")
private String name;
@NotBlank(message = "手机号不能为空")
@Pattern(regexp = "^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$", message = "手机号格式有误")
private String phone;
@NotBlank(message = "地址不能为空")
private String address;
}
全局异常捕获
/**
* 統一异常处理
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(value = Exception.class)
public AjaxResult defaultErrorHandler(HttpServletRequest request, Exception exception) throws Exception {
log.error(exception.getMessage(), exception);
AjaxResult result;
if (exception instanceof BindException){
result = AjaxResult.error("参数错误 - " + Objects.requireNonNull(((BindException) exception).getFieldError()).getDefaultMessage());
}else {
result = AjaxResult.error("服务器异常");
}
return result;
}
}
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.HashMap;
import java.util.Map;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ApiResponse<Map<String, String>>> handleValidationExceptions(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
Map<String, String> errors = new HashMap<>();
result.getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ApiResponse<>("400", "Validation Error", errors));
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<ApiResponse<Map<String, String>>> handleConstraintViolationException(ConstraintViolationException ex) {
Map<String, String> errors = new HashMap<>();
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
String fieldName = violation.getPropertyPath().toString();
String errorMessage = violation.getMessage();
errors.put(fieldName, errorMessage);
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(new ApiResponse<>("400", "Validation Error", errors));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<String>> handleOtherExceptions(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new ApiResponse<>("500", "Internal Server Error", null));
}
}
MethodArgumentNotValidException 主要用于处理通过 @Valid 或 @Validated 注解进行的请求参数验证失败的情况。这种异常通常发生在以下场景:
当使用 @Valid 或 @Validated 注解对请求参数进行验证时,如果验证失败,就会抛出 MethodArgumentNotValidException。
这种异常通常发生在控制器层,用于处理单个对象或多个对象的验证。
ConstraintViolationException 主要用于处理通过 javax.validation 包中的注解(如 @NotNull, @Size, @Pattern 等)进行的验证失败情况。这种异常通常发生在以下场景:
当使用 javax.validation 包中的注解进行验证时,如果验证失败,就会抛出 ConstraintViolationException。
这种异常通常发生在实体对象或领域模型对象的验证过程中。
接口如下:
在接口中使用vo类来接受参数,加上@Validated才会生效,不然不生效
在实际开发中,后台数据校验一般放在controller层,使用@Validated集合hibernate提供的一些列注解,可以很轻松优雅的实现数据校验的功能。
@PostMapping("/testVo")
@ResponseBody
public AjaxResult testVo(@Validated UserInfoVo infoVo){
System.out.println(infoVo);
return AjaxResult.success("成功");
}
调用接口测试效果
常用注解说明
Bean Validation 中内置的 constraint
注解 |
作用 |
@Valid |
被注释的元素是一个对象,需要检查此对象的所有字段值 |
@Null |
被注释的元素必须为 null |
@NotNull |
被注释的元素必须不为 null |
@AssertTrue |
被注释的元素必须为 true |
@AssertFalse |
被注释的元素必须为 false |
@Min(value) |
被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) |
被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) |
被注释的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) |
被注释的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) |
被注释的元素的大小必须在指定的范围内 |
@Digits (integer, fraction) |
被注释的元素必须是一个数字,其值必须在可接受的范围内 |
@Past |
被注释的元素必须是一个过去的日期 |
@Future |
被注释的元素必须是一个将来的日期 |
@Pattern(value) |
被注释的元素必须符合指定的正则表达式 |
Hibernate Validator 附加的 constraint
注解 |
作用 |
|
被注释的元素必须是电子邮箱地址 |
@Length(min=, max=) |
被注释的字符串的大小必须在指定的范围内 |
@NotEmpty |
被注释的字符串或集合不能为null或长度为0 |
@Range(min=, max=) |
被注释的数值元素必须在合适的范围内(包括指定值) |
@NotBlank |
被注释的字符串不能为null和空格字符串 |
@URL(protocol=,host=, port=,regexp=, flags=) |
被注释的字符串必须是一个有效的url |
注解属性说明
message:通用属性,用来作为自定义校验不通过提示的文案
groups:通用属性,指定一个或多个分组类
其他
@Valid和@Validated说明
@Validated由spring框架提供,@Valid由validation框架提供
@Validated可以用在类型、方法和方法参数上,但是不能用在成员属性上;
@Valid可以用在方法、构造函数、方法参数和成员属性上
分组:@Validated提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制
分组的使用
场景:新增用户信息和修改用户信息所需要验证的字段是不同的
定义两个接口用于分组
public interface AppUserVaildC {
}
public interface AppUserVaildU {
}
Model中字段上指定在什么组内时进行验证
Default 是默认分组
@Range(min = 0,max = 100,message = "年龄必须在[0,100]",groups={Default.class})
/**年龄*/
private Integer age;
@Range(min = 0,max = 2,message = "性别必须在[0,2]",groups = {AppUserVaildC.class})
/**性别 0:未知;1:男;2:女*/
private Integer sex;
Controller中指定分组
@PostMapping("save")
public void v1(@RequestBody @Validated({AppUserVaildC.class, AppUserVaildU.class}) AppUser appUser,BindingResult result){
if(result.hasErrors()){
for (ObjectError error : result.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
}
组序列:
除了按组指定是否验证之外,还可以指定组的验证顺序,前面组验证不通过的,后面组不进行验证
@GroupSequence({AppUserVaildC.class, AppUserVaildU.class, Default.class})
public interface GroupOrder {
}
Controller中使用
@PostMapping("save")
public void v1(@RequestBody @Validated({GroupOrder.class}) AppUser appUser,BindingResult result){
if(result.hasErrors()){
for (ObjectError error : result.getAllErrors()) {
System.out.println(error.getDefaultMessage());
}
}
}