Spring ConstraintValidation自定义错误码实现方案咨询
我来给你捋个清晰的方案,完全适配你想用注解简化校验+自定义错误码的需求,一步步来很容易实现:
用自定义注解实现带自定义错误码的字段校验
1. 先定义带错误码属性的自定义校验注解
首先创建一个注解,核心是加入自定义错误码属性,同时指定对应的校验器类:
import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.*; @Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = CustomFieldValidator.class) public @interface CustomFieldCheck { // 自定义错误码,可配置,给个默认通用码 String errorCode() default "VALIDATE_COMMON_001"; // 可选的错误提示(后续可以和错误码解耦,从配置文件取) String message() default "字段校验不通过"; // JSR380规范要求的分组和负载属性,保留默认即可 Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
2. 实现对应的校验器逻辑
把你之前模板里的校验逻辑搬过来,同时在初始化时获取注解里配置的错误码,校验失败时把错误码注入到校验上下文:
import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; public class CustomFieldValidator implements ConstraintValidator<CustomFieldCheck, Object> { private String customErrorCode; // 初始化时拿到注解里的错误码 @Override public void initialize(CustomFieldCheck constraintAnnotation) { this.customErrorCode = constraintAnnotation.errorCode(); } // 核心校验逻辑,替换成你自己的业务规则 @Override public boolean isValid(Object fieldValue, ConstraintValidatorContext context) { // 举个例子:校验非空+字符串长度≥4 if (fieldValue == null) { this.addErrorToContext(context); return false; } String valueStr = fieldValue.toString(); if (valueStr.trim().length() < 4) { this.addErrorToContext(context); return false; } return true; } // 把自定义错误码写入校验上下文,覆盖默认提示 private void addErrorToContext(ConstraintValidatorContext context) { // 禁用默认错误信息,避免冲突 context.disableDefaultConstraintViolation(); // 把错误码作为错误信息存入,后续异常处理时提取 context.buildConstraintViolationWithTemplate(customErrorCode) .addConstraintViolation(); } }
3. 在实体类字段上使用自定义注解
现在就可以给需要校验的字段加注解,还能灵活配置不同的错误码:
public class OrderForm { @CustomFieldCheck(errorCode = "ORDER_NO_001", message = "订单号不能为空且长度≥4") private String orderNo; @CustomFieldCheck(errorCode = "CONTACT_PHONE_001", message = "联系电话格式错误") private String contactPhone; // getter/setter 省略 }
4. 全局异常处理提取错误码
最后配置全局异常处理器,捕获校验失败的异常,从里面提取我们的自定义错误码:
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class GlobalValidationExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public Map<String, Object> handleValidationError(MethodArgumentNotValidException e) { Map<String, Object> result = new HashMap<>(); // 从异常信息里拿到我们存入的错误码 String errorCode = e.getBindingResult().getFieldError().getDefaultMessage(); // 也可以拿到出错的字段名和注解里的提示信息 String errorField = e.getBindingResult().getFieldError().getField(); String tipMessage = e.getBindingResult().getFieldError().getDefaultMessage(); result.put("code", errorCode); result.put("message", tipMessage); result.put("errorField", errorField); return result; } }
进阶优化:错误码与提示信息解耦
如果想统一管理错误提示(比如放到配置文件),可以让注解里只存错误码,在异常处理器里根据错误码读取配置:
# application.properties VALIDATE_COMMON_001=字段格式不符合要求 ORDER_NO_001=订单号不能为空且长度不能小于4位 CONTACT_PHONE_001=联系电话格式不正确,请检查
然后修改异常处理器:
import org.springframework.core.env.Environment; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.annotation.Resource; import java.util.HashMap; import java.util.Map; @RestControllerAdvice public class GlobalValidationExceptionHandler { @Resource private Environment environment; @ExceptionHandler(MethodArgumentNotValidException.class) public Map<String, Object> handleValidationError(MethodArgumentNotValidException e) { Map<String, Object> result = new HashMap<>(); String errorCode = e.getBindingResult().getFieldError().getDefaultMessage(); // 根据错误码读取配置文件里的提示信息 String tipMessage = environment.getProperty(errorCode, "未知校验错误"); result.put("code", errorCode); result.put("message", tipMessage); return result; } }
这样维护错误提示就不用改代码,直接改配置文件就行,非常方便。
内容的提问来源于stack exchange,提问作者BeefTech
相关产品推荐
相关产品推荐

