Friday, July 16, 2010

Spring 3 et Rest

C'est seulement depuis la version 3.0 de Spring que le MVC supporte les services Rest. Biensur, le framework intègre les principales implémentations tel Jersey ou Restlet, mais dans la partie concernant les web services. La décision d'ajouter une implémentation Rest dans Spring MVC vient de l'orientation prise par le framework:

  • les méthodes des contrôleurs fournissent des vues en résultat
  • des annotations trés similaires à celles de Rest permettent:
    • le binding d'une URL vers un contrôleur
    • le binding des paramétres vers les arguments des méthodes d'un contrôleur

Configurer l'application web

Pour commencer, il faut déclarer le DispatcherServlet dans le fichier de configuration de l'application web: web.xml.

<web-app>

<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/app-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>

</web-app>

En lui spécifiant le paramètre contextConfigLocation, la servlet va charger le context Spring a sa création. Le fichier de context se trouve: /WEB-INF/spring. La servlet doit mapper toutes les URLs du type:

<app_context>/services/*

Configuration Spring

La configuration Spring se fait en deux fichiers différents:

  • le context principal, le fichier app-config.xml, qui contient la configuration du backend: DAO, services et mappers.
  • le context MVC, dans le fichier mvc-config.xml, qui contient la configuration... du MVC.
<beans xmlns="<a class="external free" title="http://www.springframework.org/schema/beans" rel="nofollow" href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</a>"
xmlns:xsi="<a class="external free" title="http://www.w3.org/2001/XMLSchema-instance" rel="nofollow" href="http://www.w3.org/2001/XMLSchema-instance">http://www.w3.org/2001/XMLSchema-instance</a>"
xmlns:mvc="<a class="external free" title="http://www.springframework.org/schema/mvc" rel="nofollow" href="http://www.springframework.org/schema/mvc">http://www.springframework.org/schema/mvc</a>"
xsi:schemaLocation="
<a class="external free" title="http://www.springframework.org/schema/beans" rel="nofollow" href="http://www.springframework.org/schema/beans">http://www.springframework.org/schema/beans</a>
<a class="external free" title="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" rel="nofollow" href="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">http://www.springframework.org/schema/beans/spring-beans-3.0.xsd</a>
<a class="external free" title="http://www.springframework.org/schema/mvc" rel="nofollow" href="http://www.springframework.org/schema/mvc">http://www.springframework.org/schema/mvc</a>
<a class="external free" title="http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd" rel="nofollow" href="http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd</a>">

<mvc:annotation-driven />

</beans>

Cette configuration permet d'utiliser l'annotation @Controller pour déclarer les beans gérés par Spring MVC.

Implémentation d'un contrôleur

L'exemple suivant se base sur la gestion d'objets SampleBean:

public class SampleBean {

private String name;
private long id;
}

Et utilise le SampleController pour effectuer une recherche par id sur les SampleBean.

@Controller
@RequestMapping("/sample")
public class SampleController {

@RequestMapping(value="{id}", method=RequestMethod.GET)
public @ResponseBody SampleBean get(@PathVariable long id) {
return persistence.get(id);
}
}
  1. L'annotation @RequestMapping("/sample") sur la classe permet de mapper toutes les requêtes du type /services/sample sur ce contrôleur. /services étant l'URL sur lequel le DispatcherServlet est mappé.
  2. L'annotation @RequestMapping(value="{id}", method=RequestMethod.GET) sur la méthode get spécifie cette méthode sera appelé pour toutes les URL pouvant mapper avec /services/sample/4 pour les requêtes dont la méthode est GET.
  3. L'annotation @PathVariable permet de spécifier que l'une des valeurs ente {} de l'URL doit être mapper sur cette variable.
  4. @ResponseBody permet de déclarer que la valeur de retour de la méthode sera renvoyer dans le corps de la réponse. Reste à le convertir dans un format quelconque.

Mapper le résultat vers un format spécifique

Pour mettre en place la convertion, il faut configurer un bean de type ContentNegotiatingViewResolver. En Rest, l'opération de mapping des valeurs de retour et des paramètres vers des objets s'appel: négociation. La négociation se fait en ce basant sur la valeur du header Accept de la requête. Pour cet exemple, le mapping se fera vers du JSon. le header Accept aura donc pour valeur: application/json. Spring fournit parmis ces dépendances, le parseur Jackson, qui est utiliser dans ce qui suit:

 <bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver" p:order="1">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>

La configuration se fait en spécifiant les formats supportés avec l'attribut mediaTypes et les implémentations des mappers ave la propriété defaultViews. La propriété mediaTypes correspond au contenu du header Accept de la requête reçu par le DispatcherServvlet.

No comments:

Post a Comment