SpringBoot Webflux 无法返回 application/xml

mas*_*ick 1 java xml spring-boot jackson-dataformat-xml spring-webflux

在我的反应式 REST API 中,我试图返回一个XML响应。但是,我总是得到一个JSON,即406 NOT_ACCEPTABLE。知道为什么吗?

@RestController
@RequestMapping(path = "/xml", produces = APPLICATION_XML_VALUE)
public class RestApi {
    @GetMapping(path = "/get")
    public Publisher<ResponseEntity> get() {
        return Mono.just(ResponseEntity.ok().contentType(APPLICATION_XML).body(new Datta("test")));
    }

    @PostMapping(path = "/post", consumes = APPLICATION_XML_VALUE)
    public Publisher<ResponseEntity<Datta>> post(@RequestBody Datta datus) {
        datus.setTitle(datus.getTitle() + "!");
        return Mono.just(ResponseEntity.ok().contentType(APPLICATION_XML).body(datus));
    }
}
Run Code Online (Sandbox Code Playgroud)

java.lang.AssertionError: 预期:application/xml 实际:application/json;charset=UTF-8

plugins {
    id 'org.springframework.boot' version '2.1.3.RELEASE'
    id "io.spring.dependency-management" version "1.0.7.RELEASE"
}
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    implementation "com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.9.8"
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
Run Code Online (Sandbox Code Playgroud)

这些是到我的 REST控制器和单元测试的链接。谢谢!

mas*_*ick 5

显然,WebFlux 中jackson-dataformat-xml 尚不支持 XML 编组。至于现在我看到两种可能性:

  1. 要么添加org.springframework.boot:spring-boot-starter-web类路径(应该有starter-web和starter-webflux)。但是,这仅适用于 Servlet 3.1 运行时(例如 Tomcat)。
  2. 或者,如果您想要一个完全成熟的反应式 Web 服务器(例如 Netty),请使用来自 JAXB(Jaxb2XmlEncoder和Jaxb2XmlDecoder)的xml 编组:

构建.gradle:

sourceCompatibility = '11'

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

    // Java 11 removed these Java EE modules
    implementation "javax.xml.bind:jaxb-api:2.3.1"
    implementation "com.sun.xml.bind:jaxb-core:2.3.0.1"
    implementation "com.sun.xml.bind:jaxb-impl:2.3.2"

    compileOnly "org.projectlombok:lombok"
    annotationProcessor "org.projectlombok:lombok"
}
Run Code Online (Sandbox Code Playgroud)

POJO :

@Data
@AllArgsConstructor
@NoArgsConstructor
@XmlRootElement
public class Datta {
    private String title;
}
Run Code Online (Sandbox Code Playgroud)

注意 3 个javax.xml.bind依赖项(您不需要这些 for Java 8)和@XmlRootElement注释。此解决方案立即生效,但是如果您想要进一步定制,请实施您自己的WebFluxConfigurer:

@Configuration
@EnableWebFlux
public class WebConfig implements WebFluxConfigurer {
    @Override
    public void configureHttpMessageCodecs(ServerCodecConfigurer configurer) {
        configurer.registerDefaults(false);
        configurer.customCodecs().decoder(new Jaxb2XmlDecoder());   // <- here
        configurer.customCodecs().encoder(new Jaxb2XmlEncoder());   // <- here

    }
}
Run Code Online (Sandbox Code Playgroud)

这是源代码的链接。