Spring 使用 non-standard 启动 RequestMapping 在返回带注释的 JAXB 时产生返回 406 错误的值 object

Spring Boot RequestMapping with non-standard produces value returning 406 error when returning JAXB annotated object

我正在创建一个 Spring 引导应用程序来替换遗留 api 应用程序,因此所有 routes/headers/etc 都已经设置好了。在那个遗留应用程序中,我们使用自定义 Accept headers 来包含版本和内容类型。所以我们的 Accept header 就像:

目录。v1.xml 或目录。v2.json 等等

这是我处理请求的方法的请求映射。我正在尝试处理 v1.xml 一个。 Spring 正在寻找正确的方法并执行整个方法,它 returns 我的 JAXB 注释 object:

@RequestMapping(value = "/catalog", method = RequestMethod.GET, produces="application/catalog.v1.xml")

如何确保 Spring 根据我的 Accept header 找到这个匹配的处理程序方法,但知道输出应该是 XML 并编组我的 JAXB object 因此?

所以一旦我意识到我正在更改错误的配置,并且从深度调试到 Spring 代码,我意识到我需要替换或修改消息转换器的行为。下面是我的解决方案。他们不会让它变得超级容易。如果有人有更简单的方法来做到这一点,请告诉我。这行得通。

public void extendMessageConverters(List<HttpMessageConverter<?>> converters)     
{
    for (HttpMessageConverter<?> converter : converters) {
        if (converter.getClass() == MappingJackson2HttpMessageConverter.class){
            MappingJackson2HttpMessageConverter jacksonConverter = (MappingJackson2HttpMessageConverter)converter;
            MediaType jsonType = new MediaType("application", "catalog.v2.json");
            MediaType jsonpType = new MediaType("application", "catalog.v2.jsonp");

            List<MediaType> mediatTypes = new ArrayList<>(jacksonConverter.getSupportedMediaTypes());
            mediatTypes.add(jsonpType);
            mediatTypes.add(jsonType);
            jacksonConverter.setSupportedMediaTypes(mediatTypes);
        }
        else if (converter.getClass() == Jaxb2RootElementHttpMessageConverter.class){
            Jaxb2RootElementHttpMessageConverter xmlConverter = (Jaxb2RootElementHttpMessageConverter) converter;
            MediaType xmlType = new MediaType("application", "catalog.v1.xml");

            // Since the SupportMediaTypes list is unmodifiable, we have to create a new one based on it
            // and replace it completely
            List<MediaType> mediatTypes = new ArrayList<>(xmlConverter.getSupportedMediaTypes());
            mediatTypes.add(xmlType);
            xmlConverter.setSupportedMediaTypes(mediatTypes);
        }
    }
}

您需要为 Spring MVC 提供 HttpMessageConverter 用于您的自定义媒体类型。为此,我将利用 Spring Boot 自动将任何 HttpMessageConverter bean 添加到 Spring MVC 的默认配置,方法是配置一个知道如何转换 application/catalog.v1.xml 的 bean:

@Bean
public Jaxb2RootElementHttpMessageConverter catalogXmlConverter() {
    Jaxb2RootElementHttpMessageConverter xmlConverter = new Jaxb2RootElementHttpMessageConverter();
    xmlConverter.setSupportedMediaTypes(Arrays.asList(new MediaType("application", "catalog.v1.xml")));
    return xmlConverter;
}