Rechercher
 

Apprendre à coder votre première page JSF

Intégration GlassFish/Eclipse



Accès rapide :
La vidéo
Introduction à l'API JSF
Introduction
Historique des versions
Création d'un projet JSF
Configuration du projet
Le descripteur de déploiement de votre WAR
Le fichier de configuration JSF de votre application
Configuration de CDI (Contexts and Dependency Injection)
Mise en oeuvre d'une page Web basée sur le pattern MVC2
Définition de la vue
Le modèle
Le contrôleur
Test de notre MVC
Modèle de navigation de JSF

La vidéo

Cette vidéo vous présente le framework JSF 2.3 et vous guide pas à pas dans la mise en oeuvre de votre première page JSF. L'IDE utilisé est Eclipse 4.8 Photon et le serveur d'applications GlassFish 5.0.


Apprendre à coder votre première page JSF

Introduction à l'API JSF

Introduction

JSF (Java Server Faces) est framework de développement d'application Web intégré à la plate-forme Java EE. En quelque sorte, c'est une couche d'abstraction par-dessus l'API des servlets et des JSP (bien que l'utilisation des JSP ne soit pas obligatoire).

Le diagramme ci-dessous vous montre les liens existants entre les différentes APIs de production de page Web proposées par la plate-forme Java EE. Il s'agit d'un système en couche. L'API de plus bas niveau d'abstraction est l'API des servlets. L'API de plus haut niveau est JSF.

il existe effectivement d'autres frameworks, proposés par d'autres éditeurs, qui ne font pas parties de la spécification Java EE, mais qui sont plus ou moins équivalents à JSF et propose les mêmes services. Parmi les principaux, retenons : Struts (1 & 2), Spring MVC, Wicket, ...

Par rapport aux couches de bases, JSF rajoute (ou complète) l'obligation d'utiliser un pattern MVC (Modèle-Vue-Contrôleur ; et plus précisément un MVC2 à contrôleur unique), des possibilités d'internationalisation de vos pages Web (I18N), une gestion événementielle des actions de l'utilisateur, ... Ce sont ces différents aspects qui confère à JSF sont statut de Framework (littéralement cadre de travail, en anglais) : vous devez respecter certaines règles de constructions de vos pages Web (notamment pour le MVC).

JSF est agnostique au regard de la technologie utilisée pour la mise en oeuvre des vues. JSF peut utiliser des pages JSP classiques ou des Facelets. Une Facelet est en quelque sorte une JSP, basée sur une définition XML. Cette API propose aussi des extensions telles que la mise en oeuvre de templates. Etant donné l'aspect plus strict d'une approche XML (par rapport à HTML), je préfère vous présenter, dans ce tutoriel, la mise en oeuvre des vues via les facelets.

bien qu'utilisé par JSF, l'API des facelets n'est pas, à proprement parler, une spécification Java EE. Il s'agit d'une librairie tierce, utilisée par JSF. C'est pour cela, que dans le diagramme ci-dessus, je l'ai colorié en gris afin de la distinguer des autres APIs.

Historique des versions

La branche 1.x de l'API JSF était fortement orientée XML pour tout ce qui avait attrait à la configuration de l'application.

Bien que supportant l'approche XML, la branche 2.x a proposé des mécanismes de configuration de l'application orientés annotations.

La version 2.3 (la plus récente au moment de l'écriture de cette page) déprécie certaines annotations JSF au profit d'annotations CDI. CDI (Contexts and Dependency Injection) est un framework d'injection de dépendance (JSR 299) qui a été intégrée au Java EE à partir de sa version 6.0.

bien entendu, dans ce tutoriel, je vais vous présenter la manière la plus moderne de procéder et donc l'approche JSF/CDI proposée à partir de JSF 2.3. Nous utiliserons Glassfish 5.0 (compatible Java EE 8.0) comme serveur d'application : au moment de l'écriture de ce tutoriel, c'est le seul proposant nativement (sans ajout de librairies tierces) les JSF 2.3. Glassfish sera piloté par Eclipse 4.8 Photon (ou supérieur).

Création d'un projet JSF

pour mettre en oeuvre le tutoriel qui suit, l'exécution des manipulations du chapitre précédent est un prérequis.

La première étape consiste à créer un nouveau projet Web. Nous l'appellerons WebStoreJSF afin de ne pas rentrer en conflit avec le projet web développé dans les chapitres précédents. Encore une fois, il s'agit de faire un mini prototype de site de vente en ligne et nous partons de l'idée que ce site n'est accessible qu'à des personnes autorisées.

Donc, cliquez avec le bouton droit de la souris dans l'explorateur de projet (« Package Explorer »), sélectionner « New », puis cliquez sur « Dynamic Web Project ».

pour avoir accès à ce type de projet, vous devez bien entendu être en perspective Java EE (boutons placés en haut, à droite de la fenêtre Eclipse), comme le montre la capture d'écran ci-dessous. Vérifiez ce point en plaçant la souris sur la perspective en cours d'utilisation : son nom doit apparaître sous forme d'info-bulle.

La boîte de dialogue suivante doit s'ouvrir : elle permet de configurer votre nouveau projet. Saisissez-y le nom de projet : WebStoreJSF. Vérifier au niveau de l'entrée « Target runtime » que le serveur GlassFish soit bien sélectionné. Si ce n'est pas le cas, vérifiez s'il apparaît dans la liste déroulante. Si ce n'est pas le cas, c'est que vous n'avez pas réalisé les étapes proposées dans le chapitre précédent : veuillez procéder à la configuration de votre serveur GlassFish avant de retenter une création de projet.

Ensuite, il faut indiquer à Eclipse que votre projet va utiliser l'outillage JSF. Effectivement, comme expliqué précédemment, il existe des frameworks équivalents et concurrents à JSF. Par défaut, Eclipse ne propose pas tous les assistants possibles et imaginables. Il faut donc lui demander d'activer dans votre projet les plugins JSF : cela se fait en rajoutant une « Facet Eclipse » (à ne pas confondre avec la notion de Facelets). Une Facet Eclipse est un ensemble de plugins à activer dans votre projet. Bien entendu la Facet à activer se nomme « JavaServer Faces ».

comme vous le constatez Eclipse ne connaît pas encore la version 2.3 de JSF. Rien de bien grave, sélectionner la version 2.2, nous corrigerons ce point un peu plus tard. Bien sur, si vous avez une version plus moderne d'Eclipse et que la version 2.3 vous est proposée, sélectionnez-la.
si vous vous demandez ou sont les facets Spring MVC ou Struts, sachez qu'il faut d'abord installer les plugins avant de pouvoir les activer dans le projet, tout simplement. Rendez-vous sur le marketplace Eclipse pour trouver ces plugins.

Ensuite, fermez les boîtes de dialogues en confirmant les changements. Normalement, le projet est crée. Si vous ouvrez l'arborescence du projet, vous devriez y retrouver les éléments suivants.

Configuration du projet

Le descripteur de déploiement de votre WAR

Le projet est en partie configuré, mais de vous propose quelques dernières modifications. Premièrement, nous allons modifier le descripteur de déploiement de votre application Web (le fichier WEB-INF/web.xml). Deux manières sont proposées pour consulter le contenu de ce descripteur de déploiement.

  1. soit vous utilisez l'assistant graphique proposé par Eclipse. Il est disponible dans l'explorateur de projet, en première entrée dans l'arborescence correspondante à votre projet (menu Deployment Descriptor: WebStoreJSF). Voici une capture d'écran montrant cet outil.

  2. soit vous ouvrez directement le fichier XML. C'est la solution que je préfère, car on peut tout contrôler. L'éditeur de descripteur de déploiement propose, à son tour, deux vues différentes : la vue Design qui permet de travailler principalement via des menus contextuels ou la vue Source qui permet directement de voir le fichier au format XML. C'est encore cette solution que je vais préférer.

Voici le nouveau contenu du fichier WEB-INF/web.xml. Quelques explications suivront.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
         xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0">
  
    <display-name>WebStoreJSF</display-name>
  
    <context-param>
        <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
        <param-value>.xhtml</param-value>
    </context-param>
    
    <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>
    
</web-app>
Descripteur de déploiement WEB-INF/web.xml

Le fichier de configuration JSF de votre application

Depuis sa première version, JSF fournit un fichier de configuration, qui doit lui aussi être placé dans le dossier WEB-INF de votre WAR. Il doit se nommer WEB-INF/faces-config.xml. Comme nous avons activé la facet Eclipse pour JSF, un outil de visualisation/édition est proposé spécifiquement pour ce fichier. Cet outil propose plusieurs onglets (en bas de la fenêtre d'édition) afin de traiter chaque aspect de la configuration. Voici une capture d'écran de cet outil.

Pour l'heure nous ne modifierons pas son contenu et il restera donc tel qu'il a été généré à la construction du projet, à une exception près : n'oubliez pas qu'au moment de l'écriture de ce tutoriel, l'assistant Eclipse de génération de projet ne connaît pas la version 2.3 (il propose au mieux la version 2.2). J'ai donc modifié la version (à deux endroits dans le tag <faces-config>) pour passer de la version 2.2 à la version 2.3. Si vous avez pu choisir directement la version 2.3, ne touchez à rien. Pour réaliser ces modifications, je me suis placé dans l'onglet « Source » de l'outil d'édition.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.3"
              xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                                  http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd">
    
</faces-config>
Fichier de configuration JSF : WEB-INF/faces-config.xml
si vous connaissez déjà le framework Apache Struts, vous noterez une certaine ressemblance dans les noms des fichiers de configuration. Effectivement, sous Struts, le fichier doit être nommé WEB-INF/struts-config.xml.

Configuration de CDI (Contexts and Dependency Injection)

Dernier point de configuration : le framework JSF peut fonctionner de différentes manières. Comme nous l'avons dit plus haut, depuis sa version 2.3, JSF propose de remplacer l'ancien jeu d'annotations (aujourd'hui déprécié) par les annotations CDI, le framework d'injection de dépendances proposé par la plate-forme Java EE depuis sa version 6.0. Pour autant, le couplage JSF/CDI n'est pas démarré par défaut. Si vous souhaitez utiliser cette nouvelle manière de procéder, de ce que je vous encourage à faire, il faut configurer JSF pour démarrer ce couplage. Pour ce faire, il suffit de rajouter la classe suivante à votre projet.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
package fr.koor.webstore;

import javax.enterprise.context.ApplicationScoped;
import javax.faces.annotation.FacesConfig;

@ApplicationScoped
@FacesConfig( version = FacesConfig.Version.JSF_2_3 )         // Activation de CDI
public class ApplicationConfiguration {
    
}
Configuration de JSF pour exploiter les annotations CDI
cette classe peut être placée dans n'importe quel package de votre projet et elle peut avoir le nom de votre choix. C'est la présence des annotations qui permet le lancement de CDI. Si vous oubliez de fournir cette classe, vous pourrez avoir un message d'erreur proche de celui-ci. Il faudra juste comprendre qu'il n'aura pas réalisé certaines injections de dépendances (ligne en gras).
2018-06-20T15:37:13.430+0200|Avertissement: StandardWrapperValve[Faces Servlet]: Servlet.service() for servlet Faces Servlet threw exception
javax.el.PropertyNotFoundException: Target Unreachable, identifier 'loginBean' resolved to null
    at com.sun.el.parser.AstValue.getTarget(AstValue.java:173)
    at com.sun.el.parser.AstValue.getType(AstValue.java:85)
    ...

Il faut aussi fournir un fichier de configuration de CDI qui doit être placé dans le dossier WEB-INF de votre application Web. Ce fichier doit se nommer WEB-INF/beans.xml. Son chargement en mémoire est conditionné à la présence de la classe précédente. En voici son contenu initial.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                           http://xmlns.jcp.org/xml/ns/javaee/beans_2_0.xsd"
       bean-discovery-mode="annotated" version="2.0">
       
</beans>
Configuration de CDI - Fichier WEB-INF/beans.xml
l'attribut bean-discovery-mode="annotated" est important, c'est lui qui indique que CDI doit rechercher des annotations pour trouver les injections de dépendances à réaliser.

Mise en oeuvre d'une page Web basée sur le pattern MVC2

Définition de la vue

Comme nous l'avons déjà dit, la vue sera générée par une facelet. Il s'agit d'un fichier XML donc l'objectif est assez proche d'une JSP. Comme il s'agit d'un fichier XML, il est très important de respecter la syntaxe XML (et plus précisément XHTML) sans quoi une erreur de compilation sera produite. Cette facelet va utiliser deux taglibs. Mais comme nous avons opté pour une approche XML, l'ajout des taglibs dans la page ne sera plus réalisé via la syntaxe <%@ taglib ... %>. En lieu et place, nous utiliserons la notion de namespace XML et d'alias sur ces namespace (pour le préfixe). Voici le contenu de notre première vue.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
<!DOCTYPE html>
<html xmlns:f="http://xmlns.jcp.org/jsf/core" 
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <f:view>
        <head>
            <title>Login screen</title>
            <link rel='stylesheet' type='text/css' href='styles.css' />
        </head>
        <body>
            <h1 align="center">Login screen</h1>
                    
            <h:form>
            
                Login: 
                <h:inputText id="login" value="#{loginBean.login}" />
                <br/>
                
                Password:
                <h:inputText id="password" value="#{loginBean.password}" />
                <br/>
            
                
                <h:commandButton action="#{loginBean.returnAction}" value="Connect" />
                
           </h:form>
        </body>
    </f:view>
</html>
Notre première vue (facelet) : une page d'authentification - Fichier login.xhtml

Le modèle

En JSF, on a introduit une nouvelle terminologie : on parle de « backing beans »

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
 17 
 18 
 19 
 20 
 21 
 22 
 23 
 24 
 25 
 26 
 27 
 28 
 29 
 30 
 31 
 32 
 33 
 34 
 35 
 36 
 37 
 38 
 39 
 40 
 41 
 42 
 43 
 44 
 45 
package fr.koor.webstore.ihm;

import java.io.Serializable;

import javax.enterprise.context.SessionScoped;
import javax.inject.Named;


@Named /*("loginBean")*/ 
@SessionScoped
public class LoginBean implements Serializable {


    private static final long serialVersionUID = -5433850275008415405L;

    private String login = "James";
    private String password = "007";
    
    public String getLogin() {
        System.out.println( "in getLogin" );
        return login;
    }

    public void setLogin(String login) {
        System.out.println( "in setLogin with " + login );
        this.login = login;
    }
    
    public String getPassword() {
        System.out.println( "in getPassword" );
        return password;
    }
    
    public void setPassword(String password) {
        System.out.println( "in setPassword with " + password );
        this.password = password;
    }
    
    
    public String returnAction() {
        System.out.println( "in returnAction" );
        return password.equals( "007" ) ? "success" : "failure";
    }
    
}
Notre « backing bean » - Classe fr.koor.webstore.LoginBean

Le contrôleur

Comme nous avons un contrôleur unique, la servlet JSF, associé à toutes URL de la forme http://serveur:port/WebStoreJSF/faces/*, rien de plus n'est requis à ce niveau.

la configuration du contrôleur de votre MVC2 est répartie sur deux fichiers XML : WEB-INF/web.xml et WEB-INF/faces-config.xml.

Test de notre MVC

Il est temps de tester notre page Web. Commençons par déployer l'application dans GlassFish. Le mieux est de cliquer avec le bouton droit de la souris sur le fichier login.xhtml (dans l'explorateur de projet) et de choisir « Run As », puis « Run On server ». Si l'application est déjà déployée elle sera automatiquement mise à jour afin de tenir compte des dernières modifications.

Une autre solution consiste à cliquer avec le bouton droit de la souris sur le serveur GlassFish (Dans la vue « Servers »), puis de sélectionner « Add and Remove... ». Une boîte de dialogue doit s'ouvrir afin de vous proposer les projets à déployer dans le serveur. Assurez-vous que le projet WebStoreJSF soit bien positionné dans la colonne de droite, comme le montre la capture d'écran ci-dessous. Enfin, cliquez sur « Finish ». Si vous souhaitez, avec cet outil, mettre à jour une application existante alors il vous faut supprimer l'application (la placer dans la colonne de gauche), puis la redéployer.

les modifications réalisées sur votre projet ne sont pas automatiquement poussées sur le seveur Glassfish. Ne l'oubliez pas.

Il ne reste plus qu'à demander à notre navigateur d'afficher la page Web. L'URL d'appel est la suivante : http://localhost:8080/WebStoreJSF/faces/login.xhtml. Voici le résultat affiché dans le navigateur (le formulaire est centré dans la page, via une définition de style CSS localisée dans le fichier styles.css).

Déjà on peut remarquer que la liaison aux données du modèle a fonctionné étant donné que l'on retrouve notre login et notre password initialisé lors de la construction de l'instance loginBean. Si vous souhaitez que par défaut les deux champs soient vides, modifiez la classe pour initialiser les deux attributs à chaîne vide.

Maintenant, il faut comprendre que JSF va bien plus loin que ce que nous avions vu dans les chapitres précédents. Le fait d'utiliser des expressions EL commençant par un # demande à JSF d'analyser le contenu de la requête HTTP. Si celle-ci est soumise en POST, alors les données soumises sont transmises au backing bean par appel des différents setters. Contrairement au MVC que nous avions mis en oeuvre, à base de servlets et de JSP, nous n'avons plus à utiliser la méthode request.getParameter( String param ). Les appels à cette méthode sont pris en charge directement par JSF. Voici les logs produits par GlassFish en cas de soumissions du formulaire (les données soumises sont bien entendu toto pour le login et titi pour le password).

2018-06-20T21:51:27.540+0200|Infos: in getLogin
2018-06-20T21:51:27.540+0200|Infos: in getPassword
2018-06-20T21:51:27.541+0200|Infos: in setLogin with toto
2018-06-20T21:51:27.541+0200|Infos: in setPassword with titi
2018-06-20T21:51:27.541+0200|Infos: in returnAction
2018-06-20T21:51:27.544+0200|Infos: in getLogin
2018-06-20T21:51:27.545+0200|Infos: in getPassword

Donc, JSF prend en charge automatiquement le maintient des données du formulaire durant sa soumission au serveur. Cela nous fait gagner du temps et des lignes de codes inutiles : c'est très bien.

Modèle de navigation de JSF

Bien entendu, une application Web n'est pas constituée que d'une seule page. Il faut donc pouvoir passer d'une page à une autre. Afin de répondre à ce besoin, JSF propose la notion d'actions.

Une action consiste en un calcul permettant de déterminer un nom logique de page Web. Dans l'exemple de code proposé, la classe LoginBean fournit une méthode de calcul associée à une action : cette méthode se nomme returnAction. Pour rappel, en revoici son code : la signature (le prototype) de la méthode est imposé par le framework JSF, par contre le nom de la méthode est libre.

 1 
 2 
 3 
 4 
public String returnAction() {
    System.out.println( "in returnAction" );
    return password.equals( "007" ) ? "success" : "failure";
}
Définition d'une action sur notre backing bean
l'appel à System.out.println est juste là pour vous permettre de vérifier que la méthode est bien invoquée.

Cette méthode d'action produit donc un chaîne de caractères qui correspond à un nom de page logique. Dans notre cas, soit on sort du formulaire en succès (chaîne "success"), soit on en sort en échec (chaîne "failure"). Cette méthode est liée à l'appui du bouton de soumission du formulaire grâce à son attribut action. Pour rappel, voici le XML de définition du bouton de soumission du formulaire.

 1 
<h:commandButton action="#{loginBean.returnAction}" value="Connect" />
Définition du bouton de soumission et liaison à la méthode returnAction.

Donc, quand vous cliquerez sur le bouton de soumission, les données du formulaire seront transmises au serveur et un appel à la méthode returnAction sera déclenché automatiquement pour déterminer la condition de sortie de ce formulaire (l'action). Une fois l'action évaluée, il ne reste plus qu'à trouver la vue correspondante à cette action. Deux méthodes de résolution d'action sont supportées.

En l'absence de possibilité de résolution de l'action (pas de résolution implicite et aucune règle de navigation dans le fichier de configuration), la vue en cours de traitement est réutilisée pour produire la page HTML de réponse à renvoyer à l'utilisateur. Dans ce tutoriel, je vous propose de tester le modèle de navigation explicite. Modifier donc le fichier WEB-INF/faces-config.xml ainsi.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
<?xml version="1.0" encoding="UTF-8"?>
<faces-config version="2.3"
              xmlns="http://xmlns.jcp.org/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
                                  http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_3.xsd">
    
    <navigation-rule>
        <from-view-id>/login.xhtml</from-view-id>
        <navigation-case>
            <from-outcome>success</from-outcome>
            <to-view-id>/viewArticle.xhtml</to-view-id>
        </navigation-case>
    </navigation-rule>

</faces-config>
Ajout d'une règle de navigation

Les règles de navigation peuvent être visualisées graphiquement dans l'outil d'édition du fichier WEB-INF/faces-config.xml. Voici le résultat produit par la configuration proposée ci-dessus.

J'insiste : dans le cas où l'action calculée est "failure", comme aucun fichier failure.xhtml n'est présent dans le projet et comme aucune règle de navigation n'est proposée pour cette action, la page HTML retournée à l'utilisateur sera générée grâce à la vue en cours (login.xhtml).

L'avantage à utiliser les règles de navigation, réside dans le fait qu'il est possible de changer l'enchaînement des pages sans forcément retoucher au code de l'application. Imaginons un processus métier nécessitant de renseigner des données au travers de quatre formulaires successifs. Si vous souhaitez modifier l'ordonnancement de ces quatre formulaires, cela pour se faire un changeant uniquement la configuration de l'application.

Pour clore ce tutoriel, vous pouvez rajouter une vue viewArticle.xhtml afin de valider la redirection. Voici un exemple de code, que nous enrichirons dans les chapitres suivants.

 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
 10 
 11 
 12 
 13 
 14 
 15 
 16 
<!DOCTYPE html>
<html xmlns:f="http://xmlns.jcp.org/jsf/core" 
      xmlns:h="http://xmlns.jcp.org/jsf/html">
    <f:view>
        <head>
            <title>View Article</title>
            <link rel='stylesheet' type='text/css' href='styles.css' />
        </head>
        <body>
            <h1 align="center">View Article</h1>
                
            <!-- TODO: à finir -->      
        
        </body>
    </f:view>
</html>
Notre vue en cas de connexion en succès.


Intégration GlassFish/Eclipse