Spring MVC:是否可以将特定的HttpMessageConverter绑定到@RequestBody-annotated参数?

时间:2017-04-05 19:15:58

标签: java rest spring-mvc spring-boot

我有一个带有默认AbstractJackson2HttpMessageConverter的Spring Boot应用程序。绑定的杰克逊ObjectMapper实例已注册自定义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
) {
    ...
}

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

  • 我不想直接在我的控制器或相关服务的某处验证多地图。
  • 如果它是一个缺陷:我无法使用@Valid@ModelAttribute之类的Spring MVC注释,但现在我并不真正关心这些,由于以下原因:
  • 我不希望在反序列化之后验证多图,因为我想在特定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相关且更优雅的方式来实现?任何建议都非常感谢。提前谢谢!

1 个答案:

答案 0 :(得分:4)

创建一个专门的章程,即@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
) {
    ...
}