Spring MVC中如何将@RequestBody对象的空字符串属性转为null?
如何在Spring @RequestBody中仅针对特定方法将空字符串转为null?
针对你的需求(仅在save方法中将所有空/空白字符串(包括嵌套属性)转为null),可以采用以下两种方案:
方案一:使用@RequestBodyAdvice(推荐,无需手动处理请求体)
通过@RequestBodyAdvice可以在@RequestBody反序列化完成后对目标对象进行修改,并且能精准限定作用的方法和参数类型。
1. 实现RequestBodyAdvice
@ControllerAdvice public class EmptyStringToNullAdvice implements RequestBodyAdvice { @Override public boolean supports(MethodParameter methodParam, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { // 仅作用于save方法,且参数类型为Car return "save".equals(methodParam.getMethod().getName()) && Car.class.getName().equals(targetType.getTypeName()); } @Override public HttpInputMessage beforeBodyRead(HttpInputMessage inputMsg, MethodParameter param, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException { return inputMsg; } @Override public Object afterBodyRead(Object body, HttpInputMessage inputMsg, MethodParameter param, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { // 递归遍历对象,将空/空白字符串转为null convertEmptyStringsToNull(body); return body; } @Override public Object handleEmptyBody(Object body, HttpInputMessage inputMsg, MethodParameter param, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { return body; } private void convertEmptyStringsToNull(Object obj) { if (obj == null) return; Field[] fields = obj.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); try { Object value = field.get(obj); if (value instanceof String) { String strValue = (String) value; if (strValue.trim().isEmpty()) { field.set(obj, null); } } else if (value != null && !field.getType().isPrimitive() && !Collection.class.isAssignableFrom(field.getType())) { // 递归处理嵌套对象 convertEmptyStringsToNull(value); } } catch (IllegalAccessException e) { // 可根据实际需求添加日志或异常处理 e.printStackTrace(); } } } }
2. 原控制器方法无需修改
你的save方法保持原样即可:
@PutMapping public void save(@RequestBody Car car) { // 此时car中的空/空白字符串已转为null }
方案二:自定义Jackson反序列化器+局部ObjectMapper
如果希望直接通过Jackson的序列化机制处理,可以自定义字符串反序列化器,然后为save方法单独配置ObjectMapper。
1. 自定义字符串反序列化器
public class EmptyStringToNullDeserializer extends StdDeserializer<String> { public EmptyStringToNullDeserializer() { super(String.class); } @Override public String deserialize(JsonParser parser, DeserializationContext context) throws IOException { String value = parser.getText(); return (value == null || value.trim().isEmpty()) ? null : value; } }
2. 注册自定义模块
public class EmptyStringModule extends SimpleModule { public EmptyStringModule() { addDeserializer(String.class, new EmptyStringToNullDeserializer()); } }
3. 在控制器中使用自定义ObjectMapper
手动读取请求体并反序列化(注意这种方式需要放弃@RequestBody注解):
@RestController public class CarController { private final ObjectMapper defaultMapper; private final ObjectMapper customMapper; // 注入默认ObjectMapper,复制后添加自定义模块 public CarController(ObjectMapper defaultMapper) { this.defaultMapper = defaultMapper; this.customMapper = defaultMapper.copy(); this.customMapper.registerModule(new EmptyStringModule()); } @PutMapping public void save(HttpServletRequest request) throws IOException { // 读取请求体 String requestBody = request.getReader().lines().collect(Collectors.joining()); // 使用自定义ObjectMapper反序列化 Car car = customMapper.readValue(requestBody, Car.class); // 后续业务逻辑 } }
方案对比
- 方案一:无需修改原控制器方法,通过切面式处理实现,代码侵入性低,更符合Spring的开发习惯。
- 方案二:直接基于Jackson机制处理,适合需要更精细控制序列化逻辑的场景,但需要手动处理请求体。
内容的提问来源于stack exchange,提问作者James
相关产品推荐
相关产品推荐

