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

Spring中如何处理@RequestBody传入错误枚举的异常?

问题描述

在Spring项目中,通过@RequestBody接收枚举类型时,传入正确值功能正常,但传入错误值会直接返回400状态码。我尝试实现了一个Converter来处理,但没有效果:

@Component
public class EventTypeConverter implements Converter<String, EventType> {
    @Override
    public EventType convert(String s) {
        return EventType.valueOf(s.toUpperCase());
    }
}

我不想先接收String再手动转换处理异常,希望通过@ExceptionHandler来统一处理枚举转换异常,或者有其他更简洁的方案。我的枚举定义如下:

public enum EvenType {
    // 枚举实例...

    @Getter
    Character type;

    EvenType(Character type) {
        this.type = type;
    }

    public static EvenType of(String eventType) {
        return EvenType.valueOf(eventType);
    }

}
解决方案

一、用@ExceptionHandler统一处理枚举转换异常

Spring反序列化@RequestBody中的枚举失败时,会抛出HttpMessageNotReadableException,其根源是枚举valueOf方法抛出的IllegalArgumentException。你可以通过全局异常处理器捕获该异常,自定义返回内容:

@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseEntity<Map<String, String>> handleEnumConvertError(HttpMessageNotReadableException e) {
        Throwable rootCause = e.getRootCause();
        if (rootCause instanceof IllegalArgumentException && rootCause.getMessage().contains("No enum constant")) {
            Map<String, String> errorResp = new HashMap<>();
            errorResp.put("code", "INVALID_ENUM");
            errorResp.put("message", "传入的枚举值非法,请检查参数");
            return new ResponseEntity<>(errorResp, HttpStatus.BAD_REQUEST);
        }
        // 处理其他请求格式错误
        Map<String, String> defaultError = new HashMap<>();
        defaultError.put("code", "REQUEST_FORMAT_ERROR");
        defaultError.put("message", "请求格式不符合要求");
        return new ResponseEntity<>(defaultError, HttpStatus.BAD_REQUEST);
    }
}

该方式能统一捕获所有枚举类型的转换错误,无需在每个接口单独处理。

二、修复Converter无效问题

你之前实现的Converter<String, EventType>仅适用于URL参数的类型转换,而@RequestBody的反序列化依赖Jackson的机制,因此该Converter不起作用。要处理RequestBody中的枚举反序列化,需自定义Jackson反序列化器:

public class EventTypeDeserializer extends StdDeserializer<EvenType> {

    protected EventTypeDeserializer() {
        super(EvenType.class);
    }

    @Override
    public EvenType deserialize(JsonParser parser, DeserializationContext context) throws IOException {
        String inputValue = parser.getText().trim().toUpperCase();
        try {
            return EvenType.valueOf(inputValue);
        } catch (IllegalArgumentException e) {
            // 可抛出自定义异常,或根据业务返回默认枚举值
            throw new IOException("非法事件类型:" + inputValue, e);
        }
    }
}

在枚举类上添加注解指定该反序列化器:

@JsonDeserialize(using = EventTypeDeserializer.class)
public enum EvenType {
    // 枚举实例...

    @Getter
    Character type;

    EvenType(Character type) {
        this.type = type;
    }

    public static EvenType of(String eventType) {
        return EvenType.valueOf(eventType);
    }
}

当传入错误值时,Jackson会调用自定义反序列化器,抛出的异常可被全局异常处理器捕获并返回自定义信息。

三、优化枚举的of方法结合@JsonCreator

若不想自定义反序列化器,可修改枚举的of方法并添加@JsonCreator注解,指定Jackson反序列化时调用该方法:

public enum EvenType {
    // 枚举实例...

    @Getter
    Character type;

    EvenType(Character type) {
        this.type = type;
    }

    @JsonCreator
    public static EvenType of(String eventType) {
        try {
            return EvenType.valueOf(eventType.toUpperCase());
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("无效的事件类型:" + eventType);
        }
    }
}

@JsonCreator会引导Jackson使用该静态方法完成反序列化,抛出的异常同样会被全局异常处理器捕获处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 15:55:17