1.给Bean添加校验注解:javax.validation.constraints,并定义自己的message提示
例如:
@NotNull(message = "修改必须指定ID", groups = {UpdateGroup.class})
@Null(message = "新增不能指定ID", groups = {AddGroup.class})
@TableId
private Long brandId;
@NotBlank(message = "名称不能为空", groups = {AddGroup.class, UpdateGroup.class})
private String name;
@Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须是一个字母")
private String firstLetter;
NotNull和Null是校验类下规则,message指定校验失败时的报错信息。groups是指定分组(UpdateGroup和AddGroup是自定义的接口类),需要配合参数注解指定分组来确定是否需要校验。
2.开启校验功能,可以使用java规范(javax.validation.Valid)@Valid,但是该注解没有任何属性。我们可以使用Spring自带的(org.springframework.validation.annotation.Validated)@Validated可以支持分组功能。
@RequestMapping("/update")
public RespData update(@Validated({UpdateGroup.class}) @RequestBody BrandEntity brand)
UpdateGroup.class指定这是更新操作,只有上面1中属于UpdateGroup分组的字段才需要校验,
@RequestBody 自动将传递的json参数映射为BrandEntity实体对象。
注意:默认没有指定分组的校验注解,在分组校验情况下不生效,只会在@Validated生效;
3.获取校验结果:
方式一通过参数后紧跟BindingResult对象:
public RespData save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand, BindingResult result){
if(result.hasErrors()){
Map<String, String> map = new HashMap<>();
//获取校验的错误结果
result.getFieldErrors().forEach((item) -> {
//FieldError获取错误提示
String message = item.getDefaultMessage();
//获取错误的属性的名字
String field = item.getField();
map.put(field, message);
});
return RespData.error(400, "提交的数据不合法").put("data", map);
}
}
方式二统一处理异常,自定义异常处理类:
/**
* 集中处理所有异常
*/
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.example.controller")
@RestControllerAdvice(basePackages = "com.example.controller")
public class ExampleExceptionControllerAdvice {
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public RespData handleValidException(MethodArgumentNotValidException e){
log.error("数据校验出现问题{},异常类型{}", e.getMessage(), e.getClass());
BindingResult bindingResult = e.getBindingResult();
Map<String, String> errorMap = new HashMap<>();
bindingResult.getFieldErrors().forEach((fieldError) -> {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return RespData.error(BizCodeEnume.VALID_EXCEPTION.getCode(), BizCodeEnume.VALID_EXCEPTION.getMsg()).put("data", errorMap);
}
@ExceptionHandler(value = Throwable.class)
public RespData handleException(Throwable throwable){
return RespData.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(), BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
}
}
错误类型枚举类:
public enum BizCodeEnume {
UNKNOW_EXCEPTION(10000, "系统未知异常"),
VALID_EXCEPTION(10001, "参数格式校验失败");
private int code;
private String msg;
BizCodeEnume(int code, String msg){
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
@RestControllerAdvice是@ResponseBody和@ControllerAdvice的合并效果,
basePackages指定处理该包下的异常。
@ExceptionHandler指定处理的异常
以上即可实现基本的数据校验功能,但有时候需要我们自定义校验方法,创建自定义校验器
例如我们要实现一个字段只能是指定值中的一个:
@ListValue(vals= {0, 1}, message = "必须是指定的值")
private Integer status;
首先需要导入依赖:
<dependency>
<groupId>jakarta.validation</groupId>
<artifactId>jakarta.validation-api</artifactId>
<version>2.0.2</version>
<scope>compile</scope>
</dependency>
然后我们可以参考@NotBlank编写:
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class})
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListValue {
String message() default "{com.example.valid.ListValue.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] vals() default {};
}
message对应错误消息,可以在resources文件夹下创建ValidationMessages.properties文件,在文件中编写对应的错误消息:
com.example.valid.ListValue.message=必须是指定的值
也可以在写注解时指定message。
@Constraint(validatedBy = {ListValueConstraintValidator.class})确定注解的校验器:
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> {
private Set<Integer> set = new HashSet<>();
//初始化方法
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int val : vals){
set.add(val);
}
}
/**
*
* @param value 需要校验的值
* @param constraintValidatorContext
* @return
*/
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(value);
}
}
至此完成了ListValue的自定义校验功能。