Spring Boot REST API 返回 XML 作为响应

Posted

技术标签:

【中文标题】Spring Boot REST API 返回 XML 作为响应【英文标题】:SprintBoot REST API to return XML as response 【发布时间】:2022-01-23 20:19:04 【问题描述】:

我正在学习 SpringBoot,并且拥有能够理解传入 JSON 响应并将 JSON 响应返回给客户端 (POSTMAN) 的这段代码。我正在尝试体验 SpringBoot,并希望将其配置为返回 XML 响应。

@PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces =  MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE )
    public ResponseEntity<Movie> addMovies(@RequestBody Movie movie) 
        service.addToMovies(movie);

        // Return a ResponseEntity instead.
        return new ResponseEntity<Movie>(movie, HttpStatus.OK);

如果我使用值 application/xml 设置 Accept HTTP 标头,我会收到此错误:

Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class io.fireacademy.restapi.restapiaws.models.Movie] with preset Content-Type 'null']

不知道为什么会出现这个错误。另外,为什么它说,已解决? 我查看了现有的线程,发现我的 pom.xml 已经有条目:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
</dependency>

我的 SpringBoot 控制器类代码:

package io.fireacademy.restapi.restapiaws.controllers;

import io.fireacademy.restapi.restapiaws.models.Movie;
import io.fireacademy.restapi.restapiaws.services.MovieRecommendationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/movies")
public class RestAPIController 

    @Autowired
    private MovieRecommendationService service;

    // When to return a ResponseEntity
    // Read https://***.com/questions/49673660/return-responseentity-vs-returning-pojo

    @GetMapping
    public List<Movie> getMovies() 
        return service.getMovies();
    

    // Learning: The annotation @PathVariable is needed to inject the value in the URL onto the variable.
    @GetMapping(path="/movieId")
    public ResponseEntity<Movie> getMovieById(@PathVariable String movieId) 
        return new ResponseEntity<Movie>(service.getMovie(Integer.parseInt(movieId)), HttpStatus.OK);
    

    // TODO: Why is a List<Movie> failing in POST API and not in GET API
    // TODO: What is the use of produces/consumes
    // Learning: The client need to set Content-Type HTTP header set so that the server can understand how to process the body data.
    @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces =  MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE )
    public ResponseEntity<Movie> addMovies(@RequestBody Movie movie) 
        service.addToMovies(movie);

        // Return a ResponseEntity instead.
        return new ResponseEntity<Movie>(movie, HttpStatus.OK);
    

    @PutMapping(path="/movieId")
    public ResponseEntity<Movie> updateMovies(@PathVariable String movieId, @RequestBody Movie movie) 

        // Return a ResponseEntity instead.
        return new ResponseEntity<Movie>(service.updateAMovie(Integer.parseInt(movieId), movie), HttpStatus.OK);
    

    @DeleteMapping(path="/movieId")
    public ResponseEntity<Movie> deleteMovies(@PathVariable String movieId) 

        // Return a ResponseEntity instead.
        return new ResponseEntity<Movie>(service.removeAMovie(Integer.parseInt(movieId)), HttpStatus.OK);
    

    // TODO: Integrate this onto a javascript code

我也更新了消费者。还是一样的结果。

@PostMapping(consumes =  MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE , produces =  MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE )

请给我任何线索。

【问题讨论】:

【参考方案1】:
    使用杰克逊 Spring MVC 默认使用 Jackson 库来处理 JSON 响应。当我们将 Jackson 扩展 jackson-dataformat-xml 添加到类路径时,Spring MVC 会自动选择它并用于 XML 响应。
<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>
    使用 JAXB 如果 Jackson XML 扩展在类路径中不可用,Spring MVC 将使用 JAXB 进行转换。但是,要使其正常工作,我们必须使用 @XmlRootElement 注释来注释我们的响应对象。
@XmlRootElement
public class CommentDTO 
    private String id;

返回 JSON 和 XML 有时我们希望在相同的端点和方法实现上支持 JSON 和 XML 响应。为此,我们只需要在产品参数中添加第二个 MediaType,例如:

@RequestMapping(value = "/id", produces =  MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE  )
public CommentDTO getComment(@PathVariable(value = "id") String commentId) throws IOException 
    return service.get(commentId);

现在客户端必须在 Accept 标头中发送它想要接收的内容类型。

Accept: application/xml

如果客户端没有发送 Accept 头,Spring MVC 将回退到配置的默认内容类型。你可以改变它:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter 
  @Override
  public void configureContentNegotiation(ContentNegotiationConfigurer configurer) 
    configurer.defaultContentType(MediaType.APPLICATION_XML);
  

【讨论】:

以上是关于Spring Boot REST API 返回 XML 作为响应的主要内容,如果未能解决你的问题,请参考以下文章

无法让spring boot hibernate rest api返回一对多关系

如何使用 Spring Boot 应用程序从 Rest API 返回 html

Spring Boot Rest API 返回与 Lombok 一起使用的空 JSON

如何在 Spring Boot Rest API 中以 XML 形式返回对象列表

Spring Boot 2 Rest Api Example

如何在 Spring Boot REST API 上设置超时?