Skip to content

9. Voorbeeldtoepassing 05: rdvmedecins-pfm-ejb

Laten we nog eens de structuur bekijken van voorbeeldtoepassing 01 JSF / EJB, ontwikkeld voor de Glassfish-server:

We brengen geen wijzigingen aan in deze architectuur, behalve aan de weblaag, die hier zal worden gerealiseerd met behulp van JSF, Primefaces en Primefaces Mobile. De doelbrowser is die van een mobiel apparaat.

We hebben twee applicaties ontwikkeld met Glassfish:

  • applicatie 01 maakte gebruik van JSF / EJB en had een vrij eenvoudige interface,
  • applicatie 03 maakte gebruik van PF / EJB en had een uitgebreide interface.

Vanwege het beperkte aantal beschikbare componenten in PrimeFaces Mobile gaan we terug naar de eenvoudige interface van applicatie 01. Bovendien moeten de weergaven zich kunnen aanpassen aan de kleinere afmetingen van mobiele schermen.

9.1. De weergaven

Om een beeld te geven, tonen we enkele weergaven van de applicatie die wordt uitgevoerd in de simulator van een iPhone 4:

  • in [1], de startpagina. Merk op dat we deze keer de naam van de machine moesten opgeven (je kunt ook het adres opgeven: IP), omdat er met de machine localhost niets werd weergegeven,
  • in [2], de lijst met artsen,
  • bij [3] de gewenste datum voor de afspraak,
  • in [4] de knop om de agenda van vandaag op te vragen,
  • in [5], toont het nieuwe scherm de beschikbare tijdvakken van de arts,
  • in [6], een reeks knoppen om door de kalender te navigeren,
  • in [7], een bericht ter herinnering aan de arts en de dag,
  • in [8], een tijdvak om te reserveren. Dat doen we,
  • in [9], het overzichtsscherm voor de klant,
  • in [10], een bericht ter herinnering aan de arts, de dag en het tijdvak van de afspraak,
  • in [11], de klantenlijst,
  • in [12], de bevestigingsknop,
  • in [13]: na bevestiging keren we terug naar de agenda,
  • in [14] is het bezette tijdvak nu gereserveerd. We gaan nu de reservering verwijderen,
  • in [15] blijven we in hetzelfde scherm,
  • maar in [16] is de afspraak verwijderd,

Op de startpagina is het mogelijk om van taal te wisselen: [17], [18], [19]:

Ten slotte is er een foutweergave voorzien:

9.2. Het NetBeans-project

Het NetBeans-project is als volgt:

  
  • [mv-rdvmedecins-ejb-dao-jpa]: project EJB van de lagen [DAO] en [JPA] uit voorbeeld 01,
  • [mv-rdvmedecins-ejb-metier]: project EJB van de laag [métier] uit voorbeeld 01,
  • [mv-rdvmedecins-pfmobile]: project van de laag [web] / PrimeFaces Mobile – nieuw,
  • [mv-rdvmedecins-pfmobile-app-ear]: bedrijfsproject om de applicatie op de Glassfish-server te implementeren – nieuw.

9.3. Het bedrijfsproject

Het bedrijfsproject dient uitsluitend voor de implementatie van de drie modules [mv-rdvmedecins-ejb-dao-jpa], [mv-rdvmedecins-ejb-metier] en [mv-rdvmedecins-pfmobile] op de Glassfish-server. Het NetBeans-project is als volgt:

Het project bestaat uitsluitend voor deze drie afhankelijkheden [1], die in het bestand [pom.xml] als volgt zijn gedefinieerd:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
...

  <groupId>istia.st</groupId>
  <artifactId>mv-rdvmedecins-pfmobile-app-ear</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>ear</packaging>

  <name>mv-rdvmedecins-pfmobile-app-ear</name>

...
    <dependencies>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>mv-rdvmedecins-ejb-dao-jpa</artifactId>
            <version>${project.version}</version>
            <type>ejb</type>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>mv-rdvmedecins-ejb-metier</artifactId>
            <version>${project.version}</version>
            <type>ejb</type>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>mv-rdvmedecins-pfmobile</artifactId>
            <version>${project.version}</version>
            <type>war</type>
        </dependency>
    </dependencies>
</project>
  • regels 6-9: het Maven-artefact van het bedrijfsproject,
  • regels 14-33: de drie afhankelijkheden van het project. Let goed op het type van deze afhankelijkheden (regels 19, 25, 31).

Om de webapplicatie uit te voeren, moet dit bedrijfsproject worden uitgevoerd.

9.4. Het PrimeFaces Mobile-webproject

Het Primefaces Mobile-webproject ziet er als volgt uit:

  • in [1], de pagina’s van het project. De pagina [index.xhtml] is de enige pagina van het project. Deze bevat vijf weergaven: [vue1.xhtml], [vue2.xhtml], [vue3.xhtml], [vueErreurs.xhtml] en [config.xhtml],
  • en in [2] de Java-beans. De bean [Application] met bereik application, de bean [Form] met bereik session. De klasse [Erreur] kapselt een fout in,
  • in [3] de berichtbestanden voor internationalisering,
  • in [4], de afhankelijkheden. Het webproject is afhankelijk van het project EJB van de laag [DAO], het project EJB van de laag [métier] en Primefaces Mobile voor de laag [web].

9.5. De projectconfiguratie

De projectconfiguratie is dezelfde als die van de Primefaces-projecten of JSF die we eerder hebben besproken. We sommen de configuratiebestanden op zonder ze opnieuw uit te leggen.

 

[web.xml]: configureert de webapplicatie.


<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
  <context-param>
    <param-name>javax.faces.PROJECT_STAGE</param-name>
    <param-value>Development</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.FACELETS_SKIP_COMMENTS</param-name>
    <param-value>true</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>
  <session-config>
    <session-timeout>
      30
    </session-timeout>
  </session-config>
  <welcome-file-list>
    <welcome-file>faces/index.xhtml</welcome-file>
  </welcome-file-list>
  <error-page>
    <error-code>500</error-code>
    <location>/faces/exception.xhtml</location>
  </error-page>
  <error-page>
    <exception-type>Exception</exception-type>
    <location>/faces/exception.xhtml</location>
  </error-page>

</web-app>

Let op: op regel 26 staat dat de pagina [index.xhtml] de startpagina van de applicatie is.

[faces-config.xml]: configureert de applicatie JSF


<?xml version='1.0' encoding='UTF-8'?>

<!-- =========== FULL CONFIGURATION FILE ================================== -->

<faces-config version="2.0"
              xmlns="http://java.sun.com/xml/ns/javaee" 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd">

  <application>
    <resource-bundle>
      <base-name>
        messages
      </base-name>
      <var>msg</var>
    </resource-bundle>
      <message-bundle>messages</message-bundle>
    <default-render-kit-id>PRIMEFACES_MOBILE</default-render-kit-id>
  </application>
</faces-config>

[beans.xml]: leeg, maar nodig voor de annotatie @Named


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

[messages_fr.properties]: het bestand met de berichten in het Frans


# pagina
page.titre=Les M\u00e9decins Associ\u00e9s
format.date=dd/MM/yyyy
format.date_detail=dd/MM/yyyy

# weergave1
vue1.header=Les M\u00e9decins Associ\u00e9s - R\u00e9servations

# formulier 1
form1.titre=R\u00e9servations
form1.medecin=M\u00e9decin
form1.jour=Jour (jj/mm/aaaa)
form1.date.requise=La date est n\u00e9cessaire
form1.date.invalide=La date est invalide
form1.date.invalide_detail=La date est invalide
form1.agenda=Agenda
form1.options=Options

# formulier 2
form2.titre={0} {1} {2}<br/>{3}
form2.titre_detail={0} {1} {2}<br/>{3}
form2.retour=Retour
form2.supprimer=Supprimer
form2.reserver=R\u00e9server
form2.precedent=Jour pr\u00e9c\u00e9dent
form2.suivant=Jour suivant
form2.today=Aujourd'hui

# formulier 3
form3.client=Client
form3.valider=Valider
form3.titre={0} {1} {2}<br/>{3}<br/>{4,number,#00}h:{5,number,#00}-{6,number,#00}h:{7,number,#00}
form3.titre_detail={0} {1} {2}<br/>{3}<br/>{4,number,#00}h:{5,number,#00}-{6,number,#00}h:{7,number,#00}
form3.retour=Retour

# fout
erreur.titre=Une erreur s'est produite.

# configuratie
config.retour=Retour
config.titre=Configuration
config.langue=Langue
config.langue.francais=Fran\u00e7ais
config.langue.anglais=Anglais
config.valider=Valider

#uitzondering
exception.titre=Application indisponible. Veuillez recommencer ult\u00e9rieurement.

[messages_en.properties]: het bestand met berichten in het Engels


# pagina
page.titre=The Associated Doctors
format.date=dd/MM/yyyy
format.date_detail=dd/MM/yyyy

# weergave1
vue1.header=The Associated Doctors - Reservations

# formulier 1
form1.titre=Reservations
form1.medecin=Doctor
form1.jour=day (dd/mm/yyyy)
form1.date.requise=The date is necessary
form1.date.invalide=Invalid date
form1.date.invalide_detail=invalid date
form1.agenda=Diary
form1.options=Options

# formulier 2
form2.titre={0} {1} {2}<br/>{3}
form2.titre_detail={0} {1} {2}<br/>{3}
form2.retour=Back
form2.supprimer=Delete
form2.reserver=Reserve
form2.precedent=Previous Day
form2.suivant=Next Day
form2.today=Today

# formulier 3
form3.client=Patient
form3.valider=Validate
form3.titre={0} {1} {2}<br/>{3}<br/>{4,number,#00}h:{5,number,#00}-{6,number,#00}h:{7,number,#00}
form3.titre_detail={0} {1} {2}<br/>{3}<br/>{4,number,#00}h:{5,number,#00}-{6,number,#00}h:{7,number,#00}
form3.retour=Back

# fout
erreur.titre=Some error happened

# configuratie
config.retour=Back
config.titre=Configuration
config.langue=Language
config.langue.francais=French
config.langue.anglais=English
config.valider=Validate

#uitzondering
exception.titre=Application not available. Please try again later.

9.6. De pagina [index.xhtml]

Het project toont steeds dezelfde pagina, namelijk de volgende pagina: [index.xhtml]


<f:view xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:p="http://primefaces.org/ui"
        xmlns:pm="http://primefaces.org/mobile"
        contentType="text/html"
        locale="#{form.locale}">

  <pm:page title="#{msg['page.titre']}">
    <pm:view id="vue1">
      <ui:fragment rendered="#{form.form1Rendered}">
        <ui:include src="vue1.xhtml"/>
      </ui:fragment>
      <ui:fragment rendered="#{form.erreurInit}">
        <ui:include src="vueErreurs.xhtml"/>
      </ui:fragment>
    </pm:view>
    <pm:view id="vue2">
      <ui:fragment rendered="#{form.form2Rendered}">
        <ui:include src="vue2.xhtml"/>
      </ui:fragment>
    </pm:view>
    <pm:view id="vue3">
      <ui:fragment rendered="#{form.form3Rendered}">
        <ui:include src="vue3.xhtml"/>
      </ui:fragment>
    </pm:view>
    <pm:view id="vueErreurs">
      <ui:fragment rendered="#{form.erreurRendered}">
        <ui:include src="vueErreurs.xhtml"/>
      </ui:fragment>
    </pm:view>
    <pm:view id="config">
      <ui:include src="config.xhtml"/>
    </pm:view>
  </pm:page>    
</f:view>
  • regel 8: de pagina is geïnternationaliseerd (attribuut locale),
  • regel 10: de pagina bevat vijf weergaven: weergave1 regel 11, weergave2 regel 19, weergave3 regel 24, vueErreurs regel 29, config regel 34. Op een bepaald moment is slechts één van deze weergaven zichtbaar. Bij het opstarten van de applicatie wordt de weergave weergave1 weergegeven. Hier stuitten we op de volgende moeilijkheid: als het opstarten van de applicatie goed is verlopen, moet [vue1.xhtml] worden weergegeven; anders moet [vueErreurs.xhtml] worden weergegeven. We hebben het probleem opgelost door ervoor te zorgen dat de inhoud van de weergave vue1 wordt beheerd door het model dat waarden toekent aan de booleaanse variabelen [Form].form1rendered (regel 12) en [Form].erreurInit (regel 15) vast te leggen, om zo de inhoud van vue1 (regel 11) vast te leggen,

In een simulator heeft de weergave [vue1.xhtml] de weergave [1], de weergave [vue2.xhtml] de weergave [2], de weergave [vue3.xhtml] de weergave [3]:

de weergave [vueErreurs.xhtml], de weergave [4], de weergave [config.xhtml], de weergave [5]:

9.7. De beans van het project

De klasse van het pakket [utils] is al besproken: de klasse [Messages] is een klasse die de internationalisering van de berichten van een applicatie vergemakkelijkt. Deze is behandeld in paragraaf 2.8.5.7.

9.7.1. De Application-bean

De bean [Application.java] is een bean met het bereik application. Zoals u zich wellicht herinnert, wordt dit type bean gebruikt om alleen-lezen gegevens op te slaan die beschikbaar zijn voor alle gebruikers van de applicatie. Deze bean is als volgt:


package beans;

import javax.ejb.EJB;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import rdvmedecins.metier.service.IMetierLocal;

@Named(value = "application")
@ApplicationScoped
public class Application {

  // bedrijfslaag
  @EJB
  private IMetierLocal metier;

  public Application() {
  }
  
  // getters

  public IMetierLocal getMetier() {
    return metier;
  }
  
}
  • regel 8: de bean krijgt de naam ‘application’,
  • regel 9: de bean heeft het bereik ‘application’,
  • regels 13-14: er wordt een verwijzing naar de lokale interface van de laag [métier] in geïnjecteerd door de container EJB van de applicatieserver. Laten we de architectuur van de applicatie nog eens in herinnering brengen:

De applicaties PFM, EJB en [Metier] worden uitgevoerd in dezelfde JVM (Java Virtual Machine). De laag [PFM] zal dus gebruikmaken van de lokale interface van de EJB. Dat is alles. De bean [Application] bevat verder niets. Om toegang te krijgen tot de laag [métier], zullen de andere beans deze uit deze bean ophalen.

9.7.2. De bean [Erreur]

De klasse [Erreur] ziet er als volgt uit:


package beans;

public class Erreur {
  
  public Erreur() {
  }
  
  // veld
  private String classe;
  private String message;

  // constructor
  public Erreur(String classe, String message){
    this.setClasse(classe);
    this.message=message;
  }
  
  // getters en setters
...  
}
  • regel 9: de naam van een uitzonderingsklasse als er een uitzondering is gegenereerd,
  • regel 10: een foutmelding.

9.7.3. De bean [Form]

De code ervan is als volgt:


package beans;

...

@Named(value = "form")
@SessionScoped
public class Form implements Serializable {

  public Form() {
  }
  // Application-bean
  @Inject
  private Application application;
  private IMetierLocal metier;
  // sessiecache
  private List<Medecin> medecins;
  private List<Client> clients;
  private Map<Long, Medecin> hMedecins = new HashMap<Long, Medecin>();
  private Map<Long, Client> hClients = new HashMap<Long, Client>();
  // model
  private Long idMedecin;
  private Date jour = new Date();
  private String strJour;
  private Boolean form1Rendered;
  private Boolean form2Rendered;
  private Boolean form3Rendered;
  private Boolean erreurRendered;
  private String form2Titre;
  private String form3Titre;
  private AgendaMedecinJour agendaMedecinJour;
  private Long idCreneauChoisi;
  private Medecin medecin;
  private Long idClient;
  private CreneauMedecinJour creneauChoisi;
  private List<Erreur> erreurs;
  private Boolean erreurInit = false;
  private String action;
  private String locale = "fr";
  private String msgErreurDate = "";
  private SimpleDateFormat dateFormatter;
  private Boolean erreurDate;
  
  @PostConstruct
  private void init() {
    System.out.println("init");
    // in eerste instantie geen fout
    erreurInit = false;
    // de opmaak van datums
    dateFormatter = new SimpleDateFormat(Messages.getMessage(null, "format.date", null).getSummary());
    dateFormatter.setLenient(false);
    // de huidige dag
    strJour = dateFormatter.format(jour);
    // de bedrijfslaag wordt opgehaald
    metier = application.getMetier();
    // artsen en klanten in de cache plaatsen
    try {
      medecins = metier.getAllMedecins();
      clients = metier.getAllClients();
    } catch (Throwable th) {
      // de fout wordt genoteerd
      erreurInit = true;
      prepareVueErreur(th);
      return;
    }
    // controle van de lijsten
    if (medecins.size() == 0) {
      // de fout wordt genoteerd
      erreurInit = true;
      erreurs = new ArrayList<Erreur>();
      erreurs.add(new Erreur("", "La liste des médecins est vide"));
    }
    if (clients.size() == 0) {
      // de fout wordt genoteerd
      erreurInit = true;
      erreurs = new ArrayList<Erreur>();
      erreurs.add(new Erreur("", "La liste des clients est vide"));
    }
    // fout?
    if (erreurInit) {
      // het foutenoverzicht wordt weergegeven
      setForms(false, false, false, true);
      return;
    }

    // de woordenboeken
    for (Medecin m : medecins) {
      hMedecins.put(m.getId(), m);
    }
    for (Client c : clients) {
      hClients.put(c.getId(), c);
    }
    // weergave 1
    setForms(true, false, false, false);
  }

  // weergave van het overzicht
  private void setForms(Boolean form1Rendered, Boolean form2Rendered, Boolean form3Rendered, Boolean erreurRendered) {
    this.form1Rendered = form1Rendered;
    this.form2Rendered = form2Rendered;
    this.form3Rendered = form3Rendered;
    this.erreurRendered = erreurRendered;
  }

  // voorbereiding vueErreur
  private void prepareVueErreur(Throwable th) {
    // de foutenlijst wordt aangemaakt
    erreurs = new ArrayList<Erreur>();
    erreurs.add(new Erreur(th.getClass().getName(), th.getMessage()));
    while (th.getCause() != null) {
      th = th.getCause();
      erreurs.add(new Erreur(th.getClass().getName(), th.getMessage()));
    }
// de foutweergave wordt getoond
    setForms(false, false, false, true);
  }

  // getters en setters
  ..
}
  • regels 5-7: de klasse [Form] is een bean met de naam ‘form’ en een bereik van ‘session’. We herinneren eraan dat de klasse in dat geval serialiseerbaar moet zijn,
  • regels 12-13: de bean ‘form’ heeft een verwijzing naar de bean ‘application’. Deze wordt geïnjecteerd door de servletcontainer waarin de applicatie wordt uitgevoerd (aanwezigheid van de annotatie @Inject).
  • regels 24-27: regelen de weergave van de weergaven vue1 (regel 24), vue2 (regel 25), vue3 (regel 26) en vueErreurs (regel 27),
  • regels 43-44: de methode init wordt direct na het instantiëren van de klasse uitgevoerd (aanwezigheid van de annotatie @PostConstruct),
  • regels 49-50: regelen de datumnotatie. PrimeFaces Mobile biedt geen kalender. Bovendien zijn de validators JSF niet bruikbaar in een PFM-pagina. Daarom moeten we de invoer van de agendadatum handmatig regelen,
  • regel 49: bepaalt de datumnotatie. Deze notatie wordt overgenomen uit de geïnternationaliseerde bestanden:

format.date=dd/MM/yyyy
format.date_detail=dd/MM/yyyy
  • regel 50: hier wordt aangegeven dat de datum niet "laxiste" mag zijn. Als dit niet wordt gedaan, wordt een invoer zoals 32/12/2011 – wat een onjuiste invoer is – beschouwd als de geldige datum 01/01/2012,
  • regel 54: er wordt een referentie opgehaald uit de laag [métier] via de bean [Application],
  • regels 57-58: we vragen de laag [métier] om de lijst met artsen en klanten,
  • regels 66-91: als alles goed is verlopen, worden de lijsten met artsen en klanten samengesteld. Ze worden geïndexeerd op nummer. Vervolgens wordt de weergave [vue1.xhtml] weergegeven (regel 93),
  • regel 59: in geval van een fout wordt het sjabloon van de pagina [vueErreurs.xhtml] opgebouwd. Dit sjabloon is de foutenlijst uit regel 35,
  • regels 105-115: de methode [prepareVueErreur] stelt de weer te geven foutenlijst samen. De pagina [index.xhtml] geeft vervolgens de weergave [vueErreurs.xhtml] weer (regel 114).

De pagina [erreur.xhtml] is als volgt:


<?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:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:pm="http://primefaces.org/mobile"
      xmlns:ui="http://java.sun.com/jsf/facelets">

  <!-- Foutenoverzicht -->
  <pm:header title="#{msg['page.titre']}" swatch="b">
    <f:facet name="left">
      <p:button icon="home" value=" " href="#vue1?reverse=true" />
    </f:facet>
  </pm:header>
  <pm:content>
    <div align="center">
      <h1><h:outputText value="#{msg['erreur.titre']}" style="color: blue"/></h1>
    </div>

    <p:dataList value="#{form.erreurs}" var="erreur">
      <b>#{erreur.classe}</b> : <i>#{erreur.message}</i>
    </p:dataList>
  </pm:content>
</html>

Deze maakt gebruik van een <p:dataList>-tag (regels 21-23) om de lijst met fouten weer te geven. Met de knop op regel 13 kunt u terugkeren naar weergave vue1.

  • de knop [1] wordt gegenereerd door regel 13. Het attribuut icon bepaalt het pictogram van de knop. De knop keert terug naar de weergave vue1 (attribuut href),
  • de koptekst [2] wordt gegenereerd door de regels 11-15,
  • de titel [3] wordt gegenereerd door regel 18,
  • de tekst [4] wordt gegenereerd door het sjabloon #{erreur.classe} in regel 22,
  • de tekst [5] wordt gegenereerd door het sjabloon #{erreur.message} in regel 22.

We gaan nu de verschillende fasen in de levenscyclus van de applicatie definiëren. Voor elke actie van de gebruiker zullen we de betreffende weergaven en de gebeurtenishandlers die daar plaatsvinden, bestuderen.

9.8. De weergave van de startpagina

Als alles goed gaat, is de eerste weergegeven weergave [vue1.xhtml]. Dit levert de volgende weergave op:

De code van de weergave [vue1.xhtml] is als volgt:


<?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:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:pm="http://primefaces.org/mobile"
      xmlns:ui="http://java.sun.com/jsf/facelets">

  <!-- Weergave 1 -->
  <pm:header title="#{msg['page.titre']}" swatch="b">
    <f:facet name="left">
      <p:button icon="gear" value=" "  href="#config" />
    </f:facet>
  </pm:header>
  <pm:content>
    <h:form id="form1">
      <div align="center">
        <h1><h:outputText value="#{msg['form1.titre']}" style="color: blue"/></h1>
      </div>
      <pm:field>
        <h:outputLabel value="#{msg['form1.medecin']}" for="choixMedecin"/>
        <h:selectOneMenu id="choixMedecin" value="#{form.idMedecin}">  
          <f:selectItems value="#{form.medecins}" var="medecin" itemLabel="#{medecin.titre} #{medecin.prenom} #{medecin.nom}" itemValue="#{medecin.id}"/>  
        </h:selectOneMenu>              
      </pm:field>
      <pm:field>
        <h:outputLabel value="#{msg['form1.jour']}" for="jour"/>
        <p:inputText id="jour" value="#{form.strJour}"/>
        <ui:fragment rendered="#{form.erreurDate}">
          <p:spacer width="50px"/>
          <h:outputText id="msgErreurDate" value="#{form.msgErreurDate}" style="color: red"/>
        </ui:fragment>
      </pm:field>
      <p:commandButton value="#{msg['form1.agenda']}" update=":form1, :vue2, :vueErreurs" action="#{form.getAgenda}" />
    </h:form>
  </pm:content>
</html>
  • regels 11-15: genereren de koptekst [1],
  • regel 13: genereert de knop [2]. Als je hierop klikt, wordt de configuratieweergave weergegeven (attribuut href),
  • regel 19: genereert de titel [3],
  • regels 21-26: genereren de keuzelijst met artsen [4],
  • regels 27-34: genereren het datumveld [5]. Dit veld wordt weergegeven met een <p:inputText>-tag zonder validatie. De validatie van de datum vindt plaats aan de serverzijde. Als de datum onjuist is, wordt er een foutmelding weergegeven via de regels 30-34,
  • regel 35: de knop die het formulier valideert. Deze werkt drie velden bij: form1 (het formulier in vue1), vue2 en vueErreurs. Als de datum ongeldig is, moet namelijk form1 worden bijgewerkt. Als de datum correct is, moet vue2 worden bijgewerkt. Als er ten slotte een uitzondering optreedt (bijvoorbeeld een verbroken verbinding met de database), moet vueErreurs worden weergegeven. Het kan verleidelijk zijn om vue1 in plaats van form1 te gebruiken (waardoor de hele weergave wordt bijgewerkt). In dat geval vertoont de applicatie fouten.

Deze weergave is gekoppeld aan het volgende model:


@Named(value = "form")
@SessionScoped
public class Form implements Serializable {

  public Form() {
  }

  // Application-bean
  @Inject
  private Application application;
  private IMetierLocal metier;
  // sessiecache
  private List<Medecin> medecins;
  private List<Client> clients;
  // sjabloon
  private Long idMedecin;
  private Date jour = new Date();
  private String strJour;
  private Boolean form1Rendered;
  private Boolean form2Rendered;
  private Boolean form3Rendered;
  private Boolean erreurRendered;
  private String msgErreurDate = "";
  private Boolean erreurDate;
  
    // lijst met artsen
  public List<Medecin> getMedecins() {
    return medecins;
  }

  // agenda
  public String getAgenda() {
...
    }
  }
  • het veld op regel 16 levert de waarde voor de lijst op regel 23 van de pagina, zowel voor lezen als schrijven. Bij de eerste weergave van de pagina stelt het de geselecteerde waarde in de keuzelijst vast,
  • de methode op regels 27-29 genereert de opties voor de keuzelijst met artsen (regel 24 van de weergave). Elke gegenereerde optie heeft als label (itemLabel) de titel, achternaam en voornaam van de arts en als waarde (itemValue) de id van de arts,
  • het veld op regel 18 voorziet het invoerveld op regel 29 van de pagina van gegevens (lezen/schrijven),
  • regels 32-34: de methode getAgenda verwerkt de klik op de knop [Agenda] op regel 35 van de pagina. De code ervan is als volgt:

// agenda
  public String getAgenda() {
    try {
      // de dag wordt gecontroleerd
      jour = dateFormatter.parse(strJour);
      // geen fout
      erreurDate=false;
      msgErreurDate = "";
      // agenda wordt aangemaakt
      return getAgenda(jour);
    } catch (ParseException ex) {
      // foutmelding
      erreurDate=true;
      msgErreurDate = Messages.getMessage(null, "form1.date.invalide", null).getSummary();
      // weergave 1      
      setForms(true, false, false, false);
      return "pm:vue1";
    }
  }
  • de methode begint met het controleren van de geldigheid van de door de gebruiker ingevoerde datum,
  • regel 5: de datum is parsée volgens het datumformaat dat door de methode init bij het instantiëren van het model is geïnitialiseerd,
  • regel 11: als er een uitzondering optreedt, wordt er een fout vastgesteld (regel 13), wordt er een geïnternationaliseerd foutbericht samengesteld (regel 14), wordt de weergave vue1 voorbereid (regel 16) en wordt de weergave vue1 weergegeven (regel 17),
  • regel 10: als de datum correct is, wordt de volgende methode uitgevoerd:

  // agenda
  public String getAgenda(Date jour) {
    // er is nog geen tijdvak geselecteerd
    creneauChoisi = null;
    try {
      // de gekozen arts wordt opgehaald
      medecin = hMedecins.get(idMedecin);
      // titel formulier 2
      form2Titre = Messages.getMessage(null, "form2.titre", new Object[]{medecin.getTitre(), medecin.getPrenom(), medecin.getNom(), new SimpleDateFormat("dd MMM yyyy").format(jour)}).getSummary();
      // de agenda van de arts voor een bepaalde dag
      agendaMedecinJour = metier.getAgendaMedecinJour(medecin, jour);
      // we geven weergave 2 weer
      setForms(false, true, false, false);
      return "pm:vue2";
    } catch (Throwable th) {
      System.out.println(th);
      // foutenoverzicht
      prepareVueErreur(th);
      return "pm:vueErreurs";
    }
}

Dit is code die we al meerdere keren zijn tegengekomen. In regel 9 wordt een geïnternationaliseerde foutmelding samengesteld voor de weergave vue2:


form2.titre={0} {1} {2}<br/>{3}
form2.titre_detail={0} {1} {2}<br/>{3}

Merk op dat we XHTML in het bericht hebben opgenomen. Dit wordt als volgt weergegeven:

9.9. De agenda van een arts weergeven

De agenda van de arts wordt weergegeven via de weergave [vue2.xhtml]:

De code van de weergave [vue2.xhtml] is als volgt:


<?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:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:pm="http://primefaces.org/mobile"
      xmlns:ui="http://java.sun.com/jsf/facelets">

  <!-- Weergave 2 -->
  <pm:header title="#{msg['page.titre']}" swatch="b"/>
  <pm:content>
    <h:form id="form2">
      <div align="center">
        <pm:buttonGroup orientation="horizontal">
          <p:commandButton inline="true" icon="back" value=" " action="#{form.showVue1}" update=":vue1"/>
          <p:commandButton inline="true" icon="minus" value=" " action="#{form.getPreviousAgenda}" update=":form2"/>
          <p:commandButton inline="true" icon="home" value=" " action="#{form.getTodayAgenda}" update=":form2"/>
          <p:commandButton inline="true" icon="plus" value=" " action="#{form.getNextAgenda}" update=":form2"/>
        </pm:buttonGroup>
        <h3><h:outputText value="#{form.form2Titre}" style="color: blue" escape="false"/></h3>
      </div>

      <p:dataList id="creneaux" type="inset" value="#{form.agendaMedecinJour.creneauxMedecinJour}" var="creneauMedecinJour">
        <p:column>
          <div align="center">
            <h2>
              <h:outputFormat value="{0,number,#00}h:{1,number,#00} - {2,number,#00}h:{3,number,#00}">
                <f:param value="#{creneauMedecinJour.creneau.hdebut}" />
                <f:param value="#{creneauMedecinJour.creneau.mdebut}" />
                <f:param value="#{creneauMedecinJour.creneau.hfin}" />
                <f:param value="#{creneauMedecinJour.creneau.mfin}" />
              </h:outputFormat>
              <ui:fragment rendered="#{creneauMedecinJour.rv!=null}">
                <br/>
                <h:outputText value="#{creneauMedecinJour.rv.client.titre} #{creneauMedecinJour.rv.client.prenom} #{creneauMedecinJour.rv.client.nom}" style="color: blue"/>
              </ui:fragment>
            </h2>
          </div>
          <div align="center">
            <ui:fragment rendered="#{creneauMedecinJour.rv!=null}">
              <p:commandButton inline="true" action="#{form.action}" value="#{msg['form2.supprimer']}" icon="minus" update=":form2, :vue3, :vueErreurs">
                <f:setPropertyActionListener value="#{creneauMedecinJour.creneau.id}" target="#{form.idCreneauChoisi}"/>
              </p:commandButton>
            </ui:fragment>
            <ui:fragment rendered="#{creneauMedecinJour.rv==null}">
              <p:commandButton inline="true" action="#{form.action}" value="#{msg['form2.reserver']}" icon="plus" update=":form2, :vue3, :vueErreurs">
                <f:setPropertyActionListener value="#{creneauMedecinJour.creneau.id}" target="#{form.idCreneauChoisi}"/>
              </p:commandButton>
            </ui:fragment>
          </div>
        </p:column>
      </p:dataList>
    </h:form>
  </pm:content>
</html>
  • regel 11: genereert de koptekst [1],
  • regels 15-20: genereert de knoppengroep [2],
  • regel 21: genereert de titel [3]. Let op de waarde van het escape-attribuut. Dit maakt het mogelijk om de code XHTML te interpreteren die we in form2Titre hebben geplaatst,
  • regel 24: de tijdvakken worden weergegeven met behulp van een dataList,
  • regels 28-33: genereren de titel van het tijdslot [4],
  • regels 34-37: geven een fragment weer als er een afspraak in het tijdslot staat,
  • regel 36: toont de identiteit van de klant die de afspraak heeft gemaakt,
  • regels 41-45: geven de knop [Supprimer] weer als er een afspraak is,
  • regels 46-50: geven de knop [Réserver] weer als er geen afspraak is.

Deze weergave wordt voornamelijk gevoed door het volgende model:


private AgendaMedecinJour agendaMedecinJour;

dat het veld dataList in regel 24 vult. Dit veld is aangemaakt door de methode getAgenda, toen er werd overgeschakeld van weergave1 naar weergave2.

9.10. Een afspraak verwijderen

Het verwijderen van een afspraak verloopt volgens de volgende reeks:

De weergave waarop deze actie betrekking heeft, is de volgende:


<ui:fragment rendered="#{creneauMedecinJour.rv!=null}">
              <p:commandButton inline="true" action="#{form.action}" value="#{msg['form2.supprimer']}" icon="minus" update=":form2, :vueErreurs">
                <f:setPropertyActionListener value="#{creneauMedecinJour.creneau.id}" target="#{form.idCreneauChoisi}"/>
              </p:commandButton>
            </ui:fragment>
  • regel 2: de knop [Supprimer] is gekoppeld aan de methode [Form].action (attribuut action),
  • regel 3: de id van het tijdvak waarin men zich bevindt, wordt naar het model [Form].idCreneauChoisi verzonden,
  • regel 2: de aanroep AJAX werkt de velden van form2 (formulier van weergave 2) en de weergave vueErreurs bij. Er zijn namelijk twee gevallen: als alles goed gaat, wordt de weergave vue2 opnieuw weergegeven; anders wordt de weergave vueErreurs weergegeven.

De methode [action] is als volgt:


  // actie op RV
  public String action() {
    // er wordt gezocht naar een tijdvak in de agenda
    int i = 0;
    Boolean trouvé = false;
    while (!trouvé && i < agendaMedecinJour.getCreneauxMedecinJour().length) {
      if (agendaMedecinJour.getCreneauxMedecinJour()[i].getCreneau().getId() == idCreneauChoisi) {
        trouvé = true;
      } else {
        i++;
      }
    }
    // Is er iets gevonden?
    if (!trouvé) {
      // dat is vreemd – form2 wordt opnieuw weergegeven
      setForms(false, true, false, false);
      return "pm:vue2";
    } else {
      creneauChoisi = agendaMedecinJour.getCreneauxMedecinJour()[i];
    }
    // gevonden
    // afhankelijk van de gewenste actie
    if (creneauChoisi.getRv() == null) {
      return reserver();
    } else {
      return supprimer();
    }
  }

  // reservering
  public String reserver() {
 ...
  }

  public String supprimer() {
    try {
      // een afspraak verwijderen
      metier.supprimerRv(creneauChoisi.getRv());
      // de agenda wordt bijgewerkt
      agendaMedecinJour = metier.getAgendaMedecinJour(medecin, jour);
      // formulier 2 weergeven
      setForms(false, true, false, false);
      return "pm:vue2";
    } catch (Throwable th) {
      // foutenweergave
      prepareVueErreur(th);
      return "pm:vueErreurs";
    }
}
  • regels 3-12: we zoeken het tijdvak waarvan we de id hebben ontvangen (regel 7),
  • als deze niet wordt gevonden – wat ongebruikelijk is – wordt weergave2 opnieuw weergegeven (regels 16-17),
  • regel 19: als het wel wordt gevonden, wordt het bijbehorende object [CreneauMedecinJour] opgeslagen. Dit object geeft ons toegang tot de afspraak die moet worden verwijderd,
  • regel 26: we verwijderen deze,
  • regels 35-48: de methode ‘verwijderen’ retourneert het scherm vue2 als het verwijderen goed is verlopen (regels 42-43) of het scherm vueErreurs als er een probleem is opgetreden (regels 46-47).

9.11. Afspraak maken

Het maken van een afspraak verloopt volgens de volgende volgorde:

We gaan van weergave vue2 naar weergave vue3. De code die bij deze actie hoort, is de volgende:


<ui:fragment rendered="#{creneauMedecinJour.rv==null}">
              <p:commandButton inline="true" action="#{form.action}" value="#{msg['form2.reserver']}" icon="plus" update=":vue3, :vueErreurs">
                <f:setPropertyActionListener value="#{creneauMedecinJour.creneau.id}" target="#{form.idCreneauChoisi}"/>
              </p:commandButton>
            </ui:fragment>
  • regel 2: de knop [Réserver] is gekoppeld aan de methode [Form].action (attribuut action), dus dezelfde als voor de knop [Supprimer]. De aanroep AJAX werkt de weergaven vue3 en vueErreurs bij, afhankelijk van of er al dan niet fouten optreden tijdens de verwerking van de aanroep.
  • regel 3: net als bij de knop [Supprimer] wordt de id van het tijdslot doorgegeven aan het model.

Het model dat deze actie verwerkt, is het volgende:


// actie op RV
  public String action() {
    ...
    // afhankelijk van de gewenste actie
    if (creneauChoisi.getRv() == null) {
      return reserver();
    } else {
      return supprimer();
    }
  }

  // reservering
  public String reserver() {
    try {
      // titel formulier 3
      form3Titre = Messages.getMessage(null, "form3.titre", new Object[]{medecin.getTitre(), medecin.getPrenom(), medecin.getNom(), new SimpleDateFormat("dd MMM yyyy").format(jour),
                creneauChoisi.getCreneau().getHdebut(), creneauChoisi.getCreneau().getMdebut(), creneauChoisi.getCreneau().getHfin(), creneauChoisi.getCreneau().getMfin()}).getSummary();
      // formulier 3 wordt weergegeven
      setForms(false, false, true, false);
      return "pm:vue3";
    } catch (Throwable th) {
      // foutenoverzicht
      prepareVueErreur(th);
      return "pm:vueErreurs";
    }
  }
  • regels 2-10: de methode action bepaalt de referentie creneauChoisi van het object [CreneauMedecinJour] waarop de reservering betrekking heeft en roept vervolgens de methode reserver aan,
  • regel 16: er wordt een geïnternationaliseerd bericht samengesteld. Dit is het volgende:
form3.titre={0} {1} {2}<br/>{3}<br/>{4,number,#00}h:{5,number,#00}-{6,number,#00}h:{7,number,#00}
form3.titre_detail={0} {1} {2}<br/>{3}<br/>{4,number,#00}h:{5,number,#00}-{6,number,#00}h:{7,number,#00}

Dit wordt de titel van weergave vue3. Net als bij weergave vue2 bevat deze titel XML. Het bevat ook opgemaakte parameters om de tijden van het tijdslot weer te geven,

  • regels 19-20: het overzicht vue3 wordt weergegeven,
  • regels 23-24: de weergave vueErreurs wordt weergegeven als er problemen zijn opgetreden.

9.12. Een afspraak bevestigen

Het bevestigen van een afspraak verloopt volgens de volgende stappen:

In [1] wordt weergave vue3 getoond en in [2] wordt weergave vue2 getoond na het toevoegen van een afspraak.

De code [vue3.xhtml] van vue3 is als volgt:


<?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:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:pm="http://primefaces.org/mobile"
      xmlns:ui="http://java.sun.com/jsf/facelets">

  <!-- Weergave 3 -->
  <pm:header title="#{msg['page.titre']}" swatch="b"/>
  <pm:content>
    <h:form id="form3">
      <p:commandButton inline="true" value=" " icon="back" action="#{form.showVue2}" update=":vue2"/>
      <div align="center">
        <h3><h:outputText value="#{form.form3Titre}" style="color: blue" escape="false"/></h3>
      </div>
      <pm:field>
        <h:outputLabel value="#{msg['form3.client']}" for="choixClient"/>
        <h:selectOneMenu id="choixClient" value="#{form.idClient}">
          <f:selectItems value="#{form.clients}" var="client" itemLabel="#{client.titre} #{client.prenom} #{client.nom}" itemValue="#{client.id}"/>
        </h:selectOneMenu>
      </pm:field>
      <div align="center">
        <p:commandButton inline="true" value="#{msg['form3.valider']}" action="#{form.validerRv}" update=":vue2, :vueErreurs" icon="check"/>
      </div>
    </h:form>
  </pm:content>
</html>
  • regel 16: genereert de titel van de weergave [3]. Let op de waarde van het attribuut escape, dat de interpretatie van de tekens XHTML in de titel mogelijk maakt,
  • regels 18-23: genereren de klantenlijst [4],
  • regel 25: genereert de knop [Valider] [5]. De methode [Form].validerRv is aan deze knop gekoppeld:

// afspraakbevestiging
  public String validerRv() {
    try {
      // we halen een instantie van het gekozen tijdvak op
      Creneau creneau = metier.getCreneauById(idCreneauChoisi);
      // de afspraak wordt toegevoegd
      metier.ajouterRv(jour, creneau, hClients.get(idClient));
      // de agenda wordt bijgewerkt
      agendaMedecinJour = metier.getAgendaMedecinJour(medecin, jour);
      // form2 wordt weergegeven
      setForms(false, true, false, false);
      return "pm:vue2";
    } catch (Throwable th) {
      // foutweergave
      prepareVueErreur(th);
      return "pm:vueErreurs";
    }
  }

Deze code is al eerder aangetroffen in versie 01. We wijzen alleen even op de weergave van de weergaven:

  • weergave vue2 (regels 11-12) als alles goed is gegaan,
  • de weergave vueErreurs (regels 15-16) als dat niet het geval is.

9.13. Een afspraak annuleren

Dit komt overeen met de volgende reeks:

De knop [1] in de weergave [vue3.xhtml] is de volgende:


      <p:commandButton inline="true" value=" " icon="back" action="#{form.showVue2}" update=":vue2"/>

De methode [Form].showVue2 wordt dus aangeroepen. Deze methode geeft alleen weergave2 weer:


  public String showVue2() {
    // weergave 2
    setForms(false, true, false, false);
    return "pm:vue2?reverse=true";
}

9.14. Navigeren in de kalender

In weergave2 kun je met knoppen door de kalender navigeren:

Vorige dag:

Volgende dag:

Vandaag:

Hoewel dit niet te zien is op de bovenstaande schermafbeeldingen, wordt de agenda bijgewerkt en worden de afspraken van de nieuw geselecteerde dag weergegeven.

De tags van de drie betreffende knoppen zijn als volgt in [vue2.xhtml]:


<pm:buttonGroup orientation="horizontal">
          <p:commandButton inline="true" icon="back" value=" " action="#{form.showVue1}" update=":vue1"/>
          <p:commandButton inline="true" icon="minus" value=" " action="#{form.getPreviousAgenda}" update=":form2"/>
          <p:commandButton inline="true" icon="home" value=" " action="#{form.getTodayAgenda}" update=":form2"/>
          <p:commandButton inline="true" icon="plus" value=" " action="#{form.getNextAgenda}" update=":form2"/>
        </pm:buttonGroup>

De methoden [Form].getPreviousAgenda, [Form].getNextAgenda, [Form].today zijn in voorbeeld 03 besproken.

9.15. Wijziging van de weergavetaal

Het wijzigen van de taal gebeurt via een knop op de startpagina:

De code van de knop is als volgt:


      <p:button icon="gear" value=" "  href="#config" />

Het schakelt dus over naar de weergave config [2]. De weergave [config.xhtml] ziet er als volgt uit:


<?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:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:pm="http://primefaces.org/mobile"
      xmlns:ui="http://java.sun.com/jsf/facelets">

  <!-- Weergave 1 -->
  <pm:header title="#{msg['page.titre']}" swatch="b">
    <f:facet name="left">
      <p:button icon="back" value=" " href="#vue1?reverse=true" />
    </f:facet>
  </pm:header>
  <pm:content>
    <h:form id="frmConfig">
      <div align="center">
        <h3><h:outputText value="#{msg['config.titre']}" style="color: blue"/></h3>
      </div>
      <pm:field>
        <h:outputLabel value="#{msg['config.langue']}" for="langue"/>
        <h:selectOneRadio id="langue" value="#{form.locale}">
          <f:selectItem itemLabel="#{msg['config.langue.francais']}" itemValue="fr"/>
          <f:selectItem itemLabel="#{msg['config.langue.anglais']}" itemValue="en" />
        </h:selectOneRadio>
      </pm:field>
      <p:commandButton value="#{msg['config.valider']}" action="#{form.configurer}" update=":vue1"/>
    </h:form>
  </pm:content>
</html>
  • regel 11: geeft [3] weer,
  • regel 13: geeft de knop [4] weer. Met deze knop kunt u terugkeren naar weergave vue1,
  • regel 17: het formulier van de weergave,
  • regel 19: geeft de titel van de weergave [5] weer,
  • regels 21-27: geven de keuzerondjes weer. De waarde (itemValue) van het geselecteerde keuzerondje wordt verzonden naar het model [Form].locale (attribuut value van regel 23),
  • regel 28: geeft de knop [Valider] weer. De aanroep AJAX werkt de weergave vue1 bij (attribuut update). De aangeroepen methode is [Form].configurer:

public String configurer(){
    // na configuratie - we geven weergave 1 opnieuw weer
    redirect();
    return null;
  }
  
  private void redirect() {
    // de client wordt doorgestuurd naar de servlet
    ExternalContext ctx = FacesContext.getCurrentInstance().getExternalContext();
    try {
      ctx.redirect(ctx.getRequestContextPath());
    } catch (IOException ex) {
      Logger.getLogger(Form.class.getName()).log(Level.SEVERE, null, ex);
    }
  }

De methode configurer (regel 1) leidt de mobiele browser gewoon door naar de URL van de applicatie. De pagina [index.xhtml] wordt dus geladen:


<f:view xmlns="http://www.w3.org/1999/xhtml"
        xmlns:f="http://java.sun.com/jsf/core"
        xmlns:h="http://java.sun.com/jsf/html"
        xmlns:ui="http://java.sun.com/jsf/facelets"
        xmlns:p="http://primefaces.org/ui"
        xmlns:pm="http://primefaces.org/mobile"
        contentType="text/html"
        locale="#{form.locale}">

  <pm:page title="#{msg['page.titre']}">
    <pm:view id="vue1">
      ...
    </pm:view>
    ...
  </pm:page>    
</f:view>
  • regel 8: de weergave gebruikt de taal die zojuist is gewijzigd (attribuut `locale`) en geeft weergave1 weer (regel 11).

9.16. Conclusion

Laten we nog eens de architectuur van de applicatie die we zojuist hebben gebouwd in herinnering brengen:

De overstap naar een mobiele interface maakte het herschrijven van de pagina's noodzakelijk XHTML. Het model daarentegen is nauwelijks veranderd. De lagere lagen [métier], [DAO] en [JPA] zijn helemaal niet gewijzigd.

9.17. Eclipse-tests

Net zoals we bij de vorige versies van de voorbeeldtoepassing hebben gedaan, laten we zien hoe je deze versie 05 met Eclipse kunt testen. Allereerst importeren we de Maven-projecten van voorbeeld 05 [1] in Eclipse:

  • [mv-rdvmedecins-ejb-dao-jpa]: de lagen [DAO] en [JPA],
  • [mv-rdvmedecins-ejb-metier]: de laag [métier],
  • [mv-rdvmedecins-pfmobile]: de laag [web] geïmplementeerd door PrimeFaces Mobile,
  • [mv-rdvmedecins-pfmobile-app]: het bovenliggende project van het bedrijfsproject [mv-rdvmedecins-pfmobile-app-ear]. Wanneer het bovenliggende project wordt geïmporteerd, wordt het onderliggende project automatisch geïmporteerd,
  • in [2] wordt het bedrijfsproject [mv-rdvmedecins-pfmobile-app-ear] uitgevoerd,
  • in [3], de Glassfish-server geselecteerd,
  • in [4], op het tabblad [Servers], is de applicatie geïmplementeerd. Deze start niet vanzelf. Je moet de URL [http://localhost:8080/mv-rdvmedecins-pfmobile/] opvragen in een browser of een mobiele simulator [5]: