– CQP/Mastère ASI Cours Java EE –
Exercices

Création d'un projet web avec NetBeans

Les indications ci-dessous vous guident dans la création et la configuration d'un projet d'application web JSF avec NetBeans.

Initialiation du projet

Aller dans le menu Fichier > Nouveau Projet. Choisir Web Application dans la catégorie Java Web.

Dans l'écran Name and Location donner un nom au au projet, par exemple "CQPASI-JavaEE", et
l'enregistrer dans le répertoire de travail local créé précédemment (C:\Utilisateurs\[votre_login]\Documents\WorkspaceCQPASI). ATTENTION, cette étape est très importante sans quoi vous ne pourrez pas déployer votre module sur le serveur !

Dans l'écran Server and settings, laisser les valeurs par défaut.

Dans l'écran Frameworks, cocher Java Server Faces. Cette étape de configuration est nécessaire afin de pouvoir utiliser JavaServer Faces (JSF) pour le développement du tiers présentation de l'application.

Configuration du projet : utilisation de JSF

Enfin, cliquer sur Terminer.

Modification des propriétés du projet

Il reste une dernière étape de configuration à effectuer pour terminer la création du projet NetBeans.

Cliquer sur le projet puis, avec le clic-droit de la souris, choisir Propriétés dans le menu contextuel :

Configuration du projet : accès aux propriétés

Dans la catégorie Run, décocher la case Deploy on Save comme indiqué sur la figure ci-dessous :

Configuration du projet : pas de déploiement à la sauvegarde

Remarque : cette étape de configuration peut être considérée comme optionnelle pour les développeurs expérimentés. Il s'agit d'une opération préventive pour limiter l'apparition de problèmes de désynchronisation entre le code source dans NetBeans et le code déployé sur GlassFish...

Vues et ManagedBeans JSF

Télécharger le projet NetBeans CQPASI-JavaEE-JSF-Base.zip.

Pour utiliser ce projet :

  • Décompresser l'archive zip dans le répertoire de travail créé précédemment pour NetBeans puis, dans NetBeans, choisir le menu File > Open Project et sélectionner le dossier du projet ;
  • Déployer le projet sur le serveur et l'exécuter (clic droit sur le projet puis choisir le menu Run).

Faire un schéma UML représentant les différents éléments de ce projets ainsi que leurs liens.

Compléter les vues product-view et product-edit et le ProductController pour afficher et éditer le prix des produits

Scopes JSF

Repartir du code de l'exercice précédent.

Créer un catalogue de produits

Créer un ManagedBean CatalogController contenant une liste de produits (List<Product>).

Pour stocker et utiliser une liste d'objets dans un bean Java, il faut procéder en deux temps :

  1. Créer l'attribut qui va servir à stocker la liste ;
  2. Puis initialiser l'attribut en créant une liste vide dans le constructeur du bean. On peut aussi ajouter des objets dans la liste.

Voici un exemple d'utilisation, dans lequel le bean MyManagedBean contient une liste d'objets de type Thing :


@ManagedBean(name="myManagedBean")
public class MyManagedBean { 
	private List<Thing> thingList;
	
	public MyBean(){
		// initialisation : création d'une liste vide
		this.thingList = new ArrayList<Thing>();

		// ajout d'un objet à la liste
		Thing t = new Thing();
		this.thingList.add(t);
	}

}

Pour pouvoir ensuite utiliser la liste de votre ManagedBean dans une vue JSF, il ne faut pas oublier d'ajouter un getter et un setter

Quel scope donner au ManagedBean CatalogController ?

Créer une vue pour l'affichage de la liste des produits (affichage d'un tableau de produits avec h:dataTable)

Le composant JSF permettant d'afficher une liste d'objets est la DataTable. Un exemple d'utilisation est donné ci-dessous. Dans cet exemple, le ManagedBean contient une liste d'objets de type Thing ayant deux attributs "x" et "y" :


@ManagedBean(name="myManagedBean")
public class MyManagedBean {
	…	
	public List<Thing> getThingList(){…}
	public void setThingList(List<Thing> list){…}
	…
}

<h:dataTable value="#{myManagedBean.thingList}" var="item">
	<h:column>
		<h:outputText value="#{item.x}" />
	</h:column>
	<h:column>
		<h:outputText value="#{item.y}" />
	</h:column>
</h:dataTable>

Vous pouvez trouver en ligne plus de détails sur le fonctionnement de la DataTable, et également sur le fonctionnement d'autres composants classiques de JSF.

Dans la vue présentant le catalogue de produits, ajouter un bouton action dans la datatable permettant de voir les détails d'un produit.

Pour pouvoir effectuer une action sur un objet dans une DataTable, il faut pouvoir sélectionner l'objet en question et le passer à un ManagedBean chargé du traitement.

Cela peut être réalisé de différentes façons. Voici un des exemples les plus simples :

  • Mettre la DataTable dans un formulaire h:form ;
  • Ajouter une colonne à la DataTable, afin de créer pour chaque objet un lien/bouton permettant de déclencher l'action. Ce lien transmettra l'objet au ManagedBean ;
  • Créer dans le ManagedBean une méthode qui récupère l'objet sélectionné en argument, effectue le traitement, et renvoie un outcome de navigation.

@ManagedBean(name="myManagedBean")
public class MyManagedBean {
	…	
	public List<Thing> getThingList(){…}
	public void setThingList(List<Thing> list){…}
	…
	public String executeActionOnThing(Thing t){
		// traitement quelconque sur l'objet t
		return "view-id"; // outcome de navigation vers une vue
	}
}

<h:form id="formId">
	<h:dataTable value="#{myManagedBean.thingList}" var="item">
		<h:column>
			<h:outputText value="#{item.x}" />
		</h:column>
		<h:column>
			<h:outputText value="#{item.y}" />
		</h:column>
		<h:column>
			<h:commandLink action="#{myManagedBean.executeActionOnThing(item)}" 
				value="Execute Action !" />
		</h:column>
	</h:dataTable>
</h:form>

Quel scope le ProductController doit-il avoir pour réaliser cette fonctionnalité ?

[Pour ceux qui vont vite] Mettre en place un panier

Créer un JavaBean BasketItem qui contient un produit et une quantité

Créer un ManagedBean BasketController et la vue basket-view associée (penser au scope que doit avoir ce bean)

Permettre d'ajouter un produit au panier depuis le catalogue

[Pour le fun] Améliorer l'apparence des pages

Le navigateur web donne une apparence par défaut aux différents éléments d'une page web. Il est possible de modifier cette apparence en définissant un ensemble de styles CSS. Un ensemble de styles CSS basiques vous est proposé ici :

  • Télécharger ce fichier de définition de styles CSS ;
  • Créer un dossier "resources" dans le dossier "Web Pages" de votre projet NetBeans, et placer le fichier de styles dans ce dossier ;
  • Dans chacune de vos pages JSF, placer un composant h:outputStylesheet dans le composant h:head comme indiqué ci-dessous :

<h:head>
	<title>Titre de ma page web</title>
	<h:outputStylesheet name="style.css"/>
</h:head>

Eléments de solution

Télécharger le projet NetBeans CQPASI-JavaEE-JSF-Complet.zip.

Pour utiliser ce projet :

  • Décompresser l'archive zip dans le répertoire de travail créé précédemment pour NetBeans puis, dans NetBeans, choisir le menu File > Open Project et sélectionner le dossier du projet ;
  • Déployer le projet sur le serveur et l'exécuter (clic droit sur le projet puis choisir le menu Run).

EJB Session Singleton

Repartir du code de l'exercice précédent (ou des éléments de solution correspondants).

Création d'un EJB Singleton pour gérer le catalogue

Transférer la gestion du catalogue qui se trouve dans le CatalogController dans un EJB Session Singleton

Est-il nécessaire de garder un scope Application pour le CatalogController ?

Quels verrous peut-on mettre sur les différentes méthodes du Singleton ?

[Pour ceux qui vont vite] Ajout et suppression de produits dans le catalogue

Ajouter les éléments nécessaires pour permettre à un utilisateur…

  • D'ajouter un produit dans le catalogue
  • De supprimer un produit du catalogue

Voici comment ajouter/supprimer un objet d'une liste Java :


// soit une liste d'objet
List<Thing> thingList = new ArrayList<Thing>();
// et un objet
Thing t = new Thing();

// pour ajouter l'objet à la liste :
thingList.add(t);
// pour supprimer l'objet de la liste :
thingList.remove(t);

Vous pouvez consulter la documentation de Java pour connaitre toutes les méthodes disponibles sur une liste Java.

Concernant les vues, un design classique (patron CRUD = Create, Read, Update, Delete) consiste à faire des vues JSF différentes pour les différents actions disponibles sur la liste d'objets :

  • Pour l'affichage d'un objet, la vue product-view existe déjà ;
  • Pour l'édition d'un objet, la vue product-edit existe déjà ;
  • Pour la création d'un objet, créer une vue product-create ;
  • Pour la suppression d'un objet, ajouter une colonne à la DataTable qui se trouve dans la vue qui contient la liste des objets (catalog-view) et créer un lien/bouton permettant de supprimer chaque objet séparément.

Pour la récupération de l'objet à supprimer dans la liste des objets, s'inspirer de ce qui a été fait précédemment pour permettre de voir les détails d'un produit du catalogue.

Est-il nécessaire d'avoir deux ManagedBeans ProductController et CatalogController ? Si les deux beans étaient fusionnés en un seul, quel devrait être son scope ?

Eléments de solution

Télécharger le projet NetBeans CQPASI-JavaEE-JSFEJB-StatelessSingleton.zip.

Pour utiliser ce projet :

  • Décompresser l'archive zip dans le répertoire de travail créé précédemment pour NetBeans puis, dans NetBeans, choisir le menu File > Open Project et sélectionner le dossier du projet ;
  • Déployer le projet sur le serveur et l'exécuter (clic droit sur le projet puis choisir le menu Run).

EJB Session Stateful

Repartir du code de l'exercice précédent (ou des éléments de solution correspondants).

Création d'un EJB Stateful pour gérer le panier

Transférer la gestion du panier qui se trouve dans le BasketController dans un EJB Session Stateful.

Quelle sera la durée de vie de cet EJB ?

[Pour ceux qui vont vite] Gestion du panier

Ajouter les éléments nécessaires pour permettre à un utilisateur…

  • De supprimer un produit de son panier
  • De calculer le prix de son panier (soit par clic sur un bouton, soit par mise à jour à chaque ajout d'un produit dans le panier)

Pour parcourir une liste d'objets, il est possible d'utiliser la boucle "for-each" :


// soit une liste d'objet
List<Thing> thingList = new ArrayList<Thing>();
… 
// pour parcourir tous les objets de la liste :
for(Thing t : thingList){
	// la variable t contient à chaque tour de boucle un objet différent
	t.getX();
}

Eléments de solution

Télécharger le projet NetBeans CQPASI-JavaEE-JSFEJB-StatelessSingletonStateful.zip.

Pour utiliser ce projet :

  • Décompresser l'archive zip dans le répertoire de travail créé précédemment pour NetBeans puis, dans NetBeans, choisir le menu File > Open Project et sélectionner le dossier du projet ;
  • Déployer le projet sur le serveur et l'exécuter (clic droit sur le projet puis choisir le menu Run).

Création de la base de données et de la table PRODUCT

Démarrage du serveur de bases de données Java DB

Dans l'onglet Services de NetBeans, cliquer sur Databases.

Cliquer sur Java DB puis avec le clic-droit de la souris choisir Start Server dans le menu contextuel (si le serveur est déjà démarré, cette option apparaîtra en grisé).

Vous avez ainsi accès au serveur Java DB qui tourne sur votre machine : en cliquant sur la croix (ou la flèche) qui se trouve à gauche de Java DB, vous accédez à une vue de l'ensemble des bases de données hébergées par le serveur.

Pour le moment la base de données nécessaire pour l'application de gestion des produits n'existe pas, nous allons la créer.

Création de la base de données

Aller à Databases > Java DB et choisir Create Database… dans le menu contextuel (clic-droit avec la souris).

Si l'assistant de configuration vous demande de choisir l'emplacement où sera stockée la base de donnée (Database Location), indiquer un emplacement local similaire à celui choisi pour le répertoire de travail de NetBeans, comme par exemple C:\Utilisateurs\[votre_login]\Documents\JavaDB\ (créer le dossier si celui-ci n'existe pas).

Pour le nom de la base de données, saisir "cqpasi" puis "cqpasi" pour le nom d'utilisateur et choisir un mot de passe ("cqpasi" par exemple).

Attention : vous devez absolument retenir le mot de passe que vous avez choisi pour l'accès à la base de données car vous en aurez besoin par la suite.

Cette opération créée la base de données sur le serveur et créée une connexion entre NetBeans et cette base. Celle-ci apparait sous la forme jdbc:derby://localhost:1527/cqpasi dans la liste des bases de données, un peu plus bas dans l'onglet Services > Databases.

Rappelons que chaque base de données contient un ensemble de tables, et que ce sont les tables qui contiennent les données. Il faut donc maintenant créer une table pour stoker les produits.

Création de la table PRODUCT

Cliquer sur jdbc:derby://localhost:1527/cqpasi et choisir Connect… dans le menu contextuel (si la base est déjà connectée, cette option apparaitra en grisé), puis dans le même menu choisir Execute command… .

Dans l'éditeur de commandes SQL qui s'est ouvert, coller le contenu du script automatique de création de table et de données que nous avons réalisé pour vous. Puis cliquer sur l'icône Run SQL… comme indiqué sur la figure ci-dessous.

Peuplement de la base de données

Ce script créée la table PRODUCT nécessaire pour stocker les produits.

En cas de problème avec le contenu de table PRODUCT au cours du développement, vous pourrez supprimer la table puis la recréer en suivant les indications ci-dessus.

Affichage du contenu de la table

Cliquer sur la croix (ou sur la flèche) à gauche de CQPASI dans jdbc:derby://localhost:1527/cqpasi pour faire apparaître son contenu, puis faire apparaître de la même manière le contenu de CQPASI puis Tables.

Le répertoire Tables contient les tables de la base. En développant les items vous pouvez voir les différentes colonnes de chaque table.

Choisir la table PRODUCT, puis choisir View Data… dans le menu contextuel (clic droit).

Cette commande à pour effet de faire exécuter par NetBeans une commande SQL de sélection de l'ensemble des données sur la table choisie :

select * from product;

Les données sont représentées par NetBeans dans un tableau comme celui visible sur la figure ci-dessous. Pour le moment cette table est vide. Vous pourrez de la même manière afficher le contenu de la table au cours de l'exécution de votre application afin de vérifier que les données de l'application sont bien sauvegardées en base.

Accès à la base de données sur Java DB via NetBeans

Configuration de l'unité de persistance pour JPA

Pour utiliser JPA dans une application, il faut fournir dans l'application les informations de configuration de l'accès à la base de données. Cela se fait en deux étapes :

  1. Il faut configurer le connecteur JDBC qui sera utilisé par JPA. Cela consiste à :
    1. Lui donner un nom unique permettant à l'application de le référencer comme une source de données ;
    2. Définir un pool de connexion, c'est-à-dire un ensemble de liens prédéfinis entre le serveur d'applications et le serveur de bases de données qui pourront être utilisés par l'application. La configuration du pool de connexion consiste à donner l'adresse du serveur de bases de données, le nom de la base à laquelle accéder ainsi qu'un login/mdp d'accès.
  2. Il faut ensuite fournir à l'EntityManager de JPA un fichier appelé unité de persistance qui contient une référence sur le connecteur JDBC à utiliser en tant que source de données.

Les instructions ci-dessous vous guident dans ces différentes étapes de configuration.

Réaliser ces étapes de configuration sur le projet de l'exercice précédent (ou des éléments de solution correspondants).

Création d'une source de données JDBC

Nous allons commencer par configurer le connecteur JDBC permettant d'accéder à la base de données.

Aller dans le menu File > New File > GlassFish puis choisir l'assistant JDBC Resource :

Création d'une source de données - Etape 1

Sélectionner Create New JDBC Connection Pool et donner un nom JNDI à la source de donnée (par exemple "jdbc/cqpasi"). Laisser les autres champs tels qu'ils sont :

Création d'une source de données - Etape 2

Laisser l'écran "Additional Properties" vide :

Création d'une source de données - Etape 2bis

Donner un nom au pool de connexion JDBC (par exemple "cqpasiConnectionPool"). Sélectionner Extract from Existing Connection et choisir la connexion jdbc:derby://localhost:1527/cqpasi dans la liste déroulante :

Création d'une source de données - Etape 3

NetBeans pré-remplit les propriétés nécessaires à la configuration de la source de données. Vérifiez simplement qu'elles sont correctes. Les principales informations à vérifier son que le nom de la base de données est "cqpasi", l'utilisateur est "cqpasi" et le mot de passe est celui que vous avez choisi :

Création d'une source de données - Etape 4

Laisser les valeurs par défaut dans l'écran "Optional Properties for Connection Pool" et cliquer sur "Finish" :

Création d'une source de données - Etape 4bis

L'assistant de NetBeans génère automatiquement la configuration de la source de données pour vous !

Les informations de configuration qui ont été générées se trouvent dans le fichier "glassfish-resources.xml" qui se trouve dans le répertoire "Server Resources" de votre projet. Ce fichier contient deux types d'informations :

  1. Les informations concernant la ressource JDBC avec un nom de pool de connexions :
    	
    	  <jdbc-resource enabled="true" jndi-name="jdbc/cqpasi" object-type="user" pool-name="cqpasiConnectionPool">
    	    <description/>
    	  </jdbc-resource>
    		
  2. Les informations concernant le pool de connexions, juste après la déclaration de la ressource JDBC :
    	
    	  <jdbc-connection-pool allow-non-component-callers="false" associate-with-thread="false" connection-creation-retry-attempts="0" connection-creation-retry-interval-in-seconds="10" connection-leak-reclaim="false" connection-leak-timeout-in-seconds="0" connection-validation-method="auto-commit" datasource-classname="org.apache.derby.jdbc.ClientDataSource" fail-all-connections="false" idle-timeout-in-seconds="300" is-connection-validation-required="false" is-isolation-level-guaranteed="true" lazy-connection-association="false" lazy-connection-enlistment="false" match-connections="false" max-connection-usage-count="0" max-pool-size="32" max-wait-time-in-millis="60000" name="cqpasiConnectionPool" non-transactional-connections="false" pool-resize-quantity="2" res-type="javax.sql.DataSource" statement-timeout-in-seconds="-1" steady-pool-size="8" validate-atmost-once-period-in-seconds="0" wrap-jdbc-objects="false">
    	    <property name="URL" value="jdbc:derby://localhost:1527/cqpasi"/>
    	    <property name="serverName" value="localhost"/>
    	    <property name="PortNumber" value="1527"/>
    	    <property name="DatabaseName" value="cqpasi"/>
    	    <property name="User" value="cqpasi"/>
    	    <property name="Password" value="cqpasi"/>
    	  </jdbc-connection-pool>
    		

Création d'une unité de persistance

Nous allons maintenant créer une unité de persistance qui sera utilisée par l'EntityManager de JPA.

Aller dans le menu File > New File > Persistence puis choisir l'assistant Persistence Unit.

Création d'une unité de persistance - Etape 1

Donner un nom à l'unité de persistance ("cqpasiPU" par exemple), sélectionner la source de données JDBC que vous avez créé à l'étape précédente et sélectionner Drop and Create pour la Table Generation Strategy comme indiqué ci-dessous. Puis cliquez sur "Finish".

Création d'une unité de persistance - Etape 2

L'assistant de NetBeans génère automatiquement la configuration de l'unité de persistance pour vous !

La configuration de l'unité de persistance ainsi générée se trouve dans le fichier "persistence.xml" dans le répertoire "Configuration Files" du projet.

L'unité référence le nom de la ressource JDBC que nous avons créé à l'étape précédente :

	
	<?xml version="1.0" encoding="UTF-8"?>
	<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
	  <persistence-unit name="cqpasiPU" transaction-type="JTA">
	    <jta-data-source>jdbc/cqpasi</jta-data-source>
	    <exclude-unlisted-classes>false</exclude-unlisted-classes>
	    <properties>
	    </properties>
	  </persistence-unit>
	</persistence>
		

Vous pouvez maintenant utiliser des EJB Entity et interagir avec la base de données via l'EntityManager.

Report des modifications sur le catalogue en base de données

Télécharger le projet NetBeans CQPASI-JavaEE-JSFEJBJPA-Base.zip.

Pour utiliser ce projet :

  • Décompresser l'archive zip dans le répertoire de travail créé précédemment pour NetBeans puis, dans NetBeans, choisir le menu File > Open Project et sélectionner le dossier du projet ;
  • Vérifier le contenu du fichier glassfish-resources.xml : en effet, celui-ci contient les informations d'accès à la base de données et ces informations peuvent ne pas correspondre à la configuration de votre serveur. Vérifier et modifier si nécessaire :
    • l'URL de la base : <property name="URL" value="…" />
    • le nom de la base : <property name="DatabaseName" value="…" />
    • le login/mot de passe de la base : <property name="User" value="…" />, <property name="Password" value="…" />
  • Déployer le projet sur le serveur et l'exécuter (clic droit sur le projet puis choisir le menu Run).

Cette implémentation n'est pas complète : les modifications faites sur le catalogue ne sont pas reportées en base et ne sont donc pas prises en compte.

Faire en sorte que lorsque l'ajout, la suppression et la modification d'un produit soient reportées en base de données.

Les modifications sur les produits sont faites dans le Tiers Présentation. Il ne faut pas oublier que les EJB Entity sont détachées de l'EntityManager lorsqu'elles sont transmises à la partie JSF.

Pour que les modifications faites par l'utilisateur soient reportées automatiquement en base de données, il faut que l'EJB Entity concernée soit transmise par la partie JSF à l'EJB chargé de gérer la liste des entités. Cet EJB doit alors rattacher l'EJB Entity concernée à l'EntityManager en utilisant la méthode merge().

Par quel autre type d'EJB pourrait-on remplacer notre CatalogSingleton ?.

Eléments de solution

Télécharger le projet NetBeans CQPASI-JavaEE-JSFEJBJPA-Complet.zip.

Pour utiliser ce projet :

  • Décompresser l'archive zip dans le répertoire de travail créé précédemment pour NetBeans puis, dans NetBeans, choisir le menu File > Open Project et sélectionner le dossier du projet ;
  • Vérifier le contenu du fichier glassfish-resources.xml : en effet, celui-ci contient les informations d'accès à la base de données et ces informations peuvent ne pas correspondre à la configuration de votre serveur. Vérifier et modifier si nécessaire :
    • l'URL de la base : <property name="URL" value="…" />
    • le nom de la base : <property name="DatabaseName" value="…" />
    • le login/mot de passe de la base : <property name="User" value="…" />, <property name="Password" value="…" />
  • Déployer le projet sur le serveur et l'exécuter (clic droit sur le projet puis choisir le menu Run).