【问题标题】:How do you configure spring boot 2 to return xml by default?如何配置spring boot 2默认返回xml?
【发布时间】:2021-04-17 17:07:01
【问题描述】:

首先我读过这篇文章:

Spring boot - setting default Content-type header if it's not present in request

旧版本在 spring boot 1 上工作。但是当接收到带有以下接受标头Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2"的请求时

响应是 json 格式。

我已经上课了

@Configuration
public class MyWebMvcConfigurer implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(
            ContentNegotiationConfigurer configurer) {
        configurer.defaultContentType(MediaType.APPLICATION_XML);
    }

}

我可以看到正在设置 defaultContentType 策略。但是它被 AcceptHeaderConfig 策略覆盖。

看起来 defaultContentType 仅用作备用。

请注意,spring boot 1 中的相同代码可以正常工作并默认为 XML。


完整示例

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.annotation.XmlRootElement;

@SpringBootApplication
@RestController
public class CnApp {

    @RequestMapping("/")
    public Person person(HttpServletRequest request, ModelMap model){
        return new Person();
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(CnApp.class, args);
    }

    @XmlRootElement
    public static class Person {
        public String firstName = "Jon";
        public String lastName = "Doe";
    }

    @Configuration
    public static class ServerConfig implements WebMvcConfigurer {
        @Override
        public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
            configurer.defaultContentType(MediaType.APPLICATION_XML);
        }

    }

}

你可以通过运行看到 curl localhost:8080 -H"Accept: text/html, image/gif, image/jpg;q=0.2, */*;q=0.2" 默认为 json,虽然 XML 是默认的


来自我在下面发布的评论

问题在于旧版本的 spring 我们可以发送一个接受标头并获取默认为 XML 的请求。但是仍然支持 JSON。

因此,当一个接受头以相同的特性支持 JSON 和 XML 时,我们需要返回 XML。

【问题讨论】:

    标签: java spring-boot spring-mvc content-negotiation


    【解决方案1】:

    您的WebMvc 配置与您的配置一样正常工作。

    如果没有Accept 标头,则使用默认的ContentType。

    要达到您的范围,您必须继续使用内容协商策略,并禁用 Accept 标头。您的 configureContentNegotiation 方法应如下所示:

    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false)
        .parameterName("mediaType")
        .ignoreAcceptHeader(true)
        .useJaf(false)
        .defaultContentType(MediaType.APPLICATION_XML)
        .mediaType("xml", MediaType.APPLICATION_XML;
    }
    

    您可以查看 Spring 博客上的this 文章和 Baeldung 上的this 文章。

    【讨论】:

    • 好的,谢谢,但问题在于旧版本的 spring 我们可以发送一个接受标头并获取默认为 xml 的请求。但是仍然支持 json。因此,当一个接受头以相同的特性同时支持 JSON 和 XML 时,我们需要返回 XML
    【解决方案2】:

    对此进行进一步调查。 @thepaoloboi 在他的回答中建议的是正确的 defaultMessageConverter 只有在没有发生其他形式的内容协商时才会发生。

    为了解决这个问题,我逐步检查了org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor 使用的代码,我发现它依赖于已配置的转换程序的顺序。

    因此,作为 hack,以下代码在 spring 1 和 spring 2 中都有效。

    package com.example;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.http.MediaType;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.xml.Jaxb2CollectionHttpMessageConverter;
    import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
    import org.springframework.ui.ModelMap;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.xml.bind.annotation.XmlRootElement;
    import java.util.List;
    
    @SpringBootApplication
    @RestController
    public class CnApp {
    
        @RequestMapping("/")
        public Person person(HttpServletRequest request, ModelMap model){
            return new Person();
        }
    
        public static void main(String[] args) throws Exception {
            SpringApplication.run(CnApp.class, args);
        }
    
        @XmlRootElement
        public static class Person {
            public String firstName = "Jon";
            public String lastName = "Doe";
        }
    
        @Configuration
        public static class ServerConfig extends WebMvcConfigurerAdapter {
            @Override
            public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
                configurer.defaultContentType(MediaType.APPLICATION_XML);
            }
    
            @Override
            public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    
                converters.add(0, new Jaxb2CollectionHttpMessageConverter<>());
                converters.add(0, new Jaxb2RootElementHttpMessageConverter());
                System.out.println("Converters:" + converters);
            }
        }
    
    }
    

    它的工作原理是将 Jaxb2 转换器设置为比 jackson 转换器更高的优先级。

    可以这样测试

    curl localhost:8080 -H"Accept: text/html, image/gif, image/jpg;q=0.2, */*;q=0.2"
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?><person><firstName>Jon</firstName><lastName>Doe</lastName></person>%
    
    curl localhost:8080 -H"Accept: text/html, image/gif, image/jpg;q=0.2, application/json, */*;q=0.2"
    {"firstName":"Jon","lastName":"Doe"}%            
    

    请注意,如果在标头中的任何位置指定了 application/json,这仍然是首选。

    这仍然感觉像是一种 hack,如果有一种方法可以对首选的 mime 类型进行排序而不需要添加或重新排序转换器,那就太好了

    【讨论】:

      猜你喜欢
      • 2019-08-16
      • 2020-11-14
      • 2017-09-15
      • 2020-12-12
      • 2016-06-06
      • 2021-08-20
      • 2014-07-04
      • 1970-01-01
      • 2017-01-29
      相关资源
      最近更新 更多