Spring MVC中使用Jackson动态映射GET请求参数到BaseRequest子类问题
GET请求动态参数映射到BaseRequest子类解决方案
问题根因
你当前使用的@JsonTypeInfo、@JsonSubTypes等Jackson多态注解,仅在JSON反序列化场景(如POST请求通过@RequestBody接收参数)生效。GET请求的查询参数默认走Spring自带的Servlet参数绑定逻辑,不会触发Jackson反序列化,因此无法自动映射到子类,只能拿到基类属性。
另外你配置的多态逻辑要求请求携带type参数标识子类类型,你给出的请求示例中没有携带该参数,即使走Jackson反序列化也无法匹配到对应子类。
解决方案:自定义HandlerMethodArgumentResolver
通过自定义Spring MVC参数解析器,手动将GET查询参数转为Map后调用Jackson反序列化,触发多态逻辑,是适配GET场景的最优解。
步骤1:实现自定义参数解析器
@Component public class BaseRequestArgumentResolver implements HandlerMethodArgumentResolver { @Autowired private ObjectMapper objectMapper; @Override public boolean supportsParameter(MethodParameter parameter) { // 仅处理BaseRequest及其子类的参数 return BaseRequest.class.isAssignableFrom(parameter.getParameterType()); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // 提取所有查询参数转为Map Map<String, String[]> paramMap = webRequest.getParameterMap(); Map<String, Object> paramObjMap = new HashMap<>(); for (Map.Entry<String, String[]> entry : paramMap.entrySet()) { if (entry.getValue().length > 0) { paramObjMap.put(entry.getKey(), entry.getValue()[0]); } } // 调用Jackson反序列化,自动触发多态匹配 return objectMapper.convertValue(paramObjMap, BaseRequest.class); } }
步骤2:注册参数解析器到Spring MVC
@Configuration public class WebMvcConfig implements WebMvcConfigurer { @Autowired private BaseRequestArgumentResolver baseRequestArgumentResolver; @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(baseRequestArgumentResolver); } }
步骤3:调整请求格式,携带type参数
你需要在请求中增加type参数,值对应子类的@JsonTypeName配置,示例:
- RequestA请求:
http://localhost:8080/request?type=RequestA&token=abc&error=test - RequestB请求:
http://localhost:8080/request?type=RequestB&id=abc&error=test
无type参数适配方案
如果不想在请求中加type字段,希望根据参数自动判断子类类型(如有token对应RequestA,有id对应RequestB),可以修改参数解析器的resolveArgument逻辑,不需要依赖Jackson多态注解:
@Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { BaseRequest request; if (webRequest.getParameter("token") != null) { request = new RequestA(); } else if (webRequest.getParameter("id") != null) { request = new RequestB(); } else { request = new BaseRequest(); } // 用Spring自带的DataBinder自动绑定所有属性,无需手动赋值 WebDataBinder binder = binderFactory.createBinder(webRequest, request, parameter.getParameterName()); binder.bind(new ServletRequestParameterPropertyValues((HttpServletRequest) webRequest.getNativeRequest())); return request; }
备选简化方案(改POST请求)
如果可以接受接口改为POST请求,无需自定义任何配置,只需要给控制器参数加@RequestBody注解即可直接生效:
@PostMapping(value = "/request", produces = MediaType.APPLICATION_JSON_VALUE) public String request(@RequestBody BaseRequest request) { // 直接即可获取对应子类实例 }
前端将参数放在JSON请求体中传输,携带type字段即可自动完成多态映射。
内容的提问来源于stack exchange,提问作者Jerry
相关产品推荐
相关产品推荐

