Spring @ResponseBody 注释是如何工作的?

How does the Spring @ResponseBody annotation work?

我有一个方法,注释如下:

/**
* Provide a list of all accounts.
*/
//  TODO 02: Complete this method.  Add annotations to respond
//  to GET /accounts and return a List<Account> to be converted.
//  Save your work and restart the server.  You should get JSON results when accessing 
//  http://localhost:8080/rest-ws/app/accounts
@RequestMapping(value="/orders", method=RequestMethod.GET)
public @ResponseBody List<Account> accountSummary() {
    return accountManager.getAllAccounts();
}

所以我通过这个注释知道:

@RequestMapping(value="/orders", method=RequestMethod.GET)

此方法处理对由 URL /orders.[=28= 表示的资源发出的 GET HTTP 请求]

此方法调用 returns 一个 List.

的 DAO 对象

其中 Account 代表系统上的用户,并且有一些字段代表该用户,例如:

public class Account {

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long entityId;

    @Column(name = "NUMBER")
    private String number;

    @Column(name = "NAME")
    private String name;

    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name = "ACCOUNT_ID")
    private Set<Beneficiary> beneficiaries = new HashSet<Beneficiary>();

    ...............................
    ...............................
    ...............................
}

我的问题是:@ResponseBody 注释究竟是如何工作的?

它位于返回的 List<Account> 对象之前,所以我认为它指的是这个列表。课程文档指出此注释的作用是:

ensure that the result will be written to the HTTP response by an HTTP Message Converter (instead of an MVC View).

同时阅读官方 Spring 文档:http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html

它似乎把 List<Account> 对象放到了 Http Response 中。这是正确的还是我误解了?

前面accountSummary()方法的注释里写的是:

You should get JSON results when accessing http://localhost:8080/rest-ws/app/accounts

那么这到底是什么意思呢?是不是说accountSummary()方法返回的List<Account>对象会自动转成JSON格式,然后放入Http Response?或者什么?

如果这个断言是真的,那么在哪里指定对象会自动转换成JSON格式?使用@ResponseBody注解时是采用标准格式还是在别处指定?

首先要了解的是体系结构的差异。

一方面你有 MVC 架构,它基于你的普通网络应用程序,使用网页,浏览器发出页面请求:

Browser <---> Controller <---> Model
               |      |
               +-View-+

浏览器发出请求,控制器 (@Controller) 获取模型 (@Entity),并从模型创建视图 (JSP),视图被 return 返回给客户。这是基本的 Web 应用架构。

在另一端,您有一个 RESTful 架构。在这种情况下,没有视图。控制器仅发回模型(或资源表示,更多 RESTful 术语)。客户端可以是 JavaScript 应用程序,Java 服务器应用程序,我们向其中公开 REST API 的任何应用程序。有了这个架构,客户决定如何处理这个模型。以推特为例。 Twitter 作为 Web (REST) API,它允许我们的应用程序使用它 API 来获取诸如状态更新之类的东西,这样我们就可以使用它来将这些数据放入我们的应用程序中。该数据将以某种格式出现,例如 JSON.

也就是说,在使用 Spring MVC 时,它最初是为处理基本的 Web 应用程序架构而构建的。可能有不同的方法签名风格允许从我们的方法中生成视图。该方法可以 return 一个 ModelAndView 我们明确创建它的地方,或者有隐含的方式我们可以 return 一些任意对象被设置到模型属性中。但无论哪种方式,在请求-响应周期的某处,都会产生一个视图。

但是当我们使用 @ResponseBody 时,我们是在说我们不希望生成视图。我们只想以我们指定的任何格式将 return 对象作为正文发送。我们不希望它成为序列化的 Java 对象(尽管可能)。所以是的,它需要转换为其他一些常见类型(这种类型通常通过内容协商处理 - 请参阅下面的 link)。老实说,我对 Spring 的工作不多,尽管我时不时地涉猎一下。通常,我使用

@RequestMapping(..., produces = MediaType.APPLICATION_JSON_VALUE)

设置内容类型,但可能 JSON 是默认值。不要引用我的话,但是如果您得到 JSON,并且您没有指定 produces,那么它可能是默认值。 JSON 不是唯一的格式。例如,上面的内容可以很容易地在 XML 中发送,但是您需要 producesMediaType.APPLICATION_XML_VALUE,我相信您需要为 JAXB 配置 HttpMessageConverter。至于 JSON MappingJacksonHttpMessageConverter 配置,当我们在类路径上有 Jackson 时。

我会花一些时间来了解 Content Negotiation。它是 REST 的一个非常重要的部分。它将帮助您了解不同的响应格式以及如何将它们映射到您的方法。

首先,注解不注解List。它注释方法,就像 RequestMapping 一样。您的代码相当于

@RequestMapping(value="/orders", method=RequestMethod.GET)
@ResponseBody
public List<Account> accountSummary() {
    return accountManager.getAllAccounts();
}

现在注释的意思是方法的返回值将构成 HTTP 响应的 body。当然,HTTP 响应不能包含 Java objects。因此,这个帐户列表被转换为适合 REST 应用程序的格式,通常是 JSON 或 XML.

格式的选择取决于安装的消息转换器、@RequestMapping 注释的 produces attribute 的值以及客户端接受的内容类型(可在HTTP 请求 headers)。例如,如果请求说它接受 XML,但不接受 JSON,并且安装了可以将列表转换为 XML 的消息转换器,那么 XML 将是返回。

此外,return 类型由

决定
  1. HTTP 请求在其接受 header 中表达了它想要的内容。尝试查看初始请求,看看 Accept 设置了什么。

  2. 什么 HttpMessageConverters Spring 设置。 Spring MVC 将为 XML(使用 JAXB)和 JSON 设置转换器(如果 Jackson 库在类路径中)。

如果有选择,它会选择一个 - 在这个例子中,它恰好是 JSON。

包含在课程笔记中。查找有关消息转换器和内容协商的说明。

@RequestBody 注释将 HTTPRequest 主体绑定到域对象。 Spring 使用 HttpMessageConverters 自动将传入的 HTTP 请求反序列化为对象。 HttpMessageConverter 转换请求主体以根据请求的内容类型解析方法参数。 许多示例如何使用转换器 https://upcodein.com/search/jc/mg/ResponseBody/page/0