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

如何通过Swagger注解配置自定义数字错误码?

问题描述

我在OpenAPI契约中定义了如下用于表示佣金金额的Schema:

"properties": {
    "Amount": {
        "type": "number",
        "description": "The amount of tnx",
        "pattern" : "^-?[0-9]*(\\.([0-9]{1,2}))?$",
        "format": "big-decimal",
        "minimum": 0.01,
        "maximum": 49999.99,
        "exclusiveMinimum": false,
        "exclusiveMaximum": false,
        "example" : "9999.99"
    }
}

生成的Java代码如下:

@NotNull @Valid @DecimalMin("0.01") @DecimalMax("49999.99") 
@Schema(name = "amount", example = "9999.99", description = "The amount of tnx", required = true)
public BigDecimal getAmount() {
    return amount;
}

当输入金额超过49999.99或低于0.01时,Postman返回的验证信息如下:

{
    "errors": [
        {
            "code": "DecimalMax",
            "message": "must be less than or equal to 49999.99",
            "field": "Amount"
        }
    ]
}

{
    "errors": [
        {
            "code": "DecimalMin",
            "message": "must be greater than or equal to 0.01",
            "field": "Amount"
        }
    ]
}

但我希望将其中的错误码替换为自定义数字,比如:

{
    "errors": [
        {
            "code": "100",
            "message": "must be less than or equal to 49999.99",
            "field": "Amount"
        }
    ]
}

{
    "errors": [
        {
            "code": "101",
            "message": "must be greater than or equal to 0.01",
            "field": "Amount"
        }
    ]
}

请问是否可以通过Swagger注解实现这一需求?


解答

不能直接通过Swagger(OpenAPI)注解实现自定义错误码的需求,原因如下:

  • Swagger的@Schema等注解核心作用是生成API文档,不负责后端验证逻辑的执行和错误码映射。
  • 当前使用的@DecimalMin、@DecimalMax属于JSR-380(Java Bean Validation)规范的注解,验证逻辑由Spring Validation这类框架执行,默认返回的错误码是约束注解的名称(如DecimalMax)。

要实现自定义数字错误码,需要通过全局异常处理器拦截验证异常,将默认错误码替换为自定义值,具体步骤和示例代码如下:

实现步骤

  1. 创建全局异常处理器类,捕获请求体/参数验证时抛出的MethodArgumentNotValidException、ConstraintViolationException。
  2. 定义约束类型与自定义错误码的映射关系。
  3. 遍历异常中的验证错误,替换错误码并构造符合要求的响应格式返回。

示例代码

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@RestControllerAdvice
public class GlobalValidationExceptionHandler {

    // 约束类型到自定义错误码的映射
    private static final Map<String, String> CONSTRAINT_ERROR_CODE_MAP = Map.of(
            "DecimalMax", "100",
            "DecimalMin", "101"
    );

    // 处理请求体验证异常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ErrorResponse> handleRequestBodyValidation(MethodArgumentNotValidException ex) {
        List<ErrorDetail> errors = new ArrayList<>();
        for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
            String customCode = CONSTRAINT_ERROR_CODE_MAP.getOrDefault(fieldError.getCode(), fieldError.getCode());
            errors.add(new ErrorDetail(customCode, fieldError.getDefaultMessage(), fieldError.getField()));
        }
        return new ResponseEntity<>(new ErrorResponse(errors), HttpStatus.BAD_REQUEST);
    }

    // 处理路径/请求参数验证异常
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<ErrorResponse> handleParamValidation(ConstraintViolationException ex) {
        List<ErrorDetail> errors = new ArrayList<>();
        for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
            String constraintName = violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName();
            String customCode = CONSTRAINT_ERROR_CODE_MAP.getOrDefault(constraintName, constraintName);
            String field = violation.getPropertyPath().toString();
            errors.add(new ErrorDetail(customCode, violation.getMessage(), field));
        }
        return new ResponseEntity<>(new ErrorResponse(errors), HttpStatus.BAD_REQUEST);
    }

    // 错误响应结构类
    public static class ErrorResponse {
        private List<ErrorDetail> errors;

        public ErrorResponse(List<ErrorDetail> errors) {
            this.errors = errors;
        }

        public List<ErrorDetail> getErrors() { return errors; }
        public void setErrors(List<ErrorDetail> errors) { this.errors = errors; }
    }

    // 错误详情类
    public static class ErrorDetail {
        private String code;
        private String message;
        private String field;

        public ErrorDetail(String code, String message, String field) {
            this.code = code;
            this.message = message;
            this.field = field;
        }

        public String getCode() { return code; }
        public void setCode(String code) { this.code = code; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
        public String getField() { return field; }
        public void setField(String field) { this.field = field; }
    }
}

通过上述代码,即可将默认的DecimalMax、DecimalMin错误码替换为自定义的100、101数字码,同时保留原有的错误消息和字段信息。


内容的提问来源于stack exchange,提问作者jcrshankar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 21:15:34