web-dev-qa-db-fra.com

Comment l'annotation Spring @ResponseBody fonctionne-t-elle dans cet exemple d'application RESTful?

J'ai une méthode qui est annotée de la manière suivante:

/**
* 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();
}

Je sais donc que par cette annotation:

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

ce handle de méthode GET Les requêtes HTTP adressées à la ressource représentée par l'URL /orders .

Cette méthode appelle un objet DAO qui renvoie une liste .

Compte représente un utilisateur sur le système et contient des champs qui représentent cet utilisateur, par exemple:

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>();

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

Ma question est la suivante: Comment fonctionne exactement l'annotation @ResponseBody?

Il est situé avant l'objet List<Account> renvoyé, donc je pense qu'il fait référence à cette liste. La documentation du cours indique que cette annotation sert à la fonction:

assurez-vous que le résultat sera écrit dans la réponse HTTP par un convertisseur de message HTTP (au lieu d'une vue MVC).

Et également sur la documentation officielle de Spring: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html

il semble qu'il prenne l'objet List<Account> et le place dans le Http Response. Est-ce correct ou ai-je mal compris?

Dans le commentaire de la méthode accountSummary() précédente, il y a:

Vous devriez obtenir des résultats JSON lorsque vous accédez à http: // localhost: 8080/rest-ws/app/accounts

Alors qu'est-ce que cela signifie exactement? Cela signifie-t-il que l'objet List<Account> renvoyé par la méthode accountSummary() est automatiquement converti au format JSON, puis placé dans le Http Response? Ou quoi?

Si cette assertion est vraie, où est-il spécifié que l'objet sera automatiquement converti au format JSON? Le format standard est-il adopté lorsque l'annotation @ResponseBody est utilisée ou est-il spécifié ailleurs?

80
AndreaNobili

Tout d'abord, l'annotation n'annote pas List. Il annote la méthode, tout comme RequestMapping. Votre code est équivalent à

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

À présent, l'annotation signifie que la valeur renvoyée par la méthode constituera le corps de la réponse HTTP. Bien entendu, une réponse HTTP ne peut pas contenir d'objets Java. Cette liste de comptes est donc transformée dans un format adapté aux applications REST, généralement JSON ou XML.

Le choix du format dépend des convertisseurs de messages installés, des valeurs de l'attribut produces de l'annotation RequestMapping et du type de contenu accepté par le client (disponible dans les en-têtes de la requête HTTP). . Par exemple, si la demande indique qu'elle accepte XML, mais pas JSON, et qu'un convertisseur de message est installé pour transformer la liste en XML, XML est alors renvoyé.

136
JB Nizet

La première chose à comprendre est la différence d'architectures.

À une extrémité, vous avez l'architecture MVC, basée sur votre application Web normale, utilisant des pages Web, et le navigateur demande une page:

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

Le navigateur émet une requête, le contrôleur (@Controller) obtient le modèle (@Entity), crée la vue (JSP) à partir du modèle et la vue est renvoyée au client. C'est l'architecture de base de l'application Web.

De l'autre côté, vous avez une architecture RESTful. Dans ce cas, il n'y a pas de vue. Le contrôleur renvoie uniquement le modèle (ou la représentation des ressources, en termes plus RESTful). Le client peut être une application JavaScript, une application serveur Java, toute application dans laquelle nous exposons notre API REST. Avec cette architecture, le client décide quoi faire avec ce modèle. Prenons par exemple Twitter. Twitter en tant qu'API Web (REST), qui permet à nos applications d'utiliser son API pour obtenir des informations telles que les mises à jour de statut, afin que nous puissions l'utiliser pour mettre ces données dans notre application. Ces données viendront dans un format tel que JSON.

Cela étant dit, lorsque Spring MVC était utilisé, il avait été conçu pour gérer l’architecture des applications Web de base. Il existe plusieurs types de signature de méthode permettant de produire une vue à partir de nos méthodes. La méthode peut retourner un ModelAndView où nous le créons explicitement, ou il existe des moyens implicites de retourner un objet arbitraire qui est défini dans les attributs du modèle. Mais de toute façon, quelque part dans le cycle demande-réponse, une vue sera produite.

Mais lorsque nous utilisons @ResponseBody, nous disons que nous ne voulons pas qu'une vue soit produite. Nous voulons simplement envoyer l'objet de retour comme corps, dans le format que nous spécifions. Nous ne voudrions pas que ce soit un objet Java sérialisé (bien que possible). Donc, oui, il doit être converti en un autre type courant (ce type est normalement traité par la négociation de contenu - voir le lien ci-dessous). Honnêtement, je ne travaille pas beaucoup avec le printemps, bien que je le touche ici et là. Normalement, j'utilise

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

pour définir le type de contenu, mais peut-être que JSON est la valeur par défaut. Ne me citez pas, mais si vous obtenez du JSON et que vous n'avez pas spécifié le produces, alors c'est peut-être la valeur par défaut. JSON n'est pas le seul format. Par exemple, ce qui précède pourrait facilement être envoyé en XML, mais vous auriez besoin du produces à MediaType.APPLICATION_XML_VALUE et je pense que vous devez configurer le HttpMessageConverter pour JAXB. En ce qui concerne le JSON MappingJacksonHttpMessageConverter configuré, nous avons Jackson sur le classpath.

Je prendrais un peu de temps pour en apprendre davantage sur négociation de conten . C'est une partie très importante de REST. Cela vous aidera à connaître les différents formats de réponse et à les adapter à vos méthodes.

52
Paul Samsotha

Comme mentionné par JB Nizet,

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

et

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

les deux sont identiques. as @ResponseBody annote la méthode et non la liste. @GMsoF - Les convertisseurs de messages installés ici peuvent être utilisés comme suit.

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

Merci :)

4
Nupur

De plus, le type de retour est déterminé par

  1. Ce que la requête HTTP dit vouloir - dans son en-tête Accept. Essayez de regarder la requête initiale pour voir ce que Accept est défini sur.

  2. Ce que printemps HttpMessageConverters met en place. Spring MVC installera les convertisseurs pour XML (avec JAXB) et JSON si les bibliothèques de Jackson sont sur le chemin de classe.

S'il y a un choix, il en choisit un - dans cet exemple, il s'agit du format JSON.

Ceci est couvert dans les notes de cours. Recherchez les notes sur les convertisseurs de messages et la négociation de contenu.

1
paulchapman