12. Versão 7 – Aplicativo web PAM com múltiplas visualizações/múltiplas páginas
Voltamos aqui à arquitetura inicial, na qual a camada [métier] era simulada. Sabemos agora que ela pode ser facilmente substituída pela camada real [métier]. A camada simulada [métier] facilita os testes.
![]() |
Uma aplicação JSF é do tipo MVC (Modelo-Visão-Controlador):
- o servlet [Faces Servlet] é o controlador genérico fornecido pelo JSF. Esse controlador é estendido pelos gerenciadores de eventos específicos da aplicação. Os gerenciadores de eventos encontrados até agora eram métodos das classes que serviam de modelos para as páginas JSF
- as páginas JSF enviam as respostas ao navegador do cliente. Essas são as visualizações da aplicação.
- As páginas JSF contêm elementos dinâmicos chamados de modelo da página. Vale lembrar que, para alguns autores, o modelo abrange as entidades manipuladas pela aplicação, como, por exemplo, as classes FeuilleSalaire ou Employe. Para distinguir esses dois modelos, pode-se falar em modelo da aplicação e modelo de uma página JSF.
Na arquitetura JSF, a transição de uma página JSFi para uma página JSFj pode ser problemática.
- A página JSFi foi exibida. A partir dessa página, o usuário aciona um POST por meio de algum evento [1]
- em JSF, esse POST será processado, em geral, por um método C do modelo Mi da página JSFi. Pode-se dizer que o método C é um controlador secundário.
- Se, ao final desse método, a página JSFj precisar ser exibida, o controlador C deve:
- atualizar o modelo Mj da página JSFj com [2c]
- retornar ao controlador principal, em [2a], a chave de navegação que permitirá a exibição da página JSFj
A etapa 1 exige que o modelo Mi da página JSFi tenha uma referência ao modelo Mj da página JSFj. Isso complica um pouco as coisas, tornando os modelos Mi dependentes uns dos outros. De fato, o gerenciador C do modelo Mi que atualiza o modelo Mj precisa conhecê-lo. Se for necessário alterar o modelo Mj, será necessário alterar também o gerenciador C do modelo Mi.
Existe um caso em que a dependência entre os modelos pode ser evitada: aquele em que há um único modelo M que serve para todas as páginas JSF. Essa arquitetura só é utilizável em aplicativos com poucas visualizações, mas, nesse caso, revela-se muito simples de usar. É essa que estamos utilizando atualmente.
Nesse contexto, a arquitetura da aplicação é a seguinte:
![]() |
12.1. As visualizações da aplicação
As diferentes visualizações apresentadas ao usuário serão as seguintes:
-
a tela [VueSaisies], que apresenta o formulário de simulação
-
a visualização [VueSimulation], utilizada para exibir o resultado detalhado da simulação:


- a visualização [VueSimulations], que exibe a lista das simulações realizadas pelo cliente

- a visualização [VueSimulationsVides], que indica que o cliente não possui ou não possui mais simulações:

- a visualização [VueErreur], que indica um ou mais erros:

12.2. O projeto NetBeans da camada [web]
O projeto NetBeans desta versão será o seguinte projeto Maven:
![]() |
- em [1], os arquivos de configuração,
- em [2], as páginas JSF,
- em [3], a folha de estilo e a imagem de fundo das visualizações,
- em [4], as classes da camada [web],
- em [5], as camadas inferiores do aplicativo,
- em [6], o arquivo de mensagens para a internacionalização da aplicação,
- em [7], as dependências do projeto.
Vamos examinar alguns desses elementos.
12.2.1. Os arquivos de configuração
Os arquivos [web.xml] e [faces-config.xml] são idênticos aos do projeto anterior, com exceção de um detalhe no [web.xml]:
<?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>
- linhas 4-6: a página inicial é a página [saisie.xhtml]
12.2.2. A folha de estilo
O arquivo [styles.css] é o seguinte:
.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
}
Aqui estão alguns exemplos de código JSF que utilizam esses estilos:
Visualização de Simulações
<h:dataTable value="#{form.simulations}" var="simulation"
headerClass="simulationsHeaders" columnClasses="simuNum,simuNom,simuPrenom,simuHT,simuJT,simuSalaireBase,simuIndemnites,simuCotisationsSociales,simuSalaireNet">
O resultado obtido é o seguinte:

Visualização de erro
<h:dataTable value="#{form.erreurs}" var="erreur"
headerClass="erreursHeaders" columnClasses="erreurClasse,erreurMessage">

12.2.3. O arquivo de mensagens
O arquivo de mensagens [messages_fr.properties] é o seguinte:
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. A camada [métier]
A camada [métier] simulada é modificada da seguinte forma:
package metier;
...
public class Metier implements ImetierLocal, Serializable {
// lista de funcionários
private Map<String,Employe> hashEmployes=new HashMap<String,Employe>();
private List<Employe> listEmployes;
// obter a folha de pagamento
public FeuilleSalaire calculerFeuilleSalaire(String SS,
double nbHeuresTravaillées, int nbJoursTravaillés) {
// recuperar o funcionário
Employe e=hashEmployes.get(SS);
// retorna uma exceção se o funcionário não existir
if(e==null){
throw new PamException(String.format("L'employé de n° SS [%s] n'existe pas",SS),1);
}
// retorna uma folha de pagamento fictícia
return new FeuilleSalaire(e,new Cotisation(3.49,6.15,9.39,7.88),e.getIndemnite(),new ElementsSalaire(100,100,100,100,100));
}
// lista de funcionários
public List<Employe> findAllEmployes() {
if(listEmployes==null){
// cria-se uma lista com três funcionários
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)));
// dicionário de funcionários
for(Employe e:listEmployes){
hashEmployes.put(e.getSS(),e);
}
// adiciona-se um funcionário que não existe no dicionário
listEmployes.add(new Employe("X","Y","Z","La brûlerie","St Marcel","49014",new Indemnite(1,1.93,2,3,12)));
}
// retornamos a lista de funcionários
return listEmployes;
}
}
- linha 8: a lista de funcionários
- linha 7: a mesma lista na forma de um dicionário indexado pelo número SS dos funcionários
- linhas 24-39: o método findAllEmployes que retorna a lista de funcionários. Esse método cria uma lista estática e faz referência ao campo employés da linha 8.
- linhas 27-33: são criadas uma lista e um dicionário com dois funcionários
- linha 35: um funcionário é adicionado à lista de funcionários (linha 8), mas não ao dicionário hashEmployes (linha 7). Isso faz com que ele apareça na lista suspensa de funcionários, mas não seja reconhecido pelo método calculerFeuilleSalaire (linha 14), de modo que este lance uma exceção (linha 17).
- linhas 11-21: o método calculerFeuilleSalaire
- linha 14: o funcionário é procurado no dicionário hashEmployes por meio de seu nº SS. Se não for encontrado, é lançada uma exceção (linhas 16-18). Assim, teremos uma exceção para o funcionário com o número SS X, adicionado na linha 35 à lista de funcionários, mas não no dicionário hashEmployes.
- Na linha 20, uma folha de pagamento fictícia é criada e retornada.
12.3. Os beans do aplicativo
Haverá três beans com três escopos diferentes:
![]() |
12.3.1. O bean ApplicationData
O bean ApplicationData terá o escopo application:
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 {
// camada de negócios
private IMetierLocal metier = new Metier();
// registrador
private boolean logsEnabled = true;
private final Logger logger = Logger.getLogger("pam");
public ApplicationData() {
}
@PostConstruct
public void init() {
// registro
if (isLogsEnabled()) {
logger.info("ApplicationData");
}
}
// getters e setters
...
}
- linha 11: a anotação @Named transforma a classe em um bean gerenciado. Observe que, ao contrário do projeto anterior, não utilizamos a anotação @ManagedBean. O motivo é que a referência a essa classe deve ser injetada em outra classe por meio da anotação @Inject, e esta injeta apenas classes com a anotação @Named.
- linha 12: a anotação @ApplicationScoped torna a classe um objeto de escopo de aplicação. Observe que a classe da anotação é [javax.enterprise.context.ApplicationScoped] (linha 6) e não [javax.faces.bean.ApplicationScoped], como nos beans do projeto anterior.
O bean ApplicationData tem duas funções:
- linha 16: manter uma referência à camada [métier],
- linhas 18-19: definir um registrador de logs que poderá ser utilizado pelos outros beans para gerar registros no console do GlassFish.
12.3.2. O bean SessionData
O bean SessionData terá escopo de sessão:
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 {
// aplicativo
@Inject
private ApplicationData applicationData;
// simulações
private List<Simulation> simulations = new ArrayList<Simulation>();
private int numDerniereSimulation = 0;
private Simulation simulation;
// menus
private boolean menuFaireSimulationIsRendered = true;
private boolean menuEffacerSimulationIsRendered = true;
private boolean menuEnregistrerSimulationIsRendered;
private boolean menuVoirSimulationsIsRendered;
private boolean menuRetourSimulateurIsRendered;
private boolean menuTerminerSessionIsRendered = true;
// local
private String locale="fr_FR";
// construtor
public SessionData() {
}
@PostConstruct
public void init() {
// log
if (applicationData.isLogsEnabled()) {
applicationData.getLogger().info("SessionData");
}
}
// gerenciamento de menus
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);
}
// getters e setters
...
}
- linha 13: a classe SessionData é um bean gerenciado (@Named) que poderá ser injetado em outros beans gerenciados,
- linha 14: ele tem escopo de sessão (@SessionScoped),
- linhas 18-19: uma referência ao bean ApplicationData é injetada nele (@Inject),
- linhas 21-32: os dados do aplicativo que devem ser mantidos ao longo das sessões.
- linha 21: a lista das simulações realizadas pelo usuário,
- linha 22: o número da última simulação registrada,
- linha 23: a última simulação realizada,
- linhas 25-30: as opções do menu,
- linha 32: a configuração regional do aplicativo.
Linhas 39-44: o método init é executado após a instanciação da classe (@PostConstruct). Aqui, ele é usado apenas para deixar um registro de sua execução. Deve ser possível verificar que ele é executado apenas uma vez por usuário, já que a classe tem escopo de sessão. Linha 42: o método utiliza o logger definido na classe ApplicationData. É por esse motivo que foi necessário injetar uma referência nesse bean (linhas 18-19).
12.3.3. O bean Form
O bean Form tem escopo requête:
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() {
}
// outros beans
@Inject
private ApplicationData applicationData;
@Inject
private SessionData sessionData;
// o modelo das visualizações
private String comboEmployesValue = "";
private String heuresTravaillées = "";
private String joursTravaillés = "";
private Integer numSimulationToDelete;
private List<Erreur> erreurs = new ArrayList<Erreur>();
private FeuilleSalaire feuilleSalaire;
// lista de funcionários
public List<Employe> getEmployes(){
return applicationData.getMetier().findAllEmployes();
}
// ação do menu
public String faireSimulation() {
...
}
public String enregistrerSimulation() {
...
}
public String effacerSimulation() {
...
}
public String voirSimulations() {
...
}
public String retourSimulateur() {
...
}
public String terminerSession() {
...
}
public String retirerSimulation() {
...
}
private void razFormulaire() {
...
}
// getters e setters
...
}
- na linha 17, a classe é um bean gerenciado (@Named),
- linha 18, com escopo de requisição (@RequestScoped),
- linhas 24-25: injeção de uma referência no bean de escopo de aplicação ApplicationData,
- linhas 26-27: injeção de uma referência ao bean de escopo de sessão SessionData.
12.4. As páginas do aplicativo
![]() |
12.4.1. [layout.xhtml]
A página [layout.xhtml] é responsável pela formatação de todas as visualizações:
<?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(){
// alteramos os valores enviados
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">
<!-- cabeçalho -->
<ui:include src="entete.xhtml" />
<!-- conteúdo -->
<ui:insert name="part1" >
Gestion des assistantes maternelles
</ui:insert>
<ui:insert name="part2"/>
</h:form>
</h:body>
</f:view>
</html>
Cada visualização é composta pelos seguintes elementos:
- um cabeçalho exibido pelo fragmento [entete.xhtml] (linha 24),
- um corpo formado por dois fragmentos chamados part1 (linhas 26-28) e part2 (linha 29),
- linha 8: o atributo locale garante a internacionalização das páginas. Aqui, haverá apenas um: fr_FR,
- linhas 14-19: um código JavaScript.
A exibição da página [layout.xhtml] é a seguinte:
![]() |
- em [1], o cabeçalho [entete.xhtml],
- em [2], o fragmento part1.
12.4.2. O cabeçalho [entete.xhtml]
O código da página [entete.xhtml] é o seguinte:
<?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>
<!-- cabeçalho -->
<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>
- linha 12: o título do aplicativo,
- linhas 16-21: os seis links correspondentes às seis ações que o usuário pode realizar. Esses links são controlados (atributo rendered) por valores booleanos do bean SessionData,
- linha 17: um clique no link [Effacer la simulation] aciona a execução da função JavaScript raz. Essa função foi definida no modelo [layout.xhtml],
- linha 18: o atributo immediate=true faz com que a validade dos dados não seja verificada antes da execução do método [Form].enregistrerSimulation. Isso é intencional. Pode ser necessário gravar a última simulação realizada há um minuto, mesmo que os dados inseridos desde então no formulário (mas ainda não validados) não sejam válidos. O mesmo se aplica às ações [Voir les simulations], [Effacer la simulation], [Retour au simulateur] e [Terminer la session].
12.5. Casos de uso do aplicativo
12.5.1. Exibição da página inicial
A página inicial é a seguinte página [saisie.xhtml]:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns: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>
- linha 8: ela é exibida dentro da página [layout.xhtml],
- linha 9: no lugar do fragmento chamado part1. Nesse fragmento, é exibida a página [saisie2.xhtml]:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns: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>
Este código exibe a seguinte visualização:
![]() |
Pergunta: complete a linha 13 do código XHTML. A lista de elementos da lista suspensa de funcionários é fornecida por um método do bean [Form]. Escreva esse método. Os elementos exibidos no menu suspenso terão sua propriedade itemValue igual ao número SS de um funcionário, e a propriedade itemLabel será uma sequência de caracteres formada pelo nome e sobrenome desse funcionário.
Pergunta: como o bean [SessionData] deve ser inicializado para que, durante a consulta inicial GET feita ao formulário, o menu do cabeçalho seja o mostrado acima?
12.5.2. A ação [faireSimulation]
O código JSF da ação [faireSimulation] é o seguinte:
<h:commandLink id="cmdFaireSimulation" value="#{msg['form.menu.faireSimulation']}" action="#{form.faireSimulation}" rendered="#{sessionData.menuFaireSimulationIsRendered}"/>
A ação [faireSimulation] calcula uma folha de pagamento:

A partir da página anterior, obtém-se o seguinte resultado:
![]() |
![]() |
A simulação é exibida na página [simulation.xhtml] a seguir:
<?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>
- na linha 8, a página [simulation.xhtml] é inserida na página [layout.xhtml],
- linhas 9-11: a área de entradas é exibida no fragmento part1 da página de layout,
- linhas 12-91: a simulação é exibida no fragmento part2 da página de layout.
Pergunta: escreva o método [faireSimulation] da classe [Form]. A simulação será gravada no bean SessionData.
12.5.3. Gerenciamento de erros
Queremos poder gerenciar adequadamente as exceções que possam ocorrer durante o cálculo de uma simulação. Para isso, o código do método [faireSimulation] utilizará um try/catch:
// ação do menu
public String faireSimulation(){
try{
// calcula-se a folha de pagamento
feuilleSalaire= ...
// exibe-se a simulação
...
// atualiza-se o menu
...
// retorna à visualização da simulação
return "simulation";
}catch(Throwable th){
// limpa-se a lista de erros anteriores
...
// cria-se a nova lista de erros
...
// exibe-se a visualização vueErreur
...
// atualiza o menu
...
// exibe-se a visualização de erros
return "erreurs";
}
}
A lista de erros criada na linha 15 é a seguinte:
// o modelo das visualizações
...
private List<Erreur> erreurs=new ArrayList<Erreur>();
...
A classe Erro é definida da seguinte forma:
package web.entities;
public class Erreur {
public Erreur() {
}
// campo
private String classe;
private String message;
// construtor
public Erreur(String classe, String message){
this.setClasse(classe);
this.message=message;
}
// getters e setters
...
}
Os erros serão exceções cujo nome da classe é armazenado no campo classe e cuja mensagem é armazenada no campo mensagem.
A lista de erros criada no método [faireSimulation] é composta por:
- a exceção inicial th do tipo Throwable que ocorreu,
- sua causa th.getCause(), caso exista,
- da causa da causa h.getCause().getCause(), caso exista.
- ...
Aqui está um exemplo de lista de erros:

No exemplo acima, o funcionário [Z Y] não existe no dicionário de funcionários utilizado pela camada simulada [métier]. Nesse caso, a camada simulada [métier] lança uma exceção (linha 6 abaixo):
public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravaillées, int nbJoursTravaillés) {
// recupera-se o funcionário
Employe e=hashEmployes.get(SS);
// lança-se uma exceção se o funcionário não existir
if(e==null){
throw new PamException(String.format("L'employé de n° SS [%s] n'existe pas",SS),1);
}
...
}
O resultado obtido é o seguinte:

Essa visualização é exibida pela página [erreurs.xhtml] a seguir:
<?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>
Pergunta: complete o método [faireSimulation] para que, em caso de exceção, ele exiba a visualização [vueErreur].
12.5.4. A ação [effacerSimulation]
A ação [effacerSimulation] permite que o usuário acesse um formulário em branco:
![]() |
O código JSF do link [effacerSimulation] é o seguinte:
<h:commandLink id="cmdEffacerSimulation" onclick="raz()" value="#{msg['form.menu.effacerSimulation']}" action="#{form.effacerSimulation}" rendered="#{sessionData.menuEffacerSimulationIsRendered}"/>
Um clique no link [EffacerSimulation] provoca, em primeiro lugar, a chamada da função JavaScript raz(). Esse método está definido na página [layout.xhtml]:
<script type="text/javascript">
function raz(){
// alteramos os valores enviados
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>
As linhas 4 a 6 alteram os valores enviados. Observe que
- os valores enviados são válidos, c.a.d, e que eles passarão nos testes de validação dos campos de entrada heuresTravaillees e joursTravailles.
- a função raz não envia o formulário. Na verdade, ele será enviado pelo link cmdEffacerSimulation. Esse post será executado após a execução da função JavaScript raz.
Durante a execução da função post, os valores enviados seguirão um fluxo normal: validação e, em seguida, atribuição aos campos do modelo. Esses campos são os seguintes na classe [Form]:
// o modelo das visualizações
private String comboEmployesValue;
private String heuresTravaillées;
private String joursTravaillés;
...
Esses três campos receberão os três valores lançados {"0","0","0"}. Após essa atribuição, o método effacerSimulation será executado.
Pergunta: escreva o método [effacerSimulation] da classe [Form]. Certifique-se de que:
-
apenas a área de entrada de dados seja exibida,
-
a lista suspensa esteja posicionada no primeiro elemento,
-
os campos de entrada heuresTravaillees e joursTravailles exibam strings vazias.
12.5.5. A ação [enregistrerSimulation]
O código JSF do link [enregistrerSimulation] é o seguinte:
<h:commandLink id="cmdEnregistrerSimulation" immediate="true" value="#{msg['form.menu.enregistrerSimulation']}" action="#{form.enregistrerSimulation}" rendered="#{sessionData.menuEnregistrerSimulationIsRendered}"/>
A ação [enregistrerSimulation] associada ao link permite gravar a simulação atual em uma lista de simulações mantida na classe [SessionData]:
private List<Simulation> simulations=new ArrayList<Simulation>();
A classe “ Simulação” é a seguinte:
package web.entities;
import metier.FeuilleSalaire;
public class Simulation {
public Simulation() {
}
// campos de uma simulação
private Integer num;
private FeuilleSalaire feuilleSalaire;
private String heuresTravaillées;
private String joursTravaillés;
// construtor
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();
}
// getters e setters
...
}
Essa classe permite armazenar uma simulação realizada pelo usuário:
- linha 11: o número da simulação,
- linha 12: a folha de pagamento que foi calculada,
- linha 13: o número de horas trabalhadas,
- linha 14: o número de dias trabalhados.
Veja um exemplo de registro:

A partir da página anterior, obtém-se o seguinte resultado:

O número da simulação é um número incrementado a cada novo registro. Ele pertence ao bean SessionData:
// simulações
private List<Simulation> simulations = new ArrayList<Simulation>();
private int numDerniereSimulation = 0;
private Simulation simulation;
- linha 2: o número da última simulação realizada.
O método [enregistrerSimulation] pode proceder da seguinte forma:
- recuperar o número da última simulação no bean [SessionData] e incrementá-lo,
- adicionar a nova simulação à lista de simulações mantida pela classe [SessionData],
- exibir a tabela de simulações:
![]() |
A tabela de simulações é exibida pela página [simulations.xhtml]:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns: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">
<!-- tabela de simulações -->
<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>
- na linha 8, a página [simulations.xhtml] é inserida dentro da página [layout.xhtml],
- na linha 9, no lugar do fragmento denominado part1,
- na linha 11, a tag <h:dataTable> utiliza o campo #{sessionData.simulations} como fonte de dados, c.a.d. O campo seguinte:
// simulações
private List<Simulation> simulations;
-
o atributo var="simulation" define o nome da variável que representa a simulação atual dentro da tag <h:datatable>
-
o atributo headerClass="simulationsHeaders" define o estilo dos títulos das colunas da tabela.
-
o atributo columnClasses="...." define o estilo de cada uma das colunas da tabela
Vamos examinar uma das colunas da tabela e ver como ela é construída:
![]() |
O código JSF da coluna Nom é o seguinte:
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.nom']}"/>
</f:facet>
<h:outputText value="#{simulation.feuilleSalaire.employe.nom}"/>
</h:column>
- linhas 2-4: a tag <f:facet name="header"> define o título da coluna
- linha 5: o nome do funcionário é escrito como:
- a simulação faz referência ao atributo var da tag <h:dataTable ...>:
<h:dataTable value="#{sessionData.simulations}" var="simulation" ...>
“simulação” designa a simulação atual da lista de simulações: primeiro a 1ª, depois a 2ª, …
- (continuação)
- simulation.feuilleSalaire refere-se ao campo feuilleSalaire da simulação atual
- simulation.feuilleSalaire.employe refere-se ao campo “empregado” do campo feuilleSalaire
- simulation.feuilleSalaire.employe.nom refere-se ao campo “nom” do campo “employe”
A mesma técnica é repetida para todas as colunas da tabela. Há uma dificuldade na coluna “Indenizações”, que é gerada com o seguinte código:
<h:column>
<f:facet name="header">
<h:outputText value="#{msg['simulations.headers.indemnites']}"/>
</f:facet>
<h:outputText value="#{simulation.indemnites}"/>
</h:column>
Na linha 5, é exibido o valor de simulation.indemnites. No entanto, a classe Simulação não possui o campo indemnites. É importante lembrar aqui que o campo indemnites não é utilizado diretamente, mas sim por meio do método simulation.getIndemnites(). Portanto, basta que esse método exista. O campo indemnites, por sua vez, pode não existir. O método getIndemnites deve retornar o total das indenizações do funcionário. Isso requer um cálculo intermediário, pois esse total não está disponível diretamente na folha de pagamento. O método getIndemnites é fornecido no parágrafo 12.5.5.
Pergunta: escreva o método [enregistrerSimulation] da classe [Form].
12.5.6. A ação [retourSimulateur]
O código JSF do link [retourSimulateur] é o seguinte:
<h:commandLink id="cmdRetourSimulateur" immediate="true" value="#{msg['form.menu.retourSimulateur']}" action="#{form.retourSimulateur}" rendered="#{sessionData.menuRetourSimulateurIsRendered}"/>
A ação [retourSimulateur] associada ao link permite que o usuário retorne da visualização [vueSimulations] para a visualização [vueSaisies]:

O resultado obtido:

Pergunta: escreva o método [retourSimulateur] da classe [Form]. O formulário de entrada apresentado deve estar vazio, conforme mostrado acima.
12.5.7. A ação [voirSimulations]
O código JSF do link [voirSimulations] é o seguinte:
<h:commandLink id="cmdVoirSimulations" immediate="true" value="#{msg['form.menu.voirSimulations']}" action="#{form.voirSimulations}" rendered="#{sessionData.menuVoirSimulationsIsRendered}"/>
A ação [voirSimulations] associada ao link permite que o usuário visualize a tabela de simulações, independentemente do status de suas entradas:

O resultado obtido:

Pergunta: escreva o método [voirSimulations] da classe [Form].
Faremos com que, se a lista de simulações estiver vazia, a visualização exibida seja [vueSimulationsVides]:

Para exibir a visualização acima, utilizaremos a seguinte página [simulationsVides.xhtml]:
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns: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. A ação [retirerSimulation]
O usuário pode remover simulações de sua lista:

O resultado obtido é o seguinte:

Se, no exemplo acima, removemos a última simulação, obteremos o seguinte resultado:

O código JSF da coluna [Retirer] da tabela de simulações é o seguinte:
<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>
- linha 5: o link [Retirer] está associado ao método [retirerSimulation] da classe [Form]. Esse método precisa saber o número da simulação a ser removida. Esse número é fornecido pela tag <f:setPropertyActionListener> da linha 8. Essa tag possui dois atributos: target e value; o atributo target indica um campo do modelo ao qual o valor do atributo value será atribuído. Aqui, o número da simulação a ser removida #{simulation.num} será atribuído ao campo numSimulationToDelete da classe [Form]:
// modelo das visualizações
...
private Integer numSimulationToDelete;
Quando o método [retirerSimulation] da classe [Form] for executado, ele poderá utilizar o valor que foi armazenado anteriormente no campo numSimulationToDelete.
Tarefa: escreva o método [retirerSimulation] da classe [Form].
12.5.9. A ação [terminerSession]
O código JSF do link [Terminer la session] é o seguinte:
<h:commandLink id="cmdTerminerSession" immediate="true" value="#{msg['form.menu.terminerSession']}" action="#{form.terminerSession}" rendered="#{sessionData.menuTerminerSessionIsRendered}"/>
A ação [terminerSession] associada ao link permite que o usuário encerre sua sessão e retorne ao formulário de preenchimento vazio:


Caso o usuário tivesse uma lista de simulações, ela é esvaziada. Além disso, a numeração das simulações recomeça do 1.
Questão: escreva o método [terminerSession] da classe [Form].
12.6. Integração da camada web em uma arquitetura de três camadas JSF / EJB
A arquitetura da aplicação web anterior era a seguinte:
![]() |
Substituímos a camada simulada [métier] pelas camadas [métier, DAO, jpa] implementadas por EJB no parágrafo 7.1:
![]() |
Exercício prático: realizar a integração das camadas JSF e EJB seguindo a metodologia do parágrafo 11.
![]() |














