Spring Boot中如何处理空RequestBody?无法修改Swagger生成模型类
解决方案:Spring Boot中拦截空JSON请求体(模型类不可修改)
我之前帮同事处理过完全一样的场景——Swagger生成的模型类碰不得,但又要避免空JSON被转换成全null的实例。下面几个方案都能解决问题,按优雅度和适用场景排序:
1. 自定义RequestBodyAdvice(全局拦截,推荐)
Spring提供的RequestBodyAdvice可以在请求体被转换成Java对象的前后插入自定义逻辑,完美适配这种不能修改模型类的场景,一次配置全局生效。
实现步骤:
- 创建类实现
RequestBodyAdvice,加@ControllerAdvice让Spring扫描到 - 在
supports方法里指定要拦截的目标模型类 - 在
afterBodyRead方法里检查转换后的对象是否所有字段都为null,是的话直接抛异常
代码示例:
import org.springframework.core.MethodParameter; import org.springframework.http.HttpInputMessage; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice; import java.lang.reflect.Field; import java.lang.reflect.Type; @ControllerAdvice public class EmptyRequestBodyCheckAdvice implements RequestBodyAdvice { // 指定要拦截的模型类,替换成你的实际类名 @Override public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return targetType.getTypeName().equals(YourRequestModel.class.getName()); } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return inputMessage; } @Override public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { if (isAllFieldsNull(body)) { throw new RuntimeException("All fields are empty."); } return body; } @Override public Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { // 处理完全没有请求体的情况(不是{},而是空内容) throw new RuntimeException("Request body cannot be empty."); } // 反射遍历字段,判断是否全为null private boolean isAllFieldsNull(Object obj) { for (Field field : obj.getClass().getDeclaredFields()) { field.setAccessible(true); try { if (field.get(obj) != null) { return false; } } catch (IllegalAccessException e) { // 反射异常可以打日志或者做其他处理 e.printStackTrace(); } } return true; } }
2. Controller层手动检查(适合单个端点)
如果只有一个端点用到这个模型类,直接在Controller方法里加检查逻辑最直接,不用写全局组件。可以封装一个工具类复用检查逻辑:
// 封装检查工具类 public class ObjectCheckUtils { public static boolean isAllFieldsNull(Object obj) { if (obj == null) return true; for (Field field : obj.getClass().getDeclaredFields()) { field.setAccessible(true); try { if (field.get(obj) != null) { return false; } } catch (IllegalAccessException e) { e.printStackTrace(); } } return true; } } // Controller中的用法 @PostMapping("/your-api-endpoint") public ResponseEntity<?> handleRequest(@RequestBody YourRequestModel requestObj) { if (ObjectCheckUtils.isAllFieldsNull(requestObj)) { throw new RuntimeException("All fields are empty."); } // 后续业务逻辑处理 return ResponseEntity.ok("Processed successfully"); }
3. Jackson Mixin + 自定义反序列化器(进阶方案)
如果想从序列化源头拦截空JSON,可以用Jackson的Mixin功能——不用修改原模型类,就能给它绑定自定义反序列化逻辑:
步骤:
- 创建一个和模型类字段匹配的Mixin接口
- 写自定义反序列化器,检查JSON是否为空
- 在Spring Boot中注册Mixin和反序列化器
代码示例:
// Mixin接口,和你的模型类结构保持一致 public interface YourRequestModelMixin { } // 自定义反序列化器 public class EmptyCheckDeserializer extends StdDeserializer<YourRequestModel> { protected EmptyCheckDeserializer() { super(YourRequestModel.class); } @Override public YourRequestModel deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { JsonNode node = p.getCodec().readTree(p); // 检查JSON节点是否没有任何非空字段 if (node.isEmpty()) { throw new RuntimeException("All fields are empty."); } // 用默认逻辑转换对象 ObjectMapper mapper = (ObjectMapper) p.getCodec(); return mapper.treeToValue(node, YourRequestModel.class); } } // 注册到Spring容器 @Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper mapper = new ObjectMapper(); mapper.addMixIn(YourRequestModel.class, YourRequestModelMixin.class); mapper.registerModule(new SimpleModule() .addDeserializer(YourRequestModel.class, new EmptyCheckDeserializer())); return mapper; } }
注意事项:
- 如果模型类里有基本数据类型(比如
int、boolean),空JSON会把它们转换成默认值(0、false),这时候需要调整isAllFieldsNull的逻辑,判断这些默认值是否属于“空”的范畴 - 全局拦截方案适合多个端点共用同一模型类的场景,能减少重复代码
- 要是需要更友好的前端提示,可以自定义业务异常,再用
@ExceptionHandler统一处理返回格式
内容的提问来源于stack exchange,提问作者mi.mo
相关产品推荐
相关产品推荐

