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 作为响应的主要内容,如果未能解决你的问题,请参考以下文章