Dans cet article il est proposé de développer une petite application JSF 2.2 avec un rechargement Ajax. Il existe beaucoup d’exemples qui utilisent par simplicité des objets en session. Le problème dans ce cas c’est que l’on ne comprend pas forcément l’importance des scopes et de la structure que l’on peut utiliser lors d’un développement en prenant en compte les problématiques de production classiques (limiter et simplifier la taille et l’utilisation de la mémoire).
Vue d’ensemble et configurations
Dans cet exemple en conditions réelles nous pouvons séparer les objets Java
en trois catégories d’où les trois packages suivant :
Le modèle
(les données dans le modèle MVC) : dans l’exemple un simple POJO, dans une application réelle cela peut être une entité JPA.
Le contrôleur
(le contrôleur dans le modèle MVC) : dans l’exemple un simple POJO, dans une application réelle cela peut aussi être une EJB.
Le DAO
pour l’accès aux données. Dans ce cas il s’agit d’un producer.
Le fichier XHTML
représente la vue dans le modèle MVC. Les fichiers de configuration restent vides.

Le model
Dans cet exemple il s’agit d’un simple POJO avec une variable d’instance de type String
pour sauvegarder le nom de l’utilisateur.
package org.eiw.model;
/**
* Dans un cas réel, ce bean pourrait être un objet persistant.
*
*/
public class HelloBean {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Le producer
Le producer, est un POJO enregistré dans le scope Request afin de limiter le nombre d’objets en session. C’est lui qui se charge de délivrer le modèle aux autres parties de l’application, dont la vue. Il y a deux méthodes d’initialisations :
@PostConstruct
: méthode qui est exécutée automatiquement à la création de l’objet donc à chaque nouvelle requête HTTP.
@Observes
: méthode qui est exécuté lorsqu’un événement de type HelloBean est lancé. Elle remplace la valeur par défaut du modèle par la valeur de l’objet passé en paramètre.
package org.eiw.data;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.event.Reception;
import javax.enterprise.inject.Produces;
import javax.inject.Named;
import org.eiw.model.HelloBean;
/**
* Le producer es dans le scope Request,
* il sera recréé à chaque nouvelle requete HTTP.
*/
@RequestScoped
public class HelloWorldProducer {
private HelloBean myHelloBean;
/**
* La méthode qui produit l'objet de données vis à vis de la page XHTML.
*/
@Named
@Produces
public HelloBean getMyHelloBean() {
return myHelloBean;
}
/**
* Initialise myHelloBean via un évènement.
* Méthode observeur qui s'éxécute lorsqu'un évènement
* de type HelloBean est lancé.
* @param helloBean Le paramètre de l'évènement détecté.
*/
public void myHelloBeanObserver(
@Observes(notifyObserver = Reception.IF_EXISTS)
HelloBean helloBean) {
myHelloBean = helloBean;
}
/**
* La méthode qui initialise l'objet,
* à chaque nouvelle requête HTTP.
*/
@PostConstruct
public void initMessage() {
myHelloBean = new HelloBean();
}
}
Le contrôleur
Cet objet est annoté avec @Model
. Cela lui permet d’être enregistré dans le scope Request et d’être “outjecter” dans le contexte CDI. Il est donc visible dans la vue. Il possède une méthode public
que la vue peut appeler. Il a aussi une variable d’instance de type javax.enterprise.event.Event
qui va permettre de déclencher un événement de type HelloBean et donc de prévenir le producer que l’objet myHelloBean doit être initialisé avec la méthode @Observes
.
package org.eiw.controller;
import javax.enterprise.event.Event;
import javax.enterprise.inject.Model;
import javax.inject.Inject;
import org.eiw.model.HelloBean;
/**
* Controller qui va traiter les demandes des vues.
* L'annotation est utilisée pour :
* - Positionner l'objet dans le scope Request
* - Outjecter l'objet dans le contexte d'injection CDI
* - Pouvoir référencer l'objet dans la vue XHTML
*/
@Model
public class HelloController {
/**
* Injection d'un evènement pour pouvoir prévenir
* le producer que l'objet myHelloBean doit être modifier.
*/
@Inject
private Event<HelloBean> helloBeanEventSrc;
/**
* Action pour traiter la soumission du formulaire.
* @param helloBean Cet instance vient de l'IHM.
*/
public void modifierBean(HelloBean helloBean) {
// Lancement de l'évènement de type HelloBean pour
// provoquer l'exécution de la méthode observeur
// pour mettre à jour le bean HeeloBean
helloBeanEventSrc.fire(helloBean);
}
}
La vue
Dans le fichier XHTML
, il est important de remarquer que le composant de saisi et le bouton d’action sont encapsulés dans un formulaire (<h:form/>
). Dès qu’un composant fait appel à une action ou un listner il faut l’encapsuler dans un formulaire. Sinon, la vue ne peut pas interagir avec le code Java. Cela provient de la façon de travailler de JSF, en effet, toutes les interactions entre XHTML
et Java
passent par la soumission d’un formulaire en POST
.
En revanche, la partie de la page qui se rafraîchit n’est pas nécessairement dans un formulaire.
<!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:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core">
<h:head>
</h:head>
<h:body>
<h:form>
Saisir votre nom :
<h:inputText value="#{myHelloBean.name}" />
<h:commandButton value="valider">
<f:ajax render="message" execute="@form"
listener="#{helloController.modifierBean(myHelloBean)}" />
</h:commandButton>
</h:form>
<h:outputText id="message" value="Hello #{myHelloBean.name} !" />
</h:body>
</html>
La seule contrainte pour que le composant puisse être mis à jour correctement c’est d’exister dans la page générée avant la demande de rechargement. Le code suivant ne fonctionnerai pas par exemple :
<h:outputText id="message" value="Hello #{myHelloBean.name} !"
render="#{not emty myHelloBean.name}" />
Le déploiement
Pour déployer cette application, il suffit d’utiliser le plugin wildfly avec la commande suivante : mvn wildfly:run
. Ensuite de se rendre sur l’adresse http://localhost:8080/hello-world-ajax/index.jsf et de visualiser le résultat :

Après avoir saisi son nom et cliqué sur le bouton validé, seul le libellé “Hello !” est mis à jour :

Que s’est-il passé coté HTTP lorsque le bouton “valider” est pressé ? Une requête POST est envoyée à la servlet JSF qui donne la main au contrôleur. Ensuite pour le rechargement seul un rechargement partiel est envoyé à la page d’origine. On peut d’ailleurs voir le contenu du message mis à jour. Le flux qui transite sur le réseau est donc limité au strict minimum.

Ce tutoriel est disponible sur GitHub à l’adresse suivante : https://github.com/yanLanglois/jsf-2.2-tutoriel/tree/master/hello-world-ajax.