Spring MVC:是否可以将特定的 HttpMessageConverter 绑定到@RequestBody注释参数



我有一个带有默认AbstractJackson2HttpMessageConverter的 Spring Boot 应用程序。绑定的 JacksonObjectMapper实例已注册自定义SimpleModule,因此现在它支持来自 Google Guava 库的Multimap

@Bean
public ObjectMapper objectMapper() {
return new ObjectMapper()
.setSerializationInclusion(NON_NULL)
.configure(FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(new SimpleModule()
.addSerializer(multimapType, multimapDuplicateKeysSerializer)
.addDeserializer(multimapType, multimapJsonDeserializer)
);
}

假设我的控制器中有以下方法:

@RequestMapping(method = POST)
@ResponseStatus(OK)
public Object post(
@RequestBody final Multimap<String, Object> multimap
) {
...
}

在这一步,一切都很好。现在,我必须验证多重映射中的空键或空白键,如果在传入的多重映射中发现任何无效键,则返回 HTTP 400。这是一个简单的操作,可以轻松遍历传入的多重映射并抛出要在控制器建议中处理的异常。但这至少还有下一个缺陷:

  • 我不想直接在控制器或关联服务中的某个位置验证多重地图。
  • 如果这是一个缺陷:我无法让它与 Spring MVC 注释一起使用,如@Valid@ModelAttribute等,但现在我并不真正关心这些,因为以下原因:
  • 我不希望在反序列化后验证 multimap,因为我想在特定HttpMessageConverter的某个位置的解析器级别验证传入的请求正文 - 我需要的验证纯粹是 JSON 流验证,即使对于不需要在验证之前反序列化整个多重映射的大型多重映射,也可以完美运行。当然,如果可能的话。

是否可以仅将特定HttpMessageConverter绑定到特定@RequestBody?可能是这样的:

@RequestMapping(method = POST)
@ResponseStatus(OK)
public Object post(
@SomeMagicSpringAnnotationHere("specificHttpMessageConverter") @RequestBody final Multimap<String, Object> multimap
OR
@AnotherMagicSpringAnnotationHere("specificObjectMapper") @RequestBody final Multimap<String, Object> multimap
OR
@WhateverMagicSpringAnnotationHere @RequestBody final Multimap<String, Object> multimap
) {
...
}

还是我对这种方法的看法是错误的,它可以通过与 Spring 更相关和更优雅的东西来完成?任何建议都非常感谢。提前感谢!

创建一个专门的注释,即@MultiMapRequestBody

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MultiMapRequestBody {
boolean required() default true;

然后创建一个知道该怎么做的MultiMapRequestBodyMethodArgumentResolver

public class MultiMapRequestBodyMethodArgumentResolver implements HandlerMethodArgumentResolver {
public  boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(MultiMapRequestBody.class); // maybe check argument type too.
}
public  Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
// Logic for validation and converting using Jackson
// Take a look at MappingJackson2HttpMessageConverter
}
}

现在,您可以自己处理正文转换和验证。您可能想查看MappingJackson2HttpMessageConverter,以获取有关如何阅读和解析正文的一些灵感。或者可以扩展用于参数转换的abstract类之一。

现在,在您的请求处理方法中使用@MultiMapRequestBody而不是@RequestBody注释。

@RequestMapping(method = POST)
@ResponseStatus(OK)
public Object post(
@MultiMapRequestBody final Multimap<String, Object> multimap
) {
...
}

最新更新