web-dev-qa-db-fra.com

Spring 4.x / 3.x (Web MVC) REST API et requêtes JSON2 Post, comment faire les choses une fois pour toutes?

Avant d'entrer dans les détails, je sais qu'il y a eu beaucoup de conversations et de questions connexes sur Stackoverflow. Tous m'aident en quelque sorte de différentes manières, j'ai donc pensé regrouper mes résultats en un seul FAQ pour résumer mes résultats).

Concepts associés

Vous les connaissez sûrement, mais je les écris comme un bref examen. N'hésitez pas à modifier au cas où je manquerais quelque chose.

HTTP POST Requête:

Une demande de publication est utilisée lorsque vous souhaitez envoyer un objet à un service Web ou à une application côté serveur.

Sérialisation:

Processus consistant à transférer l'objet de votre navigateur Web vers votre application côté serveur. Un appel jQuery Ajax ou une demande de publication Curl peut être utilisé.

Protocoles de sérialisation:

Les jours les plus populaires ces jours-ci sont JSON et XML. XML est de moins en moins populaire car les objets xml sérialisés sont de taille relativement plus grande en raison de la nature du balisage XML. Dans ce FAQ l'objectif principal est JSON2 la sérialisation.

Printemps:

Le framework Spring et sa puissante annotation permettent d'exposer le service web de manière efficace. Il existe de nombreuses bibliothèques différentes au printemps. Celui qui est notre objectif ici est Spring web MVC .

Curl vs JQuery:

Ce sont les outils que vous pouvez utiliser pour faire une demande de publication dans votre côté client. Même si vous prévoyez d'utiliser l'appel ajQuery JQuery, je vous suggère d'utiliser Curl à des fins de débogage car il vous fournit une réponse détaillée après avoir effectué la demande de publication.

@RequestBody vs @ RequestParam/@ PathVariable vs @ModelAttribute:

Dans les cas où vous disposez d'un service Web qui ne dépend pas de votre Java EE, @RequestBody doit être utilisé. Si vous utilisez le modèle et que votre objet JSON est ajouté au modèle, vous peut accéder à l'objet via @ModelAttribute. Uniquement pour les cas où votre demande est soit une demande GET soit une combinaison GET et POST combinaison de demandes, vous devrez utiliser @ RequestParam/@ PathVariable.

@RequestBody vs @ResposeBody:

Comme vous pouvez le voir sur le nom, c'est aussi simple que cela, vous n'avez besoin de @ResponseBody que si vous envoyez une réponse au client après que la méthode côté serveur a traité la demande.

RequestMappingHandlerAdapter vs AnnotationMethodHandlerAdapter:

RequestMappingHandlerAdapter est le nouveau gestionnaire de mappage pour le framework Spring qui a remplacé AnnotationMethodHandlerAdapter depuis Spring 3.1. Si votre configuration existante est toujours dans AnnotationMethodHandlerAdapter, vous pourriez trouver ce message utile. La configuration fournie dans mon article vous donnera une idée de la façon de configurer le RequestMappingHandlerAdapter.

Installer

Vous devrez configurer un convertisseur de messages. C'est ainsi que votre corps de message JSON sérialisé est converti en un objet local Java côté serveur).

Configuration de base de ici . Les convertisseurs étaient MarshallingHttpMessageConverter et CastorMarshaller dans l'exemple exemple de configuration de base , je les ai remplacés par MappingJackson2HttpMessageConverter et MappingJacksonHttpMessageConverter.

Où mettre la configuration

La façon dont mon projet est mis en place, j'ai deux fichiers de configuration:

  • XML de contexte d'application: un fichier XML de contexte d'application où se trouvent votre bean sessionFactory, bean dataSource, etc.
  • MVC Dispatcher Servlet XML: c'est là que vous avez votre bean de résolution de vues et importez le XML de votre contexte d'application.

le bean hadlerAdapter doit être situé dans la dernière version du fichier XML MVC Dispatcher.

<bean name="handlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
    <property name="messageConverters">
        <list>
            <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
            <ref bean="jsonConverter"/>

        </list>

    </property>
    <property name="requireSession" value="false"/>

</bean>
<bean id="jsonConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
    <property name="supportedMediaTypes" value="application/json"/>
</bean>

Vous pouvez avoir plusieurs convertisseurs de messages. ici, j'ai créé un JSON normal ainsi qu'un convertisseur de message JSON 2. Le format Ref et le bean normal dans le fichier XML ont tous deux été utilisés (personnellement, je préfère la balise ref comme plus nette).

API REST

Voici un exemple de contrôleur qui expose l'API REST.

Le controlle

C'est là que votre API REST pour une demande de publication HTTP est exposée.

@Component
@Controller
@RequestMapping("/api/user")
public class UserController {
@RequestMapping(value = "/add", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public String insertUser(@RequestBody final User user) {
    System.out.println(user.toString());
    userService.insertUser(user);
    String userAdded = "User-> {" + user.toString() + "} is added";
    System.out.println(userAdded);
        return userAdded;
    }
}

L'objet Java

@JsonAutoDetect
public class User {

private int id;
private String username;
private String name;
private String lastName;
private String email;

public int getId() {
    return externalId;
}

public void setId(final int id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(final String name) {
    this.name = name;
}

public String getEmail() {
    return email;
}

public void setEmail(final String email) {
    this.email = email;
}
public String getUsername() {
    return username;
}

public void setUsername(final String username) {
    this.username = username;
}

public String getLastName() {
    return lastName;
}

public void setLastName(final String lastName) {
    this.lastName = lastName;
}

@Override
public String toString() {
    return this.getName() + " | " + this.getLastName()  + " | " + this.getEmail()
            + " | " + this.getUsername()  + " | " + this.getId()  + " | ";
    }

}

CURL Post call

curl -i -H "Content-Type: application/json" -X POST -d '{"id":100,"username":"JohnBlog","name":"John","lastName":"Blog","email":"[email protected]"}' http://localhost:8080/[YOURWEBAPP]/api/user/add

Articles et questions connexes

Ceci FAQ n'était pas possible si ce n'était pas pour toutes les personnes qui ont fourni les messages et questions suivants (cette liste se développera si je rencontre des messages/questions utiles)):

  1. Quel est le type de contenu JSON correct ?
  2. Spring 3.0 faisant une réponse JSON en utilisant le convertisseur de messages jackson
  3. Comment POST données JSON avec Curl du terminal/ligne de commande pour tester Spring REST?
  4. Publication de JSON sur REST API
  5. https: //github.com/geowarin/spring-mvc-examples
  6. Comment publier JSON sur PHP avec curl
  7. Spring REST | MappingJacksonHttpMessageConverter produit un JSON invalide
  8. https: //github.com/eugenp/REST
  9. Spring Web MVC - valider les paramètres de requête individuels
  10. Comment POST données JSON avec Curl du terminal/ligne de commande pour tester Spring REST?
  11. Comment renvoyer un objet JSON à partir d'un Java Servlet
  12. Quel type MIME si JSON est retourné par une REST?
42
AmirHd

CURL Post call

curl -i -H "Content-Type: application/json" -X POST -d '{"id":100,"username":"JohnBlog","name":"John","lastName":"Blog","email":"[email protected]"}' http://localhost:8080/[YOURWEBAPP]/api/user/add

Différents scénarios d'erreur:

Ici, j'explore différentes erreurs que vous pourriez rencontrer après avoir effectué un appel curl et ce qui pourrait avoir mal tourné.

Scénario un:

HTTP/1.1 404 Not Found
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 949
Date: Tue, 04 Jun 2013 02:59:35 GMT

Cela implique que l'API REST n'existe pas dans l'URL que vous avez fournie.

  • Vous pourriez avoir une faute de frappe dans votre demande (croyez-moi, cela peut arriver)!
  • Il se peut que votre configuration de ressort ne soit pas correcte. Si tel est le cas, il faut approfondir ce qui s'est réellement passé, mais j'ai fourni quelques actions initiales que vous devez faire avant de commencer votre enquête plus sophistiquée.

Après vous être assuré que tout est parfaitement bien fait et que rien ne va mal avec votre configuration ni votre URL: - Exécutez un maven clean. - Annulez le déploiement de votre application Web ou supprimez-la simplement. - Redéployez l'application web - Assurez-vous d'utiliser une seule version de Spring dans votre maven/gradle

Scénario deux:

HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 968
Date: Tue, 04 Jun 2013 03:08:05 GMT
Connection: close

La seule raison derrière cela est le fait que votre demande n'est pas formatée correctement. Si vous extrayez la réponse détaillée de curl, vous devriez pouvoir voir "La demande envoyée par le client était syntaxiquement incorrecte.".

Soit votre format JSON n'est pas correct, soit il vous manque un paramètre obligatoire pour l'objet Java.

Assurez-vous de fournir l'objet JSON au format correct et avec le bon nombre de paramètres. Les propriétés Nullable ne sont pas obligatoires mais vous devez fournir des données pour toutes les propriétés NotNullable. Il est TRÈS important de se rappeler que Spring utilise Java réflexion pour transformer votre fichier JSON en Java objets, qu'est-ce que cela signifie? Cela signifie que la variable et la méthode les noms sont CasE SensItiVe. Si votre fichier JSON envoie la variable "userName", alors votre variable correspondante dans votre Java objet DOIT également être nommé "userName". Si vous avez des getters et setters, ils doivent également suivre la même règle. getUserName et setUserName pour correspondre à notre exemple précédent.

Senario Three:

HTTP/1.1 415 Unsupported Media Type
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Length: 1051
Date: Wed, 24 Aug 2011 08:50:17 GMT

Le type de support Json n'est pas pris en charge par votre service Web. Cela peut être dû au fait que votre annotation ne spécifie pas le type de média ou que vous ne spécifiez pas le type de média dans la commande Curl post.

Vérifiez que votre convertisseur de messages est correctement configuré et assurez-vous que l'annotation du service Web correspond à l'exemple ci-dessus. Si cela était correct, assurez-vous de spécifier le type de contenu dans votre demande de publication Curl.

Le type de support json n'est pas pris en charge par votre service Web.

Senario N (!):

HTTP/1.1 200 OK 
Server: Apache-Coyote/1.1 
Content-Type: application/json;charset=UTF-8 
Transfer-Encoding: chunked 
Date: Tue, 04 Jun 2013 03:06:16 GMT 

Félicitations, l'utilisateur est réellement envoyé à votre serveur REST.

Pour plus de détails sur la configuration de votre commande de printemps, consultez le guide Spring MVC.

Articles et questions connexes

Ceci FAQ n'était pas possible si ce n'était pas pour toutes les personnes qui ont fourni les messages et questions suivants (cette liste se développera si je rencontre des messages/questions utiles)):

  1. Quel est le type de contenu JSON correct ?
  2. Spring 3.0 faisant une réponse JSON en utilisant le convertisseur de messages jackson
  3. Comment POST données JSON avec Curl du terminal/ligne de commande pour tester Spring REST?
  4. Publication de JSON sur REST API
  5. https: //github.com/geowarin/spring-mvc-examples
  6. Comment publier JSON sur PHP avec curl
  7. Spring REST | MappingJacksonHttpMessageConverter produit un JSON invalide
  8. https: //github.com/eugenp/REST
  9. Spring Web MVC - valider les paramètres de requête individuels
  10. Comment POST données JSON avec Curl du terminal/ligne de commande pour tester Spring REST?
  11. Comment renvoyer un objet JSON à partir d'un Java Servlet
  12. Quel type MIME si JSON est retourné par une REST?
11
AmirHd

Cela devrait être bon de remarquer qu'une classe de bean peut PAS être gérée si elle a 2 ou plus setter pour un champ sans @JsonIgnore sur les options. Spring/Jackson throw HttpMediaTypeNotSupportedException et statut http 415 Type de support non pris en charge.

Exemple:

@JsonGetter
public String getStatus() {
    return this.status;
}

@JsonSetter
public void setStatus(String status) {
    this.status = status;
}

@JsonIgnore
public void setStatus(StatusEnum status) {
    if (status == null) {
        throw new NullPointerException();
    }

    this.status = status.toString();
}

pdate: Nous devons également spécifier @JsonGetter et @JsonSetter dans ce cas, ne pas avoir de problèmes lorsqu'il est utilisé comme type de retour.

Je viens de le tester avec Spring 3.2.2 et Jackson 2.2. Cela fonctionne très bien comme paramètre (@RequestBody) et/ou comme type de retour (@ResponseBody).

Mise à jour 2:

Si @JsonGetter et @JsonSetter sont spécifiés, @JsonIgnore ne semble pas nécessaire.

1