如何为javax.validation.constraints.NotEmpty自定义响应错误码?
替换javax.validation默认错误码的实现方案
可以替换默认的"NotEmpty"错误码为自定义值,以下是几种实用的实现方案:
方案1:全局异常处理器映射错误码
这是最直接的方式,通过捕获验证异常,手动将默认注解名映射为自定义错误码。
创建全局异常处理类,拦截MethodArgumentNotValidException(Spring中处理请求参数验证的异常):
@RestControllerAdvice public class GlobalValidationExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, Object>> handleValidationErrors(MethodArgumentNotValidException ex) { Map<String, Object> response = new HashMap<>(); List<Map<String, String>> errorList = new ArrayList<>(); ex.getBindingResult().getAllErrors().forEach(error -> { FieldError fieldError = (FieldError) error; Map<String, String> errorDetails = new HashMap<>(); // 映射自定义错误码 String customCode = switch (fieldError.getCode()) { case "NotEmpty" -> "INVALID_NAME"; // 可扩展其他注解的映射,比如"NotNull" -> "REQUIRED_FIELD" default -> fieldError.getCode(); }; errorDetails.put("field", fieldError.getField()); errorDetails.put("code", customCode); errorDetails.put("message", error.getDefaultMessage()); errorList.add(errorDetails); }); response.put("status", HttpStatus.BAD_REQUEST.value()); response.put("errors", errorList); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } }
配置后,当name字段为空时,返回的错误码会被替换为"INVALID_NAME"。
方案2:自定义约束注解
如果需要长期复用特定的错误码规则,可以自定义注解替代@NotEmpty,直接内置自定义错误码。
步骤1:创建自定义注解
@Target({ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = CustomNotEmptyValidator.class) public @interface CustomNotEmpty { // 自定义错误消息 String message() default "Name is required"; // 自定义错误码 String code() default "INVALID_NAME"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
步骤2:实现验证逻辑
public class CustomNotEmptyValidator implements ConstraintValidator<CustomNotEmpty, String> { @Override public boolean isValid(String value, ConstraintValidatorContext context) { // 实现和@NotEmpty一致的验证逻辑:非空且非空白 return value != null && !value.trim().isEmpty(); } }
步骤3:在POJO中使用自定义注解
@ApiModelProperty(value = "Name", required = true) @CustomNotEmpty(message = "Name is required") private String name;
步骤4:在异常处理器中读取自定义码
修改全局异常处理器的错误码获取逻辑,读取自定义注解的code属性:
@RestControllerAdvice public class GlobalValidationExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, Object>> handleValidationErrors(MethodArgumentNotValidException ex) { Map<String, Object> response = new HashMap<>(); List<Map<String, String>> errorList = new ArrayList<>(); ex.getBindingResult().getAllErrors().forEach(error -> { FieldError fieldError = (FieldError) error; Map<String, String> errorDetails = new HashMap<>(); String customCode = fieldError.getCode(); // 读取自定义注解的code属性 ConstraintDescriptor<?> descriptor = fieldError.getConstraintDescriptor(); if (descriptor.getAnnotation() instanceof CustomNotEmpty customNotEmpty) { customCode = customNotEmpty.code(); } errorDetails.put("field", fieldError.getField()); errorDetails.put("code", customCode); errorDetails.put("message", error.getDefaultMessage()); errorList.add(errorDetails); }); response.put("status", HttpStatus.BAD_REQUEST.value()); response.put("errors", errorList); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } }
方案3:配置文件批量映射错误码
适合需要批量管理多个字段、多个注解的错误码场景,通过ValidationMessages.properties配置映射关系。
步骤1:创建配置文件
在src/main/resources下创建ValidationMessages.properties:
# 格式:[注解名].[字段名].code=自定义错误码 NotEmpty.name.code=INVALID_NAME # 可添加其他配置,比如 NotNull.email.code=REQUIRED_EMAIL
步骤2:在异常处理器中读取配置
注入MessageSource读取配置文件中的自定义错误码:
@RestControllerAdvice public class GlobalValidationExceptionHandler { @Autowired private MessageSource messageSource; @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, Object>> handleValidationErrors(MethodArgumentNotValidException ex) { Map<String, Object> response = new HashMap<>(); List<Map<String, String>> errorList = new ArrayList<>(); Locale currentLocale = Locale.getDefault(); ex.getBindingResult().getAllErrors().forEach(error -> { FieldError fieldError = (FieldError) error; Map<String, String> errorDetails = new HashMap<>(); // 构建配置文件中的键 String codeKey = fieldError.getCode() + "." + fieldError.getField() + ".code"; // 读取自定义错误码,不存在则使用默认码 String customCode = messageSource.getMessage(codeKey, null, fieldError.getCode(), currentLocale); errorDetails.put("field", fieldError.getField()); errorDetails.put("code", customCode); errorDetails.put("message", error.getDefaultMessage()); errorList.add(errorDetails); }); response.put("status", HttpStatus.BAD_REQUEST.value()); response.put("errors", errorList); return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST); } }
内容的提问来源于stack exchange,提问作者Zia
相关产品推荐
相关产品推荐

