Comme le décrit bien ce post, l'un des problèmes qui se pose avec GWT c'est l'utilisation des RPC pour les échanges avec le Serveur. Cette façon de faire complique allègrement le code pour finalement pas grand chose (RPC, RPCAsync, protocole non transparent...).
Le post de Zack Grossbart propose une solution simple, utiliser les mécanismes REST pour communiquer avec les serveurs.
Cela implique cependant deux choses,
REST is everything GWT RPC isn’t: fast, easy to debug, and simple. It also does more.
Cela implique cependant deux choses,
- pouvoir manipuler REST dans GWT et en Java
- implémenter REST pour les communications côté serveur
Sachant qu'un autre critère pour tirer un bénéfice du passage à REST est que cela doit pouvoir se faire sans dupliquer a priori le modèle métier (partage des POJOs entre client et serveur), ce qui est l'une des possibilités natives des RPC GWT (pas de duplications du modèles métier, pas de DTO).
En résumé: Comment remplacer les mécanismes RPC de GWT par des appels REST sans -trop- toucher à mon existant ?
Dans GWT
La façon de faire de RestyGWT est assez intéressante, il suffit en effet de définir un ServiceRest comme ceci pour être ensuite capable de faire des appels via REST :
public interface MyResource extends RestService { @POST public void save(Item item,MethodCallback<Item> callback); @GET public void list(MethodCallback<list<Item>> callback); }
Une fois cette Resource définie, on peut l'appeler n'importe où dans le code client, en faisant par exemple :
final MyResourceservice service= GWT.create(MyResource.class); final Resource resource = new Resource(GWT.getHostPageBaseURL()+"rest/item"); ((RestServiceProxy) service).setResource(resource); service.save(anyItem, new MethodCallback<Item>() { @Override public void onSuccess(Method method, Item response) { doSomethingAjaxly(response); } @Override public void onFailure(Method method, Throwable exception) { doSomethingOnError(); } });
Et voilà, tout est déjà fait, les appels seront transmis au serveur sur l'url http://monserveur.com/rest/item au format Json. RestyGWt propose aussi des APIs REST permettant de manipuler autre chose que du JSON pour la sérialisation, mais dans ce cas, impossible d'utiliser le RestService.
Et sur mon Tomcat alors ?
Du côté du serveur, Jersey permet d'obtenir des resources Rest simplicimes et respectant les standards. Considérons que l'on a déjà configurer Jersey pour démarrer dans le web.xml comme décrit sur le guide utilisateur de jersey, il suffit alors de coder la classe suivante pour obtenir un consommateur/producteur d'objets Json pour notre client GWT.
@Path("/item") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class ItemResource{ @GET @Path("list") public List<Item> list(){ return ...list my items ...; } @POST public Item save(Item item){ return ...save my item... } }
Et si on allait plus loin ? (Et sur mon Cloud alors ?)
A condition d'utiliser un mécanisme de persistance tolérant les annotations JPA, il est possible de faire traverser toutes les couches à nos objets métiers sans effort (couche GWT <=> Servlet <=> JPA).Il est par exemple possible d'utiliser JPA sur l'appengine et ainsi déployer nos ressources REST et notre application GWT sur l'infrastructure de Google. Pour cela, en utilisant Objectify sur notre entité Item, on peut agrémenté la resource ItemResource de la manière suivante :
@Path("/item") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class ItemResource extends DAOBase{ static { ObjectifyService.register(Item.class); } @GET @Path("{id}") public Item get(@PathParam("id") Long id){ try{ //Requête sur le DataStore Google return ofy().get(new Key<Item>(Item.class, id)); }catch(NotFoundException notFoundEx){ throw new WebApplicationException(notFoundEx, Status.NOT_FOUND); } } @GET @Path("list") public List<Item> list(){ //Requête sur le DataStore Google return ofy().query(Item.class).limit(10).order("-id").list(); } @POST public Item save(Item hike){ //Requête sur le DataStore Google final Key<Item> key = ofy().put(hike); hike.setId(key.getId()); return hike; } }
Remarque : Dans notre cas nous avons choisi de ne pas passer par une couche supplémentaire, ce qui nous force à faire étendre DAOBase par ItemResource (qui n'est plus un POJO).
Moralité
Voilà comment en 2/3 classes (et un peu de configuration que je n'ai pas détaillée ici) il est possible de faire communiquer une application Web et un serveur Web sur la base du même modèle métier en se passant de RPC et en se basant sur des standards Java.
Libs
Jersey : https://jersey.dev.java.net/
Jersey Repo : http://download.java.net/maven/2/com/sun/jersey/jersey-archive/
RestyGWT : http://restygwt.fusesource.org/documentation/index.html
Objectify : http://code.google.com/p/objectify-appengine/
Blogs
Hackito Ergo Sum : http://www.zackgrossbart.com/hackito/
GAE4J + JAX-RS : http://blog.iparissa.com/google-app-engine-jax-rs-jersey/
Aucun commentaire:
Enregistrer un commentaire