首页 > 解决方案 > Spring Boot Web 客户端 XML

问题描述

我的 Spring Boot 应用程序想要使用 Webclient 发出 http 请求(XML 请求正文)并接收 XML 响应。因此,我使用 jackson-dataformat-xml 创建了另一个 Spring Boot 应用程序,并创建了一个端点来接收和返回 XML,如下所示。

spring-boot-version=2.2.5
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.dataformat</groupId>
  <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

@PostMapping(value = "/api",
            consumes = MediaType.APPLICATION_XML_VALUE,
            produces = MediaType.APPLICATION_XML_VALUE)
public ResponseEntity<MyXmlResponse> trip(@RequestBody MyXmlRequest request) throws Exception {
   MyXmlResponse response = new MyXmlResponse();
   response.setStatus("SUCCESS");
   response.setTripID(request.getTripID());
   return ResponseEntity.ok().body(response);
}

它工作完美,显然不需要 JaxB 注释,因为我使用 jackson-dataformat-xml。此外,请求 XML 可以不区分大小写。

现在,在我的第一个应用程序中,我想通过 webclient 使用这个 API。我读到 Spring webflux 还不支持 Jackson-dataformat-xml。因此,我必须使用 Jaxb 注释来注释我的类。

spring-boot-version=2.2.5
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>

webClient.post()
.uri(URI.create("url-to-api-endpoint"))
.body(Mono.just(myXmlRequest), MyXmlRequest.class)
.exchange()
.doOnSuccess(response -> {
    HttpStatus statusCode = response.statusCode();
    log.info("Status code of external system request {}", statusCode);
})
.doOnError(onError -> {
    log.error("Error on connecting to external system {}", onError.getMessage());
})
.flatMap(response -> response.bodyToMono(MyXmlResponse.class))
.subscribe(this::handleResponse);

上面的代码抛出异常如下

org.springframework.webreactive.function.UnsupportedMediaTypeException: Content type 'application/xml' not supported for bodyType=com.example.MyXmlRequest
    at org.springframework.web.reactive.function.BodyInserters.unsupportedError(BodyInserters.java:391)

我通过使用 XmlRootElement 进行如下注释来解决此问题

@Getter @Setter @NoArgsConstructor @ToString
@XmlRootElement()
public class MyXmlRequest {
    private String attribute1;
}

在下一次尝试中,我遇到了另一个错误,如下所示

reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/xml' not supported for bodyType=com.example.MyXmlResponse
Caused by: org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/xml' not supported for bodyType=com.example.MyXmlResponse

这可以通过使用 XmlRootElement 注释 MyXmlResponse 来解决,如下所示

@Getter @Setter @NoArgsConstructor @ToString
@XmlRootElement()
public class MyXmlResponse {

    private String attr1;

    private String attr2;
}

这次我得到 unmarshallexception 如下

reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.core.codec.DecodingException: Could not unmarshal XML to class com.example.MyXmlResponse; nested exception is javax.xml.bind.UnmarshalException
 - with linked exception:
[com.sun.istack.internal.SAXParseException2; lineNumber: 1; columnNumber: 15; unexpected element (uri:"", local:"MyXmlResponse"). Expected elements are <{}myXmlResponse>]
Caused by: org.springframework.core.codec.DecodingException: Could not unmarshal XML to class com.example.MyXmlResponse; nested exception is javax.xml.bind.UnmarshalException
 - with linked exception:

我使用传递给注释的附加属性来修复它,如下所示。

@XmlRootElement(name = "MyXmlResponse", namespace = "")
public class MyXmlResponse {

将来,我的 XML 结构将变得非常复杂。我想知道我的做法是否正确。

标签: spring-bootjaxbspring-webfluxspring-webclientjackson-dataformat-xml

解决方案


推荐阅读