<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Le Touilleur Express &#187; grails</title>
	<atom:link href="http://www.touilleur-express.fr/tag/grails/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.touilleur-express.fr</link>
	<description>Blog sur Java, J2EE, Scrum,Apple,iphone par Nicolas Martignole</description>
	<lastBuildDate>Wed, 28 Jul 2010 09:07:18 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>fr</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Grails étape 3 : Bootstrap, XML, JSON, Ajax et création d&#8217;un GTag</title>
		<link>http://www.touilleur-express.fr/2009/12/30/grails-etape-3-bootstrap-xml-json-ajax-et-creation-dun-gtag/</link>
		<comments>http://www.touilleur-express.fr/2009/12/30/grails-etape-3-bootstrap-xml-json-ajax-et-creation-dun-gtag/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 22:39:06 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[grails]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=2763</guid>
		<description><![CDATA[3ème et dernier article sur Grails après une prise en main et la réalisation d&#8217;un écran complet, nous allons voir comment créer un tag pour Grails et comment mettre en place Ajax. En bonus et pour débuter je vais vous montrer aussi quelques fonctionnalités de Grails : le Bootstraping et les fonctions orientées REST pour afficher la liste des Contacts au format XML ou JSON en quelques minutes.
Bootstrapping
Avant tout, vous pouvez télécharger le code source de la partie 2 si vous ne l&#8217;avez pas déjà fait. Avez-vous remarqué qu&#8217;à chaque ...]]></description>
			<content:encoded><![CDATA[<p>3ème et dernier article sur <a href="http://www.grails.org">Grails</a> après <a href="http://www.touilleur-express.fr/2009/12/20/grails-lapplication-zencontact-de-zenika/ ">une prise en main</a> et <a href="http://www.touilleur-express.fr/2009/12/29/grails-etape-2-iterer-une-collection-et-afficher-le-resultat/">la réalisation d&#8217;un écran complet</a>, nous allons voir comment créer un tag pour Grails et comment mettre en place Ajax. En bonus et pour débuter je vais vous montrer aussi quelques fonctionnalités de Grails : le Bootstraping et les fonctions orientées REST pour afficher la liste des Contacts au format XML ou JSON en quelques minutes.</p>
<h3>Bootstrapping</h3>
<p>Avant tout, vous pouvez télécharger <a href="http://www.touilleur-express.fr/code/grails_zencontactdemo_debut_article2.tar.gz">le code source de la partie 2</a> si vous ne l&#8217;avez pas déjà fait. Avez-vous remarqué qu&#8217;à chaque démarrage de l&#8217;application, il n&#8217;y a aucuns contacts ? C&#8217;est un peu gênant car il faut créer quelques Contacts pour voir la liste s&#8217;afficher. Grails en mode développement utilise une base de données en mémoire qui n&#8217;est pas persistée. A chaque démarrage il est donc normal que la liste des Contacts soit vide. </p>
<p>Pour créer quelques enregistrements, ouvrez le fichier /grails-app/conf/BootStrap.groovy. Ce script est exécuté lors du démarrage. Nous allons créer quelques Contacts afin de tester. Rien de plus simple avec Grails, et vous verrez qu&#8217;il n&#8217;y a pas besoin de services, tout est livré sur l&#8217;entité Contact. Voici comment ajouter les contacts : dans la méthode init, créer un nouveau Contact :</p>
<pre class="brush:groovy">
class BootStrap {
     def init = { servletContext ->
          def nm = new Contact(prenom: "Nicolas", nom: "Martignole", dateNaissance: new Date()-120, email: "nicolas@test.fr")
          nm.save()

     }
     def destroy = {
     }
}
</pre>
<p>En Groovy il est possible d&#8217;utiliser ce que l&#8217;on appelle des arguments nommés. Franchement, vous ne trouvez pas cela plus clair que la version Java ? Là les paramètres sont clairement exprimés, sans ambiguïté. Notez aussi au passage qu&#8217;il est possible de retirer 120 jours à la date courante, car une Date en Groovy est facilement manipulable. C&#8217;est de la surcharge d&#8217;opérateur comme au bon vieux temps du C++.</p>
<p>Si vous arrêtez et vous relancez le serveur, vous devriez voir maintenant que votre liste d&#8217;utilisateur s&#8217;est remplie :<br />
<img src="http://www.touilleur-express.fr/wp-content/grails_etape3_debut.jpg" alt="grails_etape3_debut" title="grails_etape3_debut" width="400" height="194" class="alignnone size-full wp-image-2764" /></p>
<p>Je vous laisse ajouter quelques utilisateurs, vous avez compris le principe.</p>
<p>Sur votre version de production, il faudra ajouter un test afin de vérifier si l&#8217;application est en mode développement ou en mode production. Sans cela, ces entrées seront créées à chaque démarrage. Si vous voulez simplifier la saisie de la date de naissance, vous pouvez modifier la class Contact afin de rendre la date de naissance optionnel avec l&#8217;option nullable=true et retirer la contrainte max que j&#8217;avais placé dans la première version. Cela permettra de créer rapidement quelques enregistrements pour tester.</p>
<p>La class Contact modifiée :</p>
<pre class="brush:groovy">
package org.letouilleur.demo

class Contact {
	String nom
	String prenom
	Date dateNaissance
	String email

	static constraints={
		prenom(blank:false)
		nom(blank:false)
		dateNaissance(nullable:true)
		email(email:true,nullable:true,blank:true,unique:true)
	}
}
</pre>
<p>Voici mon fichier Bootstrap final :</p>
<pre class="brush:groovy">
import org.letouilleur.demo.Contact
import javax.servlet.ServletContext

/**
 * Script de demarrage
 */
class BootStrap {

  def init = {ServletContext ctx ->

    environments {
      production {

        ctx.setAttribute("env", "prod")
      }
      development {
        createTestEntries()
        ctx.setAttribute("env", "dev")
      }
    }

  }

  def destroy = {
  }

  // Cette methode est appele uniquement en mode developpement afin de creer des Contacts

  void createTestEntries() {
    def nm = new Contact(prenom: "Nicolas", nom: "Martignole", dateNaissance: new Date() - 120, email: "nicolas@test.fr")
    nm.save()

    // Permet de verifier que le Contact est bien stocke ou non
    def c = new Contact(prenom: "Paul", nom: "Gontran", dateNaissance: new Date(), email: "paul@toto.fr")
    c.save()
    if (c.hasErrors())
      println c.errors

    new Contact(prenom: "Georges", nom: "Lucas", dateNaissance: new Date() - 1, email: "lucas@star.fr").save(failOnError: true)
    new Contact(prenom: "Gregory", nom: "Madisson", dateNaissance: new Date() - 3, email: "mads@son.com").save()
    new Contact(prenom: "Jonathan", nom: "Lalou", dateNaissance: new Date() - 2, email: "john@lecowboy.fr").save()
    new Contact(prenom: "Katherine", nom: "Grah", dateNaissance: new Date() - 3, email: "kat@noop.fr").save()
    new Contact(prenom: "Amelie", nom: "Blou", dateNaissance: new Date() - 56, email: "amelie@noop.fr").save()
    new Contact(prenom: "Anatole", nom: "Ducib", dateNaissance: new Date() - 23, email: "am@noop.fr").save()
    new Contact(prenom: "Kim", nom: "ProdMan", dateNaissance: new Date() - 4, email: "kim@noop.fr").save()
    new Contact(prenom: "David", nom: "CeChau", dateNaissance: new Date() - 91, email: "david@noop.fr").save()
    new Contact(prenom: "Pierre", nom: "Henry", dateNaissance: new Date() - 3, email: "pierre@noop.fr").save()
    new Contact(prenom: "Andre", nom: "Magphone", email: "ant@noop.fr").save()
  }
}
</pre>
<p><strong>Générer une liste au format XML ou JSON</strong><br />
Certaines fonctions de Grails sont vraiment sympas. Nous allons voir comment retourner la liste des contacts au format XML simple, au format avancé et enfin au format JSON. Pour cela, éditez ContactController. Vous savez maintenant que pour déclarer une nouvelle action, il suffit de créer une méthode. Grails rend accessible cette méthode sans même qu&#8217;il ne soit nécessaire de relancer le serveur. Essayez d&#8217;ajouter ces quelques lignes à la fin de votre fichier :</p>
<pre class="brush:groovy">
  def listAsXml = {
    def newList = Contact.listOrderByNom()
    render newList as grails.converters.XML
  }
</pre>
<p>Si vous regardez maintenant la page <a href="http://localhost:8080/zencontactdemo/contact/listAsXml">http://localhost:8080/zencontactdemo/contact/listAsXml</a> vous verrez que Grails génère une liste triée par nom de famille des Contacts.<br />
<img src="http://www.touilleur-express.fr/wp-content/grails_list_as_xml_converter.jpg" alt="grails_list_as_xml_converter" title="grails_list_as_xml_converter" width="450" height="479" class="alignnone size-full wp-image-2767" /></p>
<p>Grails propose les Converters. Il en existe 4 par défaut (<a href="http://grails.org/Converters+Reference" target="new32">voir la doc</a> dans une autre fenêtre). Les converters &laquo;&nbsp;deep&nbsp;&raquo; gérent les associations, les relations alors que les 2 autres Converters ne rendent pas les feuilles. Ici Contact n&#8217;ayant aucunes relations, j&#8217;utilise le Converter par défaut. </p>
<p>Il est aussi possible de générer un fichier XML très facilement par exemple:</p>
<pre class="brush:groovy">

def converter = Contact.list() as XML
converter.render(new java.io.FileWriter("/path/to/my/file.xml"));
</pre>
<p><strong>Générer la liste des Contacts au format JSON</strong><br />
Le converter JSON par défaut gére en plus très bien l&#8217;encoding au format UTF-8 des entités, ce qui nous permettra de gérer sans soucis les accents par exemple : </p>
<pre class="brush:groovy">
import grails.converters.JSON
class ContactController {
..
...

 def listAsJson = {
    def newList = Contact.listOrderByNom()
    render newList as JSON
  }
</pre>
<p>Ce qui donne </p>
<pre>
[{"class":"org.letouilleur.demo.Contact","id":7,"prenom":"Amelie","dateNaissance":"2009-11-04T18:12:31Z","email":"amelie@noop.fr","nom":"Blou"},{"class":"org.letouilleur.demo.Contact","id":6,"prenom":"Katherine","dateNaissance":"2009-12-27T18:12:31Z","email":"kat@noop.fr","nom":"Blou"},
...
etc.
</pre>
<p><strong>Un seul enregistrement au format XML</strong><br />
Enfin si vous ne voulez retourner qu'un seul enregistrement, cela ne poste pas plus de problèmes. Voici une méthode showAsXml qui affichera un seul des enregistrements. Il suffit de passer l'id en argument.</p>
<pre class="brush:groovy">

  def showAsXml = {
    def contactInstance = Contact.get(params.id)
    if (!contactInstance) {
      flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'contact.label', default: 'Contact'), params.id])}"
      redirect(action: "list")
    }
    else {
       render contactInstance as XML
    }
  }
</pre>
<p>Et pour tester cette méthode (toujours sans relancer Grails) ouvrez par exemple cette URL :<br />
<a href="http://localhost:8080/zencontactdemo/contact/showAsXml?id=7">http://localhost:8080/zencontactdemo/contact/showAsXml?id=7</a></p>
<p>Voilà, vous savez maintenant que Grails peut exposer facilement au format XML ou JSON des entités. </p>
<h3>Le tag editInLine</h3>
<p>Là nous attaquons une partie un peu plus compliquée. Dans le cahier des charges de Zenika, il faut mettre en place une fonction d&#8217;édition du nom de famille en Ajax, en utilisant la fonction <a href="http://wiki.github.com/madrobby/scriptaculous/ajax-inplaceeditor">Ajax.InPlaceEditor</a> de la librairie Javascript <a href="http://script.aculo.us/">Scriptaculous</a>. J&#8217;ai un peu cherché mais il ne semble pas qu&#8217;il existe de tag Grails pour faire cela. Pas de plugins non plus. Enfin cela tombe bien, l&#8217;objectif est de vous montrer comment écrire ce tag.<br />
Mais avant cela, voici une petite vidéo du résultat final, de ce que vous allez coder dans un instant (désolé si vous n&#8217;avez pas Quicktime) : </p>
<p><object CLASSID="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" CODEBASE="http://www.apple.com/qtactivex/qtplugin.cab" WIDTH="640" HEIGHT="600" ><param NAME="src" VALUE="/code/grails_edit_in_place.mp4"/><param NAME="autoplay" VALUE="false"/><embed SRC="/code/grails_edit_in_place.mp4" TYPE="image/x-macpaint" PLUGINSPAGE="http://www.apple.com/quicktime/download" WIDTH="640" HEIGHT="600" AUTOPLAY="false"></embed></object></p>
<p>Pour réaliser cela voici ce que nous allons faire:<br />
- créer un tag personnalisé dans la class ToolsTagLib<br />
- modifier le fichier list.gsp pour utiliser ce tag<br />
- ajouter une méthode dans ContactController pour sauver le changement de nom<br />
- ajouter une page gsp pour afficher en gras le nom édité</p>
<p>Le tout sans relancer le serveur. </p>
<p>Avant tout, vérifiez bien que le fichier grails-app/views/layout/main.gsp contient bien la déclaration de la librairie Prototype et de la librairie Scriptaculous. </p>
<pre class="brush:groovy">
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;&lt;g:layoutTitle default="Zencontact"/&gt;&lt;/title&gt;
  &lt;link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}"/&gt;
  &lt;link rel="shortcut icon" href="${resource(dir: 'images', file: 'favicon.ico')}" type="image/x-icon"/&gt;
  &lt;g:layoutHead/&gt;
  &lt;g:javascript library="prototype"/&gt;
  &lt;g:javascript library="scriptaculous"/&gt;
&lt;/head&gt;
</pre>
<p><strong>Création d&#8217;un tag personnalisé</strong><br />
Lors du premier atelier nous avons créé une class ToolsTagLib.groovy dans le répertoire grails-app/taglib. Nous allons ajouter une nouvelle méthode dans cette classe afin de créer un tag editInPlace pour Grails. J&#8217;ai décidé que ce tag prendrait quelques arguments. Dans la page list.gsp, remplacez la ligne suivante utilisée lors de l&#8217;affichage du nom du contact par le code suivant : </p>
<pre class="brush:html">
Dans grails-app/views/contact/list.gsp 

effacez la ligne
 &lt;td&gt;${fieldValue(bean: contactInstance, field: "nom")}&lt;/td&gt;

et remplacez par :

&lt;td&gt;
     &lt;g:editInPlace id="${contactInstance.id}" action="inlineEdit" controller="contact" paramName="nom" initialValue="${contactInstance.nom}"/&gt;
&lt;/td&gt;
</pre>
<p>Notre tag prend plusieurs arguments. L&#8217;id du contact édité, l&#8217;action à appeler sur le controlleur, le nom de celui-ci, le nom du parametre initial et enfin la valeur à afficher lors du chargement de la page. </p>
<p>Je vous donne le code du tag, avant de l&#8217;expliquer. C&#8217;est pas très simple, j&#8217;y ai passé une bonne demie heure le temps de le tester et de trouver comment récupérer les paramètres facilement :</p>
<pre class="brush:groovy">
def editInPlace = {attrs, body -&gt;
    def id = attrs.remove('id')
    def initialVal = attrs.remove('initialValue')

    out &lt;&lt; "&lt;span id='${id}' class='editInline'&gt;"
    out &lt;&lt; initialVal
    out &lt;&lt; "&lt;/span&gt;"

    out &lt;&lt; "&lt;script type='text/javascript'&gt;"
    out &lt;&lt; "new Ajax.InPlaceEditor('${id}', '"

    // id has alread been removed from attrs map
    out &lt;&lt; createLink(action: attrs.action, id: id, controller: attrs.controller)

    out &lt;&lt; "',{"

    if (attrs.paramName) {
      out &lt;&lt; "callback: function(form,value) { return '${attrs.paramName}=' + encodeURIComponent(value) }  "
    }
    out &lt;&lt; "}); "
    out &lt;&lt; "&lt;/script&gt;"
  }
</pre>
<p>Ligne 2 et 3 : je retire les parametres passés en argument du tag dans la page GSP et je les stocke dans des variables<br />
Ligne 13: j&#8217;utilise la fonction createLink de Grails qui est présente par défaut pour créer un lien<br />
Ligne 17: je précise aussi le nom du parametre</p>
<p>Le tout repose sur la fonction Ajax.InPlaceEditor qui permet facilement de gérer l&#8217;édition. C&#8217;est cette même librairie qui est utilisée dans la version de Zenika. Exactement la même. La différence étant que là, au lieu d&#8217;avoir un composant, je dois coder un tag. </p>
<p><strong>Modification de la page list.gsp</strong><br />
Editez et vérifiez que la page list.gsp utilise maintenant votre tag. Nous avons maintenant la version finale de cette page. Regardez attentivement le code, c&#8217;est relativement simple.</p>
<pre class="brush:html">
&lt;html&gt;
&lt;head&gt;
  &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;
  &lt;meta name="layout" content="main"/&gt;
  &lt;g:set var="entityName" value="${message(code: 'contact.label', default: 'Contact')}"/&gt;
  &lt;title&gt;&lt;g:message code="default.list.label" args="[entityName]"/&gt;&lt;/title&gt;

&lt;/head&gt;
&lt;body&gt;

&lt;div class="body"&gt;
  &lt;g:if test="${flash.message}"&gt;
    &lt;div class="message"&gt;${flash.message}&lt;/div&gt;
  &lt;/g:if&gt;

  &lt;P&gt;Sur cette page vous pouvez éditer une fiche, ajouter rapidement un nouvel utilisateur avec un formulaire Ajax. Nous
  montrons aussi comment il est possible d'inclure une autre vue dans la vue active sans ajouter une ligne de code
  au controleur.&lt;/P&gt;
  &lt;P&gt;Vous pouvez éditer directement le nom de famille d'un utilisateur en cliquant sur son nom grâce à la librairie Scriptaculous.&lt;/P&gt;

  &lt;div id="updateMe"&gt;
    &lt;g:each in="${contactInstanceList}" status="i" var="contactInstance"&gt;
      &lt;img src='&lt;g:resource dir="images" file="people.png"/&gt;' alt="icon"/&gt;
      ${contactInstance.prenom}

      &lt;!-- Exemple d'utilisation d'un tag custom --&gt;
      &lt;g:editInPlace id="${contactInstance.id}" action="inlineEdit" controller="contact" paramName="nom" initialValue="${contactInstance.nom}"/&gt;

      &lt;g:link action="show" id="${contactInstance.id}"&gt;
        &lt;img src="${resource(dir: 'images', file: 'edit.png')}" alt="edit" border="0"/&gt;
      &lt;/g:link&gt;
      &lt;br/&gt;
    &lt;/g:each&gt;
    &lt;div class="paginateButtons"&gt;
      &lt;g:paginate total="${contactInstanceTotal}"/&gt;
    &lt;/div&gt;

  &lt;/div&gt;

&lt;/div&gt;

&lt;div class="contact"&gt;
  &lt;g:include action="create" controller="contact"/&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Nous retrouvons bien notre tag à la ligne 27, et aussi ce que nous avions préparé dans l&#8217;article précedent. Il ne manque plus que l&#8217;édition avec le formulaire Ajax et nous aurons terminé. </p>
<p><strong>Ajout d&#8217;une méthode pour sauver le nouveau nom</strong><br />
Si vous testez le code à cet instant, vous verrez que cela marche pas. Le nom de famille n&#8217;est pas persisté. Il manque encore 2 choses : une méthode dans ContactController et une vue GSP. Le nom de la méthode appelée par le code Ajax.EditInPlace a été passé en argument : <em>inlineEdit</em>. Il faut donc créer cette méthode et ensuite une vue inlineEdit.gsp pour terminer cette partie. Voici la nouvelle méthode à ajouter à la fin de ContactController :</p>
<pre class="brush:groovy">
def inlineEdit = {
    def contactInstance = Contact.get(params.id)
    if (!contactInstance) {
      flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'contact.label', default: 'Contact'), params.id])}"
      redirect(action: "list")
    }
    else {
      contactInstance.nom=params.nom
      contactInstance.save()
      return [contactInstance: contactInstance]
    }
  }
</pre>
<p>Retenez que seul la ligne 8 est intéressante : nous modifions le nom de l&#8217;entité chargée et nous la sauvons ensuite.</p>
<p>Il ne reste plus qu&#8217;à ajouter un fichier inlineEdit.gsp dans le répertoire grails-app/views/contact avec cette seule et unique ligne:</p>
<pre class="brush:groovy">
// Une seule ligne
&lt;strong&gt;${contactInstance.nom}&lt;/strong&gt;
</pre>
<p>Une seule ligne car cette page est rendue&#8230; via Ajax. Il n&#8217;y a rien d&#8217;autres à ajouter. </p>
<p>Voilà c&#8217;est terminé pour l&#8217;édition. Regardez la vidéo complète à la fin de cet article si vous souhaitez faire une pause avant la dernière partie. </p>
<p><strong>Dernière modification : le formulaire de saisie rapide Ajax</strong><br />
Tout d&#8217;abord nous allons modifier la vue contact.gsp car nous n&#8217;avons pas encore activé de datePicker. Et comme la vue create est utilisée aussi dans la vue list, autant faire d&#8217;une pierre, deux coups. Pour le datePicker nous avons l&#8217;embarras du choix car il existe plusieurs plugins Grails. J&#8217;ai pris le plugin &laquo;&nbsp;<a href="http://www.grails.org/Calendar+Plugin">Calendar</a>&laquo;&nbsp;. Allons-y, il y en a pour 3 minutes. Tout d&#8217;abord installons le plugin </p>
<pre>
grails install-plugin calendar
 </pre>
<p>Voici la version finale de la page create.gsp avec la mise en page de la version Wicket de Zenika :</p>
<pre class="brush:groovy">
&lt;%@ page import="org.letouilleur.demo.Contact" %&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;
  &lt;meta name="layout" content="main"/&gt;
  &lt;g:set var="entityName" value="${message(code: 'contact.label', default: 'Contact')}"/&gt;
  &lt;title&gt;&lt;g:message code="default.create.label" args="[entityName]"/&gt;&lt;/title&gt;
  &lt;calendar:resources/&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;div class="body"&gt;
  &lt;g:if test="${flash.message}"&gt;
    &lt;div class="message"&gt;${flash.message}&lt;/div&gt;
  &lt;/g:if&gt;
  &lt;g:hasErrors bean="${contactInstance}"&gt;
    &lt;div class="errors"&gt;
      &lt;g:renderErrors bean="${contactInstance}" as="list"/&gt;
    &lt;/div&gt;
  &lt;/g:hasErrors&gt;
  &lt;g:form action="save" method="post"&gt;
    &lt;div class="dialog"&gt;
      &lt;table&gt;
        &lt;tbody&gt;

        &lt;tr class="prop"&gt;
          &lt;td valign="top" class="name"&gt;
            &lt;label for="prenom"&gt;&lt;g:message code="contact.prenom.label" default="Prenom"/&gt;&lt;/label&gt;
          &lt;/td&gt;
          &lt;td valign="top" class="value ${hasErrors(bean: contactInstance, field: 'prenom', 'errors')}"&gt;
            &lt;g:textField name="prenom" value="${contactInstance?.prenom}"/&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr class="prop"&gt;
          &lt;td valign="top" class="name"&gt;
            &lt;label for="nom"&gt;&lt;g:message code="contact.nom.label" default="Nom"/&gt;&lt;/label&gt;
          &lt;/td&gt;
          &lt;td valign="top" class="value ${hasErrors(bean: contactInstance, field: 'nom', 'errors')}"&gt;
            &lt;g:textField name="nom" value="${contactInstance?.nom}"/&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr class="prop"&gt;
          &lt;td valign="top" class="name"&gt;
            &lt;label for="dateNaissance"&gt;&lt;g:message code="contact.dateNaissance.label" default="Date Naissance"/&gt;&lt;/label&gt;
          &lt;/td&gt;
          &lt;td valign="top" class="value ${hasErrors(bean: contactInstance, field: 'dateNaissance', 'errors')}"&gt;
            &lt;!-- utilisation du plugin calendar, a installer avec grails install-plugin calendar --&gt;
            &lt;calendar:datePicker name="dateNaissance" defaultValue="${contactInstance?.dateNaissance}" dateFormat="%d/%m/%Y"/&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr class="prop"&gt;
          &lt;td valign="top" class="name"&gt;
            &lt;label for="email"&gt;&lt;g:message code="contact.email.label" default="Email"/&gt;&lt;/label&gt;
          &lt;/td&gt;
          &lt;td valign="top" class="value ${hasErrors(bean: contactInstance, field: 'email', 'errors')}"&gt;
            &lt;g:textField name="email" value="${contactInstance?.email}"/&gt;
          &lt;/td&gt;
        &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
    &lt;/div&gt;
    &lt;div class="buttonbox"&gt;
      &lt;g:submitButton name="create" class="button" value="${message(code: 'default.button.create.label', default: 'Create')}"/&gt;
    &lt;/div&gt;
  &lt;/g:form&gt;
&lt;/div&gt;
&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Ligne 8 : cette déclaration permet de charger les ressources javascript nécessaires au plugin calendar.<br />
Ligne 48: utilisation du datePicker</p>
<p>Si vous rechargez maintenant <a href="http://localhost:8080/zencontactdemo/contact/create">la page de création</a> nous avons un datePicker en bonne et due forme. De même pour <a href="http://localhost:8080/zencontactdemo/contact/list">la page qui liste les contacts</a> car celle-ci importe la page create.gsp. </p>
<p>Passons maintenant à l&#8217;ajout du formulaire de saisie rapide à proprement parler. </p>
<p>Grails fournit un support d&#8217;AJAX très puissant et simple à utiliser. La librairie des tags de base permet de réaliser rapidement des fonctions puissantes en Javascript, tout en assurant l&#8217;envers du décor avec les actions dans le Controller. En fait c&#8217;est tellement simple que vous n&#8217;aurez pas le temps de terminer votre café en lisant ce qui suit : </p>
<p>Dans list.gsp, ajoutez un nouveau formulaire basé sur le tag formRemote:</p>
<pre class="brush:html">
&lt;div id="updateMe"&gt;
    &lt;g:each in="${contactInstanceList}" status="i" var="contactInstance"&gt;
      &lt;img src='&lt;g:resource dir="images" file="people.png"/&gt;' alt="icon"/&gt;
      ${contactInstance.prenom}

      &lt;!-- Exemple d'utilisation d'un tag custom --&gt;
      &lt;g:editInPlace id="${contactInstance.id}" action="inlineEdit" controller="contact" paramName="nom" initialValue="${contactInstance.nom}"/&gt;

      &lt;g:link action="show" id="${contactInstance.id}"&gt;
        &lt;img src="${resource(dir: 'images', file: 'edit.png')}" alt="edit" border="0"/&gt;
      &lt;/g:link&gt;
      &lt;br/&gt;
    &lt;/g:each&gt;
    &lt;div class="paginateButtons"&gt;
      &lt;g:paginate total="${contactInstanceTotal}"/&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div&gt;
    &lt;g:formRemote name="quickSave"
                                action="saveQuickInput"
                                on404="alert('not found!')"
                                update="updateMe"
                                url="${[action:'saveQuickInput']}"&gt;
      Prénom : &lt;g:textField name="prenom" value="${contactInstance?.prenom}"/&gt;
      Nom :   &lt;g:textField name="nom" value="${contactInstance?.nom}"/&gt;

      &lt;g:submitButton name="create" class="button" value="Créer"/&gt;

    &lt;/g:formRemote&gt;
&lt;/div&gt;
</pre>
<p>Ligne 1 : vous notez que j&#8217;ai nommé le DIV principal &laquo;&nbsp;updateMe&nbsp;&raquo; qui comme vous l&#8217;avez deviné&#8230; doit se rafraîchir dès qu&#8217;un contact est ajouté.<br />
Ligne 21 : nom de l&#8217;action à appeler sur ContactController<br />
Ligne 23 : nom du DIV à rappeler en cas de succès</p>
<p>Le reste du formulaire est tout à fait normal, il n&#8217;y a rien d&#8217;exceptionnel. Il ne reste plus qu&#8217;à ajouter une nouvelle action dans ContactController. Je vous laisse faire maintenant, vous savez comment faire :</p>
<pre class="brush:groovy">
 def saveQuickInput = {
    params.max = Math.min(params.max ? params.max.toInteger() : 10, 100)

    def contactInstance = new Contact(params)

    def existingUser = Contact.findByNomAndPrenom(params.nom, params.prenom)
    if (!existingUser) {

      contactInstance.save(flush: true)
      [contactInstanceList: Contact.listOrderByNom(params), user: contactInstance, contactInstanceTotal: Contact.count()]
    } else {
      [contactInstanceList: Contact.list(params), user: contactInstance, erreur: "Cet utilisateur existe déjà"]
    }
  }
</pre>
<p>Et enfin comme toute action, il nous faut une vue. Je dis cela, ce n&#8217;est pas tout à fait vrai. Il est possible d&#8217;appeler une autre vue et vous n&#8217;êtes pas obligé de créer un fichier GSP par action dans votre Controller. Pour terminer voici le contenu de la page qui sera affichée lorsque l&#8217;utilisateur aura saisi un nouveau Contact :</p>
<pre class="brush:html">
&lt;div class="errors"&gt;
  ${erreur}  &lt;br/&gt;
&lt;/div&gt;

&lt;g:if test="${flash.message}"&gt;
  &lt;div class="errors"&gt;${flash.message}&lt;/div&gt;
&lt;/g:if&gt;

&lt;g:each in="${contactInstanceList}" status="i" var="contactInstance"&gt;
  &lt;img src='&lt;g:resource dir="images" file="people.png"/&gt;' alt="icon"/&gt;

  &lt;g:if test="${contactInstance.nom == user.nom}"&gt;
    &lt;strong&gt;
  &lt;/g:if&gt;
  ${contactInstance.prenom}

  &lt;!-- Exemple d'utilisation d'un tag custom --&gt;
  &lt;g:editInPlace id="${contactInstance.id}" action="inlineEdit" controller="contact" paramName="nom" initialValue="${contactInstance.nom}"/&gt;

  &lt;g:if test="${contactInstance.nom == user.nom}"&gt;
    &lt;/strong&gt;
  &lt;/g:if&gt;

  &lt;g:link action="show" id="${contactInstance.id}"&gt;
    &lt;img src="${resource(dir: 'images', file: 'edit.png')}" alt="edit" border="0"/&gt;
  &lt;/g:link&gt;
  &lt;br/&gt;
&lt;/g:each&gt;
&lt;div class="paginateButtons"&gt;
  &lt;g:paginate total="${contactInstanceTotal}" controller="contact" action="list" next="Suivant" prev="Précedent"/&gt;
&lt;/div&gt;

&lt;div class="errors"&gt;
  ${erreur}  &lt;br/&gt;
&lt;/div&gt;
</pre>
<p>La pagination sur la page de résultat pose un souci : si vous créez un utilisateur appelé Bob Zorro par exemple, celui-ci sera affiché sur la 2ème page et vous ne le verrez pas tout de suite&#8230; Je pense que c&#8217;est un souci d&#8217;ergonomie plus que technique, donc nous n&#8217;en tiendrons pas compte ici. </p>
<p>Voilà c&#8217;est terminé. Nous avons maintenant aussi le formulaire de création rapide. Si vous avez tout suivi jusqu&#8217;ici&#8230; chapeau. Cet article est énorme à lire, et il doit tenir sur 12 pages. Je vous remercie si vous êtes encore là, car tout ceci peut vous sembler un peu indigeste. </p>
<h3>Conclusion</h3>
<p>Pour terminer voici une vidéo de l&#8217;application complète, avec une feuille de style adaptée, quelques améliorations sur la mise en page, mais le tout sans trucages, sans fil en nylon qui font bouger les tags sur la page et en essayant de coller à l&#8217;esprit du projet de Zenika au plus juste. Pour les observateurs attentifs il y a un bug à un moment donné&#8230; je vous laisse regarder :<br />
<object CLASSID="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" CODEBASE="http://www.apple.com/qtactivex/qtplugin.cab" WIDTH="740" HEIGHT="640" ><param NAME="src" VALUE="/code/version_finale.mp4"/><param NAME="autoplay" VALUE="false"/><embed SRC="/code/version_finale.mp4" TYPE="image/x-macpaint" PLUGINSPAGE="http://www.apple.com/quicktime/download" WIDTH="740" HEIGHT="640" AUTOPLAY="false"></embed></object></p>
<p><strong>Alors Grails c&#8217;est mieux que Wicket ?</strong><br />
Il est temps de poser un peu le clavier et de porter une autocritique sur le projet. Là où j&#8217;ai clairement gagné du temps : sur tout ce qui est test, construction des actions et de la partie Controller. Là où j&#8217;ai bien passé 1 heure, c&#8217;est sur la création du tag personnalisé et sur la gestion de la partie Ajax. Pas compliqué, mais ne connaissant pas&#8230; j&#8217;ai un peu navigué dans la documentation de Grails pour boucler le tout. Je me demande combien de temps il me faudrait pour refaire le projet en partant de zéro, en connaissant ce qu&#8217;il y a à faire&#8230; Je dirai 1h00 je pense, en imaginant que je conserve le code du tag editInPlace quelque part. Le reste est faisable rapidement. </p>
<p>Dans vos commentaires vous me demandez si Grails est mieux que GWT. Ils ne sont pas comparables sur le plan de la création d&#8217;application. GWT est fait pour la création d&#8217;application riche du côté du navigateur. Je préfère comparer GWT à Flex. GWT vous laisse écrire la partie serveur avec la persistence gérée par un ORM comme Hibernate, et l&#8217;injection de dépendance gérée par Spring par exemple. Grails ne vous laisse pas mettre le nez dans cette partie, ce qui je pense doit avoir ses limites. Vous êtes tributaire des mises à jour des versions de Spring et d&#8217;Hibernate puisque celles-ci font parties intégrantes de Grails&#8230; D&#8217;un autre côté, je vois cela comme un avantage : Grails vous prépare une version qui marche des différentes librairies, et tant que vous n&#8217;avez pas un bug dans celle-ci, vous êtes tranquille. </p>
<p><strong>Peut-on utiliser Grails en production ? </strong><br />
Oui. Souvenez-vous qu&#8217;à la fin, vous faîtes &laquo;&nbsp;grails war&nbsp;&raquo; et votre archive est prête à être déployée comme vous l&#8217;auriez construit à la main. SpringSource fournit aussi du support il me semble sur Grails <a href="http://www.springsource.com/services/enterprisesupport">d&#8217;après cette page</a> mais difficile à dire. </p>
<p><strong>Est-ce que Grails est réservé à des petites applications ou des maquettes ? </strong><br />
Je ne pense pas. Si je suis votre raisonement, dès que votre application devient &laquo;&nbsp;<em>sérieuse</em>&nbsp;&raquo; il vous faut Java EE 6 ? C&#8217;est pas un peu bête comme raisonnement ? Je suis certain que vous pensez que PHP c&#8217;est &laquo;&nbsp;<em>pour des petits sites</em>&nbsp;&raquo; et Python &laquo;&nbsp;<em>c&#8217;est pour des gars qui n&#8217;aiment pas Java</em>&laquo;&nbsp;.<br />
Excusez-moi de vous parler franchement : va falloir sortir un peu mon garçon. La majorité des projets Webs aujourd&#8217;hui tournent sur du PHP. Python a des Closures depuis 2004 je crois là où nous, dans le monde Java, nous n&#8217;aurons rien avant fin 2010&#8230; Coluche disait : &laquo;&nbsp;<em>JE ME MARRE !</em>&nbsp;&raquo;</p>
<p><strong>Est-ce que Grails c&#8217;est vraiment de la balle et tu es prêt à mettre ton projet dessus ?</strong><br />
Un autre Nicolas m&#8217;a posé cette question. Est-ce que je suis prêt à risquer un projet, une entreprise en l&#8217;occurrence, sur ce framework ? Ma réponse est oui. Je limite le risque en prenant un outil qui me donne un feedback plus rapidement qu&#8217;avec Java. Cela me permet de valider rapidement ou non des idées. Et dans le cadre d&#8217;une start-up où vous devez trouver des idées, je suis vraiment content de ce choix. Je commence à voir les limites de Grails, mais aussi à voir les parties où il ne faut pas hésiter à se servir deux fois.</p>
<p><strong>Et Groovy  ? Et la suite ?</strong><br />
Depuis mi-2009 j&#8217;ai changé. Je dirai presque que j&#8217;ai muri : je sens de moins en moins l&#8217;option &laquo;&nbsp;<em>Java seul contre le reste du monde</em>&laquo;&nbsp;. Je pense qu&#8217;il est intéressant pour vous de commencer à apprendre Scala ou Groovy en ce moment, bref n&#8217;importe quel langage qui tourne sur la JVM.<br />
<strong><em>La force de Java ce n&#8217;est plus le langage. C&#8217;est la communauté, c&#8217;est les projets open-sources de qualité et c&#8217;est la machine virtuelle.</em></strong></p>
<p><strong>Play! ou Grails ?</strong><br />
Ben j&#8217;en sais trop rien&#8230; Je dirai que je préfère Grails à cause de Groovy. Play! m&#8217;a semblé proche de Grails, et rejoint la famille des frameworks Webs Hyper-productifs qui écrasent gentiment les frameworks orientés composants comme JSF pour n&#8217;en citer qu&#8217;un. C&#8217;est mon avis très personnel, et souvenez-vous que je portais aux louanges JSF 1.2 il y a 2 ou 3 ans. A mon avis, le ticket d&#8217;entrée avec Play! doit être moins élevé.<br />
Souvenez-vous de la différence entre apprendre à faire du Ski Alpin et apprendre à faire du Snowboard. Grails c&#8217;est plutôt du Ski : tu vas bien galérer au début, là où Play! c&#8217;est ton pote Java avec donc le bénéfice de toutes les librairies qui existent déjà&#8230; Peut-être que tu risques de te faire moins mal ? </p>
<p>Il faudrait confronter les deux frameworks. Alors je vais lancer un appel solennel :<br />
<strong>Si quelqu&#8217;un de l&#8217;équipe Play! lit cet article, ça ne vous dit pas de faire votre version du projet de Zenika ? </strong> </p>
<p>Là on aura une idée plus précise je pense. </p>
<p>Voilà j&#8217;espère que cette série d&#8217;articles vous aura donné une idée de ce que l&#8217;on peut faire avec Grails 1.2.</p>
<p>Je vous proposerai d&#8217;autres articles sur les sujets que j&#8217;ai découvert ces derniers mois, il y a de quoi se chauffer cet hiver. </p>
<h3>Code du projet</h3>
<p>Vous pouvez télécharger le code source de la version finale :<br />
<a href="http://www.touilleur-express.fr/code/grails_final_touilleurexpress.tar.gz">grails_final_touilleurexpress.tar.gz</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2009/12/30/grails-etape-3-bootstrap-xml-json-ajax-et-creation-dun-gtag/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Grails étape 2: itérer une collection et afficher le résultat</title>
		<link>http://www.touilleur-express.fr/2009/12/29/grails-etape-2-iterer-une-collection-et-afficher-le-resultat/</link>
		<comments>http://www.touilleur-express.fr/2009/12/29/grails-etape-2-iterer-une-collection-et-afficher-le-resultat/#comments</comments>
		<pubDate>Tue, 29 Dec 2009 20:54:28 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[grails]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=2727</guid>
		<description><![CDATA[Les fêtes sont passées, voici la deuxième partie de mon article sur Grails consacrée à l&#8217;écriture de l&#8217;application Zencontact. Dans le premier article j&#8217;ai expliqué comment installer Grails et débuter son projet. Figurez-vous que depuis ce dernier article, j&#8217;ai trouvé comment utiliser les 2 librairies Prototype et Scriptaculous. Parfois il faut juste chercher un peu&#8230; Bref la version 2 est plus proche du cahier des charges de Zenika. Il ne manque presque rien je pense pour remplir le cahier des charges.
Aujourd&#8217;hui au programme :
- comment mettre à jour sa version ...]]></description>
			<content:encoded><![CDATA[<p>Les fêtes sont passées, voici la deuxième partie de mon article sur Grails consacrée à l&#8217;écriture de l&#8217;application Zencontact. Dans <a href="http://www.touilleur-express.fr/2009/12/20/grails-lapplication-zencontact-de-zenika/">le premier article</a> j&#8217;ai expliqué comment installer Grails et débuter son projet. Figurez-vous que depuis ce dernier article, j&#8217;ai trouvé comment utiliser les 2 librairies Prototype et Scriptaculous. Parfois il faut juste chercher un peu&#8230; Bref la version 2 est plus proche du cahier des charges de Zenika. Il ne manque presque rien je pense pour remplir <a href="http://blog.zenika.com/index.php?post/2009/03/10/Concours-D%C3%A9velopper-une-application-web-en-Wicket3">le cahier des charges.</a></p>
<p>Aujourd&#8217;hui au programme :<br />
- comment mettre à jour sa version de Grails ?<br />
- Itérer une collection et afficher les résultats</p>
<p><strong>Mettre à jour son application vers une nouvelle version de Grails</strong><br />
Pendant le break de la semaine de Noël, l&#8217;équipe de Grails a annoncé la sortie de <a href="http://www.grails.org/1.2+Release+Notes">la version 1.2</a> du framework Grails. C&#8217;est parfait, cela va me permettre de vous montrer comment mettre à jour votre version de Grails, ainsi que notre projet zencontact.<br />
- Renommez votre ancien répertoire C:\grails en C:\grails-old par exemple<br />
- Téléchargez et décompressez Grails 1.2 dans le répertoire C:\grails<br />
- Téléchargez le projet de démarrage pour cet article, qui a été allégé depuis la version 1 via ce lien : <a href="http://www.touilleur-express.fr/code/grails_zencontactdemo_debut_article2.tar.gz">grails_zencontactdemo_debut_article2.tar.gz</a><br />
- Placez-vous à la racine du projet zencontactdemo après avoir décompressé l&#8217;archive<br />
- Tapez simplement <code>grails upgrade</code><br />
- Faites aussi le ménage avec <code>grails clean</code> avant de relancer le serveur avec <code>grails run-app</code> afin de tester la mise à jour</p>
<p>Le script de mise à jour de Grails démarre. Nous pouvons constater que la version utilisée est bien la 1.2. Suivez les instructions, en principe cela ne devrait pas poser de problèmes. </p>
<pre>
macbook-pro-de-nicolas-martignole:zencontactdemo nicolas$ grails upgrade
Welcome to Grails 1.2.0 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Users/nicolas/Dev/grails/grails

Base Directory: /Users/nicolas/Dev/Zenika/zencontactdemo/zencontactdemo
Resolving dependencies...
Dependencies resolved in 1502ms.
Running script /Users/nicolas/Dev/grails/grails/scripts/Upgrade.groovy
Environment set to development
NOTE: Your application currently expects grails version [1.2-M4], this target will upgrade it to Grails 1.2.0 ...

		WARNING: This target will upgrade an older Grails application to 1.2.0.
		However, tag libraries provided by earlier versions of Grails found in grails-app/taglib will be removed.
		The target will not, however, delete tag libraries developed by yourself.
		Are you sure you want to continue?
				    (y, n)
</pre>
<p>Lors du premier redémarrage, vous verrez que Grails met aussi à jour les Plugins, ce qui peut parfois poser des soucis avec les versions &laquo;&nbsp;beta&nbsp;&raquo;. Mais ici, s&#8217;agissant de la version 1.2 il n&#8217;y aura aucuns soucis. </p>
<p><strong>Les améliorations de la version 1.2 de Grails</strong><br />
La <a href="http://www.grails.org/1.2+Release+Notes">release notes</a> de la version 1.2 est longue comme un guide d&#8217;installation de Windows. Cette version a été optimisée pour les performances. Spring 3.0 est utilisé par Grails et devient aussi utilisable pour votre code. N&#8217;importe quelle classe (java ou groovy) peut donc être annotée avec @Component afin d&#8217;être injectée dans une autre classe. Concernant la gestion des transactions, il est possible de définir un niveau de granularité plus bas pour les transactions, là où auparavant, l&#8217;ensemble d&#8217;un service Grails était transactionnel ou non. GORM est aussi configurable avec un ensemble de règle par défaut. J&#8217;aime beaucoup les nouveaux finders dynamiques qui traitent les Booleans. Enfin le support des requêtes nommées (named queries) la possibilité de faire des mappins &laquo;&nbsp;hasOne&nbsp;&raquo;, la liste est longue.<br />
Attention dans la version 1.2,  WebFlow est maintenant un plugin à part qu&#8217;il faut installer. Il n&#8217;est plus livré par défaut. Basé sur Spring WebFlow, ce plugin est très pratique pour faire des questionnaires, des wizards, des formulaires multi-écrans.<br />
Je pourrai écrire un article complet sur cette nouvelle version, mais croyez-moi, c&#8217;est une version très mature et très complète. Je dis cela pour les chagrineurs qui attendent que &laquo;&nbsp;<em>Grails soit stable</em>&laquo;&nbsp;. </p>
<p><strong>Scriptaculous et Prototype sur la même page</strong><br />
Avec la version 1.2 il est possible d&#8217;utiliser les 2 librairies Javascript Prototype et Scriptaculous sans soucis. Il suffit de les déclarer à la suite dans notre fichier main.gsp qui sert de template pour Sitemesh:</p>
<pre class="brush:html">
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;&lt;g:layoutTitle default="Zencontact"/&gt;&lt;/title&gt;
  &lt;link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}"/&gt;
  &lt;link rel="shortcut icon" href="${resource(dir: 'images', file: 'favicon.ico')}" type="image/x-icon"/&gt;
  &lt;g:layoutHead/&gt;
&lt;!-- ****************************************** //--&gt;
  &lt;g:javascript library="prototype"/&gt;
  &lt;g:javascript library="scriptaculous"/&gt;
&lt;!-- ****************************************** //--&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id="header"&gt;
  &lt;g:link controller="contact" action="index"&gt;Accueil&lt;/g:link&gt; |
  &lt;g:link controller="contact" action="list"&gt;Liste des contacts&lt;/g:link&gt; |
  &lt;g:link controller="contact" action="create"&gt;Ajouter un contact&lt;/g:link&gt;

&lt;/div&gt;
&lt;div id="content"&gt;
  &lt;div id="contacts"&gt;
    &lt;div class="contact"&gt;
      &lt;g:layoutBody/&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div id="footer"&gt;
  &lt;p id="legal"&gt;&lt;a href="http://www.touilleurexpress.fr/"&gt;Le Touilleur Express&lt;/a&gt; Copyright© 2009-2010&lt;/p&gt;
&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p><strong>La version de l&#8217;article 1</strong><br />
A la fin de l&#8217;article 1 il était possible de créer un contact, de le lister, et d&#8217;afficher l&#8217;heure sur la page d&#8217;accueil. Pour vous montrer maintenant une nouvelle version, j&#8217;ai préparé une archive du code source du début de l&#8217;étape 2.<br />
- Téléchargez le fichier <a href="http://www.touilleur-express.fr/code/grails_zencontactdemo_debut_article2.tar.gz">grails_zencontactdemo_debut_article2.tar.gz</a><br />
- Décompressez-le dans un nouveau répertoire et lancez l&#8217;application.</p>
<p>Comme je vous sens un peu fatigué après les fêtes je vous ai fait une vidéo avec ma belle voix que vous pouvez regarder en buvant une tisane (par exemple)<br />
<object width="656" height="517"><param name="movie" value="http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/01d05fad-afa2-41de-80d7-43bb5ae0eff1/jingh264player.swf"></param><param name="quality" value="high"></param><param name="bgcolor" value="#FFFFFF"></param><param name="flashVars" value="thumb=http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/01d05fad-afa2-41de-80d7-43bb5ae0eff1/FirstFrame.jpg&#038;containerwidth=656&#038;containerheight=517&#038;content=http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/01d05fad-afa2-41de-80d7-43bb5ae0eff1/00000011.mp4"></param><param name="allowFullScreen" value="true"></param><param name="scale" value="showall"></param><param name="allowScriptAccess" value="always"></param><param name="base" value="http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/01d05fad-afa2-41de-80d7-43bb5ae0eff1/"></param>  <embed src="http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/01d05fad-afa2-41de-80d7-43bb5ae0eff1/jingh264player.swf" quality="high" bgcolor="#FFFFFF" width="656" height="517" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/01d05fad-afa2-41de-80d7-43bb5ae0eff1/FirstFrame.jpg&#038;containerwidth=656&#038;containerheight=517&#038;content=http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/01d05fad-afa2-41de-80d7-43bb5ae0eff1/00000011.mp4" allowFullScreen="true" base="http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/01d05fad-afa2-41de-80d7-43bb5ae0eff1/" scale="showall"></embed></object></p>
<p><strong>Itérer une collection</strong><br />
Comment itérer une collection et afficher le résultat ? Plus clairement, nous devons lister les contacts et les afficher sur une page. Voyons comment cela fonctionne. Tout d&#8217;abord, souvenez-vous, nous utilisons une class Controller avec Grails. Tout se passe dans l&#8217;unique class ContactController.groovy.<br />
Pour récupérer la liste des contacts, nous utilisons un &laquo;&nbsp;finder&nbsp;&raquo;. C&#8217;est une méthode statique qui est déclaré sur la classe Contact et qui permet à Grails de vous câbler tout cela sans aucuns efforts. Voici quelques exemples pour expliquer ce principe. Sachez qu&#8217;avec IDEA IntelliJ, celui-ci est capable de vous proposer via l&#8217;auto-complétion des méthodes, ce qui aide pas mal lorsque vous codez.</p>
<pre class="brush:groovy">
// Pour obtenir la liste des Contact
def myList = Contact.list()

// Pour obtenir la liste des utilisateurs dont le nom de famille est Martin
def myList = Contact.findAllByNom("Martin")

// Qui ressemble à Mar
def myList = Contact.findAllByNomLike("Ma%")

// Seulement le premier trouvé
def c1 = Contact.findByNomLike("Ma%")

// Trouve toutes les personnes dont la date de naissance
// est inférieur à la date d'aujourd'hui
def myList=Contact.findAllByDateNaissanceLessThan(new Date())

// Combine 2 attributs pr la recherche
def nicolas=Contact.findByNomAndPrenom("nicolas","martignole")
</pre>
<p>Que pensez-vous de tout cela ? Pas mal non ? Imaginez que le tout devient des requêtes avec Spring et Hibernate. Il est possible de combiner 2 attributs de la classe Contact au maximum comme sur le dernier exemple. J&#8217;adore Grails car <strong>c&#8217;est précisément ce genre d&#8217;astuces qui font gagner du temps</strong>.</p>
<p>Pour vous expliquer comment construire la liste des contacts, nous allons casser un peu de code. Reprenez le fichier ContactController. Effacez pour l&#8217;instant tout ce qui se trouve dans la méthode list() et utilisez ce que vous venez de voir pour créer un objet myList. Comme vous pouvez le constater, on se fiche pas mal du type ici, à savoir un List<contact>. Pour retourner un objet à la vue, il suffit de le placer dans une Map, ce que je fais avec ces crochets à la fin de la méthode. Il n&#8217;y a pas de return car la dernière expression évaluée avec Grails est automatiquement retournée. La clé sera &laquo;&nbsp;contactInstanceList&nbsp;&raquo; et la valeur sera &laquo;&nbsp;myList&nbsp;&raquo;. </p>
<pre class="brush:groovy">
package org.letouilleur.demo

class ContactController {

  static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

  def index = {
    redirect(uri: '/')
  }

  def list = {
    // Recupere la liste des contacts
    def myList=Contact.list()

    // place dans une Map cette liste avec la cle contactInstanceList
    [contactInstanceList: myList]
  }
...
</pre>
<p>Convention au lieu de configuration : pour afficher le résultat il suffit de créer un fichier list.gsp dans le répertoire views/contact. Ce fichier sera automatiquement appelé par Grails à la fin de l&#8217;exécution de la méthode list. Nous allons donc récupérer une liste de Contacts. Pour itérer cette collection du côté de la vue, nous utiliserons le tag &lt;g:each&gt;. Ce tag prend en argument une collection, et vous retourne une variable qu&#8217;il suffit d&#8217;utiliser. L&#8217;attribut status est un compteur très pratique lorsque vous souhaitez afficher une ligne sur deux dans un tableau avec une autre couleur. Il est possible d&#8217;utiliser le tag fieldValue ou directement le nom du curseur (ici contactInstanceList) et d&#8217;appeler l&#8217;attribut qui vous intéresse. </p>
<pre class="brush:groovy">
&lt;g:each in="${contactInstanceList}"
                status="i"
                var="contactInstance"&gt;
    // version 1
    ${fieldValue(bean: contactInstance, field: "prenom")}
    // version 2 (voir explication)
   ${contactInstance?.nom}
    &lt;br/&gt;
&lt;/g:each&gt;
</pre>
<p>Vous voyez ce point d&#8217;interrogation à la ligne 7 ?<br />
C&#8217;est un pattern de Groovy appelé <a href="http://grailslog.blogspot.com/2008/09/safe-dereferencing-with-operator.html">Safe Dereferencing</a> qui dit en quelque sorte : &laquo;&nbsp;<em>&#8230;si tu as une valeur pour contactInstance alors appelle getNom() sinon ne fait rien</em>&laquo;&nbsp;. C&#8217;est un moyen de gérer les valeurs nulles sans if/then/else supplémentaire. </p>
<p>Voilà comment afficher une collection : appeler l&#8217;un des finders, retourner la liste vers la vue et itérer la collection avec un curseur. Pour terminer nous allons afficher les noms des utilisateurs par ordre alphabétique. C&#8217;est très simple, il suffit d&#8217;utiliser le finder adéquat :</p>
<pre class="brush:groovy">
 def list = {
    // Recupere la liste des contacts triee par Nom
    def myList=Contact.listOrderByNom()

    // place dans une Map cette liste avec la cle contactInstanceList
    [contactInstanceList: myList]
  }
</pre>
<p>Voilà je vous laisse souffler et imaginez ce qu&#8217;il faudrait faire en Java avec du Spring et un peu d&#8217;Hibernate&#8230; Ce que j&#8217;aime dans Grails c&#8217;est que si vous voulez tester quelque chose rapidement, c&#8217;est faisable. </p>
<p><strong>Paginer nos 102020 enregistrements sans pleurer</strong><br />
Tant qu&#8217;à faire, nous allons aussi préparer de quoi gérer la pagination. Imaginez que la base de données contienne beaucoup d&#8217;enregistrements. Il serait souhaitable de limiter le nombre d&#8217;enregistrement retournés et de paginer les résultats non ? Tout d&#8217;abord nous ajoutons le tag paginate dans le fichier list.gsp après le tag g:each. Ce tag va générer automatiquement les liens de navigation, le nombre de pages, bref toute l&#8217;artillerie nécessaire pour naviguer dans la liste des résultats. Si ce tag ne vous plaît pas, n&#8217;oubliez pas que vous pouvez créer le vôtre.<br />
Pour l&#8217;instant on note l&#8217;apparition d&#8217;un nouveau paramètre appelé contactInstanceTotal dans la vue :</p>
<pre class="brush:groovy">
&lt;g:each in="${contactInstanceList}"
                status="i"
                var="contactInstance"&gt;
    // version 1
    ${fieldValue(bean: contactInstance, field: "prenom")}
    // version 2 (voir explication)
   ${contactInstance?.nom}
    &lt;br/&gt;
&lt;/g:each&gt;
  &lt;g:paginate total="${contactInstanceTotal}"/>
</pre>
<p>Je modifie maintenant le code du Controller afin de gérer la pagination. Il est intéressant de vous expliquer en détail ce qui se passe dans ces 2 lignes car nous avons là plusieurs notions qui n&#8217;existent pas en Java, et qui viennent du monde de Groovy.</p>
<pre class="brush:groovy">
  def list = {
    params.max = Math.min(params.max ? params.max.toInteger() : 10, 100)
    [contactInstanceList: Contact.listOrderByNom(params), contactInstanceTotal: Contact.count()]
  }
</pre>
<p>Tout d&#8217;abord les paramètres de la requête HTTP (GET ou POST) sont automatiquement placés dans une Map appelé <em>params</em>.<br />
Vous pouvez écrire params.get(&laquo;&nbsp;max&nbsp;&raquo;) ou directement params.max afin de récupérer la valeur d&#8217;un paramètre HTTP.</p>
<pre>
params.max
</pre>
<p>Ensuite vous reconnaissez l&#8217;opérateur ternaire du monde java qui dit &laquo;&nbsp;<em>si le parametre max est spécifié alors prendre sa valeur en le transformant en un Interger, sinon prend 10</em>&nbsp;&raquo;</p>
<pre>
params.max ? params.max.toInteger() : 10
</pre>
<p>Cela me permet de vous donner un petit cours de Groovy et de vous parler de l&#8217;opérateur Elvis. L&#8217;opérateur Elvis comme en Java est un opérateur ternaire (If&#8230; then&#8230; else&#8230;) qui se lit de cette façon : </p>
<pre>&lt;condition&gt; ? &lt;expr1&gt; : &lt;expr2&gt;</pre>
<p>Si la condition est vraie alors l&#8217;opérateur 1 est évalué, sinon ce sera l&#8217;opérateur 2. Nous pourrions par exemple écrire en Java ce bout de code qui affecte le nom de la personne :</p>
<pre class="brush:java">

String name = (person.getName() != null) ? person.getName() : "unknown"
</pre>
<p>Groovy étant capable de simplifier cela, un nouvel opérateur noté ?: permet de raccourcir cette expression simplement :</p>
<pre class="brush:groovy">

// groovy
def name = person.getName() ?: "unknown"
</pre>
<p>L&#8217;opérateur Elvis en Groovy retourne le contenu de ce qu&#8217;il a sur la tête (à gauche) si cette expression est vraie, sinon ce qu&#8217;il a en dessous (à droite). </p>
<p>Reprenons les quelques lignes de la méthode list de ContactController :</p>
<pre class="brush:groovy">

  def list = {
    params.max = Math.min(params.max ? params.max.toInteger() : 10, 100)
    [contactInstanceList: Contact.listOrderByNom(params), contactInstanceTotal: Contact.count()]
  }
</pre>
<p>La première ligne s&#8217;assure que le paramètre max existe et qu&#8217;il est dans une plage de valeur authorisée. La seconde ligne passe directement la map &laquo;&nbsp;params&nbsp;&raquo; à la méthode listOrderByNom. Grails utilise à mort ce principe de convention au lieu de la configuration. Il se trouve que cette méthode listXXX recherche automatiquement une clé &laquo;&nbsp;max&nbsp;&raquo; pour toute Map que vous lui passez en argument&#8230; Là je reconnais qu&#8217;il faut lire la documentation pour le savoir. Nous perdons en expressivité ce que l&#8217;on gagne en raccourci. Bref ce paramètre max va permettre de limiter le nombre d&#8217;enregistrements retournés. Enfin pour initialiser le nombre de contacts, nous utilisons la méthode count qui se charge de vous donner le nombre de contacts en base. C&#8217;est simple non ? </p>
<p><strong>Faire un lien vers une autre page (méga super dur)</strong><br />
Bon quoi d&#8217;autre ? Il faut afficher une image devant chaque contact et créer un lien sur une image afin d&#8217;aller vers la page édition lorsque la personne clique dessus. Voici tout d&#8217;abord le code partiel de la page list.gsp :  </p>
<pre class="brush:html">
// Iteration sur la liste des contacts tries par nom
&lt;g:each in="${contactInstanceListByName}"
                status="i"
                var="contactInstance"&gt;
     &lt;img src='&lt;g:resource dir="images" file="people.png"/&gt;' alt="icon"/&gt;
     ${contactInstance.prenom}
     ${contactInstance.nom}

     &lt;g:link action="show" id="${contactInstance.id}"&gt;
       &lt;img src="${resource(dir: 'images', file: 'edit.png')}" alt="edit" border="0"/&gt;
     &lt;/g:link&gt;
     &lt;br/&gt;
   &lt;/g:each&gt;
   &lt;div class="paginateButtons"&gt;
     &lt;g:paginate total="${contactInstanceTotal}"/&gt;
   &lt;/div&gt;

&lt;div class="contact"&gt;
  &lt;g:include action="create" controller="contact"/&gt;
&lt;/div&gt;
</pre>
<p>Ligne 5 : chargement d&#8217;une image<br />
Ligne 9 : utilisation du tag g:link. Nous allons appeler la méthode show du controleur ContactController. A noter que vous pouvez spécifier un autre controleur, que vous pouvez passer des paramètres, etc. Ce tag est assez puissant, <a href="http://www.grails.org/Tag+-+link">la documentation</a> vous donnera un aperçu de ce qu&#8217;il est possible de faire facilement.<br />
Ligne 14/15 et 16 nous retrouvons notre pagination avec une feuille de style pour l&#8217;affichage. </p>
<p>Dans le cahier des charges de Zenika il est demandé aussi d&#8217;utiliser une autre page et de l&#8217;inclure dans la page qui liste les contacts. Le tag g:include permet de spécifier le nom d&#8217;un controller et d&#8217;une action précise afin de charger la vue. Ligne 19 nous appelons l&#8217;action create de ContactController, et voilà c&#8217;est tout pour l&#8217;instant.</p>
<p><strong>Reste à faire</strong><br />
Il reste maintenant 2 étapes compliquées :<br />
- mettre en place l&#8217;édition &laquo;&nbsp;in-place&nbsp;&raquo; du nom de famille<br />
- mettre en place un formulaire Ajax afin d&#8217;ajouter rapidement un nouvel utilisateur</p>
<p>Nous verrons dans le troisième article comment écrire un tag personnalisé et ensuite comment mettre en place un formulaire Ajax en 3mn top chrono. </p>
<p>A demain pour la suite ! </contact></p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2009/12/29/grails-etape-2-iterer-une-collection-et-afficher-le-resultat/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Grails : l&#8217;application Zencontact de Zenika</title>
		<link>http://www.touilleur-express.fr/2009/12/20/grails-lapplication-zencontact-de-zenika/</link>
		<comments>http://www.touilleur-express.fr/2009/12/20/grails-lapplication-zencontact-de-zenika/#comments</comments>
		<pubDate>Sun, 20 Dec 2009 22:36:56 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[grails]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=2689</guid>
		<description><![CDATA[Le 10 mars 2009, Zenika a présenté Apache Wicket au Paris JUG. Carl Azoury et Nicolas André ont construit en une heure une application de gestion simple, avec des fonctionnalités avancées en Ajax. L&#8217;objet de l&#8217;article c&#8217;est de vous montrer, vidéo à l&#8217;appui, comment construire la même application avec Grails. Le gros plus : je vais réellement persister mes Contacts en base, sans efforts supplémentaires, là où la version Wicket s&#8217;arrête à la partie Web, sans la partie persistance de l&#8217;application.
Le cahier des charges proposé par Zenika est très clair, ...]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.touilleur-express.fr/2009/03/11/compte-rendu-de-la-presentation-de-wicket-et-du-web-semantique/">Le 10 mars 2009</a>, Zenika a présenté Apache Wicket au Paris JUG. Carl Azoury et Nicolas André ont construit en une heure une application de gestion simple, avec des fonctionnalités avancées en Ajax. L&#8217;objet de l&#8217;article c&#8217;est de vous montrer, vidéo à l&#8217;appui, comment construire la même application avec Grails. Le gros plus : je vais réellement persister mes Contacts en base, sans efforts supplémentaires, là où la version Wicket s&#8217;arrête à la partie Web, sans la partie persistance de l&#8217;application.</p>
<p>Le cahier des charges proposé par Zenika est très clair, vous pouvez retrouver <a href="http://blog.zenika.com/index.php?post/2009/03/10/Concours-D%C3%A9velopper-une-application-web-en-Wicket3">à cette adresse</a> la liste détaillée des fonctions à coder.</p>
<p><strong>Le résultat final</strong><br />
Voici la liste du cahier des charges. Pour chaque élément j&#8217;ai mis en italique les points inutiles pour Grails et en rouge les fonctions que je n&#8217;ai pas développé.<br />
    * La navigation entre pages<br />
    * L&#8217;organisation d&#8217;une structure commune des pages (Type Tiles / Sitemesh)<br />
    * <font color="darkred">La désactivation du lien correspondant à la page courante</font><br />
    * L&#8217;édition d&#8217;un contact<br />
    * La création d&#8217;un contact<br />
    * Lister les contacts<br />
    * L&#8217;ajout rapide d&#8217;un contact dans une liste<br />
    * Le refresh de la date courante via appels Ajax<br />
    * L&#8217;édition &laquo;&nbsp;in place&nbsp;&raquo; d&#8217;un libellé sans passer par un écran d&#8217;édition<br />
    * L&#8217;ajout de la validation (Nom et prénom obligatoires, contrôle du format date, contrôle du type email)<br />
    * Utilisation d&#8217;un date picker<br />
    * <em>Synchronisation du format du DatePicker avec le format utilisé par le convertisseur</em><br />
    * <em>Ajout des mêmes contrôles de validation côté client, en Javascript</em><br />
    * Gestion de la problématique du refresh afin d&#8217;éviter la double soumission<br />
    * <font color="darkred">Non duplication du code du formulaire&#8230; le même composant doit être utilisé pour la page d&#8217;édition de contacts et de liste des contacts</font><br />
    * <font color="darkred">Le drag &#038; drop depuis la liste vers le formulaire d&#8217;édition</font> (en fait même sur ma version Wicket cela ne marchait pas)<br />
    * L&#8217;affichage de message d&#8217;erreurs<br />
    * <em>La réutilisation des mêmes messages d&#8217;erreurs en validation serveur et javascript</em><br />
    * Le tri de la liste des contacts par nom et par prénom</p>
<p><strong>Le résultat final</strong></p>
<p>Avant tout, voici une vidéo du résultat final. </p>
<p><object width="698" height="661"><param name="movie" value="http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/da22ad34-585f-49fe-92bb-527390045701/jingh264player.swf"></param><param name="quality" value="high"></param><param name="bgcolor" value="#FFFFFF"></param><param name="flashVars" value="thumb=http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/da22ad34-585f-49fe-92bb-527390045701/FirstFrame.jpg&#038;containerwidth=698&#038;containerheight=661&#038;content=http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/da22ad34-585f-49fe-92bb-527390045701/00000006.mp4"></param><param name="allowFullScreen" value="true"></param><param name="scale" value="showall"></param><param name="allowScriptAccess" value="always"></param><param name="base" value="http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/da22ad34-585f-49fe-92bb-527390045701/"></param>  <embed src="http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/da22ad34-585f-49fe-92bb-527390045701/jingh264player.swf" quality="high" bgcolor="#FFFFFF" width="698" height="661" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/da22ad34-585f-49fe-92bb-527390045701/FirstFrame.jpg&#038;containerwidth=698&#038;containerheight=661&#038;content=http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/da22ad34-585f-49fe-92bb-527390045701/00000006.mp4" allowFullScreen="true" base="http://content.screencast.com/users/nmartignole/folders/Le%20Touilleur%20Express/media/da22ad34-585f-49fe-92bb-527390045701/" scale="showall"></embed></object></p>
<p><strong>Les fonctions non réalisées</strong><br />
Je n&#8217;ai pas codé la fonction qui désactive dans le menu du haut la page courante. Cela serait possible en codant un taglib dans Grails, mais ce n&#8217;est pas disponible par défaut.<br />
Pour des raisons de problèmes Javascript, dans cette version j&#8217;ai créé 2 pages distinctes pour implémenter d&#8217;une part la saisie rapide et d&#8217;autre part l&#8217;édition inPlace. Une page utilise Scriptaculous, une autre page utilise Prototype. Il faut voir pourquoi lorsque j&#8217;ai les deux sur la même page cela ne fonctionne pas.<br />
Enfin concernant la non-duplication du code, par défaut la pratique de Grails propose de créer une page gsp par action, ce que j&#8217;ai fait pour simplifier le code. Il est possible sinon de rappeler une vue. Sur ce point je n&#8217;ai pas bataillé. </p>
<p><strong>Ce que fait cette application en plus</strong><br />
Tout d&#8217;abord, c&#8217;est une vraie application avec une base de données, Hibernate, Spring, bref tout ce que vous avez l&#8217;habitude d&#8217;utiliser. En version développeur, j&#8217;utilise une base en mémoire HSQLDB qui est effacé à chaque redémarrage. En mode production nous pouvons utiliser n&#8217;importe quelle base supportée par Hibernate. </p>
<p>L&#8217;application est constituée d&#8217;une entité Contact associé à un contrôleur en charge de tout ce qui est opération CRUD (Create, Research, Update et Delete). </p>
<p>Au total, voici le nombre de fichiers et de lignes de code de l&#8217;application :</p>
<pre><code>
    +----------------------+-------+-------+
    | Name                 | Files |  LOC  |
    +----------------------+-------+-------+
    | Controllers          |     2 |   121 |
    | Domain Classes       |     1 |    12 |
    | Tag Libraries        |     1 |    26 |
    +----------------------+-------+-------+
    | Totals               |     4 |   159 |
    +----------------------+-------+-------+

</code></pre>
<p>Grails n&#8217;a besoin que de 4 classes : une classe Contact pour le domaine, un controlleur et une Taglib Grails pour me simplifier la vie. Si je dresse un tableau de comparaison des 2 versions :</p>
<table border="1">
<tr>
<th scope="col">&nbsp;</th>
<th scope="col">Code</th>
<th scope="col">Pages</th>
<th scope="col">Fichiers de conf</th>
<th scope="col">JS</th>
<th scope="col">Lignes de code</th>
</tr>
<tr>
<th scope="row">Wicket</th>
<td>7 fichiers java</td>
<td>5 pages HTML</td>
<td>1 seul ds web.xml</td>
<td>Aucuns</td>
<td>237 lignes</td>
</tr>
<tr>
<th scope="row">Grails</th>
<td>4 fichiers groovy</td>
<td>13 fichiers GSP</td>
<td>6 fichiers</td>
<td>Aucuns</td>
<td>158 lignes</td>
</tr>
</table>
<p>Grails est moins verbeux que la version Java. J&#8217;ai utilisé l&#8217;utilitaire <a href="http://cloc.sourceforge.net/">CLOC</a> en renommant les fichiers groovy en java, afin de regarder la quantité de code. Attention cependant : Grails génère des fichiers groovy de travail dans un répertoire caché et le nombre total de lignes de code est de 787 lignes. Mais si l&#8217;on regarde le nombre de lignes que l&#8217;on manipule, c&#8217;est bien 158 lignes. N&#8217;oubliez pas que l&#8217;application persiste réellement dans une base de données les Contacts. </p>
<p><strong>Comment créer son application en 8 minutes ?</strong><br />
Assez parlé, il est temps peut-être de voir comment créer cette application. Tout compris, j&#8217;ai passé presque 2h30 pour réaliser l&#8217;ensemble de l&#8217;application. J&#8217;ai perdu beaucoup de temps sur la partie Ajax, ne connaissant pas encore les plugins de Grails par coeur. Par contre, et c&#8217;est ce que je veux vous montrer, j&#8217;ai écris le coeur de l&#8217;application en 8 minutes. </p>
<p>Pré-requis:<br />
- Téléchargez <a href="http://www.grails.org/Download">Grails 1.2-RC2</a> et décompressez l&#8217;archive dans un répertoire C:\grails par exemple<br />
- Ajoutez une variable d&#8217;environnement sous Windows appelé GRAILS_HOME qui pointe vers C:\grails.<br />
- Ajouter ensuite %GRAILS_HOME%\bin dans votre variable PATH sous windows afin que Grails se trouve dans le path. Ouvrez un terminal et vérifiez que tout fonctionne avec &laquo;&nbsp;grails -version&nbsp;&raquo;<br />
- Sous Unix, éditez votre fichier .bash_profile et ajouter la variable GRAILS_HOME. Ajoutez aussi GRAILS_HOME/bin à votre PATH. Validez l&#8217;installation avec &laquo;&nbsp;grails -version&nbsp;&raquo;</p>
<p>Ok c&#8217;était facile. On continue ? </p>
<p>Dans un répertoire, nous allons créer une application zencontact :</p>
<pre><code>
grails create-app zencontactdemo
...
...
</code></pre>
<p>Ensuite déplacez vous dans le répertoire zencontact. Nous allons commencer par créer notre entité &laquo;&nbsp;Contact&nbsp;&raquo; avec la commande create-domain-class :</p>
<pre><code>
cd zencontactdemo
grails create-domain-class  org.letouilleur.demo.Contact
...
</code></pre>
<p>Maintenant, nous avons besoin d&#8217;un Controller et de pages par défaut pour la partie CRUD. La commande generate-all va créer un Controller pour afficher, éditer, supprimer et modifier les entités de type Contact. Il va aussi créer un ensemble de pages GSP pour chacune de ces actions. Le modèle est donc la class Contact, le contrôleur sera le fichier ContactController et enfin les vues seront l&#8217;ensemble des pages GSP (edit.gsp, index.gsp, create.gsp&#8230;) correspondant à chacune des actions du contrôleur Grails.</p>
<pre><code>
grails generate-all  org.letouilleur.demo.Contact
</code></pre>
<p>Je ne sais pas pour vous&#8230; mais comme cela fait déjà 6 minutes il faudrait peut-être tester non ? Alors nous allons lancer un serveur Jetty préconfiguré et déjà intégré à notre application. C&#8217;est le mode &laquo;&nbsp;développement&nbsp;&raquo; qui permet de travailler très rapidement sans devoir installer un serveur. La base de données est vraiment là, c&#8217;est une base en mémoire HSQLDB. Par défaut, en mode développement Grails efface et recrée la base et les tables à chaque redémarrage. Vous pouvez changer ce comportement bien sûr&#8230; En fait vous pouvez tout faire. </p>
<p>Bref nous allons démarrer notre serveur et ensuite regarder la tête de notre application pour l&#8217;instant :</p>
<pre><code>
grails run-app
...
Environment set to development
  [groovyc] Compiling 1 source file to /Users/nicolas/.grails/1.2-M4/projects/zencontactdemo/target/classes
Running Grails application..
Server running. Browse to http://localhost:8080/zencontactdemo
</code></pre>
<p>Si vous ouvrez maintenant votre navigateur favori vous devriez voir ceci :<br />
<img src="http://www.touilleur-express.fr/wp-content/00000007-300x251.png" alt="00000007" title="00000007" width="300" height="251" class="alignnone size-medium wp-image-2699" /></p>
<p>Par contre si vous cliquez sur notre premier contrôler, le moins que l&#8217;on puisse dire c&#8217;est que pour l&#8217;instant il ne se passe rien non ?<br />
<img src="http://www.touilleur-express.fr/wp-content/grails01.png" alt="grails01" title="grails01" width="250" height="213" class="alignnone size-full wp-image-2701" /></p>
<p><strong>Etape 2 : le domaine</strong><br />
Pour l&#8217;instant il ne se passe rien car Grails ne sait pas trop quoi faire. Pour l&#8217;aider, arrêtez le serveur pour l&#8217;instant et éditez le fichier ./grails-app/domain/org/letouilleur/demo/Contact.groovy avec un éditeur de texte autre qu&#8217;Eclipse :</p>
<p>En suivant le cahier des charges, nous allons déclarer les attributs nom, prenom comme obligatoire. Remarquez aussi que le champ email est typé comme étant une adresse email. Groovy est expressig et Grails s&#8217;en sert simplement pour construire tout ce dont il a besoin. La validation, l&#8217;affichage des messages d&#8217;erreurs, les contraintes en base : la validation est déclarée ici une fois pour toute. Comme Beans Validator, Grails pense que le meilleur endroit pour déclarer les contraintes d&#8217;un modèle sont dans le modèle lui-même. Pas dans le GUI, pas dans la base. Cependant, la base de données qui est créé automatiquement par Grails reprendra ces contraintes afin de typer correctement les colonnes. </p>
<pre class="brush:groovy">
class Contact {
	String nom
	String prenom
	Date dateNaissance
	String email

	static constraints={
		prenom(blank:false)
		nom(blank:false)
		dateNaissance(max:new Date(),nullable:true)
		email(email:true,nullable:true,blank:true,unique:true)
	}
}
</pre>
<p>Après avoir changé autant notre domaine, nous allons simplement recréer toutes les vues et le contrôleur, avant de relancer le serveur. En ligne de commande, relancez la génération de cet ensemble et répondez &laquo;&nbsp;a&nbsp;&raquo; pour ALL lorsque Grails vous demande si vous voulez écraser vos anciens fichiers :</p>
<pre><code>
grails generate-all org.letouilleur.demo.Contact
...
File [...]/zencontactdemo/grails-app/views/contact/create.gsp already exists. Overwrite? [y,n,a] a

</code>
</pre>
<p>Puis relancez le serveur (grails run-app) et revenons à notre page &laquo;&nbsp;contact&nbsp;&raquo;. Vous pouvez maintenant créer un contact avec les champs que nous avons simplement déclaré dans notre POGO (Plain Old Groovy Object). Si vous cliquez sur &laquo;&nbsp;New Contact&nbsp;&raquo; vous pouvez maintenant vraiment créer des contacts et les stocker en base. Pas mal non au bout de 8 minutes ?<br />
<img src="http://www.touilleur-express.fr/wp-content/grails_etape2.png" alt="grails_etape2" title="grails_etape2" width="415" height="227" class="alignnone size-full wp-image-2707" /></p>
<p><strong>Etape 3 : mettre en place le template</strong><br />
A cette étape nous avons une class ContactController.groovy qui nous donne toutes les fonctions du cahier des charges. Il suffit maintenant de travailler sur la vue, d&#8217;adapter un peu certaines parties, mais vous verrez que c&#8217;est plutôt simple. Tout d&#8217;abord, recopiez les images et la feuille CSS de Zenika dans le répertoire <em>web-app</em> de votre application. Nous allons débuter par modifier la page d&#8217;accueil. Il faut s&#8217;occuper du menu de navigation et de l&#8217;affichage de l&#8217;heure en temps réel. </p>
<p>Dans le répertoire &laquo;&nbsp;grails-app/views/layouts/&nbsp;&raquo; nous allons d&#8217;abord nous attaquer au template. Grails utilise SiteMesh, et nous devons montrer qu&#8217;il est possible de définir le look and feel à un seul endroit. Pour cela je vais d&#8217;abord éditer le fichier main.gsp. Notez à la ligne 6 que ce tag permettra aux pages qui utiliseront ce template d&#8217;ajouter dans le HEADER du contenu. A la ligne 7 j&#8217;importe la librairie prototype. Un souci avec scriptaculous m&#8217;a obligé à déclarer un deuxième template &laquo;&nbsp;main2.gsp&nbsp;&raquo; pour certaines pages. A la ligne 12 j&#8217;ai déclaré les différentes URLs de mon application. Ici, en principe en Grails la bonne pratique veut que l&#8217;on crée une taglibs. Je l&#8217;ai fait un peu plus bas pour vous expliquer le principe. Pour nous, s&#8217;agissant d&#8217;un bout de code qui n&#8217;est pas dupliqué autre part, je peux très bien déclarer mes URLs en dur (principe DRY).<br />
La ligne 21 permet de déclarer la zone où Grails ajoutera le contenu des pages filles, que nous allons modifier dans 2 minutes.</p>
<pre class="brush:html">
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;&lt;g:layoutTitle default="Zencontact"/&gt;&lt;/title&gt;
  &lt;link rel="stylesheet" href="${resource(dir: 'css', file: 'main.css')}"/&gt;
  &lt;link rel="shortcut icon" href="${resource(dir: 'images', file: 'favicon.ico')}" type="image/x-icon"/&gt;
  &lt;g:layoutHead/&gt;
  &lt;g:javascript library="prototype"/&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id="header"&gt;
  &lt;g:link controller="contact" action="index"&gt;Accueil&lt;/g:link&gt; |
  &lt;g:link controller="contact" action="listWithIcons"&gt;Liste des contacts&lt;/g:link&gt; |
  &lt;g:link controller="contact" action="list"&gt;Liste v2&lt;/g:link&gt; |
  &lt;g:link controller="contact" action="create"&gt;Ajouter un contact&lt;/g:link&gt;

&lt;/div&gt;
&lt;div id="content"&gt;
  &lt;div id="contacts"&gt;

    &lt;div class="contact"&gt;
      &lt;g:layoutBody/&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
&lt;div id="footer"&gt;
  &lt;p id="legal"&gt;&lt;a href="http://www.touilleurexpress.fr/"&gt;Le Touilleur Express&lt;/a&gt; Copyright© 2009-2010&lt;/p&gt;
&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Créer un deuxième fichier appelé main2.gsp dans le même répertoire, et changez simplement la ligne 7 en spécifiant &lt;g:javascript library=&nbsp;&raquo;scriptaculous&nbsp;&raquo;/&gt;. Voilà vous avez créé 2 templates pour le site</p>
<p><strong>Etape 4 : mettre en place la page d&#8217;accueil</strong><br />
La page d&#8217;accueil est simple. Elle affiche la navigation, et fait appel à une taglib pour afficher l&#8217;heure en temps réel. Cela va me permettre de vous expliquer comment créer une taglib et ensuite comment ajouter un contrôleur supplémentaire. Vous allez même faire de l&#8217;Ajax dès maintenant ! </p>
<p>Voyons le code de cette page tout d&#8217;abord :</p>
<pre class="brush:html">
&lt;html&gt;
&lt;head&gt;
  &lt;title&gt;Zencontact avec Grails 1.2-M4&lt;/title&gt;
  &lt;meta name="layout" content="main2"/&gt;

&lt;/head&gt;
&lt;body&gt;
&lt;table&gt;
  &lt;tbody&gt;&lt;tr&gt;
    &lt;td width="300px"&gt;&lt;img src="images/zenika_logo.png"&gt;&lt;/td&gt;
    &lt;td width="300px"&gt;&lt;img src="images/pjug_logo.png"&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;/tbody&gt;&lt;/table&gt;
&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;!-- Appel d'un tag custom cree dans taglibs pr afficher la date --&gt;
&lt;div&gt;&lt;g:showDateAndTime/&gt;&lt;/div&gt;

&lt;P&gt;Voici la version Grails 1.2 de la démonstration Wicket de Zenika réalisée début mars 2009 au Paris Java User Group.
  Nous retrouvons les fonctions du cahier des charges avec surtout un Controller complet capable de réellement créer,
  modifier et effacer un objet Contact.&lt;/P&gt;

&lt;/body&gt;
&lt;/html&gt;
</pre>
<p>Explications :<br />
- la ligne 4 spécifie que nous utiliserons le template &laquo;&nbsp;main2&#8243; pour cette page. En effet, notre taglib pour afficher l&#8217;heure utilise Scriptaculous.<br />
- la ligne 16 devrait vous intriguer&#8230; C&#8217;est une taglib, et pour l&#8217;instant elle n&#8217;existe pas </p>
<p>Pour créer la taglib vous devez exécutez la commande suivante, relancez le serveur à la fin de la commande et laissez-le tourner. </p>
<pre>
grails create-tag-lib Tools
...
WARNING: You have not specified a package. It is good practise to place classes in packages (eg. mycompany.Book). Do you want to continue? (y, n)
y
...

grails run-app
...
</pre>
<p>Editez ensuite le fichier grails-app/taglib/ToolsTagLib.groovy et copiez-y ce bout de code:</p>
<pre class="brush:groovy">
class ToolsTagLib {
  def showDateAndTime = {attrs -&gt;
   out &lt;&lt; "&lt;script type='text/javascript'&gt;"
   out &lt;&lt; "new Ajax.PeriodicalUpdater('timerDiv', '/zencontactdemo/timer/getTime' , "
   out &lt;&lt; "{method: 'get',frequency: 1,decay: 1});"
   out &lt;&lt; "&lt;/script&gt;"
   out &lt;&lt; "&lt;div id='timerDiv'&gt;&lt;/div&gt;"
  }
}
</pre>
<p>Une taglib est automatiquement importée et devient disponible dès lors que vous la déclarez dans votre page. La ligne 16 de notre fichier index.gsp de tout à l&#8217;heure est presque prête à fonctionner. Si vous regardez le code groovy de ce tag, vous verrez que j&#8217;utilise Scriptaculous et sa fonction Ajax.PeriodicalUpdater afin d&#8217;appeler l&#8217;url /zencontactdemo/timer/getTime. Cependant pour l&#8217;instant, il n&#8217;y a pas de contrôleur associé. Nous allons donc créer un contrôleur et y ajouter la méthode getTime.</p>
<pre>
grails create-controller org.letouilleur.demo.Timer
...
</pre>
<p>Editez le fichier grails-app/controllers/org/letouilleur/demo/TimerController.groovy, voici comment celui-ci se présente par défaut :</p>
<pre class="brush:groovy">
package org.letouilleur.demo

class TimerController {

    def index = { }
}
</pre>
<p>En Grails, un Controller c&#8217;est une URL, et une méthode, c&#8217;est une sous-url de ce Controller. Ajoutez maintenant un fichier index.gsp dans le répertoire grails-app/views/timer. Vous l&#8217;aurez compris : chaque Controller a son répertoire, et une action correspond à un fichier de vue. Dans le fichier index.gsp, mettez &laquo;&nbsp;Coucou&nbsp;&raquo; et ensuite lancez le serveur si celui-ci est éteint. Vous verrez que l&#8217;url http://localhost:8080/zencontactdemo/timer fonctionne et affiche &laquo;&nbsp;Coucou&nbsp;&raquo;.<br />
Par ailleurs, si vous éditez le fichier index.gsp et que vous rechargez la page, <strong>votre modification est prise en compte sans relancer le serveur</strong> comme avec Tapestry.<br />
Mais pas comme Wicket.<br />
Je vais faire mal là où cela fait mal. Avec Wicket il faut relancer le serveur dès lors que vous touchez à la partie Java. Avec Grails, vous êtes tranquille tant que vous n&#8217;ajoutez pas de nouveaux Controller ou que vous ne modifiez pas une classe de la partie Domain. A l&#8217;usage, on relance moins Grails que Wicket. J&#8217;ai travaillé avec les deux, croyez-moi. </p>
<p>Pour terminer notre première page, il nous faut une méthode qui retourne la date et l&#8217;heure actuelle. </p>
<pre class="brush:groovy">
class TimerController {

  def index = { }

  def getTime = {
    def theTime = new java.text.SimpleDateFormat("HH:mm:ss dd MMMM yyyy").format(new Date())
    [currentTime: theTime]
  }
}
</pre>
<p>Ajoutez aussi un fichier <strong>getTime.gsp</strong> dans le répertoire /grails-app/views/timer avec ce contenu:</p>
<pre class="brush:html">
  Il est ${currentTime}
</pre>
<p>Pour tester le tout, ouvrez l&#8217;url <a href="http://localhost:8080/zencontactdemo/timer/getTime">http://localhost:8080/zencontactdemo/timer/getTime</a> et vous devriez voir votre message s&#8217;afficher. </p>
<p>Cette partie nous permet de voir comment Grails passe des paramètres du Modèle vers la Vue. La ligne 7 de la méthode getTime construit une Map avec pour clé  &laquo;&nbsp;currentTime&nbsp;&raquo; et pour valeur le contenu de ma chaîne &laquo;&nbsp;theTime&nbsp;&raquo;. Si je vous dis que derrière tout cela, c&#8217;est du Spring MVC, vous vous rendez compte de la simplicité de ce bout de code ?  Notre vue utilise la syntaxe ${currentTime$} pour afficher la valeur de l&#8217;objet passé en paramètre. C&#8217;est simple non ?</p>
<p>Il est temps maintenant de charger notre page de démarrage et de vérifier que l&#8217;heure change toutes les secondes.</p>
<p>Voilà pour la première page ! </p>
<p><img src="http://www.touilleur-express.fr/wp-content/grails_final_etape01.png" alt="grails_final_etape01" title="grails_final_etape01" width="654" height="497" class="alignnone size-full wp-image-2724" /></p>
<p>Je vous ai préparé un fichier zip avec l&#8217;ensemble du code de cette étape afin de vous aider si vous n&#8217;avez pas pu suivre toutes les explications. Cliquez-ici pour télécharger le fichier <a href="/code/grails_touilleur_etape1.tar.gz">grails_touilleur_etape1.tar.gz</a></p>
<p><strong>Conclusion etape 1</strong><br />
Je m&#8217;arrête là pour ce premier article. Si vous testez de votre côté vous verrez que la liste des contacts et l&#8217;ajout d&#8217;un nouveau contact fonctionne. A propos de validation, je ne sais pas si vous avez remarqué, mais l&#8217;email est vérifié. Si vous ne spécifiez pas de prénom ou de nom lors de la création, Grails vous affichera une erreur. Bref il ne reste plus qu&#8217;à implémenter les fonctions avancées de la liste de résultat, mais vous verrez que ce n&#8217;est pas beaucoup d&#8217;effort. </p>
<p>Grails est un framework Web qui va de la couche présentation à la partie service et métier. Il vous suprendra par la rapidité à laquelle vous produisez un résultat parfait. Si lors de la lecture vous avez pensé parfois que je donnais trop de détails, c&#8217;est aussi pour vous montrer un <strong>vrai</strong> projet et pas un simple HelloWorld. C&#8217;est aussi pour cette raison que je trouve l&#8217;idée de Zenika intéressante : puisque l&#8217;on dit que c&#8217;est simple, autant montrer un exemple qui marche en une heure ! Wicket est certainement plus intégré et plus fort pour une application orientée vue. Et c&#8217;est un très bon framework. Je pense que Grails vous séduira plus par la partie Hibernate/CRUD que par la partie vue, qui reste simple. Du côté Ajax et Javascrpit j&#8217;ai un peu galéré, et là où Wicket propose des composants prêts à l&#8217;emploi, j&#8217;ai dû bidouiller pour couvrir le cahier des charges. J&#8217;exagère un peu car d&#8217;un autre côté, certaines fonctions sont très simples avec Grails. Vous souhaitez la liste de tous les contacts triés par nom ? En Grails c&#8217;est Contact.listAllByNom() que vous placez dans une list, et que vous itérez du côté de la vue&#8230; </p>
<p>Nous verrons la prochaine fois que j&#8217;ai fait appel à des plugins pour compléter mon application. La vidéo vous montre le résultat terminé en moins de 5 minutes. La suite de cet article sera en ligne dans une semaine. </p>
<p>A bientôt !</p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2009/12/20/grails-lapplication-zencontact-de-zenika/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Grails en quelques mots</title>
		<link>http://www.touilleur-express.fr/2009/12/19/grails-en-quelques-mots/</link>
		<comments>http://www.touilleur-express.fr/2009/12/19/grails-en-quelques-mots/#comments</comments>
		<pubDate>Fri, 18 Dec 2009 23:31:00 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[Startup]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=2678</guid>
		<description><![CDATA[ Je travaille depuis quelques mois avec le framework Web Grails.  Cela fait quelques semaines que je m&#8217;en sers presque 8 heures par jour. Je vous propose un petit tour du propriétaire. 
Grails est un framework Web basé sur le langage Groovy clairement orienté productivité. J&#8217;ai ramené 4 livres de Devoxx sur Groovy et Grails, et le meilleur ouvrage pour rentrer dedans reste &#171;&#160;Grails in Action&#160;&#187; de Glen Smith et Peter Ledbrook. 470 pages plus tard vous serez en mesure de construire une application industrielle, et il vous manquera ...]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.touilleur-express.fr/wp-content/tag-150-150-grails1.jpg" alt="tag-150-150-grails" title="tag-150-150-grails" width="150" height="150" class="alignleft size-full wp-image-2685" /> Je travaille depuis quelques mois avec le framework Web Grails.  Cela fait quelques semaines que je m&#8217;en sers presque 8 heures par jour. Je vous propose un petit tour du propriétaire. </p>
<p><a href="http://www.grails.org">Grails</a> est un framework Web basé sur le langage Groovy clairement orienté productivité. J&#8217;ai ramené 4 livres de Devoxx sur Groovy et Grails, et le meilleur ouvrage pour rentrer dedans reste &laquo;&nbsp;<a href="http://www.manning.com/gsmith/">Grails in Action</a>&nbsp;&raquo; de Glen Smith et Peter Ledbrook. 470 pages plus tard vous serez en mesure de construire une application industrielle, et il vous manquera un peu de détails sur Groovy, facilement couvert par exemple avec &laquo;&nbsp;<a href="http://pragprog.com/titles/sdgrvr/groovy-recipes">Groovy Recipes</a>&nbsp;&raquo; de Scott Davis. </p>
<p>Grails s&#8217;installe en 5 minutes, se découvre en 30 minutes et se maîtrise en une semaine. Je me dis que si mon aventure de Startup ne marche pas, je pourrai toujours écrire un livre sur le sujet en Français. C&#8217;est vous dire si j&#8217;ai envie de vous en parler. </p>
<p><strong>Introduction à Grails</strong><br />
Grails m&#8217;est tombé dessus car j&#8217;avais besoin d&#8217;une solution pour démarrer rapidement, valider rapidement (et éventuellement me planter rapidement). Je me surprends à tester des bouts de code, à écrire des choses comme &laquo;&nbsp;Books.findByAuthor(&#8216;Guillaume Laforge&#8217;)&nbsp;&raquo; et à voir que Grails génère le code de ce finder pour moi&#8230; Envie d&#8217;Ajax ? je transforme mes tags form en remoteForm et ça marche. Envie de faire un formulaire avec 4 écrans ? Spring Webflow est intégré, le flow est écrit en Groovy, rien de plus simple&#8230; Et c&#8217;est comme cela depuis 3 semaines&#8230; Je n&#8217;arrête pas de m&#8217;étonner de la maturité et de la puissance de ce framework Web. </p>
<p><strong>Avec ou sans état ?</strong><br />
Grails comme Play! se classe dans la catégorie des frameworks Webs sans état. Il y a bien entendu une session, des scopes pour vous aider à travailler. Mais là où Wicket et JSF sont orientés composants, Grails est clairement orienté Web / HTTP. Il n&#8217;y a pas la notion d&#8217;Application et il n&#8217;y a pas la notion de composants comme en Wicket ou JSF2 par exemple. Nous pouvons donc dire que Grails est adapté pour la réalisation de projets plutôt Web, et il n&#8217;est pas forcément le plus adapté pour réaliser une application riche. Il y a pourtant des applications basées sur du Flex pour la couche de présentation qui travaillent avec une partie serveur en Grails pour les services. Cette alchimie fonctionne donc aussi.</p>
<p><strong>Fan des conventions au lieu de la configuration</strong><br />
Grails tire ses origines du framework Rails du monde Ruby. Mais il utilise le langage Groovy qui tourne sur la JVM. Ses cousins ? JRuby on Rails, Clojure, le framework Lift du monde Scala, et Play! du monde Java. C&#8217;est un framework Web clairement orienté productivité et simplicité. Pour moi, il fait parti des frameworks webs de 4ème génération. Il y a d&#8217;abord eu les JSPs, les Servlets et les Applets. Puis ensuite Struts avec les premiers frameworks MVC de type 2. Ensuite l&#8217;apparition des RIAs (<a href="http://www.touilleur-express.fr/2008/07/04/rich-internet-application-ou-pourquoi-on-vous-parle-de-ca/">Rich Internet Applications</a>) avec GWT, JSF, Wicket. Et donc maintenant je crois dur comme fer à ces nouveaux frameworks Webs, qui reviennent sur les bases du protocole HTTP pour offrir des performances et de la simplicité. </p>
<p>Grails est sorti en 2006. Il y a des sites en production comme <a href="http://www.businessworld.in/">Businessworld</a>, Sky.com ou encore <a href="https://www.escapeer.com/">Escapeer</a>. La page <a href="http://www.grails.org/Testimonials">Testimonials</a> donne une idée de quelques projets réalisés avec Grails et Groovy. </p>
<p>Groovy est le point fort de Grails. Je vous parlais de trouver des livres quelques lignes plus hauts. Vous pouvez aussi écrire des bouts de code comme par exemple:<br />
<code><br />
Book.findAllByDatePublishedGreaterThanAndTitleLike(myDate,"Grails par le Touilleur Express") </code></p>
<p>Grails sera capable de générer le code Hibernate, Spring et Groovy afin de trouver tous les livres dont la date de publication est postérieure à une date, et dont le titre ressemble à ce que je précise&#8230; Lorsque je vous dis que vous allez gagner du temps, vous commencez à me croire ? </p>
<p><strong>Grails utilise des standards</strong><br />
Grails utilise Groovy, et ensuite le couple Hibernate/Spring de base. Il est assez facile d&#8217;ajouter de nouvelles librairies grâce à des plugins. Dans mon projet par exemple j&#8217;utilise Drools. Je n&#8217;ai eu besoin que de 10 minutes pour créer un controleur simple et une règle Drools pour tester une idée. </p>
<p><strong>Les idées de Grails</strong><br />
Ce qui suit est tiré du livre &laquo;&nbsp;Grails in Action&nbsp;&raquo;. Il y a 7 idées clés à comprendre pour adopter Grails:<br />
- Convention au lieu de la Configuration<br />
- Philosophie Agile<br />
- Des fondations solides<br />
- Scaffolding et moteur de template<br />
- Intégration avec Java<br />
- Une communauté et des plugins<br />
- La Productivité améliore la qualité et réduit le risque d&#8217;erreur</p>
<p>Concernant <strong>l&#8217;aspect convention au lieu de configuration,</strong> cela revient à vous dire que pour gagner du temps, il faut suivre ce que dis le framework. J&#8217;ai juste un mot à dire aux gens qui font du Maven2, mais qui ne veulent pas ranger leurs fichiers dans src/main/java, qui désactivent les tests, qui veulent lancer des scripts Ant avec Maven : <strong>arrêtez Maven</strong>.<br />
Vous n&#8217;avez rien compris à sa philosophie, vous pleurez car &laquo;&nbsp;Maveneu il rameuu&nbsp;&raquo; alors que si vous aviez pris le soin de lire l&#8217;excellent livre &laquo;&nbsp;Apache Maven&nbsp;&raquo;, vous ne seriez pas comme un gosse avec le pantalon mouillé. Si vous commencez à bidouiller l&#8217;outil, c&#8217;est que vous n&#8217;avez pas lu la documentation, que vous n&#8217;avez pas écouté ce que vous disent les développeurs. A ce titre, je trouve que les livres que j&#8217;ai lu m&#8217;ont énormément aidés par rapport à la doc de Grails, qui ne distille pas assez la philosophie, à mon sens. Donc si vous voulez me suivre : achetez des livres sur Grails.</p>
<p>Grails est simple : une entité Survey est toujours stockée dans le répertoire domain. Cela permet à Grails de gérer l&#8217;object via Hibernate pour vous. Un controlleur est nommé SurveyController, et il est placé lui-aussi dans un endroit attendu par Grails. Si vous ajouter une méthode &laquo;&nbsp;completeSurvey&nbsp;&raquo;, celle-ci est alors accessible automatiquement via une url comme &laquo;&nbsp;/survey/completeSurvey&nbsp;&raquo;. Si vous créez une nouvelle entité &laquo;&nbsp;Answer&nbsp;&raquo;, Grails se charge de créer la table en base de données. Vous n&#8217;avez pas généré de fichiers pour tout ce qui est CRUD ? Grails le fait tout seul. Pour l&#8217;affichage des pages, il suffit de créez un fichier &laquo;&nbsp;/views/survey/completeSurvey.gsp&nbsp;&raquo; et il sera alors automatiquement chargé&#8230; </p>
<p>C&#8217;est bien de la Convention par dessus la Configuration et surtout pas de la Convention &laquo;&nbsp;au lieu de&nbsp;&raquo; la Configuration. Si vous voulez utiliser vos fichiers de mapping Hibernate : oui c&#8217;est possible. Mais par défaut : vous n&#8217;en n&#8217;avez pas besoin. Tout ce qu&#8217;il est possible de faire de manière répétitive et générique, c&#8217;est offert. Et comme vous aurez besoin de mettre le nez dedans, vous pouvez aussi le faire. </p>
<p>J&#8217;en suis à 16 classes pour mon domaine, à 2700 lignes de codes, 19 contrôleurs, et en 3 semaines j&#8217;ai déjà une application qui tourne&#8230; Je vous assure que je vous montrerai tout cela dans une vidéo très bientôt.</p>
<p><strong>Grails est adapté au développement Agile</strong>. En fait je pense même que l&#8217;on peut dire que c&#8217;est un framework Web Agile. Les tests unitaires comme les tests fonctionnels sont faciles à écrire. Le fait de pouvoir créer un War, c&#8217;est aussi très pratique. Je vous explique cela : j&#8217;ai installé un Tomcat sur une machine, avec une base MySQL. Sur mon Mac, en ligne de commande il suffit que je tappe &laquo;&nbsp;grails war production&nbsp;&raquo; pour que cela me construise un fichier WAR, qu&#8217;il me suffit de déployer ensuite sur Tomcat pour la version en production. A aucuns moments je n&#8217;ai eu besoin de mettre le nez dans un quelconque fichier web.xml&#8230;<br />
Au quotidien je ne construis pas de WAR. Je tappe simplement &laquo;&nbsp;grails run-app&nbsp;&raquo; et un serveur Jetty démarre, intégré à Grails. Lorsque je code, je n&#8217;arrête presque pas le serveur. En fait, lorsque vous changez un bout de page GSP, celle-ci se rafraîchit tout en gardant votre session. Si vous ajoutez une nouvelle méthode dans votre contrôleur, l&#8217;url est disponible et vous pouvez continuer à coder. Il n&#8217;y a qu&#8217;en cas de plantages que je relance parfois le serveur, lorsque ma session est pourrie. Je trouve que la remontée d&#8217;erreur pourrait encore faire des progrès par rapport à Play! mais c&#8217;est déjà pas mal. </p>
<p><strong>Grails est basé sur des fondations solides.</strong> Spring et Hibernate. Spring 3 depuis la toute dernière version 1.2.RC2 que je teste en ce moment. En fait vous ne voyez pas Hibernate et Spring, mais vous savez que vous pouvez aller voir si nécessaire. Le moteur de scheduling ? C&#8217;est Quartz. Le moteur de recherche ? Lucene et Compass pour les entités. Le moteur de construction ? SiteMesh&#8230; Bref il n&#8217;y a pas d&#8217;innovations. Nous parlons bien de techniques que vous connaissez déjà. Imaginez simplement ceci : écrire moins de code, travailler plus vite. </p>
<p><strong>Le moteur de scaffolding et de templating</strong>. J&#8217;adore Spring MVC. Je m&#8217;en suis servi l&#8217;été dernier pour mon projet sur Google App Engine (<a href="http://touilleur.appspot.com">http://touilleur.appspot.com</a>), projet que je ne finirai pas faute de temps. Grails est assez radical par rapport à Spring MVC. Là où vous auriez quelques beans annotés, des fichiers de configuration, un peu d&#8217;Hibernate et une configuration avec la base, Grails fait la même chose en quelques minutes.<br />
<code><br />
grails create-app myapp<br />
...<br />
...<br />
grails run-app<br />
</code><br />
Ouvrez votre navigateur : http://localhost:8080/myapp, c&#8217;est prêt. Ensuite si vous voulez ajouter un nouveau contrôler :<br />
<code><br />
grails create-controller MonControleur<br />
</code><br />
C&#8217;est tout ! </p>
<p>Lorsque vous créez une nouvelle entité, un nouvel objet du domaine, il est facile aussi pour Grails de vous générez automatiquement tout ce qui est CRUD. C&#8217;est ce que l&#8217;on appelle le scaffolding. Ce n&#8217;est pas destiné à remplacer votre application. En fait voici comment je travaille : je génère d&#8217;abord mes entités avec des idées à tester. Ensuite je crée un controleur pour cette entité en mode &laquo;&nbsp;scaffold&nbsp;&raquo;. Cela me permet de tester mon objet, de valider les relations one-to-one, one-to-many, many-to-many et de m&#8217;assurer que tout marche. Enfin, je refais un vrai contrôleur pour mon application finale, et je ne touche pas à ce que Grails m&#8217;a généré. Je recopie quelques petits bouts de code pour gagner du temps, mais c&#8217;est là que je code vraiment mon application. Cela me fait gagner un temps fou. </p>
<p><strong>L&#8217;intégration avec Java</strong> est là pour rassurer les bons pères de famille. Il y a un répertoire Java. Vous pouvez y placer ce que vous voulez. Pour peu qu&#8217;une librairie de votre ERP soit en Java, et qu&#8217;il soit nécessaire d&#8217;écrire un peu de code orienté Service, Grails vous aménage un espace dédié pour le faire, et se débrouille pour injecter vos services Java dans les contrôleurs Grails&#8230; C&#8217;est très pratique. Je m&#8217;en suis servi pour une partie avec du Drools, que j&#8217;ai migré vers du Groovy car finalement, c&#8217;est plus simple. </p>
<p><strong>Grails a une communauté</strong>. C&#8217;est bête, mais lorsque le lundi matin vous êtes seul dans votre bureau de 7m2, croyez-moi vous êtes super content de voir qu&#8217;il y a pleins de gens qui se servent de Grails sur Internet. Google est ton ami. La documentation est bonne. Le produit vit, et la liste de diffusion users est très active. J&#8217;ai appris beaucoup en lisant les échanges ces dernières semaines. Enfin côté livre je vous le disais tout à l&#8217;heure, il y a de très bons livres en Anglais. Si j&#8217;avais le temps et le courage, je me lancerai bien dans l&#8217;écriture d&#8217;un livre en Français. Mais je suis trop bavard&#8230; Pas possible pour moi. </p>
<p>Enfin pour terminer, le 7e point noté par les auteurs de Grails in Action, c&#8217;est l&#8217;aspect de productivité et la possibilité de valider ou non ses idées très rapidement. Pour notre projet qui sera en ligne l&#8217;été prochain, je me remercie chaque jour d&#8217;avoir pris Grails pour gagner du temps, faire des démonstrations qui marchent chaque semaine, jeter sans souci du code écrit en 3 jours au lieu de 2 semaines, bref je peux dormir tranquillement la nuit. Est-ce que tu comprends que je peux virer des idées foireuses car elles ne m&#8217;ont coutés que 2 jours au lieu de 2 semaines ? Un vrai projet de Startup c&#8217;est beaucoup d&#8217;essais. Personne ne vous dira si ce que vous faîtes c&#8217;est bien ou pas. Il faut avoir cette possibilité de changer de cap très rapidement, encore une fois dans le cadre d&#8217;une Startup pour moi.</p>
<p><strong>Conclusion</strong><br />
Pour terminer, je vous laisse ici ce soir. Je vous montrerai un peu de Grails, du vrai code, pas un &laquo;&nbsp;Hello World&nbsp;&raquo;, plutôt une application écrite en quelques heures, afin de vous faire comprendre ce qui a retenu mon attention.</p>
<p>Je pense aussi que nous, <strong>développeurs Javas</strong>, devons nous remettre en question d&#8217;urgence. En voyant des projets sur PHP ou Ruby on Rails, j&#8217;ai un peu la gueule de bois avec mon Java. Je pense que pour le développement d&#8217;applications Webs, il faut revoir notre manière de penser, notre manière de travailler. J&#8217;ai même du mal à croire au succès de Struts hier, de Wicket/Tapestry/JSF en ce moment&#8230; Comment pouvons-nous rouler des mécaniques alors que d&#8217;autres langages sont bien meilleurs pour faire du développement webs ? Que d&#8217;autres frameworks sont bien mieux pensés et bien moins prétentieux que ce que nous vendons depuis 3-4 ans à nos clients ? Comment avons-nous pu vendre des développements avec du Struts, des JSPs à des clients finaux ? Comment ? </p>
<p>Imaginez-vous entrain d&#8217;expliquer aux clients que les développeurs  sur certains projets doivent construire un WAR, arrêter et relancer leur serveur d&#8217;application avant de voir leur résultat&#8230; alors que c&#8217;est inutile avec Grails (et d&#8217;autres)&#8230;</p>
<p>Et encore, je ne vous ai même pas encore dit que j&#8217;étais aussi tombé amoureux de Groovy&#8230; </p>
<p>J&#8217;en garde pour la prochaine fois. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2009/12/19/grails-en-quelques-mots/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Premiers pas avec Grails 1.1.1 et Google AppEngine</title>
		<link>http://www.touilleur-express.fr/2009/06/09/premiers-pas-avec-grails-111-et-google-appengine/</link>
		<comments>http://www.touilleur-express.fr/2009/06/09/premiers-pas-avec-grails-111-et-google-appengine/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 12:05:24 +0000</pubDate>
		<dc:creator>Nicolas Martignole</dc:creator>
				<category><![CDATA[Java]]></category>
		<category><![CDATA[grails]]></category>
		<category><![CDATA[groovy]]></category>

		<guid isPermaLink="false">http://www.touilleur-express.fr/?p=1419</guid>
		<description><![CDATA[Ah là là&#8230; dire qu&#8217;à la fin de la lecture de ce billet j&#8217;aurai complètement changé votre vision du Web&#8230; Je comprends mieux maintenant Didier Girard de SFEIR, il y a un avant et un après Google AppEngine&#8230; Mais bon, soyons patient et voyons ce que nous pouvons faire aujourd&#8217;hui. Ce qui suit est inspiré, pour ne pas dire affreusement copié sur ce que Guillaume Laforge a présenté le 28 mai dernier lors de la conférence Google I/O à San Francisco. J&#8217;ai simplement adapté la présentation en français, je l&#8217;ai ...]]></description>
			<content:encoded><![CDATA[<p>Ah là là&#8230; dire qu&#8217;à la fin de la lecture de ce billet j&#8217;aurai complètement changé votre vision du Web&#8230; Je comprends mieux maintenant Didier Girard de SFEIR, il y a un avant et un après Google AppEngine&#8230; Mais bon, soyons patient et voyons ce que nous pouvons faire aujourd&#8217;hui. Ce qui suit est inspiré, pour ne pas dire affreusement copié sur ce que Guillaume Laforge a présenté <a href="http://www.youtube.com/watch?v=NEnniZTdOYk">le 28 mai dernier lors de la conférence Google I/O</a> à San Francisco. J&#8217;ai simplement adapté la présentation en français, je l&#8217;ai fait fonctionner, pour le reste tout le crédit va à Guillaume.<br />
<div id="attachment_1427" class="wp-caption alignnone" style="width: 401px"><img src="http://www.touilleur-express.fr/wp-content/glaforge.jpg" alt="Guillaume Laforge Google IO 2009" title="glaforge" width="391" height="325" class="size-full wp-image-1427" /><p class="wp-caption-text">Guillaume Laforge Google IO 2009</p></div></p>
<p>A la fin de cet article vous serez en mesure de déployer sur Google AppEngine une petite application simple.</p>
<p><strong>Installer Grails</strong><br />
<a href="http://grails.org/Download">Téléchargez</a> et installer Grails 1.1.1. Pour ma part, sur Mac OS j&#8217;ai ensuite édité mon fichier .bash_profile afin de déclarer le chemin d&#8217;installation de Grails, et fixer la version de Java à la version 5 pour éviter quelques soucis plus tard avec Google AppEngine et DataNucleus.<br />
Voici le contenu du fichier $HOME/.bash_profile</p>
<pre name="code">
export M2_HOME=/usr/share/maven
export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Home
export GRAILS_HOME=/Users/nicolas/Dev/grails/grails-1.1.1
export APPENGINE_HOME=/Users/nicolas/Dev/appengine-java-sdk-1.2.1
export PATH=$PATH:$GRAILS_HOME/bin
</pre>
<p>Vérifiez que Grails est correctement installé avant d&#8217;aller plus loin:</p>
<pre>
macbook-pro-de-nicolas-martignole:~ nicolas$ export GRAILS_HOME=/Users/nicolas/Dev/grails/grails-1.1.1
macbook-pro-de-nicolas-martignole:~ nicolas$ export PATH=$PATH:$GRAILS_HOME/bin
macbook-pro-de-nicolas-martignole:~ nicolas$ grails -version
Welcome to Grails 1.1.1 - http://grails.org/
Licensed under Apache Standard License 2.0
Grails home is set to: /Users/nicolas/Dev/grails/grails-1.1.1

Base Directory: /Users/nicolas
Running pre-compiled script
Script not found: Version
macbook-pro-de-nicolas-martignole:~ nicolas$ 
</pre>
<p>Les observateurs ont remarqué certainement la variable APPENGINE_HOME. Il est temps de télécharger Google AppEngine, après avoir demandé un compte. Suivez attentivement les explications de la page principale de <a href="http://code.google.com/intl/fr/appengine/">Google AppEngine</a>. Une fois le téléchargement effectué, j&#8217;ai simplement décompressé l&#8217;archive tar.gz dans un répertoire, puis ensuite j&#8217;ai configuré la variable APPENGINE_HOME afin qu&#8217;elle pointe vers le répertoire de GAE (Google AppEngine).</p>
<p><strong>Créer sa première application Grails</strong><br />
Grails vous permet de créer rapidement une application et de la tester. Allons-y, placez-vous dans un nouveau répertoire vide et créez votre première application grails, appelée ici gaetex:</p>
<pre>
grails create-app gaetex
</pre>
<p>Lorsque nous utilisons Google AppEngine, nous devons désinstaller le plugin JPA et désinstaller le plugin Hibernate. Le plugin JPA génère un fichier persistence.xml qui vient en conflit avec celui utilisé par le mode JPA du plugin Google AppEngine. Concernant Hibernate, nous n&#8217;en avons pas besoin ici.<br />
Pour cela il suffit d&#8217;exécuter les 2 commandes Grails suivantes en vous mettant d&#8217;abord dans le répertoire gaetex que nous venons de créer  :</p>
<pre>
cd gaetex
grails uninstall-plugin hibernate
grails uninstall-plugin jpa
</pre>
<p>Notez qu&#8217;en principe, le plugin jpa n&#8217;est pas installé, j&#8217;ai ajouté cette commande au cas où vous l&#8217;auriez installé aussi.</p>
<p><strong>Installer Google AppEngine</strong><br />
L&#8217;installation de Google AppEngine est simple. Assurez-vous simplement que la variable APPENGINE_HOME pointe vers votre répertoire d&#8217;installation de GAE puis lancer la commande d&#8217;installation du plugin App-Engine :</p>
<pre>grails install-plugin app-engine</pre>
<p>Ce qui donne sur ma machine: </p>
<pre>
macbook-pro-de-nicolas-martignole:gaetex nicolas$ echo $APPENGINE_HOME
/Users/nicolas/Dev/appengine-java-sdk-1.2.1
macbook-pro-de-nicolas-martignole:gaetex nicolas$ grails install-plugin app-engine
...
...
</pre>
<p><strong>Tester le tout</strong><br />
Vérifions que tout fonctionne en démarrant le serveur Jetty intégré à Grails. Dans le répertoire gaetex, lancez grails:</p>
<pre>grails app-engine</pre>
<p>Connectez-vous à votre machine (<a href="http://localhost:8080/">http://localhost:8080/</a>) et vous devriez voir votre première page Grails s&#8217;afficher. </p>
<p><strong>Créer une première entité</strong><br />
Nous allons maintenant créer une entité Book, et générer ensuite la partie vue et contrôleur. Avec Google AppEngine, il n&#8217;est pas possible de placer ses Entités directement dans le répertoire &laquo;&nbsp;grails-app/domain&nbsp;&raquo;. Il est nécessaire d&#8217;utiliser un package. J&#8217;ai donc fait comme Guillaume durant sa démonstration, j&#8217;ai créé une entité Book dans le package &laquo;&nbsp;demo&nbsp;&raquo; avec la commande suivante :</p>
<pre>grails create-domain-class demo.Book</pre>
<p>Il serait intéressant maintenant d&#8217;ajouter deux attributs &laquo;&nbsp;title&nbsp;&raquo; et &laquo;&nbsp;author&nbsp;&raquo; à notre Book.</p>
<p>Editez le fichier gaetex/grails-app/domain/demo/Book.groovy avec un éditeur de texte, et ajoutez simplement 2 attributs pour le titre et l&#8217;auteur du livre :</p>
<pre name="code" class="groovy">
package demo

import javax.persistence.*;
// import com.google.appengine.api.datastore.Key;

@Entity
class Book {

    @Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	Long id

	// Added by Nicolas Martignole
	String title
	String author

    static constraints = {
    	id visible:false
	}
}
</pre>
<p>Avec ces deux attributs en place, nous allons maintenant générer un controlleur et tester à nouveau notre application.<br />
Lancez la commande de génération du controleur et des vues:</p>
<pre>grails generate-all demo.Book</pre>
<p>Puis relancez ensuite le serveur Grails :</p>
<pre>grails app-engine</pre>
<p>Voici ce que cela donne après avoir créé quelques livres (au logo prêt) :<br />
<img src="http://www.touilleur-express.fr/wp-content/capture_grails.jpg" alt="capture_grails" title="capture_grails" width="567" height="431" class="alignnone size-full wp-image-1420" /></p>
<p>Vous pouvez retrouver la même chose avec la voix de Guillaume à partir de la minute 50 sur la vidéo <a href="http://www.youtube.com/watch?v=NEnniZTdOYk">YouTube</a> de la présentation.</p>
<p><strong>Déployer son application Grails sur Google AppEngine</strong><br />
Voici la liste des étapes:<br />
 1) créer une application sur Google AppEngine<br />
 2) modifier le fichier grails-app/conf/Config.groovy et ajouter une ligne avec le nom de votre application<br />
 3) packager et préparer l&#8217;application<br />
 4) effacer un fichier parasite (probleme à résoudre)<br />
 5) utiliser le script appCfg.sh pour fournir votre email et votre mot-de-passe Google<br />
 6) ensuite simplement mettre à jour avec le plugin google-app-engine de Grails</p>
<p>Voyons en détail chaque étape:</p>
<p>1) Rendez-vous sur &laquo;&nbsp;Google AppEngine&nbsp;&raquo; afin de faire une demande, puis ensuite de créer votre application. L&#8217;application id doit être unique, ce pourra être par exemple testgrails1234<br />
2) Ouvrir le fichier Config.groovy se trouvant dans votre application et définissez l&#8217;application id que vous venez de mettre</p>
<pre>
google.appengine.application="touilleur"
</pre>
<p>3) Lancer la création du package avec les commandes suivantes:<br />
Il faut fixer la version à un nombre entier car GAE n&#8217;accepte pas les numéros de version type x.y.z </p>
<pre>
grails set-version 1
grails app-engine package
</pre>
<p>4) Effacer le fichier &laquo;&nbsp;datastore-indexes.xml&nbsp;&raquo; sans quoi voici l&#8217;erreur que vous rencontrerez:</p>
<pre>
macbook-pro-de-nicolas-martignole:gaetex nicolas$ /Users/nicolas/Dev/appengine-java-sdk-1.2.1/bin/appcfg.sh update target/war
Reading application configuration data...
Bad configuration: XML error validating target/war/WEB-INF/datastore-indexes.xml against /Users/nicolas/Dev/appengine-java-sdk-1.2.1/docs/datastore-indexes.xsd
  Caused by: cvc-elt.1: Cannot find the declaration of element 'datastore-indexes'.
Please see the logs [/tmp/appcfg16875.log] for further information.
</pre>
<p><strong>Pour résoudre ce problème, effacez le fichier datastore-indexes.xml</strong> avant de relancer la commande appcfg.sh (voir étape suivante)</p>
<pre>
rm target/war/WEB-INF/datastore-indexes.xml
</pre>
<p>5) Lancer la première fois seulement la mise à jour avec l&#8217;utilitaire appcfg.sh de Google AppEngine comme suit:</p>
<pre>
$APPENGINE_HOME/bin/appcfg.sh update target/war
</pre>
<p>Renseigner votre adresse mail Google ainsi que votre mot de passe. Il suffit de mettre son login en fait (mdupont et pas mdupont@gmail.com). </p>
<p>6) Ensuite à chaque fois que vous souhaitez mettre à jour votre application vous pourrez utiliser le plugin de Gae dans Grails, plugin qui ne marche pas la première fois avec l&#8217;authentification en se plantant. C&#8217;est pour cette raison qu&#8217;il faut utiliser l&#8217;utilitaire appcfg.sh la première fois.</p>
<pre>
grails app-engine deploy
</pre>
<p>Si tout se déroule sans problèmes vous devriez alors mettre en ligne votre première application !!!</p>
<p>L&#8217;url de votre application sera http://&lt;applicationid&gt;.appspot.com </p>
<p>Si vous voulez tester un exemple d&#8217;application : <a href="http://petclinic-grails.appspot.com/">PetClinic with Grails</a></p>
<p><strong>Conclusion</strong><br />
Comptez 1h la première fois, puis ensuite 10 minutes pour refaire cet exercice. J&#8217;ai été vraiment séduit par la simplicité de Grails, et cette intégration avec Google App Engine. Celui-ci est gratuit jusqu&#8217;à un certain nombre de requêtes par jour, et croyez-moi vous avez largement de quoi tester votre code sans devoir payer, toujours dans l&#8217;esprit Google.<br />
Je crois vraiment à un nouveau type de développement rapide d&#8217;applications, à la monétisation de compétences en Groovy et en Grails. Pour ma part je travaille en ce moment sur une application pour le Touilleur Express, un mix de LinkedIn avec une touche de Google Calendar, un esprit de Geek et bien entendu, toujours la pâte Touilleur Express. </p>
<p>Guillaume Laforge travaille aussi sur Gaelyk, un framework léger qui facilite l&#8217;intégration de Google App Engine si vous souhaitez n&#8217;écrire qu&#8217;en Groovy votre application Web, sans utiliser Grails. Il cite aussi <a href="http://code.google.com/p/iui/">le framework iUI</a> qui est un framework Javascript destiné à faciliter l&#8217;écriture d&#8217;application pour l&#8217;iphone, hébergé sur Internet. Cela revient à ne pas passer par l&#8217;AppleStore, à simplement offrir un service type iPhone mais hébergé sur Internet directement. </p>
<p><strong>Références</strong><br />
- <a href="http://code.google.com/intl/fr/appengine/">Page d&#8217;accueil Google App Engine</a><br />
- <a href="http://appengine.google.com/">Page pour créer sa première application GAE</a><br />
- <a href="http://grails.org/plugin/app-engine">Plugin GAE Grails</a> le site à surveiller<br />
- <a href="http://groovyconsole.appspot.com/">Groovy Web Console</a> permet de taper du Groovy, application Google App Engine<br />
- <a href="http://myowngroovy.appspot.com/">My Own Groovy</a> par Guillaume Laforge avec quelques applications pour tester<br />
- <a href="http://appgallery.appspot.com/">Portail des applications Google App Engine</a></p>
<p><strong>Problèmes connus</strong><br />
Il y a un certain nombre de soucis pour l&#8217;instant sur le plugin Google App Engine pour Grails au moment où j&#8217;écris ces lignes (juin 2009). Ne vous lancez pas dans ce test si vous ne maîtrisez pas un minimum Grails. Je n&#8217;ai testé que la version JPA, je ne sais pas si la version JDO est plus ou moins stable. </p>
<p>Pour terminer je vous recommande de regarder la présentation de Guillaume Laforge sur YouTube:</p>
<p><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/NEnniZTdOYk&#038;hl=fr&#038;fs=1&#038;"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/NEnniZTdOYk&#038;hl=fr&#038;fs=1&#038;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed></object></p>
]]></content:encoded>
			<wfw:commentRss>http://www.touilleur-express.fr/2009/06/09/premiers-pas-avec-grails-111-et-google-appengine/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
