Ahhhh, l’article que certains d’entre vous attendaient avec impatience !!!!

Nous allons voir aujourd’hui comment réaliser une application Wicket utilisant les informations d’une base de données.

Pour ce faire nous allons utiliser les composants suivants:

Databinder est un framework “data-driven”, basé sur les concepts de [IModel] de Wicket, permettant de simplifier la manipulation (récupération / mise à jour) de données en base.

N’importe quel base fait bien évidemment l’affaire (tant qu’on à le bon driver JDBC), cependant pour le coté pratique, nous allons utiliser HSQLDB (qui est une base de données embarquée écrite en Java).

Dans un premier temps, il faudra bien configurer un peu votre poste de travail pour récupérer les dépendances (via Ant et Ivy bien sûr!).
Ensuite nous créerons notre petite base de données.
Enfin nous construirons noter application Wicket, en nous servant de Databinder pour manipuler Hibernate.

Préparation

Voici le code source du fichier [build.xml]. (Si vous êtes derrière un proxy, n’oubliez pas de dé-commenter et de compléter les quelques lignes dans la target [resolve])

<project name="helloworldDB" default="resolve" xmlns:ivy="antlib:org.apache.ivy.ant">
  <property name="ivy.lib.dir" value="WebContent/WEB-INF/lib" />
  <!-- =================================
          target: resolve
  ================================= -->
  <target name="resolve" description="-->retreive dependencies with ivy">
<!--<property name="proxy.host" value="proxyHostName"/> -->
<!--<property name="proxy.port" value="proxyPort"/> -->
<!--<property name="proxy.user" value="proxyUsername"/> -->
<!--<property name="proxy.pass" value="proxyPassword"/> -->
<!--<setproxy proxyhost="${proxy.host}" proxyport="${proxy.port}" proxyuser="${proxy.user}" proxypassword="${proxy.pass}"/> -->
 
    <ivy:retrieve/>
  </target>
  <!-- =================================
          target: clean-cache
  ================================= -->
  <target name="clean-cache" description="-->clean the ivy cache">
    <ivy:cleancache />
  </target>
</project>

Sachant que nous souhaitons utiliser Databinder, mais que celui ci n’est pas déployé sur les repositories dit “officiels” (comme ibiblio), il faut donc préciser quelques petites choses au moteur d’Ivy.

Ceci n’est pas à faire dans le fichier [ivy.xml] mais dans le fichier [ivysettings.xml] que l’on mettra à la racine de notre projet (comme les autres fichiers xml d’ailleurs).
Nous allons définir l’endroit où Ivy ira essayer de chercher les jar de Databinder. Ceci est fait en ajoutant une entrée “générique” [ibiblio] en spécifiant l’URL de la racine du répository de databinder.
Cela donne le fichier [ivysettings.xml] suivant :

<ivysettings>
	<settings defaultResolver="noocodecommit-chain"/>
	<include url="${ivy.default.settings.dir}/ivysettings-public.xml"/>
	<include url="${ivy.default.settings.dir}/ivysettings-shared.xml"/>
	<include url="${ivy.default.settings.dir}/ivysettings-local.xml"/>
	<include url="${ivy.default.settings.dir}/ivysettings-main-chain.xml"/>
	<include url="${ivy.default.settings.dir}/ivysettings-default-chain.xml"/>
	<resolvers>
		<ibiblio name="databinder" m2compatible="true" root="http://databinder.net/repo/"/>
		<ibiblio name="ibiblio" m2compatible="true" root="http://www.ibiblio.org/maven"/>
		<chain name="noocodecommit-chain" returnFirst="true" checkmodified="true">
			<resolver ref="local"/>
			<resolver ref="shared"/>
			<resolver ref="databinder"/>
			<resolver ref="main"/>
			<resolver ref="ibiblio"/>
		</chain>
	</resolvers>
</ivysettings>

N’oubliez pas d’ajouter les dépendances à Databinder et à HSQLDB.

[ivy.xml]

<ivy-module version="2.0">
  <info organisation="com.noocodecommit" module="helloworld"/>
  <dependencies>
    <dependency org="org.apache.wicket" name="wicket" rev="1.4-m3"/>
    <dependency org="org.apache.wicket" name="wicket-auth-roles" rev="1.4-m3"/>
    <dependency org="org.apache.wicket" name="wicket-extensions" rev="1.4-m3"/>
    <dependency org="org.slf4j" name="slf4j-log4j12" rev="1.4.3"/>
 
    <dependency org="net.databinder" name="databinder-app-hib" rev="1.2.0"/>
    <dependency org="hsqldb" name="hsqldb" rev="1.8.0.7"/>
 
    <dependency org="dom4j" name="dom4j" rev="1.6.1"/>
    <dependency org="antlr" name="antlr" rev="2.7.7"/>
    <dependency org="cglib" name="cglib" rev="2.1_3"/>
  </dependencies>
</ivy-module>

ATTENTION : en réalisant cet article, certaines erreurs apparaissent lors de la récupération des dépendances.
C’est pour cela, dans un premier temps que j’ai rajouté les dépendances à [dom4j], [antlr] et [cglib].

De plus, et la c’est plus génant, une erreur survient concernant [javax.transaction]. Vous devriez avoir une erreur de ce type :

...
[ivy:retrieve] :: problems summary ::
[ivy:retrieve] :::: WARNINGS
[ivy:retrieve]          [FAILED     ] javax.transaction#jta;1.0.1B!jta.jar:  (0ms)
[ivy:retrieve]  ==== shared: tried
[ivy:retrieve]    C:\Documents and Settings\nicogiard\.ivy2/shared/javax.transaction/jta/1.0.1B/jars/jta.jar
[ivy:retrieve]  ==== public: tried
[ivy:retrieve]    http://repo1.maven.org/maven2/javax/transaction/jta/1.0.1B/jta-1.0.1B.jar
[ivy:retrieve]          ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve]          ::              FAILED DOWNLOADS            ::
[ivy:retrieve]          :: ^ see resolution messages for details  ^ ::
[ivy:retrieve]          ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve]          :: javax.transaction#jta;1.0.1B!jta.jar
[ivy:retrieve]          ::::::::::::::::::::::::::::::::::::::::::::::
[ivy:retrieve]
[ivy:retrieve] :: USE VERBOSE OR DEBUG MESSAGE LEVEL FOR MORE DETAILS

BUILD FAILED
D:\Ganymede-workspace\helloworldDB\build.xml:14: impossible to resolve dependencies: resolve failed - see output for details

Total time: 9 minutes 29 seconds

Je vous avoue que je ne sais pas trop pourquoi ça fait cela (si quelqu’un sait pourquoi je suis preneur de l’info). Par contre je vous met à disposition ce qu’il faut dans ce zip. Vous devrez mettre son contenu dans le répertoire [%HOME%/.ivy2/cache/javax.transaction/jta]. Ca devrait être mieux maintenant.

Base de données

Comme nous utilisons HSQLDB comme base de données, nous avons l’opportunité d’utiliser une base sans rien installer et aussi d’initialiser les données très facilement. En éffet il suffit d’écrire un fichier [helloworld.script] à mettre dans le même répertoire que le script de lancement du serveur [runHsqlDB.bat] et le tour est joué.
[helloworld.script]

CREATE SCHEMA PUBLIC AUTHORIZATION DBA
CREATE MEMORY TABLE BONJOUR(ID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL PRIMARY KEY,LIBELLE VARCHAR(255))
ALTER TABLE BONJOUR ALTER COLUMN ID RESTART WITH 7
CREATE USER SA PASSWORD ""
GRANT DBA TO SA
SET WRITE_DELAY 10
SET SCHEMA PUBLIC
INSERT INTO BONJOUR VALUES(1,'Hello World')
INSERT INTO BONJOUR VALUES(2,'Bonjour tout le Monde')
INSERT INTO BONJOUR VALUES(3,'Hallo Welt')
INSERT INTO BONJOUR VALUES(4,'Bon Dia')

Maintenant, il nous faut configurer Hibernate pour qu’il sache où se brancher. Dans un fichier [hibernate.properties], placé à la racine du répertoire [src] de notre projet, nous devons définir le dialect qu’Hibernate utilisera, ainsi que toutes les informations de connections à la base de données.
[hibernate.properties]

hibernate.dialect=org.hibernate.dialect.HSQLDialect
hibernate.connection.driver_class=org.hsqldb.jdbcDriver
hibernate.connection.url=jdbc:hsqldb:hsql://localhost/helloworld
hibernate.connection.username=sa
#hibernate.connection.password=

Application Web avec Wicket

Le fichier [web.xml] n’a pas grand chose de particulier (rappelez vous, vous aviez déjà vu ça dans le Quickstart!)
[web.xml]

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	<display-name>HelloWorldApplication</display-name>
	<context-param>
  	<param-name>configuration</param-name>
  	<param-value>development</param-value>
  	<!-- <param-value>deployment</param-value> -->
	</context-param>
	<filter>
    <filter-name>HelloWorldApplication</filter-name>
    <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class>
	<init-param>
    <param-name>applicationClassName</param-name>
    <param-value>com.noocodecommit.wicket.helloworld.wicket.HelloWorldApplication</param-value>
	</init-param>
	</filter>
	<filter-mapping>
    <filter-name>HelloWorldApplication</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

Les choses sérieuses

Le point d’entrée de toute application Wicket est une [WebApplication]. Cependant, pour pouvoir utiliser Databinder encore plus facilement, il existe une classe [DataApplication] qui est une sorte de [WebApplication] mais qui en plus sait parler Hibernate couramment.
[HelloWorldApplication.java]

package com.noocodecommit.wicket.helloworld.wicket;
import net.databinder.hib.DataApplication;
import org.hibernate.cfg.AnnotationConfiguration;
import com.noocodecommit.wicket.helloworld.model.Bonjour;
import com.noocodecommit.wicket.helloworld.wicket.pages.HelloPage;
 
public class HelloWorldApplication extends DataApplication
{
	@Override
	public Class getHomePage()
	{
		return HelloPage.class;
	}
 
	@Override
	protected void configureHibernate(AnnotationConfiguration config)
	{
		super.configureHibernate(config);
		config.addAnnotatedClass(Bonjour.class);
	}
}

En plus de l’habituelle méthode [getHomePage()], nous pouvons appercevoir ci-dessus une méthode [configureHibernate(AnnotationConfiguration config)]. Cette méthode permet de configurer la [DataApplication] avec les paramètres de connexion à la Base de données (le contenu du fichier [hibernate.properties]). De plus cette méthode permet d’ajouter toutes les classes annotées que nous souhaitons voir “bindées” (avec l’accent anglais :p) par Hibernate. C’est le cas ici de la classe [Bonjour] que nous voyons ci-dessous.

[Bonjour.java]

package com.noocodecommit.wicket.helloworld.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
 
@Entity
public class Bonjour implements Serializable
{
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Integer id;
 
	private String libelle;
 
	public String getLibelle()
	{
		return libelle;
	}
 
	public void setLibelle(String libelle)
	{
		this.libelle = libelle;
	}
}

Cette classe…(j’aime bien parler d’Objet Métier). Cet objet métier, donc, représente une donnée fonctionnelle que nous avons à traiter. Le lien est fait avec une représentaiton physique (donc sous forme de table dans une base de données) grace aux annotations d’Hibernate.
Ici, trois choses :

  • [@Entity] : On dit à Hibernate que cet classe est à binder avec une table en BDD (par défaut la table prend le meme nom que l’objet)
  • [@Id] : On dit à Hibernate quelle est la clé primaire
  • [@GeneratedValue(strategy = GenerationType.AUTO)] : On dit à Hibernate qu’on laisse la Base de donnés s’occuper de l’incrémentation des id de cette clé primaire.

Je ne vais pas ici m’attarder plus sur le fonctionnement d’Hibernate. Si vous voulez allez plus loin, c’est par ici

Ensuite, et d’une façon très naturelle, nous devons créer une [Page], avec des [Component] et des [Model].
Le [Model] est donc dans notre application, délégué à Databinder ([HibernateProvider]), qui lui va allez chercher de lui même les données en base.

[HelloPage.java]

package com.noocodecommit.wicket.helloworld.wicket.pages;
import net.databinder.models.hib.HibernateProvider;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.IDataProvider;
import com.noocodecommit.wicket.helloworld.model.Bonjour;
 
public class HelloPage extends WebPage
{
	public HelloPage()
	{
		IDataProvider<Bonjour> helloProvider = new HibernateProvider("from Bonjour");
 
		DataView<Bonjour> hellos = new DataView<Bonjour>("hellos", helloProvider)
		{
			protected void populateItem(Item<Bonjour> item)
			{
				item.add(new Label("libelle", item.getModelObject().getLibelle()));
			}
		};
		add(hellos);
	}
}

Le code Html associé est lui on ne peut plus simple :
[HelloPage.html]

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html charset=utf-8">
	<title>Ma premiere application Wicket</title>
</head>
<body>
	<div wicket:id="hellos">
		<h1 wicket:id="libelle">[fufu]</h1>
	</div>
</body>
</html>

Lancez votre serveur tomcat, allez à l’adresse http://localhost:8080/helloworldDB, normalement vous devriez avoir le résultat suivant :

Bravo

Vous avez réussi à réaliser une application Wicket utilisant les données du base de données en utilisant Hibernate et tout ça sans problème!

Merci Wicket et Databinder!!!

Les sources du projet se trouvent ici.

Imprimer cet article Imprimer cet article

  21 Responses to “Wicket main dans la main avec Hibernate grace à Databinder”

  1. J’ai p-e loupé une marche, mais où télécharge-t’on hibernate ? Je ne vois rien dans l’ivy. J’ai bien téléchargé un package hibernate mais qui ne contient pas la classe AnnotationConfiguration …

  2. Quand je repense qu’il y a quelques mois tu me disais “hein databip… quoi ? avec hibernate ? pfeuu ca sert a rien … pis tu te fais chier, pis blablabla” … comme d’hab Monsieur commence par faire son fier … mais comme on y revient hein !!! Il n’y a que les imbéciles qui ne changent pas d’avis après tout :D
    Donc je suis bien content pour le coup.

    (hey a quand un petit article sur appfuse-light ?)

    Sinon Hibernate est une dépendance de databinder… tout comme wicket d’ailleurs … donc dans ivy il faut rajouter databinder et les jars hibernate se telechargeront avec ;o)

    Par contre petite remarque… si je ne me trompe pas wicket est aussi une dépendance de databinder. Donc on est pas obligé d’importer wicket, par contre on n’aura que la version utilisée par databinder et pas forcement la derniere.
    Je ne sais pas comment ivy gere les conflits mais n’y a t’il pas un risque Nico ?

  3. Ok, en fait, je suis entrain de faire un clean du cache d’ivy et je relance le download, histoire de partir sur de bonnes bases.

  4. DU coup ça marche mieux ! Cependant, pour le package jta, je rajouterais une indication, mon ivy a cherché dans le répertoire :

    C:\Users\\.ivy2\shared\javax.transaction\jta\1.0.1B\jars\jta.jar

    Je lui ai donc collé le jar que tu nous a zippé dedans et tout à fonctionné. Le message de la compilation ant était très explicite.

  5. @Kokoni : Comme l’a dit FinalSpy, c’est une dépendance de databinder.

    @FinalSpy 1 : naabs :P (c’était de Spring que je parlai, pas de Databinder, j’aime pas Spring). Si ca te tente de faire un article sur la génération d’un projet Wicket avec app-fuse, c’est avec plaisir que je passe ton compte en rédacteur ;)

    @FinalSpy 2 : alors je me suis aperçu qu’en mettant dans mon ivy.xml explicitement la version de Wicket que je souhaite (1.4-m3), du coup Ivy n’essaye même pas de downloader la version déclarée dans les dépendances de Databinder (1.3.etquelque).

  6. @Kokoni : blizzard, chez moi ivy cherche dans %HOME%/.ivy2/cache/…

    Donc pour faire simple, suivez bien le message d’erreur d’Ivy concernant jta pour savoir où mettre le jar que je vous ai donné!

  7. On verra pour appfuse, je te promets rien mais je tenterai de te faire ca…

    Pour Ivy c’est cool qu’il gere directement les conflits, je sais que dans maven tu peux lui dire exclude/include … je suppose que ivy permet qd mm de gerer ca genre on importe 2 choses qui cascadent tout deux les meme dependances mais dans des version differentes et pour la compatibilite on doit pouvoir choisir le plus adequat … faut vraiment que je prenne le temps de fouiller la doc ivy.

    Sinon promis je te mets sur le fofo ou je ne sais ou mon xsl de conversion maven vers ivy pour la partie dependance et la tache ant qui va bien.

    Pour finir dans ivy (va falloir lui dedier une section du site ma poule) tu peux par le ivysettngs definir un répertoire spécifique dans lequel tu colles tes jars téléchargés a la main et lui demander de regarder dedans. Ca evite de se prendre la tete a chercher ou ivy stocke le truc en interne … tu colles tout dans un /libraries et zou ! (jai pas le code sous la main la mais a l’occase je peux le retrouver sinon gogole est votre ami ;) )

  8. Au fait voila le lien pour le site d’update du plugin ivy au cas ou vous le rechercheriez :

    http://www.jayasoft.fr/org/updatesite

    A mettre sous Eclipse dans Help > Software Updates > Find and Install

  9. @FiNaLsPy Bonne idée la rubrique ivy dédiée. C’est vraiment un mécanisme particulier qui mérite qu’on s’y attarde.

    @NicoGiard pour le path ivy, je suis sous Vista et toi sous XP, ça doit probablement venir de là.

  10. Une petite manip pour simplifier la récupération du jta.jar

    <ivysettings>
      <settings defaultResolver="noocodecommit-chain"/>
      <include url="${ivy.default.settings.dir}/ivysettings-public.xml"/>
      <include url="${ivy.default.settings.dir}/ivysettings-shared.xml"/>
      <include url="${ivy.default.settings.dir}/ivysettings-local.xml"/>
      <include url="${ivy.default.settings.dir}/ivysettings-main-chain.xml"/>
      <include url="${ivy.default.settings.dir}/ivysettings-default-chain.xml"/>
      <resolvers>
        <ibiblio name="databinder" m2compatible="true" root="http://databinder.net/repo/"/>
        <ibiblio name="ibiblio" m2compatible="true" root="http://www.ibiblio.org/maven"/>
     
        <!--a ajouter pour javax.transaction.jta -->
        <ibiblio name="maven2-codehaus-mule" m2compatible="true" root="http://dist.codehaus.org/mule/dependencies/maven2" changingPattern=".*SNAPSHOT"/>
     
        <chain name="noocodecommit-chain" returnFirst="true" checkmodified="true">
          <resolver ref="local"/>
          <resolver ref="shared"/>
     
          <!--a ajouter pour javax.transaction.jta -->
          <resolver ref="maven2-codehaus-mule"/>
     
          <resolver ref="databinder"/>
          <resolver ref="main"/>
          <resolver ref="ibiblio"/>
        </chain>
      </resolvers>
    </ivysettings>

    NB : ne pas oublier de supprimer l’ancienne version dans le cache.

    Tchou ;)

    edit par nicogiard pour corriger le problème de xml

  11. A priori, ton site aime pas le xml dans les commentaires … dommage

  12. Merci Butcho pour le Hack !

    Pour mettre du xml, encadre ton texte avec une balise

    <pre lang="xml">
    <du xml>
    </pre>

  13. Ca parle à quelqu’un ca :
    12 août 2008 17:51:07 org.apache.catalina.core.StandardContext start
    GRAVE: Error filterStart
    12 août 2008 17:51:07 org.apache.catalina.core.StandardContext start
    GRAVE: Erreur de démarrage du contexte [/helloworldDB] suite aux erreurs précédentes

  14. oui Tom mais la c’est pas super parlant, comme message d’erreur, il faudrait que tu active les logs (log4j et toussa). En gros la tu as un truc qui a complètement planté au démarrage de ton appli wicket et qui a empêché Tomcat de faire son travail.

  15. [...] mail de Nathan Hamblen, voilà une correction toute simple au problème, mis en avant dans le post Wicket main dans la main avec Hibernate grace à Databinder, concernant une erreur dans la gestion de la dépendance à JTA (javax.transaction) par [...]

  16. Salut

    Pour info, il y a possibilité de requêter directement la DB dans databinder via http://localhost:8080/monapp/dbrowse. Sympa pour savoir précisément le contenu de la base n’importe quand !

    ++
    Joseph

  17. Merci pour l’info Joseph, je vais allez voir ça de ce pas.

    Ça fait plaisir de voir zedros passer par ici ;)

  18. [...] Recent public urls tagged “cglib” → Wicket main dans la main avec Hibernate grace à Databinder [...]

  19. Je ne sais pas si j’étais le seul à qui c’est arrivé mais dans le lib du webinf , j’avais le jar servlet-api-2.3
    Apparement ca faisait doublon avec le jar déjà présent dans Apache -> erreur!
    Suppression dans le répertoire lib et ca marche!

    Par contre je pensais que le lancement de hsql était automatique. Il a fallu que je le lance avec une fenetre msdos

  20. Un update de prévu pour cet article en utilisant Maven (et l’update du quickstart) ?

  21. [...] links | iLinkShare 2 votesEclipse ClassLoading Hell>> saved by heathernature 21 days ago6 votesWicket main dans la main avec Hibernate grace à Databinder>> saved by killert00thbrush 32 days ago4 votesRe: [Orchestra] does orchestra require that Cglib [...]

 Leave a Reply

(required)

(required)


9 + six =

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="" highlight="">

   
© 2011 NooCodeCommit Suffusion theme by Sayontan Sinha