application web java ee avec jsf et jpa - e

Transcription

application web java ee avec jsf et jpa - e
FC-Vélizy
UVSQ
APPLICATION WEB JAVA EE AVEC JSF ET JPA
Jean-Jacques LE COZ
niveau DU
Étape 1 : conception et implémentation de la classe Personne
Dans cette étape, le modèle de données qui interagit avec l'interface Homme-Machine web est
composé de la classe Personne.
Elle encapsule les données nom, prénom et courriel qui correspondent aux champs de saisie du
formulaire web.
La classe POJO Personne
public class Personne {
private String nom;
private String prenom;
private String courriel;
public Personne() {
super();
}
// autres constructeurs, get&set
1/21
UVSQ-FC-VÉLIZY
JJLC
Étape 2 : conception et implémentation du formulaire de saisie
Chaque champ de saisie défini dans la page web JSF et qui correspond au formulaire est lié à une
donnée membre de la classe Personne par l'écriture :
.
#{ nom_du_composant_JSF nom_de_la_donnée }
Lorsque l'information dans la page JSF correspond à un champ de saisie, le cadriciel (framework)
invoque la méthode set de la donnée membre. A l'inverse s'il s'agit d'une information présentée par
la page JSF, le cadriciel invoque la méthode get de la donnée membre correspondante.
Donc chaque classe de type ManagedBean doit respecter le standard JavaBean, c'est à dire avoir
une méthode get et une méthode set pour chacune de ses données membres.
2/21
UVSQ-FC-VÉLIZY
JJLC
La classe Personne annotée ManagedBean avec un cycle de vie de type requête
@ManagedBean(name = "personne")
@RequestScoped
public class Personne {
private
private
private
private
int idp;
String nom;
String prenom;
String courriel;
obligatoire
public Personne() {
super();
}
public String enregistrer() {
return "confirmation";
}
// get&set
Pour que le cycle de vie des objets de type Personne soit pris en charge par le cadriciel JSF, il faut
que la classe possède l'annotation @ManagedBean des composants JSF.
La portée d'un composant JSF (ManagedBean), sa durée de vie dépend de l'annotation @XScoped.
Ici la portée est limitée à la requête HTTP. L'annotation est donc @RequestScoped.
La page JSF index.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view contentType="text/html"/>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>FORMULAIRE</title>
</head>
correspond à un tableau HTML
<body>
avec 2 colonnes
<h:form>
<h:panelGrid columns="2">
<h:outputLabel value="Nom
:" />
<h:inputText value="#{personne.nom}"/>
<h:outputLabel value="Prénom
:"/>
<h:inputText value="#{personne.prenom}"/>
<h:outputLabel value="Courriel
:"/>
<h:inputText value="#{personne.courriel}"/>
<h:commandButton action="#{personne.enregistrer}" value="Enregistrer"/>
</h:panelGrid>
</h:form>
</body>
</html>
3/21
UVSQ-FC-VÉLIZY
JJLC
Pour que l'application soit accessible à partir du navigateur, il faut modifier le fichier web.xml
généré par le wizard de l'IDE Eclipse for JAVA EE Developers (voir les annexes). La modification
est a effectuer dans la section <welcome-file> :
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
Ainsi le contexte de la page d'accueil (index.xhtml) correspond à celui du composant Faces Servlet
du framework JSF défini plus bas dans le fichier web.xml :
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
et qu'il ne faut pas modifier.
4/21
UVSQ-FC-VÉLIZY
JJLC
Étape 3 : conception et implémentation de la page de confirmation
La page JSF confirmation.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view contentType="text/html"/>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>CONFIRMATION</title>
</head>
<body>
<h:form>
<h:outputLabel value="Madame, Monsieur " />
<h:outputText value="#{personne.nom}"/>
<h:outputLabel value=" vous êtes bien enregistré(e)" />
<br></br>
<h:commandButton action="index" value="Retour"/>
</h:form>
</body>
</html>
correspond à la page index.xhtml
5/21
UVSQ-FC-VÉLIZY
JJLC
Étape 4 : décoration du formulaire avec les contrôles de saisie
Les contrôles de saisie avec les attributs du composant JSF (UIComponent) <h:inputText> et
le système de validation par défaut <f:validateXXX>.
L'attribut required rend obligatoire la saisie du champ :
<h:inputText id="nom" value="#{personne.nom}" required="true"/>
La validation par défaut de JSF permet de contrôler le nombre de caractères saisis et bien d'autres
choses :
<h:inputText id="codepostal" value="#{personne.adresse.codepostal}">
<f:validateLength minimum="5" maximum="5"/>
</h:inputText>
La gestion des messages d'erreur associés aux contrôles :
<h:inputText id="nom" value="#{personne.nom}" required="true"/>
<h:message for="nom" showSummary="true" showDetail="false"/>
<h:inputText id="codepostal" value="#{personne.adresse.codepostal}">
<f:validateLength minimum="5" maximum="5"/>
</h:inputText>
<h:message for="codepostal" showSummary="true" showDetail="false"/>
Les contrôles de saisie peuvent être personnalisés grâce à des classes de validation.
Exemple de contrôle sur la saisie du courriel avec les règles de gestion suivantes :
- un seul caractère @ dans l'adresse est accepté,
- seules les adresses suffixées par .fr et .com sont valides
La classe d'implémentation du contrôle de saisie
@FacesValidator(value="valideur")
public class CourrielValidite implements Validator {
@Override
public void validate(FacesContext arg0, UIComponent arg1, Object arg2)
throws ValidatorException {
String courriel = null;
courriel = arg2.toString();
StringTokenizer stk = new StringTokenizer(courriel, "@");
if (stk.countTokens() != 2) {
FacesMessage errMsg = new FacesMessage(
"mauvaise adresse de courriel");
throw new ValidatorException(errMsg);
}
}
if (!courriel.endsWith(".com") && !courriel.endsWith(".fr")) {
FacesMessage errMsg = new FacesMessage(
"adresse de courriel non permise");
throw new ValidatorException(errMsg);
}
}
Le champ de saisie du courriel
<h:outputLabel value="Courriel
:"/>
<h:inputText id="courriel" value="#{personne.courriel}" required="true">
<f:validator validatorId="valideur"/>
</h:inputText>
<h:message for="courriel" showSummary="true" showDetail="false"/>
6/21
UVSQ-FC-VÉLIZY
JJLC
Étape 5 : modification de la classe Personne afin qu'elle soit persistante avec JPA
La classe Personne annotée ManagedBean avec un cycle de vie de type requête et annotée
Entity car persistante via JPA
@Entity
@ManagedBean(name = "personne")
@RequestScoped
public class Personne {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int idp;
private String nom;
private String prenom;
private String courriel;
@Transient
@ManagedProperty(value="#{fournisseur}")
private FournisseurDeGerantDePersistance fournisseur;
public Personne() {
super();
}
public String enregistrer() {
EntityManager em = fournisseur.fournir();
em.getTransaction().begin();
em.persist(this);
em.getTransaction().commit();
em.close();
return "confirmation";
}
// get&set
La classe Personne mappe vers la table ci-dessous.
<<table>>
PERSONNE
<<PK>> IDP : INTEGER
NOM : VARCHAR(32)
PRENOM : VARCHAR(32)
COURRIEL : VARCHAR(64)
L'annotation @ManagedProperty permet l'injection de dépendance (CDI). C'est le cadriciel qui a
la responsabilité d'injecter une référence d'instance de FournisseurDeGerantDePersistance.
7/21
UVSQ-FC-VÉLIZY
JJLC
La classe FournisseurDeGerantDePersistance annotée ManagedBean avec un cycle de vie de
type application (singleton).
@ManagedBean(name="fournisseur", eager=true)
@ApplicationScoped
public class FournisseurDeGerantDePersistance {
private EntityManagerFactory emf =
Persistence.createEntityManagerFactory("jsf01");
public FournisseurDeGerantDePersistance() {
super();
}
public EntityManager fournir() {
return emf.createEntityManager();
}
}
// get&set
La classe FournisseurDeGerantDePersistance ne doit être instanciée qu'une seule fois tout au long
du cycle de vie de l'application. Car une seule instance de EntityManagerFactory est suffisante
pour fournir à toutes les sessions un gérant de persistance (EntityManager) pour les opérations de
type CRUD. L'annotation @ApplicationScoped le garanti et évite au programmeur d'avoir à
implémenter la classe comme un Singleton.
La donnée membre fournisseur dans la classe Personne ne correspond à aucune colonne dans la
table et ne doit donc pas être prise en charge par la couche ORM. Elle est donc annotée @Transient.
8/21
UVSQ-FC-VÉLIZY
JJLC
Étape 6 : conception et implémentation de la page JSF qui liste les personnes
Page JSF liste.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view contentType="text/html"/>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>LISTE DES PERSONNES</title>
</head>
<body>
<h:form>
<h:dataTable value="#{gerantdepersonnes.personnes}" var="personne"
border="2">
<h:column>
<f:facet name="header">
<f:verbatim>NOM</f:verbatim>
</f:facet>
<h:outputText value="#{personne.nom}" />
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>PRENOM</f:verbatim>
</f:facet>
<h:outputText value="#{personne.prenom}" />
</h:column>
<h:column>
9/21
UVSQ-FC-VÉLIZY
JJLC
<f:facet name="header">
<f:verbatim>COURRIEL</f:verbatim>
</f:facet>
<h:outputText value="#{personne.courriel}" />
</h:column>
</h:dataTable>
<br></br>
<h:commandButton action="index" value="Retour"/>
</h:form>
</body>
</html>
Classe GerantDePersonnes qui gére la liste des personnes à partir de la base de données
@ManagedBean(name = "gerantdepersonnes")
@RequestScoped
public class GerantDePersonnes {
private List<Personne> personnes = new ArrayList<Personne>();
@ManagedProperty(value = "#{fournisseur}")
private FournisseurDeGerantDePersistance fournisseur;
public GerantDePersonnes() {
super();
}
@PostConstruct
private void init() {
EntityManager em = fournisseur.fournir();
em.getTransaction().begin();
@SuppressWarnings("unchecked")
List<Personne> resultat = em.createNativeQuery(
"SELECT * FROM PERSONNE",
Personne.class).getResultList();
}
personnes.addAll(resultat);
em.getTransaction().commit();
em.close();
public List<Personne> getPersonnes() {
return personnes;
}
public void setPersonnes(List<Personne> personnes) {
this.personnes = personnes;
}
public FournisseurDeGerantDePersistance getFournisseur() {
return fournisseur;
}
public void setFournisseur(FournisseurDeGerantDePersistance fournisseur) {
this.fournisseur = fournisseur;
}
}
10/21
UVSQ-FC-VÉLIZY
JJLC
Étape 7 : extension du modèle avec la classe Adresse
La classe Personne avec la relation vers Adresse (relation JPA et JSF)
@Entity
@ManagedBean(name = "personne")
@RequestScoped
public class Personne {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int idp;
private String nom;
private String prenom;
private String courriel;
@Embedded
@ManagedProperty(value = "#{adresse}")
private Adresse adresse;
@Transient
@ManagedProperty(value = "#{fournisseur}")
private FournisseurDeGerantDePersistance fournisseur;
// enregistrer(), constructeurs, get&set
La classe Adresse avec double annotation : JPA et JSF
@Embeddable
@ManagedBean(name="adresse")
public class Adresse {
private String voie;
private String codepostal;
private String ville;
// constructeurs, get&set
11/21
UVSQ-FC-VÉLIZY
JJLC
La page JSF index.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view contentType="text/html"/>
<head>
<title>FORMULAIRE</title>
</head>
<body>
<h:form>
<h:panelGrid columns="2">
<h:outputLabel value="Nom
:" />
<h:inputText value="#{personne.nom}"/>
<h:outputLabel value="Prénom
:"/>
<h:inputText value="#{personne.prenom}"/>
<h:outputLabel value="Courriel
:"/>
<h:inputText value="#{personne.courriel}"/>
<h:outputLabel value="Voie
:" />
<h:inputText id="voie" value="#{personne.adresse.voie}"/>
<h:outputLabel value="Code postal:" />
<h:inputText id="codepostal" value="#{personne.adresse.codepostal}"/>
<h:outputLabel value="Ville
:" />
<h:inputText id="ville" value="#{personne.adresse.ville}"/>
<h:commandButton action="#{personne.enregistrer}" value="Enregistrer"/>
</h:panelGrid>
</h:form>
</body>
</html>
La page JSF liste.xhtml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:h="http://java.sun.com/jsf/html">
<f:view contentType="text/html"/>
<head>
<title>CONFIRMATION</title>
</head>
<body>
<h:form>
<h:dataTable value="#{gerantdepersonnes.personnes}" var="personne" border="2">
<h:column>
<f:facet name="header">
<f:verbatim>NOM</f:verbatim>
</f:facet>
<h:outputText value="#{personne.nom}" />
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>PRENOM</f:verbatim>
</f:facet>
<h:outputText value="#{personne.prenom}" />
</h:column>
<h:column>
<f:facet name="header">
12/21
UVSQ-FC-VÉLIZY
JJLC
<f:verbatim>COURRIEL</f:verbatim>
</f:facet>
<h:outputText value="#{personne.courriel}" />
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>VOIE</f:verbatim>
</f:facet>
<h:outputText value="#{personne.adresse.voie}" />
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>CODE POSTAL</f:verbatim>
</f:facet>
<h:outputText value="#{personne.adresse.codepostal}" />
</h:column>
<h:column>
<f:facet name="header">
<f:verbatim>VILLE</f:verbatim>
</f:facet>
<h:outputText value="#{personne.adresse.ville}" />
</h:column>
</h:dataTable>
<br></br>
<h:commandButton action="index" value="Retour"/>
</h:form>
</body>
</html>
13/21
UVSQ-FC-VÉLIZY
JJLC
Outils
Modeleur UML : ArgoUML, MODELIO
Environnement intégré de développement : Eclipse for JAVA EE Developers
Implémentation du cadriciel JSF : MOJARRA 2.2.4
Implémentation du cadriciel JPA : Hibernate 4.2.8
Serveur d'application JAVA EE WEB : APACHE TOMCAT 7.0.47
SGBDR : APACHE DERBY (distribution JDK1.7.0_45)
Navigateur de bases de données relationnelles : SQUIRREL
ANNEXES
Configuration minimale de TOMCAT :
fichier conf/tomcat-users.xml
<tomcat-users>
<!-NOTE: By default, no user is included in the "manager-gui" role required
to operate the "/manager/html" web application. If you wish to use this app,
you must define such a user - the username and password are arbitrary.
-->
<!-NOTE: The sample user and role entries below are wrapped in a comment
and thus are ignored when reading this file. Do not forget to remove
<!.. ..> that surrounds them.
suppression des commentaires
-->
<role rolename="tomcat"/>
<role rolename="role1"/>
<user username="tomcat" password="tomcat" roles="tomcat, manager-gui"/>
<user username="both" password="tomcat" roles="tomcat,role1"/>
<user username="role1" password="tomcat" roles="role1"/>
</tomcat-users>
ajout du rôle manager-gui
Cette modification permet d'accéder à l'application TOMCAT qui gère les applications déployées
(manager) au sein du serveur.
14/21
UVSQ-FC-VÉLIZY
JJLC
Projet Eclipse : Dynamic Web Project
15/21
UVSQ-FC-VÉLIZY
JJLC
16/21
UVSQ-FC-VÉLIZY
JJLC
17/21
UVSQ-FC-VÉLIZY
JJLC
18/21
UVSQ-FC-VÉLIZY
JJLC
19/21
UVSQ-FC-VÉLIZY
JJLC
20/21
UVSQ-FC-VÉLIZY
JJLC
Problèmes d'accents.
Les navigateurs web sont paramétrés par défaut pour encoder les caractères des requêtes HTTP. Le
serveur d'application TOMCAT est également paramétré par défaut en ISO-8859-1 pour l'encodage
des requêtes HTTP entrantes et sortantes. Il se peut que sur les champs de saisie (inputText) le
serveur TOMCAT ne récupère pas les caractères spécifiques des claviers latins « é,è,ç,à,ô,ù ». Il
existe plusieurs solutions pour remédier à ce problème d'encodage. Le plus simple et le plus efficace
consiste à configurer un composant HTTP de type filtre en amont des URL sollicitées. Le principe
est que ce filtre force l'encodage en UTF-8. Son paramétrage est réalisé via le descripteur de
déploiement, le fichier web.xml. Cette solution a l'avantage de ne pas modifier la configuration des
navigateurs web et du serveur TOMCAT. Voici la solution :
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>jsf01</display-name>
<filter>
<filter-name>Set Character Encoding</filter-name>
<filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>faces/index.xhtml</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<context-param>
<description>State saving method: 'client' or 'server' (=default). See JSF Specification
2.5.2</description>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
</web-app>
La solution repose sur une librairie fournie dans TOMCAT. Pour rappel, le fichier web.xml est
généré automatiquement par le wizard d'Eclipse JAVA EE.
21/21
UVSQ-FC-VÉLIZY
JJLC

Documents pareils