You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 00:11:04