Как работает аннотация Spring @ResponseBody в этом примере приложения RESTful?

У меня есть метод, который аннотируется следующим образом:

/**
* 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)

этот метод обрабатывает GET HTTP-запросы, сделанные для ресурса, представленного URL-адресом /orders.

Этот метод вызывает объект DAO, который возвращает Список.

где Аккаунт представляет пользователя в системе и имеет некоторые поля, которые представляют этого пользователя, например:

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>, поэтому я думаю, что он относится к этому списку. В документации к курсу указано, что эта аннотация обслуживает функцию:

убедитесь, что результат будет записан в HTTP-ответ HTTP Message Converter (вместо MVC View).

А также чтение официальной документации Spring: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html

кажется, что он принимает объект List<Account> и помещает его в Http Response. Это правильно или я не понимаю?

Написано в комментарии предыдущего метода accountSummary():

Вы должны получить результаты JSON при доступе http://localhost:8080/rest-ws/app/accounts

Так что же это значит? Означает ли это, что объект List<Account>, возвращаемый методом accountSummary(), автоматически преобразуется в формат JSON, а затем помещается в Http Response? Или что?

Если это утверждение верно, где указано, что объект будет автоматически преобразован в формат JSON? Является ли стандартный формат принятым при использовании аннотации @ResponseBody или указан в другом месте?

Ответ 1

Прежде всего, аннотация не аннотирует List. Он аннотирует метод, как это делает RequestMapping. Ваш код эквивалентен

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

Теперь, что означает аннотация, это то, что возвращаемое значение метода будет представлять собой тело ответа HTTP. Конечно, HTTP-ответ не может содержать объекты Java. Таким образом, этот список учетных записей преобразуется в формат, подходящий для приложений REST, обычно JSON или XML.

Выбор формата зависит от установленных преобразователей сообщений, от значений атрибута produces аннотации RequestMapping и от типа содержимого, который клиент принимает (который доступен в заголовках HTTP-запроса). Например, если запрос говорит, что он принимает XML, но не JSON, и есть установленный конвертер сообщений, который может преобразовать список в XML, тогда будет возвращен XML.

Ответ 2

Первое, что нужно понять, это различие в архитектуре.

На одном конце у вас есть MVC-архитектура, основанная на вашем обычном веб-приложении, с использованием веб-страниц, и браузер делает запрос на страницу:

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

Браузер делает запрос, контроллер (@Controller) получает модель (@Entity) и создает представление (JSP) из модели, и представление возвращается клиенту. Это основная архитектура веб-приложений.

С другой стороны, у вас есть архитектура RESTful. В этом случае View отсутствует. Контроллер отправляет обратно модель (или представление ресурса, в более RESTful условиях). Клиентом может быть приложение JavaScript, приложение сервера Java, любое приложение, в котором мы предоставляем наш REST API. С этой архитектурой клиент решает, что делать с этой моделью. Возьмите, например, Twitter. Twitter как API (REST), который позволяет нашим приложениям использовать свой API для получения таких вещей, как обновления статуса, чтобы мы могли использовать его для размещения этих данных в нашем приложении. Эти данные появятся в некотором формате, таком как JSON.

При этом при работе с Spring MVC он был впервые создан для обработки базовой архитектуры веб-приложений. Существуют различные отличия в методах, которые позволяют получать представление из наших методов. Метод может возвращать ModelAndView, где мы явно его создаем, или существуют неявные способы возврата некоторого произвольного объекта, который устанавливается в атрибуты модели. Но в любом случае, где-то вдоль цикла запроса-ответа, будет отображаться представление.

Но когда мы используем @ResponseBody, мы говорим, что мы не хотим, чтобы появилось представление. Мы просто хотим отправить возвращаемый объект как тело, в любом формате, который мы укажем. Мы бы не хотели, чтобы это был сериализованный объект Java (хотя это возможно). Так что да, его нужно преобразовать в какой-то другой общий тип (этот тип обычно обрабатывается путем согласования контента - см. Ссылку ниже). Честно говоря, я не очень много работаю с Spring, хотя я тут же спорю с ним. Обычно я использую

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

чтобы установить тип содержимого, но, возможно, JSON является значением по умолчанию. Не цитируйте меня, но если вы получаете JSON, и вы не указали produces, то, возможно, это значение по умолчанию. JSON - не единственный формат. Например, вышеупомянутое может быть легко отправлено в XML, но вам нужно иметь produces до MediaType.APPLICATION_XML_VALUE, и я считаю, что вам нужно настроить HttpMessageConverter для JAXB. Что касается настройки JSON MappingJacksonHttpMessageConverter, когда у нас есть Jackson на пути к классам.

Мне потребуется некоторое время, чтобы узнать о Консолидация контента. Это очень важная часть REST. Это поможет вам узнать о различных форматах ответов и о том, как их сопоставить с вашими методами.

Ответ 3

Как упоминалось JB Nizet,

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

и

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

оба одинаковы. поскольку @ResponseBody аннотирует метод, а не список. @GMsoF -Установленные преобразователи сообщений здесь можно использовать следующим образом.

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

Спасибо:)

Ответ 4

В дополнение к этому тип возврата определяется

  • Что запрашивает HTTP-запрос - в заголовке Accept. Попробуйте просмотреть первоначальный запрос, чтобы узнать, для чего установлен Accept.

  • Настройка HttpMessageConverters Spring. Spring MVC будет устанавливать преобразователи для XML (используя JAXB) и JSON, если библиотеки Jackson находятся на пути к нему.

Если есть выбор, он выбирает один - в этом примере это JSON.

Это описано в примечаниях к курсу. Найдите заметки о конвертерах сообщений и контенте контента.