Java Spring中如何将QueryParams里的JSON转为嵌套对象?
解决URL查询参数中JSON字符串转嵌套泛型对象的问题
你遇到的核心问题是URL中search参数的JSON字符串无法自动绑定到泛型记录CsvParams<T>的search字段,以下是几种无需重复编写ObjectMapper样板代码的简洁解决方案:
方案1:Spring全局注册JSON字符串转对象转换器
自定义Spring类型转换器,让框架自动将search参数的JSON字符串转为目标对象:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @Component public class JsonToTargetObjectConverter<T> implements Converter<String, T> { private final ObjectMapper objectMapper; public JsonToTargetObjectConverter(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override @SuppressWarnings("unchecked") public T convert(String jsonStr) { try { // 获取泛型目标类型并完成反序列化 return (T) objectMapper.readValue(jsonStr, objectMapper.getTypeFactory().constructType(getClass().getGenericSuperclass())); } catch (Exception e) { throw new IllegalArgumentException("search参数JSON格式错误", e); } } }
之后在Controller中直接使用泛型记录即可,框架会自动完成转换:
@GetMapping("/list/csv") public ResponseEntity<?> getCsvData(@ModelAttribute CsvParams<YourSearchDto> params) { // params.search()已自动转为YourSearchDto类型,可直接使用 return ResponseEntity.ok(params); }
方案2:自定义参数解析器(针对CsvParams专属处理)
如果不想全局生效,可自定义参数解析器,仅处理CsvParams<T>类型的参数:
import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; public class CsvParamsResolver implements HandlerMethodArgumentResolver { private final ObjectMapper objectMapper; public CsvParamsResolver(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public boolean supportsParameter(MethodParameter parameter) { return CsvParams.class.isAssignableFrom(parameter.getParameterType()); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String searchJson = webRequest.getParameter("search"); // 获取泛型参数的实际类型 Class<?> searchType = (Class<?>) parameter.getGenericParameterType().getActualTypeArguments()[0]; Object searchObj = objectMapper.readValue(searchJson, searchType); // 此处可扩展处理其他查询参数,示例简化仅处理search return new CsvParams<>(searchObj); } }
注册解析器到Spring配置:
import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @Configuration public class WebMvcConfig implements WebMvcConfigurer { private final ObjectMapper objectMapper; public WebMvcConfig(ObjectMapper objectMapper) { this.objectMapper = objectMapper; } @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(new CsvParamsResolver(objectMapper)); } }
Controller中直接使用即可:
@GetMapping("/list/csv") public ResponseEntity<?> getCsvData(CsvParams<YourSearchDto> params) { return ResponseEntity.ok(params); }
方案3:在记录类上添加Jackson反序列化注解
直接在CsvParams记录类上配置自定义反序列化器,让Jackson自动处理转换:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize; @JsonDeserialize(using = CsvParamsDeserializer.class) public record CsvParams<T>(T search) {}
实现对应的反序列化器:
import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; public class CsvParamsDeserializer extends JsonDeserializer<CsvParams<?>> { private final ObjectMapper objectMapper = new ObjectMapper(); @Override public CsvParams<?> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { Class<?> searchType = (Class<?>) ctxt.getContextualType().getActualTypeArguments()[0]; Object searchObj = objectMapper.readValue(p.getText(), searchType); return new CsvParams<>(searchObj); } }
Controller中使用@RequestParam结合注解即可:
@GetMapping("/list/csv") public ResponseEntity<?> getCsvData(@RequestParam CsvParams<YourSearchDto> params) { return ResponseEntity.ok(params); }
以上方案均基于Spring或Jackson的原生机制,彻底消除了手动调用ObjectMapper的样板代码,实现参数的自动绑定转换。
内容的提问来源于stack exchange,提问作者Marko Taht
相关产品推荐
相关产品推荐

