springboot中使用自定义的HibernateValidator校验器
目标:创建一个如下的注解,可以限制字符串值的内容是大写还是小写
@NotBlank
@CheckCase(value=CaseMode.LOWER)
private String demoName;
物料准备:一个自定义注解,一个枚举类,一个自定义的ConstraintValidator校验器
定义自定义注解@CheckCase
package cn.ath.knowwikibackend.rest.hv;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target({ElementType.FIELD,
ElementType.METHOD,
ElementType.PARAMETER,
ElementType.ANNOTATION_TYPE,
ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CheckCaseValidator.class)
@Documented
@Repeatable(CheckCase.List.class)
public @interface CheckCase {
String message() default "CheckCase默认错误信息!";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
CaseMode value();
@Target({ElementType.FIELD,
ElementType.METHOD,
ElementType.PARAMETER,
ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface List{
CheckCase[] value();
}
}
定义1个枚举类,用于指定@CheckCase 是限制大写还是限制小写
package cn.ath.knowwikibackend.rest.hv;
public enum CaseMode {
UPPER,
LOWER;
}
自定义CheckCaseValidator校验器,定义具体的校验逻辑
package cn.ath.knowwikibackend.rest.hv;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
/**
* 自定义 hibernate ConstraintValidator 校验器
*/
public class CheckCaseValidator implements ConstraintValidator<CheckCase, String> {
private CaseMode caseMode;
/**
* 定义需要校验的注解的类型
* @param constraintAnnotation
*/
@Override
public void initialize(CheckCase constraintAnnotation) {
this.caseMode = constraintAnnotation.value();
}
/**
* 自定义 对目标参数的校验逻辑
* @param value 待校验的字符串
* @param context ConstraintValidatorContext
* @return boolean
*/
@Override
public boolean isValid(String value,
ConstraintValidatorContext context) {
//jakarata bean validation 建议null是有效的。如果null不是有效数据,则需要加上注解@NotNull
if (value == null) {
return true;
}
boolean flag;
if(caseMode == CaseMode.UPPER){
flag = value.equals(value.toUpperCase());
if (!flag){
//自定义抛出的 校验不通过时的提示信息内容
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("字符串必须是大写")
.addConstraintViolation();
}
}else {
flag = value.equals(value.toLowerCase());
if (!flag){
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("字符串必须是小写")
.addConstraintViolation();
}
}
return flag;
}
}
测试使用@CheckCase 注解
@PostMapping("/addUser")
public UserTestResp addUser(@RequestBody @Validated
UserTestReq1 req){
log.info("req:{}",req);
return UserTestResp.builder()
.age(req.getAge())
.name(req.getName())
.build();
}
@Data
public class UserTestReq1 {
@Length(max = 30,min=4) //userTestReq1.name长度需要在4和30之间
@NotBlank
private String name;
@Min(1) //userTestReq1.age最小不能小于1
@Max(120) //userTestReq1.age最大不能超过120
@NotNull
private Integer age;
@NotBlank
@CheckCase(value=CaseMode.LOWER) //限制字符串内容是小写
private String demoName;
}
@Slf4j
@RestControllerAdvice(annotations = RestController.class)
public class RestGlobalExceptionHandler{
@ExceptionHandler({MethodArgumentNotValidException.class})
public ResultVO<String> MethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
log.error("自动抛的MethodArgumentNotValidException",e);
// 从异常对象中拿到ObjectError对象
ObjectError objectError = e.getBindingResult().getAllErrors().get(0);
log.error("objectError:{}", JSONObject.toJSONString(objectError, true));
String field = String.valueOf(JSONPath.eval(objectError, "$.field"));
log.error("field:{}", field);
String objName = objectError.getObjectName();
System.err.println(objName);
// 然后提取错误提示信息进行返回
return new ResultVO<>(ResultCodeEnum.VALIDATE_FAILED,
objName + "." + field + objectError.getDefaultMessage());
}
}
{
"code": 9996,
"msg": "参数校验异常",
"content": "userTestReq1.demoName字符串必须是小写",
"timestamp": 1685533250234,
"traceDateTime": "2023-05-31 19:40:50"
}