12. Sürüm 7 - Çoklu görünüm / çoklu sayfa PAM web uygulaması
Burada, [métier] katmanının simüle edildiği ilk mimariye geri dönüyoruz. Artık bu katmanın, gerçek [métier] katmanıyla kolayca değiştirilebileceğini biliyoruz. Simüle edilmiş [métier] katmanı, testleri kolaylaştırır.
![]() |
JSF uygulaması, MVC (Model-Görünüm-Denetleyici) türündedir:
- [Faces Servlet] servleti, JSF tarafından sağlanan genel denetleyicidir. Bu denetleyici, uygulamaya özgü olay işleyicileri tarafından genişletilir. Şimdiye kadar karşılaştığımız olay işleyicileri, JSF sayfalarının şablonları olarak kullanılan sınıfların yöntemleriydi
- JSF sayfaları, yanıtları istemci tarayıcısına gönderir. Bunlar, uygulamanın görünümleridir.
- JSF sayfaları, sayfa şablonu olarak adlandırılan dinamik öğeler içerir. Hatırlatmak gerekirse, bazı yazarlara göre şablon, uygulama tarafından işlenen varlıkları kapsar; örneğin FeuilleSalaire veya Employe sınıfları gibi. Bu iki şablonu birbirinden ayırmak için, uygulama şablonu ve JSF sayfası şablonu terimlerini kullanabiliriz.
JSF mimarisinde, bir JSFi sayfasından bir JSFj sayfasına geçiş sorun yaratabilir.
- JSFi sayfası görüntülendi. Bu sayfadan kullanıcı, herhangi bir olayla [1]'i tetikleyerek POST'e geçiş yapar
- JSF'te, bu POST genellikle JSFi sayfasının Mi modelindeki bir C yöntemi tarafından işlenir. C yönteminin ikincil bir denetleyici olduğu söylenebilir.
- Bu yöntemin sonucunda JSFj sayfası görüntülenecekse, C denetleyicisi şunları yapmalıdır:
- JSFj sayfasının Mj modelini [2c] olarak güncellemek
- ana denetleyiciye, JSFj sayfasının görüntülenmesini sağlayacak gezinme anahtarını ([2a]) döndürmelidir
- adım, JSFi sayfasının Mi şablonunun, JSFj sayfasının Mj şablonuna bir referans içermesini gerektirir. Bu durum, Mi şablonlarını birbirine bağımlı hale getirerek işleri biraz karmaşıklaştırır. Nitekim, Mj şablonunu güncelleyen Mi şablonunun C yöneticisi, Mj şablonunu tanımalıdır. Mj modelinde değişiklik yapmak zorunda kalırsak, Mi modelinin C yöneticisinde de değişiklik yapmak zorunda kalırız.
Modellerin birbirine bağımlılığının önlenebileceği bir durum vardır: tüm JSF sayfaları için tek bir M modelinin kullanıldığı durum. Bu mimari, yalnızca birkaç görünüme sahip uygulamalarda kullanılabilir, ancak bu durumda kullanımı oldukça basittir. Şu anda kullandığımız mimari budur.
Bu bağlamda, uygulamanın mimarisi şu şekildedir:
![]() |
12.1. Uygulamanın görünümleri
Kullanıcıya sunulan farklı görünümler şunlardır:
-
simülasyon formunu gösteren [VueSaisies] görünümü
-
Simülasyonun ayrıntılı sonucunu görüntülemek için kullanılan [VueSimulation] görünümü:


- müşteri tarafından yapılan simülasyonların listesini gösteren [VueSimulations] görünümü

- Müşterinin simülasyonu olmadığını veya artık simülasyonu kalmadığını gösteren [VueSimulationsVides] görünümü:

- Bir veya daha fazla hata olduğunu gösteren [VueErreur] görünümü:

12.2. [web] katmanının NetBeans projesi
Bu sürümün NetBeans projesi, aşağıdaki Maven projesi olacaktır:
![]() |
- [1]'te yapılandırma dosyaları,
- [2]'te, sayfalar JSF'te,
- [3]'te, görünümlerin stil sayfası ve arka plan görüntüsü,
- [4]'te, [web] katmanının sınıfları,
- [5] dosyasına, uygulamanın alt katmanları,
- [6] dosyasında, uygulamanın uluslararasılaştırılması için mesaj dosyası,
- [7] dosyasında ise projenin bağımlılıkları bulunur.
Bu öğelerden bazılarını inceleyeceğiz.
12.2.1. Yapılandırma dosyaları
[web.xml] ve [faces-config.xml] dosyaları, [web.xml] dosyasındaki bir ayrıntı dışında önceki projeninkilerle aynıdır:
<?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">
...
<welcome-file-list>
<welcome-file>faces/saisie.xhtml</welcome-file>
</welcome-file-list>
...
</web-app>
- 4-6. satırlar: Ana sayfa, [saisie.xhtml] sayfasıdır
12.2.2. Stil sayfası
[styles.css] dosyası şu şekildedir:
.simulationsHeader {
text-align: center;
font-style: italic;
color: Snow;
background: Teal;
}
.simuNum {
height: 25px;
text-align: center;
background: MediumTurquoise;
}
.simuNom {
text-align: left;
background: PowderBlue;
}
.simuPrenom {
width: 6em;
text-align: left;
color: Black;
background: MediumTurquoise;
}
.simuHT {
width: 3em;
text-align: center;
color: Black;
background: PowderBlue;
}
.simuJT {
width: 3em;
text-align: center;
color: Black;
background: MediumTurquoise;
}
.simuSalaireBase {
width: 9em;
text-align: center;
color: Black;
background: PowderBlue;
}
.simuIndemnites {
width: 3em;
text-align: center;
color: Black;
background: MediumTurquoise;
}
.simuCotisationsSociales {
width: 6em;
text-align: center;
background: PowderBlue;
}
.simuSalaireNet {
width: 10em;
text-align: center;
background: MediumTurquoise;
}
.erreursHeaders {
background: Teal;
background-color: #ff6633;
color: Snow;
font-style: italic;
text-align: center
}
.erreurClasse {
background: MediumTurquoise;
background-color: #ffcc66;
height: 25px;
text-align: center
}
.erreurMessage {
background: PowderBlue;
background-color: #ffcc99;
text-align: left
}
İşte bu stilleri kullanan JSF kod örnekleri:
Simülasyonlar Görünümü
<h:dataTable value="#{form.simulations}" var="simulation"
headerClass="simulationsHeaders" columnClasses="simuNum,simuNom,simuPrenom,simuHT,simuJT,simuSalaireBase,simuIndemnites,simuCotisationsSociales,simuSalaireNet">
Elde edilen sonuç şöyledir:

Hata Görünümü
<h:dataTable value="#{form.erreurs}" var="erreur"
headerClass="erreursHeaders" columnClasses="erreurClasse,erreurMessage">

12.2.3. Hata mesajları dosyası
[messages_fr.properties] mesaj dosyası şu şekildedir:
form.titre=Simulateur de calcul de paie
form.comboEmployes.libell\u00e9=Employ\u00e9
form.heuresTravaill\u00e9es.libell\u00e9=Heures travaill\u00e9es
form.joursTravaill\u00e9s.libell\u00e9=Jours travaill\u00e9s
form.heuresTravaill\u00e9es.required=Indiquez le nombre d'heures travaill\u00e9es
form.heuresTravaill\u00e9es.validation=Donn\u00e9e incorrecte
form.joursTravaill\u00e9s.required=Indiquez le nombre de jours travaill\u00e9s
form.joursTravaill\u00e9s.validation=Donn\u00e9e incorrecte
form.btnSalaire.libell\u00e9=Salaire
form.btnRaz.libell\u00e9=Raz
exception.header=L'exception suivante s'est produite
exception.httpCode=Code HTTP de l'erreur
exception.message=Message de l'exception
exception.requestUri=Url demand\u00e9e lors de l'erreur
exception.servletName=Nom de la servlet demand\u00e9e lorsque l'erreur s'est produite
form.infos.employ\u00e9=Informations Employ\u00e9
form.employe.nom=Nom
form.employe.pr\u00e9nom=Pr\u00e9nom
form.employe.adresse=Adresse
form.employe.ville=Ville
form.employe.codePostal=Code postal
form.employe.indice=Indice
form.infos.cotisations=Informations Cotisations sociales
form.cotisations.csgrds=CSGRDS
form.cotisations.csgd=CSGD
form.cotisations.retraite=Retraite
form.cotisations.secu=S\u00e9curit\u00e9 sociale
form.infos.indemnites=Informations Indemnit\u00e9s
form.indemnites.salaireHoraire=Salaire horaire
form.indemnites.entretienJour=Entretien / Jour
form.indemnites.repasJour=Repas / Jour
form.indemnites.cong\u00e9sPay\u00e9s=Cong\u00e9s pay\u00e9s
form.infos.salaire=Informations Salaire
form.salaire.base=Salaire de base
form.salaire.cotisationsSociales=Cotisations sociales
form.salaire.entretien=Indemnit\u00e9s d'entretien
form.salaire.repas=Indemnit\u00e9s de repas
form.salaire.net=Salaire net
form.menu.faireSimulation=| Faire la simulation
form.menu.effacerSimulation=| Effacer la simulation
form.menu.enregistrerSimulation=| Enregistrer la simulation
form.menu.retourSimulateur=| Retour au simulateur
form.menu.voirSimulations=| Voir les simulations
form.menu.terminerSession=| Terminer la session
simulations.headers.nom=Nom
simulations.headers.nom=Nom
simulations.headers.prenom=Pr\u00e9nom
simulations.headers.heuresTravaillees=Heures travaill\u00e9es
simulations.headers.joursTravailles=Jours Travaill\u00e9s
simulations.headers.salaireBase=Salaire de base
simulations.headers.indemnites=Indemnit\u00e9s
simulations.headers.cotisationsSociales=Cotisations sociales
simulations.headers.salaireNet=SalaireNet
simulations.headers.numero=N\u00b0
erreur.titre=Une erreur s'est produite.
erreur.exceptions=Cha\u00eene des exceptions
exception.type=Type de l'exception
exception.message=Message associ\u00e9
12.2.4. [métier] katmanı
Simüle edilen [métier] katmanı şu şekilde değiştirilmiştir:
package metier;
...
public class Metier implements ImetierLocal, Serializable {
// çalışan listesi
private Map<String,Employe> hashEmployes=new HashMap<String,Employe>();
private List<Employe> listEmployes;
// maaş bordrosunu almak
public FeuilleSalaire calculerFeuilleSalaire(String SS,
double nbHeuresTravaillées, int nbJoursTravaillés) {
// çalışanı bul
Employe e=hashEmployes.get(SS);
// çalışan mevcut değilse istisna döndürülür
if(e==null){
throw new PamException(String.format("L'employé de n° SS [%s] n'existe pas",SS),1);
}
// hayali bir maaş bordrosu döndürür
return new FeuilleSalaire(e,new Cotisation(3.49,6.15,9.39,7.88),e.getIndemnite(),new ElementsSalaire(100,100,100,100,100));
}
// çalışan listesi
public List<Employe> findAllEmployes() {
if(listEmployes==null){
// üç çalışandan oluşan bir liste oluşturulur
listEmployes=new ArrayList<Employe>();
listEmployes.add(new Employe("254104940426058","Jouveinal","Marie","5 rue des oiseaux","St Corentin","49203",new Indemnite(2,2.1,2.1,3.1,15)));
listEmployes.add(new Employe("260124402111742","Laverti","Justine","La brûlerie","St Marcel","49014",new Indemnite(1,1.93,2,3,12)));
// çalışan sözlüğü
for(Employe e:listEmployes){
hashEmployes.put(e.getSS(),e);
}
// sözlükte bulunmayan bir çalışan ekleniyor
listEmployes.add(new Employe("X","Y","Z","La brûlerie","St Marcel","49014",new Indemnite(1,1.93,2,3,12)));
}
// çalışan listesi döndürülüyor
return listEmployes;
}
}
- 8. satır: çalışan listesi
- 7. satır: aynı liste, çalışanların SS numaralarına göre indekslenmiş bir sözlük biçiminde
- 24-39. satırlar: Çalışan listesini döndüren findAllEmployes yöntemi. Bu yöntem, sabit bir liste oluşturur ve 8. satırdaki employés alanına referans verir.
- 27-33. satırlar: İki çalışandan oluşan bir liste ve bir sözlük oluşturulur
- satır 35: Bir çalışan, çalışanlar listesine (satır 8) eklenir, ancak hashEmployes sözlüğüne (satır 7) eklenmez. Bunun amacı, çalışanın çalışanlar açılır menüsünde görünmesini sağlamak, ancak daha sonra calculerFeuilleSalaire yöntemi (satır 14) tarafından tanınmaması ve böylece bu yöntemin bir istisna oluşturmasıdır (satır 17).
- 11-21. satırlar: calculerFeuilleSalaire yöntemi
- satır 14: Çalışan, hashEmployes sözlüğünde SS numarasıyla aranır. Bulunamazsa, bir istisna atılır (satır 16-18). Böylece, SS numaralı çalışan için bir istisna oluşur; bu çalışan, 35. satırda çalışanlar listesine eklenmiştir ancak hashEmployes sözlüğünde yer almamaktadır.
- 20. satırda, hayali bir maaş bordrosu oluşturulur ve döndürülür.
12.3. Uygulamanın bean'leri
Üç farklı kapsamda üç bean olacaktır:
![]() |
12.3.1. ApplicationData bean'i
ApplicationData bean'i, application kapsamına sahip olacaktır:
package web.beans.application;
import java.io.Serializable;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import metier.IMetierLocal;
import metier.Metier;
@Named
@ApplicationScoped
public class ApplicationData implements Serializable {
// iş mantığı katmanı
private IMetierLocal metier = new Metier();
// günlük kaydı
private boolean logsEnabled = true;
private final Logger logger = Logger.getLogger("pam");
public ApplicationData() {
}
@PostConstruct
public void init() {
// günlük
if (isLogsEnabled()) {
logger.info("ApplicationData");
}
}
// alıcı ve ayarlayıcılar
...
}
- 11. satır: @Named anotasyonu, sınıfı yönetilen bir bean haline getirir. Önceki projeden farklı olarak, @ManagedBean anotasyonunun kullanılmadığına dikkat edilmelidir. Bunun nedeni, bu sınıfın referansının @Inject anotasyonu kullanılarak başka bir sınıfa enjekte edilmesi gerektiği ve @Inject anotasyonunun yalnızca @Named anotasyonuna sahip sınıfları enjekte etmesidir.
- 12. satır: @ApplicationScoped anotasyonu, sınıfı uygulama kapsamlı bir nesne haline getirir. Anotasyonun sınıfının, önceki projedeki bean'lerde olduğu gibi [javax.faces.bean.ApplicationScoped] değil, [javax.enterprise.context.ApplicationScoped] (6. satır) olduğu unutulmamalıdır.
ApplicationData bean'i iki amaca hizmet eder:
- 16. satır: [métier] katmanına bir referans tutmak,
- 18-19. satırlar: diğer bean'lerin Glassfish konsoluna günlük kaydı yapmak için kullanabileceği bir günlük kaydedici tanımlamak.
12.3.2. SessionData bean'i
SessionData bean'i oturum kapsamında olacaktır:
package web.beans.session;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;
import javax.inject.Named;
import web.beans.application.ApplicationData;
import web.entities.Simulation;
@Named
@SessionScoped
public class SessionData implements Serializable {
// uygulama
@Inject
private ApplicationData applicationData;
// simülasyonlar
private List<Simulation> simulations = new ArrayList<Simulation>();
private int numDerniereSimulation = 0;
private Simulation simulation;
// menüler
private boolean menuFaireSimulationIsRendered = true;
private boolean menuEffacerSimulationIsRendered = true;
private boolean menuEnregistrerSimulationIsRendered;
private boolean menuVoirSimulationsIsRendered;
private boolean menuRetourSimulateurIsRendered;
private boolean menuTerminerSessionIsRendered = true;
// yerel ayar
private String locale="fr_FR";
// yapıcı
public SessionData() {
}
@PostConstruct
public void init() {
// günlük
if (applicationData.isLogsEnabled()) {
applicationData.getLogger().info("SessionData");
}
}
// menü yönetimi
public void setMenu(boolean menuFaireSimulationIsRendered, boolean menuEnregistrerSimulationIsRendered, boolean menuEffacerSimulationIsRendered, boolean menuVoirSimulationsIsRendered, boolean menuRetourSimulateurIsRendered, boolean menuTerminerSessionIsRendered) {
this.setMenuFaireSimulationIsRendered(menuFaireSimulationIsRendered);
this.setMenuEnregistrerSimulationIsRendered(menuEnregistrerSimulationIsRendered);
this.setMenuVoirSimulationsIsRendered(menuVoirSimulationsIsRendered);
this.setMenuEffacerSimulationIsRendered(menuEffacerSimulationIsRendered);
this.setMenuRetourSimulateurIsRendered(menuRetourSimulateurIsRendered);
this.setMenuTerminerSessionIsRendered(menuTerminerSessionIsRendered);
}
// alıcı ve ayarlayıcılar
...
}
- 13. satır: SessionData sınıfı, diğer yönetilen bean'lere enjekte edilebilecek bir yönetilen bean'dir (@Named),
- 14. satır: oturum kapsamındadır (@SessionScoped),
- 18-19. satırlar: ApplicationData bean'ine bir referans enjekte edilir (@Inject),
- 21-32. satırlar: oturumlar boyunca korunması gereken uygulama verileri.
- 21. satır: kullanıcı tarafından yapılan simülasyonların listesi,
- 22. satır: kaydedilen son simülasyonun numarası,
- 23. satır: Yapılan son simülasyon,
- satır 25-30: menü seçenekleri,
- satır 32: uygulamanın yerel ayarı.
39-44. satırlar: init yöntemi, (@PostConstruct) sınıfının örneklendirilmesinden sonra yürütülür. Burada, yalnızca yürütülüşünün bir izini bırakmak için kullanılmaktadır. Sınıfın kapsamı oturum olduğu için, yöntemin kullanıcı başına yalnızca bir kez yürütüldüğünü doğrulayabilmeliyiz. 42. satırda, yöntem ApplicationData sınıfında tanımlanan günlüğü kullanır. Bu nedenle, bu bean'e bir referans enjekte etmemiz gerekiyordu (18-19. satırlar).
12.3.3. Form bean'i
Form bean'i requête kapsamındadır:
package web.beans.request;
import java.util.ArrayList;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import jpa.Employe;
import metier.FeuilleSalaire;
import web.beans.application.ApplicationData;
import web.beans.session.*;
import web.entities.Erreur;
import web.entities.Simulation;
@Named
@RequestScoped
public class Form {
public Form() {
}
// diğer bean'ler
@Inject
private ApplicationData applicationData;
@Inject
private SessionData sessionData;
// görünüm şablonu
private String comboEmployesValue = "";
private String heuresTravaillées = "";
private String joursTravaillés = "";
private Integer numSimulationToDelete;
private List<Erreur> erreurs = new ArrayList<Erreur>();
private FeuilleSalaire feuilleSalaire;
// çalışan listesi
public List<Employe> getEmployes(){
return applicationData.getMetier().findAllEmployes();
}
// menü eylemi
public String faireSimulation() {
...
}
public String enregistrerSimulation() {
...
}
public String effacerSimulation() {
...
}
public String voirSimulations() {
...
}
public String retourSimulateur() {
...
}
public String terminerSession() {
...
}
public String retirerSimulation() {
...
}
private void razFormulaire() {
...
}
// getter ve setter'lar
...
}
- 17. satırda sınıf, yönetilen bir bean'dir (@Named),
- 18. satırda, istek kapsamındadır (@RequestScoped),
- 24-25. satırlar: uygulama kapsamındaki ApplicationData bean'ine bir referans enjeksiyonu,
- 26-27. satırlar: oturum kapsamındaki SessionData bean'ine referans enjeksiyonu.
12.4. Uygulamanın sayfaları
![]() |
12.4.1. [layout.xhtml]
[layout.xhtml] sayfası, tüm görünümlerin sayfa düzenini sağlar:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<f:view locale="#{sessionData.locale}">
<h:head>
<title><h:outputText value="#{msg['form.titre']}"/></title>
<h:outputStylesheet library="css" name="styles.css"/>
</h:head>
<script type="text/javascript">
function raz(){
// gönderilen değerleri değiştirme
document.forms['formulaire'].elements['formulaire:comboEmployes'].value="0";
document.forms['formulaire'].elements['formulaire:heuresTravaillees'].value="0";
document.forms['formulaire'].elements['formulaire:joursTravailles'].value="0";
}
</script>
<h:body style="background-image: url('${request.contextPath}/resources/images/standard.jpg');">
<h:form id="formulaire">
<!-- başlık -->
<ui:include src="entete.xhtml" />
<!-- içerik -->
<ui:insert name="part1" >
Gestion des assistantes maternelles
</ui:insert>
<ui:insert name="part2"/>
</h:form>
</h:body>
</f:view>
</html>
Her görünüm aşağıdaki öğelerden oluşur:
- [entete.xhtml] parçası tarafından görüntülenen bir başlık (24. satır),
- part1 (satır 26-28) ve part2 (satır 29) adlı iki parçadan oluşan bir gövde,
- 8. satır: locale özniteliği, sayfaların uluslararasılaştırılmasını sağlar. Burada sadece bir tane olacaktır: fr_FR,
- 14-19. satırlar: bir JavaScript kodu.
[layout.xhtml] sayfasının görüntüsü şöyledir:
![]() |
- [1]'te, [entete.xhtml] başlığı,
- [2]'te part1 parçası.
12.4.2. [entete.xhtml] başlığı
[entete.xhtml] sayfasının kodu şöyledir:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition>
<!-- başlık -->
<h:panelGrid columns="2">
<h:panelGroup>
<h2><h:outputText value="#{msg['form.titre']}"/></h2>
</h:panelGroup>
<h:panelGroup>
<h:panelGrid columns="1">
<h:commandLink id="cmdFaireSimulation" value="#{msg['form.menu.faireSimulation']}" action="#{form.faireSimulation}" rendered="#{sessionData.menuFaireSimulationIsRendered}"/>
<h:commandLink id="cmdEffacerSimulation" onclick="raz()" value="#{msg['form.menu.effacerSimulation']}" action="#{form.effacerSimulation}" rendered="#{sessionData.menuEffacerSimulationIsRendered}"/>
<h:commandLink id="cmdEnregistrerSimulation" immediate="true" value="#{msg['form.menu.enregistrerSimulation']}" action="#{form.enregistrerSimulation}" rendered="#{sessionData.menuEnregistrerSimulationIsRendered}"/>
<h:commandLink id="cmdVoirSimulations" immediate="true" value="#{msg['form.menu.voirSimulations']}" action="#{form.voirSimulations}" rendered="#{sessionData.menuVoirSimulationsIsRendered}"/>
<h:commandLink id="cmdRetourSimulateur" immediate="true" value="#{msg['form.menu.retourSimulateur']}" action="#{form.retourSimulateur}" rendered="#{sessionData.menuRetourSimulateurIsRendered}"/>
<h:commandLink id="cmdTerminerSession" immediate="true" value="#{msg['form.menu.terminerSession']}" action="#{form.terminerSession}" rendered="#{sessionData.menuTerminerSessionIsRendered}"/>
</h:panelGrid>
</h:panelGroup>
</h:panelGrid>
<hr/>
</ui:composition>
</html>
- 12. satır: uygulamanın başlığı,
- 16-21. satırlar: Kullanıcının gerçekleştirebileceği altı eyleme karşılık gelen altı bağlantı. Bu bağlantılar, SessionData bean'indeki boole değerleri tarafından kontrol edilir (rendered özniteliği),
- 17. satır: [Effacer la simulation] bağlantısına tıklandığında raz adlı JavaScript işlevi çalıştırılır. Bu işlev, [layout.xhtml] modelinde tanımlanmıştır,
- 18. satır: immediate=true özniteliği, [Form].enregistrerSimulation yönteminin yürütülmesinden önce verilerin geçerliliğinin kontrol edilmemesini sağlar. Bu, kasıtlıdır. Bir dakika önce yapılan son simülasyonu, o zamandan beri forma girilen (ancak henüz doğrulanmamış) veriler geçersiz olsa bile kaydetmek istenebilir. Aynı durum [Voir les simulations], [Effacer la simulation], [Retour au simulateur] ve [Terminer la session] eylemleri için de geçerlidir.
12.5. Uygulamanın kullanım senaryoları
12.5.1. Ana sayfanın görüntülenmesi
Ana sayfa, aşağıdaki [saisie.xhtml] sayfasıdır:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="part1">
<ui:include src="saisie2.xhtml"/>
</ui:define>
</ui:composition>
</html>
- 8. satır: [layout.xhtml] sayfası içinde görüntülenir,
- 9. satır: part1 adlı parçanın yerine. Bu parçada, [saisie2.xhtml] sayfası görüntülenir:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:panelGrid columns="3">
<h:outputText value="#{msg['form.comboEmployes.libellé']}"/>
<h:outputText value="#{msg['form.heuresTravaillées.libellé']}"/>
<h:outputText value="#{msg['form.joursTravaillés.libellé']}"/>
<h:selectOneMenu id="comboEmployes" value="#{form.comboEmployesValue}">
<f:selectItems .../>
</h:selectOneMenu>
<h:inputText id="heuresTravaillees" value="#{form.heuresTravaillées}" required="true" requiredMessage="#{msg['form.heuresTravaillées.required']}" validatorMessage="#{msg['form.heuresTravaillées.validation']}">
<f:validateDoubleRange minimum="0" maximum="300"/>
</h:inputText>
<h:inputText id="joursTravailles" value="#{form.joursTravaillés}" required="true" requiredMessage="#{msg['form.joursTravaillés.required']}" validatorMessage="#{msg['form.joursTravaillés.validation']}">
<f:validateLongRange minimum="0" maximum="31"/>
</h:inputText>
<h:panelGroup></h:panelGroup>
<h:message for="heuresTravaillees" styleClass="error"/>
<h:message for="joursTravailles" styleClass="error"/>
</h:panelGrid>
<hr/>
</html>
Bu kod aşağıdaki görünümü görüntüler:
![]() |
Soru: XHTML kodunun 13. satırını tamamlayınız. Çalışanlar açılır menüsündeki öğelerin listesi, [Form] bean'indeki bir yöntem tarafından sağlanmaktadır. Bu yöntemi yazınız. Açılır menüde görüntülenen öğelerin itemValue özelliği, bir çalışanın SS numarasına eşit olacak ve itemLabel özelliği ise bu çalışanın adı ve soyadından oluşan bir dize olacaktır.
Soru: Forma yapılan ilk GET isteği sırasında başlık menüsünün yukarıda gösterilen şekilde görünmesi için [SessionData] bean'i nasıl başlatılmalıdır?
12.5.2. [faireSimulation] eylemi
[faireSimulation] eyleminin JSF kodu şu şekildedir:
<h:commandLink id="cmdFaireSimulation" value="#{msg['form.menu.faireSimulation']}" action="#{form.faireSimulation}" rendered="#{sessionData.menuFaireSimulationIsRendered}"/>
[faireSimulation] eylemi bir maaş bordrosu hesaplar:

Önceki sayfadan yola çıkarak şu sonuç elde edilir:
![]() |
![]() |
Simülasyon, aşağıdaki [simulation.xhtml] sayfasında görüntülenir:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="part1">
<ui:include src="saisie2.xhtml"/>
</ui:define>
<ui:define name="part2">
<h:outputText value="#{msg['form.infos.employé']}" styleClass="titreInfos"/>
<br/><br/>
<h:panelGrid columns="3" rowClasses="libelle,info">
<h:outputText value="#{msg['form.employe.nom']}"/>
<h:outputText value="#{msg['form.employe.prénom']}"/>
<h:outputText value="#{msg['form.employe.adresse']}"/>
<h:outputText value="#{form.feuilleSalaire.employe.nom}"/>
<h:outputText value="#{form.feuilleSalaire.employe.prenom}"/>
<h:outputText value="#{form.feuilleSalaire.employe.adresse}"/>
</h:panelGrid>
<h:panelGrid columns="3" rowClasses="libelle,info">
<h:outputText value="#{msg['form.employe.ville']}"/>
<h:outputText value="#{msg['form.employe.codePostal']}"/>
<h:outputText value="#{msg['form.employe.indice']}"/>
<h:outputText value="#{form.feuilleSalaire.employe.ville}"/>
<h:outputText value="#{form.feuilleSalaire.employe.codePostal}"/>
<h:outputText value="#{form.feuilleSalaire.employe.indemnite.indice}"/>
</h:panelGrid>
<br/>
<h:outputText value="#{msg['form.infos.cotisations']}" styleClass="titreInfos"/>
<br/><br/>
<h:panelGrid columns="4" rowClasses="libelle,info">
<h:outputText value="#{msg['form.cotisations.csgrds']}"/>
<h:outputText value="#{msg['form.cotisations.csgd']}"/>
<h:outputText value="#{msg['form.cotisations.retraite']}"/>
<h:outputText value="#{msg['form.cotisations.secu']}"/>
<h:outputText value="#{form.feuilleSalaire.cotisation.csgrds} %"/>
<h:outputText value="#{form.feuilleSalaire.cotisation.csgd} %"/>
<h:outputText value="#{form.feuilleSalaire.cotisation.retraite} %"/>
<h:outputText value="#{form.feuilleSalaire.cotisation.secu} %"/>
</h:panelGrid>
<br/>
<h:outputText value="#{msg['form.infos.indemnites']}" styleClass="titreInfos"/>
<br/><br/>
<h:panelGrid columns="4" rowClasses="libelle,info">
<h:outputText value="#{msg['form.indemnites.salaireHoraire']}"/>
<h:outputText value="#{msg['form.indemnites.entretienJour']}"/>
<h:outputText value="#{msg['form.indemnites.repasJour']}"/>
<h:outputText value="#{msg['form.indemnites.congésPayés']}"/>
<h:outputFormat value="{0,number,currency}">
<f:param value="#{form.feuilleSalaire.employe.indemnite.baseHeure}"/>
</h:outputFormat>
<h:outputFormat value="{0,number,currency}">
<f:param value="#{form.feuilleSalaire.employe.indemnite.entretienJour}"/>
</h:outputFormat>
<h:outputFormat value="{0,number,currency}">
<f:param value="#{form.feuilleSalaire.employe.indemnite.repasJour}"/>
</h:outputFormat>
<h:outputText value="#{form.feuilleSalaire.employe.indemnite.indemnitesCP} %"/>
</h:panelGrid>
<br/>
<h:outputText value="#{msg['form.infos.salaire']}" styleClass="titreInfos"/>
<br/><br/>
<h:panelGrid columns="4" rowClasses="libelle,info">
<h:outputText value="#{msg['form.salaire.base']}"/>
<h:outputText value="#{msg['form.salaire.cotisationsSociales']}"/>
<h:outputText value="#{msg['form.salaire.entretien']}"/>
<h:outputText value="#{msg['form.salaire.repas']}"/>
<h:outputFormat value="{0,number,currency}">
<f:param value="#{form.feuilleSalaire.elementsSalaire.salaireBase}"/>
</h:outputFormat>
<h:outputFormat value="{0,number,currency}">
<f:param value="#{form.feuilleSalaire.elementsSalaire.cotisationsSociales}"/>
</h:outputFormat>
<h:outputFormat value="{0,number,currency}">
<f:param value="#{form.feuilleSalaire.elementsSalaire.indemnitesEntretien}"/>
</h:outputFormat>
<h:outputFormat value="{0,number,currency}">
<f:param value="#{form.feuilleSalaire.elementsSalaire.indemnitesRepas}"/>
</h:outputFormat>
</h:panelGrid>
<br/>
<h:panelGrid columns="3" columnClasses="libelle,col2,info">
<h:outputText value="#{msg['form.salaire.net']}"/>
<h:panelGroup></h:panelGroup>
<h:outputFormat value="{0,number,currency}">
<f:param value="#{form.feuilleSalaire.elementsSalaire.salaireNet}"/>
</h:outputFormat>
</h:panelGrid>
</ui:define>
</ui:composition>
</html>
- 8. satırda, [simulation.xhtml] sayfası [layout.xhtml] sayfasına eklenir,
- 9-11. satırlar: Giriş alanı, düzen sayfasının part1 parçasında görüntülenir,
- 12-91. satırlar: simülasyon, sayfa düzeninin part2 parçasında görüntülenir.
Soru: [Form] sınıfının [faireSimulation] yöntemini yazınız. Simülasyon, SessionData bean'ine kaydedilecektir.
12.5.3. Hata yönetimi
Bir simülasyonun hesaplanması sırasında ortaya çıkabilecek istisnaları düzgün bir şekilde yönetebilmek istiyoruz. Bunun için [faireSimulation] yönteminin kodu bir try / catch kullanacaktır:
// menü eylemi
public String faireSimulation(){
try{
// maaş bordrosu hesaplanıyor
feuilleSalaire= ...
// simülasyon görüntüleniyor
...
// menü güncelleniyor
...
// simülasyon görünümüne dönülür
return "simulation";
}catch(Throwable th){
// önceki hata listesi sıfırlanır
...
// yeni hata listesi oluşturulur
...
// vueErreur görünümünü görüntüler
...
// menüyü güncelliyor
...
// hata görünümünü görüntüler
return "erreurs";
}
}
- satırda oluşturulan hata listesi şöyledir:
// görünüm şablonu
...
private List<Erreur> erreurs=new ArrayList<Erreur>();
...
Hata sınıfı şu şekilde tanımlanmıştır:
package web.entities;
public class Erreur {
public Erreur() {
}
// alan
private String classe;
private String message;
// oluşturucu
public Erreur(String classe, String message){
this.setClasse(classe);
this.message=message;
}
// alıcı ve ayarlayıcılar
...
}
Hatalar, sınıf adı "sınıf" alanında ve mesajı "mesaj" alanında saklanan istisnalar olacaktır.
[faireSimulation] yönteminde oluşturulan hata listesi şunlardan oluşur:
- meydana gelen Throwable türündeki ilk istisna (th),
- varsa, bunun nedeni olan th.getCause() istisnası,
- varsa, nedenin nedeni olan h.getCause().getCause().
- ...
İşte bir hata listesi örneği:

Yukarıda, [Z Y] numaralı çalışan, simüle edilen [métier] katmanı tarafından kullanılan çalışan sözlüğünde mevcut değildir. Bu durumda, simüle edilen [métier] katmanı bir istisna oluşturur (aşağıdaki 6. satır):
public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravaillées, int nbJoursTravaillés) {
// çalışanı alıyoruz
Employe e=hashEmployes.get(SS);
// çalışan yoksa istisna atılır
if(e==null){
throw new PamException(String.format("L'employé de n° SS [%s] n'existe pas",SS),1);
}
...
}
Elde edilen sonuç şöyledir:

Bu görünüm, aşağıdaki [erreurs.xhtml] sayfası tarafından görüntülenir:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="part1">
<h3><h:outputText value="#{msg['erreur.titre']}"/></h3>
<h:dataTable value="#{form.erreurs}" var="erreur"
headerClass="erreursHeaders" columnClasses="erreurClasse,erreurMessage">
<f:facet name="header">
<h:outputText value="#{msg['erreur.exceptions']}"/>
</f:facet>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['exception.type']}"/>
</f:facet>
<h:outputText value="#{erreur.classe}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['exception.message']}"/>
</f:facet>
<h:outputText value="#{erreur.message}"/>
</h:column>
</h:dataTable>
</ui:define>
</ui:composition>
</html>
Soru: [faireSimulation] yöntemini, bir istisna durumunda [vueErreur] görünümünü görüntüleyecek şekilde tamamlayınız.
12.5.4. [effacerSimulation] eylemi
[effacerSimulation] eylemi, kullanıcının boş bir form bulmasını sağlar:
![]() |
[effacerSimulation] bağlantısının JSF kodu şöyledir:
<h:commandLink id="cmdEffacerSimulation" onclick="raz()" value="#{msg['form.menu.effacerSimulation']}" action="#{form.effacerSimulation}" rendered="#{sessionData.menuEffacerSimulationIsRendered}"/>
[EffacerSimulation] bağlantısına tıklandığında, önce raz() JavaScript işlevi çağrılır. Bu yöntem, [layout.xhtml] sayfasında tanımlanmıştır:
<script type="text/javascript">
function raz(){
// gönderilen değerleri değiştirme
document.forms['formulaire'].elements['formulaire:comboEmployes'].value="0";
document.forms['formulaire'].elements['formulaire:heuresTravaillees'].value="0";
document.forms['formulaire'].elements['formulaire:joursTravailles'].value="0";
}
</script>
4-6. satırlar, gönderilen değerleri değiştirir. Şu noktalara dikkat edilmelidir:
- gönderilen değerlerin geçerli değerler olduğu, c.a.d. Bu değerler, heuresTravaillees ve joursTravailles giriş alanlarının geçerlilik testlerini geçecektir.
- raz işlevi formu göndermez. Aslında, form cmdEffacerSimulation bağlantısı aracılığıyla gönderilecektir. Bu post işlemi, raz JavaScript işlevinin yürütülmesinden sonra gerçekleşecektir.
post işlevi sırasında, gönderilen değerler normal bir akış izleyecektir: doğrulama ve ardından şablondaki alanlara atama. [Form] sınıfında bu alanlar şunlardır:
// görünüm şablonu
private String comboEmployesValue;
private String heuresTravaillées;
private String joursTravaillés;
...
Bu üç alana {"0","0","0"} değerleri atanacaktır. Bu atama gerçekleştirildikten sonra, effacerSimulation yöntemi çalıştırılacaktır.
Soru: [Form] sınıfına ait [effacerSimulation] yöntemini yazınız. Aşağıdaki koşulların sağlanmasına özen gösteriniz:
-
Yalnızca giriş alanı görüntülenmeli,
-
açılır menü ilk öğesinin üzerine konumlandırılsın,
-
heuresTravaillees ve joursTravailles giriş alanlarında boş dizeler görüntülenmelidir.
12.5.5. [enregistrerSimulation] eylemi
[enregistrerSimulation] bağlantısının JSF kodu şöyledir:
<h:commandLink id="cmdEnregistrerSimulation" immediate="true" value="#{msg['form.menu.enregistrerSimulation']}" action="#{form.enregistrerSimulation}" rendered="#{sessionData.menuEnregistrerSimulationIsRendered}"/>
Bağlantıyla ilişkili [enregistrerSimulation] eylemi, mevcut simülasyonu [SessionData] sınıfında tutulan bir simülasyon listesine kaydetmeye olanak tanır:
private List<Simulation> simulations=new ArrayList<Simulation>();
Simülasyon sınıfı şu şekildedir:
package web.entities;
import metier.FeuilleSalaire;
public class Simulation {
public Simulation() {
}
// bir simülasyonun alanları
private Integer num;
private FeuilleSalaire feuilleSalaire;
private String heuresTravaillées;
private String joursTravaillés;
// oluşturucu
public Simulation(Integer num,String heuresTravaillées, String joursTravaillés, FeuilleSalaire feuilleSalaire){
this.setNum(num);
this.setFeuilleSalaire(feuilleSalaire);
this.setHeuresTravaillées(heuresTravaillées);
this.setJoursTravaillés(joursTravaillés);
}
public double getIndemnites(){
return feuilleSalaire.getElementsSalaire().getIndemnitesEntretien()+ feuilleSalaire.getElementsSalaire().getIndemnitesRepas();
}
// getter ve setter'lar
...
}
Bu sınıf, kullanıcı tarafından yapılan bir simülasyonu kaydetmeye olanak tanır:
- 11. satır: simülasyon numarası,
- 12. satır: hesaplanan maaş bordrosu,
- 13. satır: çalışılan saat sayısı,
- 14. satır: çalışılan gün sayısı.
İşte bir kayıt örneği:

Önceki sayfadan yola çıkarak şu sonuç elde edilir:

Simülasyon numarası, her yeni kayıtta artan bir sayıdır. Bu numara, SessionData bean'ine aittir:
// simülasyonlar
private List<Simulation> simulations = new ArrayList<Simulation>();
private int numDerniereSimulation = 0;
private Simulation simulation;
- 2. satır: yapılan son simülasyonun numarası.
[enregistrerSimulation] yöntemi şu şekilde çalışabilir:
- [SessionData] bean'inden son simülasyon numarasını alır ve bu numarayı artırır,
- yeni simülasyonu [SessionData] sınıfı tarafından yönetilen simülasyon listesine eklemek,
- simülasyon tablosunu görüntülemek:
![]() |
Simülasyon tablosu, [simulations.xhtml] sayfası tarafından görüntülenir:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="part1">
<!-- simülasyon tablosu -->
<h:dataTable value="#{sessionData.simulations}" var="simulation"
headerClass="simulationsHeaders" columnClasses="simuNum,simuNom,simuPrenom,simuHT,simuJT,simuSalaireBase,simuIndemnites,simuCotisationsSociales,simuSalaireNet">
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.numero']}"/>
</f:facet>
<h:outputText value="#{simulation.num}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.nom']}"/>
</f:facet>
<h:outputText value="#{simulation.feuilleSalaire.employe.nom}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.prenom']}"/>
</f:facet>
<h:outputText value="#{simulation.feuilleSalaire.employe.prenom}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.heuresTravaillees']}"/>
</f:facet>
<h:outputText value="#{simulation.heuresTravaillées}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.joursTravailles']}"/>
</f:facet>
<h:outputText value="#{simulation.joursTravaillés}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.salaireBase']}"/>
</f:facet>
<h:outputText value="#{simulation.feuilleSalaire.elementsSalaire.salaireBase}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.indemnites']}"/>
</f:facet>
<h:outputText value="#{simulation.indemnites}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.cotisationsSociales']}"/>
</f:facet>
<h:outputText value="#{simulation.feuilleSalaire.elementsSalaire.cotisationsSociales}"/>
</h:column>
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.salaireNet']}"/>
</f:facet>
<h:outputText value="#{simulation.feuilleSalaire.elementsSalaire.salaireNet}"/>
</h:column>
<h:column>
<h:commandLink value="Retirer" action="#{form.retirerSimulation}">
<f:setPropertyActionListener target="#{form.numSimulationToDelete}" value="#{simulation.num}"/>
</h:commandLink>
</h:column>
</h:dataTable>
</ui:define>
</ui:composition>
</html>
- 8. satırda, [simulations.xhtml] sayfası, [layout.xhtml] sayfasının içine eklenir,
- 9. satırda, part1 adlı parçanın yerine,
- 11. satırda, <h:dataTable> etiketi, #{sessionData.simulations} alanını veri kaynağı olarak kullanır, c.a.d. Bir sonraki alan:
// simülasyonlar
private List<Simulation> simulations;
-
var="simulation" özniteliği, <h:datatable> etiketi içinde geçerli simülasyonu temsil eden değişkenin adını belirler
-
headerClass="simulationsHeaders" özniteliği, tablonun sütun başlıklarının stilini belirler.
-
columnClasses="...." özniteliği, tablonun her bir sütununun stilini belirler
Tablodaki sütunlardan birini inceleyelim ve nasıl oluşturulduğuna bakalım:
![]() |
Nom sütunundaki JSF kodu şöyledir:
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.nom']}"/>
</f:facet>
<h:outputText value="#{simulation.feuilleSalaire.employe.nom}"/>
</h:column>
- 2-4. satırlar: <f:facet name="header"> etiketi, sütunun başlığını tanımlar
- 5. satır: Çalışanın adı şu şekilde yazılır:
- simülasyon, <h:dataTable ...> etiketinin var özniteliğine atıfta bulunur:
<h:dataTable value="#{sessionData.simulations}" var="simulation" ...>
simülasyon, simülasyonlar listesindeki geçerli simülasyonu belirtir: önce 1. simülasyon, sonra 2. simülasyon, …
- (devamı)
- simulation.feuilleSalaire, mevcut simülasyonun feuilleSalaire alanına atıfta bulunur
- simulation.feuilleSalaire.employe, feuilleSalaire alanındaki "çalışan" alanına atıfta bulunur
- simulation.feuilleSalaire.employe.nom, "employe" alanındaki "nom" alanına atıfta bulunur
Aynı teknik, tablonun tüm sütunları için tekrarlanır. Aşağıdaki kodla oluşturulan “Indemnités” sütununda bir sorun vardır:
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.indemnites']}"/>
</f:facet>
<h:outputText value="#{simulation.indemnites}"/>
</h:column>
- satırda, simulation.indemnites değerinin çıktısı alınır. Ancak Simulation sınıfında indemnites alanı bulunmamaktadır. Burada, indemnites alanının doğrudan değil, simulation.getIndemnites() yöntemi aracılığıyla kullanıldığını unutmamak gerekir. Dolayısıyla bu yöntemin mevcut olması yeterlidir. indemnites alanı ise mevcut olmayabilir. getIndemnites yöntemi, çalışanın toplam tazminat tutarını döndürmelidir. Bu toplam, maaş bordrosunda doğrudan mevcut olmadığından, bir ara hesaplama gerektirir. getIndemnites yöntemi, 12.5.5. paragrafında verilmiştir.
Soru: [Form] sınıfına ait [enregistrerSimulation] yöntemini yazınız.
12.5.6. [retourSimulateur] eylemi
[retourSimulateur] bağlantısının JSF kodu şöyledir:
<h:commandLink id="cmdRetourSimulateur" immediate="true" value="#{msg['form.menu.retourSimulateur']}" action="#{form.retourSimulateur}" rendered="#{sessionData.menuRetourSimulateurIsRendered}"/>
Bağlantıyla ilişkili [retourSimulateur] eylemi, kullanıcının [vueSimulations] görünümünden [vueSaisies] görünümüne geri dönmesini sağlar:

Elde edilen sonuç:

Soru: [Form] sınıfının [retourSimulateur] yöntemini yazınız. Sunulan giriş formu, yukarıdaki gibi boş olmalıdır.
12.5.7. [voirSimulations] eylemi
[voirSimulations] bağlantısının JSF kodu şöyledir:
<h:commandLink id="cmdVoirSimulations" immediate="true" value="#{msg['form.menu.voirSimulations']}" action="#{form.voirSimulations}" rendered="#{sessionData.menuVoirSimulationsIsRendered}"/>
Bağlantıyla ilişkili [voirSimulations] eylemi, kullanıcının girişlerinin durumu ne olursa olsun simülasyon tablosunu görüntülemesini sağlar:

Elde edilen sonuç:

Soru: [Form] sınıfının [voirSimulations] yöntemini yazınız.
Simülasyon listesi boşsa, görüntülenen görünümün [vueSimulationsVides] olmasını sağlayacağız:

Yukarıdaki görünümü görüntülemek için aşağıdaki [simulationsVides.xhtml] sayfasını kullanacağız:
<?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:f="http://java.sun.com/jsf/core"
xmlns:ui="http://java.sun.com/jsf/facelets">
<ui:composition template="layout.xhtml">
<ui:define name="part1">
<h2>Votre liste de simulations est vide.</h2>
</ui:define>
</ui:composition>
</html>
12.5.8. [retirerSimulation] eylemi
Kullanıcı, simülasyonları listesinden kaldırabilir:

Elde edilen sonuç şöyledir:

Yukarıdaki örnekte son simülasyonu kaldırırsak, şu sonuç elde edilir:

Simülasyon tablosundaki [Retirer] sütunundaki JSF kodu şöyledir:
<h:dataTable value="#{form.simulations}" var="simulation"
headerClass="simulationsHeaders" columnClasses="simuNum,simuNom,simuPrenom,simuHT,simuJT,simuSalaireBase,simuIndemnites,simuCotisationsSociales,simuSalaireNet">
...
<h:column>
<h:commandLink value="Retirer" action="#{form.retirerSimulation}">
<f:setPropertyActionListener target="#{form.numSimulationToDelete}" value="#{simulation.num}"/>
</h:commandLink>
</h:column>
</h:dataTable>
- 5. satır: [Retirer] bağlantısı, [Form] sınıfındaki [retirerSimulation] yöntemiyle ilişkilidir. Bu yöntemin, kaldırılacak simülasyon numarasını bilmesi gerekir. Bu numara, 8. satırdaki <f:setPropertyActionListener> etiketinden sağlanır. Bu etiketin target ve value olmak üzere iki özniteliği vardır: target özniteliği, value özniteliğinin değerinin atanacağı modeldeki bir alanı belirtir. Burada, kaldırılacak simülasyon numarası #{simulation.num}, [Form] sınıfındaki numSimulationToDelete alanına atanacaktır:
// görünüm modeli
...
private Integer numSimulationToDelete;
[Form] sınıfının [retirerSimulation] yöntemi çalıştırıldığında, daha önce numSimulationToDelete alanında depolanmış olan değeri kullanabilecektir.
Görev: [Form] sınıfının [retirerSimulation] yöntemini yazın.
12.5.9. [terminerSession] eylemi
[Terminer la session] bağlantısının JSF kodu şöyledir:
<h:commandLink id="cmdTerminerSession" immediate="true" value="#{msg['form.menu.terminerSession']}" action="#{form.terminerSession}" rendered="#{sessionData.menuTerminerSessionIsRendered}"/>
Bağlantıyla ilişkili [terminerSession] eylemi, kullanıcının oturumunu sonlandırmasına ve boş giriş formuna geri dönmesine olanak tanır:


Kullanıcının bir simülasyon listesi varsa, bu liste boşaltılır. Ayrıca, simülasyonların numaralandırması 1'den yeniden başlar.
Soru: [Form] sınıfına ait [terminerSession] yöntemini yazınız.
12.6. Web katmanının 3 katmanlı bir mimariye entegrasyonu JSF / EJB
Önceki web uygulamasının mimarisi şu şekildeydi:
![]() |
Simüle edilen [métier] katmanını, 7.1. paragrafta EJB ile uygulanan [métier, DAO, jpa] katmanlarıyla değiştiriyoruz:
![]() |
Uygulama ödevi: 11. paragrafta belirtilen metodolojiyi izleyerek JSF ve EJB katmanlarının entegrasyonunu gerçekleştirin.
![]() |














