Spring boot Validated 参数注解验证
- 必要注解
- @Validated
- 全局异常捕获 GlobalExceptionHandler
- 参数注解
- @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) 被注释的元素必须符合指定的正则表达式
- @Email 被注释的元素必须是电子邮箱地址
- @Length 被注释的字符串的大小必须在指定的范围内
- @NotEmpty 被注释的字符串的必须非空
- @Range 被注释的元素必须在合适的范围内
- @NotBlank 验证字符串非null,且长度必须大于0
- 自定义注解(判断是否在枚举值中)
必要注解
@Validated
必须配在方法上,不然不会生效
@ApiOperation("新增demo")
@PostMapping("/add")
public CommonResult<?> add(@Validated @RequestBody DemoAddVo vo) {
return CommonResult.success();
}
全局异常捕获 GlobalExceptionHandler
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.Objects;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
public CommonResult<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
return CommonResult.failed(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
}
}
参数注解
@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) 被注释的元素必须符合指定的正则表达式
@Email 被注释的元素必须是电子邮箱地址
@Length 被注释的字符串的大小必须在指定的范围内
@NotEmpty 被注释的字符串的必须非空
@Range 被注释的元素必须在合适的范围内
@NotBlank 验证字符串非null,且长度必须大于0
自定义注解(判断是否在枚举值中)
定义 IdCard 注解
@IdCard
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = IdCardValidator.class)
public @interface IdCard {
String message() default "";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
Class<? extends Enum<?>> enumClass();
String enumMethod() default "isValueValid";
}
IdCardValidator
注解实现逻辑
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class IdCardValidator implements ConstraintValidator<IdCard, Integer> {
Logger log = LoggerFactory.getLogger(IdCardValidator.class);
private Class<? extends Enum<?>> enumClass;
private String enumMethod;
@Override
public void initialize(IdCard constraintAnnotation) {
enumClass = constraintAnnotation.enumClass();
enumMethod = constraintAnnotation.enumMethod();
}
@Override
public boolean isValid(Integer o, ConstraintValidatorContext context) {
if (ObjectUtils.isEmpty(o)) return Boolean.TRUE;
if (enumClass == null || StringUtils.isEmpty(enumMethod)) return Boolean.TRUE;
Class<?> vclass = o.getClass();
try {
// 反射机制获取具体的校验方法
Method method = enumClass.getMethod(enumMethod,vclass);
if (!Boolean.TYPE.equals(method.getReturnType()) &&
!Boolean.class.equals(method.getReturnType())) {
throw new RuntimeException("校验方法不是布尔类型!");
}
if (!Modifier.isStatic(method.getModifiers())) {
throw new RuntimeException("校验方法不是静态方法!");
}
method.setAccessible(true);
// 调用具体的方法
Boolean res = (Boolean) method.invoke(null,o);
return res != null ? res : false;
} catch (NoSuchMethodException e) {
log.error("NoSuchMethodException:{}" ,e);
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
log.error("IllegalAccessException:{}" ,e);
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
log.error("InvocationTargetException:{}" ,e);
throw new RuntimeException(e);
}
}
}
controllrt&入参实体
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
@RestController
@RequestMapping("/demo")
public class DemoController {
@PostMapping("/add")
public CommonResult<?> add(@Validated(Create.class) @RequestBody DemoAddVo vo) {
return CommonResult.success();
}
@PostMapping("/update")
public CommonResult<?> update(@Validated @RequestBody DemoAddVo vo) {
return CommonResult.success();
}
@Data
@EqualsAndHashCode(callSuper = false)
private static class DemoAddVo {
@NotBlank(message = "name 不能为空")
private String name;
@NotBlank(message = "邮箱不能为空")
@Email(message = "邮箱格式错误")
private String email;
@NotBlank(message = "手机号不能为空")
@Pattern(regexp ="^[1][3,4,5,6,7,8,9][0-9]{9}$", message = "手机号格式有误")
private String mobileNo;
@NotNull(message = "类型不能为空")
//group 指定分组 才执行 (@Validated 需要指定)
@IdCard(message = "类型错误", enumClass = ConstEnum.DEMO_TYPE.class, groups = Create.class)
private Integer type;
}
}
- 指定分组注解生效
import javax.validation.groups.Default;
/**
* 参数验证: 创建 group
*/
public interface Create extends Default {
}