Як працює анотація Spring @ResponseBody?


89

У мене є метод, який анотований наступним чином:

/**
* 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-адресою / замовленнями .

Цей метод викликає об'єкт DAO, який повертає List .

де Обліковий запис представляє користувача в системі і має деякі поля, що представляють цього користувача, приблизно так:

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 (замість подання MVC).

А також читання офіційної весняної документації: 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анотація, чи він вказаний деінде?

Відповіді:


160

Перш за все, анотація не коментує 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 буде повернено.


3
привіт, як нам налаштувати "встановлені перетворювачі повідомлень"? Я хочу, щоб за замовчуванням завжди перетворювався на Json. Чи можу я це зробити?
Sam YC

@JB Nizet, чи можете ви пояснити, чому відповідь http не може містити об'єкти Java. Я новачок у Java.
Naved Ali

3
@ Er.NavedAli прочитав специфікацію http, тип вмісту відповіді http визначає юридичний вміст, який може містити відповідь http. законними значеннями для цього можуть бути "application / octet-stream", "image / jpeg", "text / HTML", але об'єкти Java для них не є юридичним значенням.
ZhaoGang,

@ZhaoGang, тип вмісту 'application / json' у моєму тестовому випадку було замінено на 'application / xml', але тіло відповіді, здається, не змінилось, формат JSON все ще присутній.
LeafiWan

1
де саме, я маю на увазі, в якому весняному класі приймається рішення про те, як повернути відповідь? Чи можете ви вказати мені джерело на github, де прийнято це рішення або назву класу? Також що станеться, якщо клієнт прийме XML, але не встановлений перетворювач XML?
anir

65

Перше, що потрібно зрозуміти, це різниця в архітектурі.

В одному кінці у вас є архітектура MVC, яка базується на вашому звичайному веб-додатку, використовуючи веб-сторінки, і браузер робить запит на сторінку:

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

Браузер робить запит, контролер (@Controller) отримує модель (@Entity) і створює подання (JSP) з моделі, і подання повертається назад клієнту. Це основна архітектура веб-додатків.

З іншого боку, у вас є архітектура RESTful. У цьому випадку немає Погляду. Контролер відправляє назад лише модель (або подання ресурсу, більш вираженими умовами). Клієнтом може бути додаток JavaScript, додаток сервера Java, будь-який додаток, в якому ми піддаємо наш REST API. За допомогою цієї архітектури клієнт вирішує, що робити з цією моделлю. Візьмемо, наприклад, Twitter. Twitter як веб-інтерфейс (REST), що дозволяє нашим програмам використовувати його API для отримання таких речей, як оновлення стану, щоб ми могли використовувати його для розміщення цих даних у нашому додатку. Ці дані надходитимуть у форматі JSON.

При цьому, працюючи з Spring MVC, він спочатку був побудований для обробки базової архітектури веб-додатків. Можуть існувати різні ароматизатори підписів методів, які дозволяють отримати подання з наших методів. Метод може повернути aModelAndView де ми його явно створимо, або є неявні способи, коли ми можемо повернути якийсь довільний об'єкт, який встановлюється в атрибути моделі. Але в будь-якому випадку, десь упродовж циклу запиту-відповіді буде створено погляд.

Але коли ми використовуємо @ResponseBody, ми говоримо, що ми не хочемо створювати погляд. Ми просто хочемо надіслати об’єкт повернення як тіло, в якому б форматі ми не вказали. Ми не хотіли б, щоб це був серіалізований об’єкт Java (хоча це можливо). Так що так, його потрібно перетворити на якийсь інший поширений тип (цей тип зазвичай розглядається шляхом узгодження вмісту - див. Посилання нижче). Чесно кажучи, я не надто працюю з Весною, хоча й бавлюся з нею тут і там. Зазвичай я використовую

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

встановити тип вмісту, але, можливо, за замовчуванням використовується JSON. Не цитуйте мене, але якщо ви отримуєте JSON і не вказали produces, можливо, це за замовчуванням. JSON - не єдиний формат. Наприклад, вказане легко може бути відправлений в XML, але ви повинні мати , producesщоб MediaType.APPLICATION_XML_VALUEі я вважаю , що вам потрібно налаштувати HttpMessageConverterдля JAXB. Що стосується MappingJacksonHttpMessageConverterналаштованого JSON , коли у нас є Джексон на шляху до класу.

Я б витратив трохи часу, щоб дізнатись про переговори про вміст . Це дуже важлива частина REST. Це допоможе вам дізнатись про різні формати відповідей та як зіставити їх із вашими методами.


Якщо ви знайшли свою відповідь під час розслідування того, як створити загальний / динамічний контролер REST, без використання @Controller/@RestController. Я виявив, що мені потрібно якось опустити шар роздільника подання. Це не так просто, оскільки клас AbstractController забезпечує метод, який повинен повертати ім'я подання. Я задав запитання щодо цього: stackoverflow.com/questions/41016018/… , якщо у вас є якісь ідеї щодо того, як я можу вирішити свою проблему, залиште коментар.
nowszy94

1

Крім цього, тип повернення визначається за

  1. Те, що вимагає запит HTTP, - в заголовку Accept. Спробуйте подивитися на початковий запит, щоб побачити, для чого встановлено Accept.

  2. Що встановлює HttpMessageConverters Spring. Spring MVC налаштує перетворювачі для XML (з використанням JAXB) та JSON, якщо бібліотеки Джексона знаходяться на шляху до класу.

Якщо є вибір, він вибирає один - у цьому прикладі це буває JSON.

Про це йдеться у примітках до курсу. Шукайте примітки щодо перетворювачів повідомлень та переговорів про вміст.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.