Accueil > Non classé > Grails – épisode 2 – Création du domaine

Grails – épisode 2 – Création du domaine

Dans l’épisode précédent …

Nous avons installé Grails sur notre machine et créé un premier projet simple. L’objectif est maintenant de passer à la pratique en écrivant un cas concret …

Relire l’épisode 1.

Cahier des charges du projet

Notre web-application se présentera sous deux formes:

  • la forme authentifiée
  • la forme publique

Dans la forme authentifiée, l’utilisateur peut créer de nouvelles chansons et les inclure dans des albums. Chaque album peut contenir de 1 à plusieurs chansons. Une chanson peut appartenir à 0 ou 1 album (cette limitation est volontaire pour les besoins de la démonstration).

Dans la forme publique, le visiteur pourra lister les albums présents dans la base de données. Pour chaque album, il pourra consulter la liste complète des chansons.

Un flux RSS permettant de suivre les albums et les chansons sera mis en place. Enfin, un formulaire de recherche permettra de faire de la recherche plein-texte (dans les descriptions par exemple).

Introduction à GORM

Avant de rentrer dans le vif du sujet, il est nécessaire d’introduire le concept “GORM”.

GORM, pour “Grail Object Relationnal Mapping”, est une surcouche Groovy au framework Hibernate. Cette couche va permettre de profiter de la souplesse impressionnante de Groovy pour l’utilisation d’Hibernate dans notre projet.

GORM va donc nous permettre:

  • de gérer les objets à mapper sur notre base de données de façon simple et quasi-automatisée
  • de faciliter le requêtage de ces objets : notamment, en incluant automatiquement des méthodes comme “save()”, “delete()”, ou encore en facilitant grandement l’accès au système de “criteria”.

Préliminaires – Création du projet

1
2
grails create-app albums
cd albums

Etape 1 – Création du domaine

Nous allons commencer par créer notre domaine. Les utilisateurs seront gérés plus tard car faisant partie du mécanisme de sécurité (et donc gérés par Spring Security, nous y reviendront).

1
2
grails create-domain-class com.excilys.grails.Song
grails create-domain-class com.excilys.grails.Album

Voici donc 2 classes créées dans le dossier grails-app/domain/com/excilys/grails/. Parce qu’elles sont dans le dossier grails-app/domain, Grails les considère maintenant comme des “classes mappées”, GORM saura les utiliser. Les classes mappées sont le reflet du modèle de la base de données.

La première chose à faire est de rajouter quelques attributs sur ces 2 classes, comme le nom, la date de publication ou la description pour l’Album ; la durée et le nom de l’artiste sur Song.

Attention, gardez bien à l’esprit que le code est écrit en Groovy : la syntaxe est différente de Java.


1
2
3
4
5
6
7
8
9
10
package com.excilys.grails
class Album {
  // 1.Attributs simples
  String name
  Date publication
  String description

  static constraints = {
  }
}

1
2
3
4
5
6
7
8
9
10
package com.excilys.grails
class Song {
  // 1. Attributs simple
  String name
  Integer duration
  String artistName

  static constraints = {
  }
}

Inutile de définir les getters et setters, Groovy s’en chargera dynamiquement pour nous. Pour modifier ce comportement, il suffit de forcer la visibilité de vos attributs (en ajoutant un “private” par exemple). Dans ce cas, vous serez obligé de définir par vous même les accesseurs.

Maintenant que nos classes sont un peu plus étoffées, établissons les liens relationnels. Pour rappel, les règles de gestion sont les suivantes:

  • un album peut contenir de 1 à plusieurs chansons
  • une chanson peut appartenir à 0 ou 1 album

Mapping 1-n

Notre premier cas est un mapping dit 1-n (ou one-to-many). Pour réaliser ce genre de mapping,  il suffit d’insérer une map statique nommée hasMany dans notre objet et Grails se chargera de repérer la relation (encore une fois COC entre en jeu et nous facilite la tâche). Pour respecter la première règle de gestion, ajoutons dans la classe Album:

1
static hasMany = [songs:Song]

Notez que la map est construite “à la mode Groovy”: a gauche le nom de la clé, à droite la valeur (en l’occurrence Song équivaut à Song.class). On indique donc ici qu’une collection typée Song et nommée “songs” est incluse dans l’objet Album.

Mapping 0-1

Le second cas est encore plus simple ! En effet, puisqu’une chanson est liée à un seul album,  il suffit juste d’indiquer cette référence en ajoutant un attribut typé Album dans Song comme n’importe quel autre attribut:

1
Album album

Par défaut, tout attribut est mappé comme non nullable en base. Or, une chanson peut ne pas être attribué à un album. Ajoutons une contrainte. Éditez le bloc statique nommé “constraints” dans la classe Song:


1
2
3
static constraints = {
  album (nullable:true)
}

Enfin, nous souhaitons que le champ “description” de la table Album soit mappé sur un champ de type “text” en base. A l’image du bloc “constraints”, Grails nous fournit un moyen original d’altérer le mapping par défaut des propriétés:  le bloc “mapping”. Ajoutons ce bloc dans la classe Album:


1
2
3
static mapping = {
  description type:'text'
}

Etape 2 – Configuration de la datasource

Maintenant que nous avons notre domaine, éditons le fichier grails-app/conf/DataSource.groovy.

Par défaut, Grails se branche sur une base de données HSQLDB. Vous pouvez continuer d’utiliser cette base. Personnellement, je préfère utiliser PostGreSQL. Si vous souhaitez utiliser autre chose que le choix par défaut, voici la marche à suivre.

  • commencez par récupérer le driver relatif à votre base (regarder dans la section Ressources si vous ne savez pas où télécharger votre driver)
  • copiez ce JAR dans le dossier lib de l’application (nous verrons plus tard comment ne pas avoir à le faire manuellement)
  • éditez le fichier DataSource.groovy

1
2
3
4
5
6
7
8
9
dataSource {
  pooled = true
  driverClassName = "org.postgresql.Driver"
  username = "cyril"
  password = "topsecret"
}
//[...]
  dbCreate = "update" // one of 'create', 'create-drop','update'
  url = "jdbc:postgresql://127.0.0.1:5432/albums"

Le même procédé s’applique aux autres SGBD (MySQL, Firebird, …). La classe du driver ainsi que le formatage de l’URL ne sont néanmoins pas les mêmes. Consultez le manuel pour votre driver …

Le paramètre dbCreate permet à Grails d’indiquer à Hibernate la stratégie de création à appliquer sur la base de données au déploiement. Les valeurs possibles peuvent être:

  • update : le schéma de la base de données sera mis à jour
  • create: si la base n’existe pas elle est créée, sinon les données sont effacées mais la base n’est pas mise à jour
  • create-drop: à chaque déploiement, le schéma est effacé puis recréé
  • validate: le schema est validé
  • none: ne rien faire (vous pouvez aussi supprimer la propriété)

Etape 3 – Premier lancement et création de la base

Lançons notre application:

1
grails run-app

Après compilation et lancement du conteneur, notre application va se connecter à la base de données et mettre à jour les tables de façon automatique.

Vérifiez votre base:

  • 2 tables ont été créées : Album et Song
  • les champs “id” et “version” ont automatiquement été ajoutés (et seront gérés de façon transparente) par Grails
  • les règle de gestions s’expriment par une clé étrangère sur la table Song vers la table Album

Tests plus approfondis

Grails embarque un shell interactif permettant de tester certaines parties de votre application.

1
grails shell

Une fois le prompt disponible, tapez:


1
new com.excilys.grails.Album(name:'Test', publication:new Date(), description:"Un album pour tester").save(flush:true);

Vérifiez que la création a bien eu lieu dans votre base.

La suite au prochain numéro !!

Maintenant que la base est créée et configurée, il nous reste à ajouter toute la mécanique qui va nous permettre de manipuler les objets du domaine: les contrôleurs, vues et services.

Ressources

Code de l’application: albums_episode2.zip
Tag sur le SVN Google Code : http://excilys.googlecode.com/svn/projects/grails-albums/tags/grails-albums_article_2/
Documentation sur le mapping Grails: http://www.grails.org/GORM+-+Defining+relationships
Driver PostgreSQL: http://jdbc.postgresql.org/download.html
Driver MySQL: http://dev.mysql.com/downloads/connector/j/5.1.html
Driver Oracle: http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html

Share
  1. Pierre-Yves RICAU
    14/12/2009 à 10:45 | #1

    Juste une question de curiosité : on a parlé dans cet article du “domaine” de l’application. D’autres part, si j’ai bien suivi, les use cases parlent d’utilisateurs authentifiés.

    Un utilisateur ne fait pas partie des notions liées au domaine ?

  2. Cyril BROUILLARD
    14/12/2009 à 10:55 | #2

    @Pierre-Yves : Si bien sûr ! Mais pour le moment, les utilisateurs ne sont pas gérés (ils le seront plus tard via un plugin de sécurité,dans l’épisode 4). On en reparlera donc ;)

  3. 06/08/2010 à 09:43 | #3

    Excellent tutorial,
    Je m’empresse de lire la suite!

  4. 04/12/2011 à 11:09 | #4

    Bonjour,
    J’utilise postgres 8.4. Lorsque le copie le driver natif de postgres, rien ne se passe. Je n’arrive pas à me connecter. On signal une erreur comme quoi, “La classe org.postgresql.Driver” n’est pas trouvée. Comment resoudre ce problème ?

  5. 04/12/2011 à 12:22 | #5

    Ouf ! Je viens de resoudre mon problème.
    Il faillait ajouter ceci : <> dans la le fichier BuildConfig.groovy dans la section “dependencies” puis créer la BD pour que ça marche.

    Merci encore !

  6. 04/12/2011 à 12:23 | #6

    Ouf ! Je viens de resoudre mon problème.
    Il faillait ajouter ceci : [ runtime ‘postgresql:postgresql:8.4-703.jdbc3′ ] dans la le fichier BuildConfig.groovy dans la section “dependencies” puis créer la BD pour que ça marche.
    Merci encore !

    • Cyril BROUILLARD
      06/12/2011 à 10:56 | #7

      Salut Danyboy,

      Content de voir que tu as pu trouver une réponse ^^
      Bonne continuation avec Grails

      Cyril

  7. NAAMA
    31/01/2014 à 01:19 | #8

    Exemple bien expliqué , merci encore une autre fois

  8. 07/04/2017 à 20:11 | #9

    Thatt is very interesting, You’re an overly professional blogger.
    I have joined your rsss feed and look ahead
    to searching for extra of your magnificent post.
    Additionally, I’ve shared your website in my social networks

  9. 08/11/2017 à 05:19 | #10

    Howdy I am so thrilled I found your webpage, I really found you by error, while I was researching on Bing for something
    else, Nonetheless I am here now and would
    just like to say thanks a lot for a incredible post and a all round thrilling blog (I also love the theme/design), I don’t
    have time to go through it all at the minute but I have
    book-marked it and also added your RSS feeds, so when I have time I
    will be back to read a great deal more, Please do keep up
    the fantastic b.

  10. 05/01/2018 à 01:34 | #11

    Hello, everything is going well here and ofcourse every one
    is sharing facts, that’s truly excellent, keep up writing.

  11. 05/01/2018 à 01:40 | #12

    Thanks for your personal marvelous posting!
    I really enjoyed reading it, you can be a great author.I
    will remember to bookmark your blog and will eventually come back in the future.
    I want to encourage you to ultimately continue your great writing, have a nice day!

  12. 12/09/2018 à 00:19 | #13

    Very good blog! Do you have any tips for aspiring writers?

    I’m hoping to start my own website soon but I’m a little lost on everything.
    Would you propose starting with a free platform like
    Wordpress or go for a paid option? There are so many options
    out there that I’m totally confused .. Any tips?
    Appreciate it!

  13. 15/09/2018 à 08:36 | #14

    Hey I know this is off topic but I was wondering if you knew of
    any widgets I could add to my blog that automatically tweet my newest
    twitter updates. I’ve been looking for a plug-in like this for quite some time and was hoping maybe you would have some experience with something like this.
    Please let me know if you run into anything. I truly enjoy reading your
    blog and I look forward to your new updates.

  1. 21/12/2009 à 15:25 | #1
  2. 17/06/2014 à 03:07 | #2
  3. 20/06/2014 à 04:31 | #3
  4. 16/07/2014 à 15:46 | #4
  5. 25/07/2014 à 00:52 | #5
  6. 02/09/2014 à 00:39 | #6
  7. 07/09/2014 à 04:33 | #7
  8. 07/09/2014 à 06:04 | #8
  9. 12/09/2014 à 06:51 | #9
  10. 22/09/2014 à 22:08 | #10
  11. 15/03/2015 à 23:54 | #11
  12. 02/11/2015 à 20:03 | #12
  13. 22/12/2015 à 18:20 | #13