Skip to content

19. Vaka çalışması – sürüm 1

19.1. Simüle edilen [metier] katmanı

Oluşturduğumuz uygulamanın mimarisine tekrar göz atalım:

[metier, dao, jpa] katmanlarının arşivine sahibiz ve [web] katmanının bilmesi gereken bu katmanların öğelerini sunduk. Struts çerçevesini kullanarak bu katmanı yazmaya hazırız.

Geliştirme aşamasındaki uygulamamızın testlerini kolaylaştırmak için, [metier] katmanının arayüzüne uygun bir simüle edilmiş iş katmanı oluşturacağız. Mimari şu şekilde olacaktır:

[web] katmanını, simüle edilmiş [métier] katmanı ile birlikte geliştireceğiz. Mimari içinde artık veritabanı bulunmadığından testleri yapmak daha kolay olacaktır. Spring ve arayüzlerin kullanımı sayesinde, simüle edilmiş [metier] katmanını daha sonra gerçek [metier, dao, jpa] mimarisiyle değiştirmek, [web / struts2] katmanının koduna hiçbir etki yapmayacaktır. Şimdi geliştireceğimiz [web / struts2] katmanı olduğu gibi kullanılabilecektir.

Kullanacağımız simüle edilmiş [metier] katmanı şöyledir:


package metier;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import jpa.Cotisation;
import jpa.Employe;
import jpa.Indemnite;

public class MetierSimule implements IMetier {

  // çalışan listesi
  private Map<String, Employe> hashEmployes = new HashMap<String, Employe>();
  private List<Employe> listEmployes;

  // maaş bordrosunu alma
  public FeuilleSalaire calculerFeuilleSalaire(String SS,
          double nbHeuresTravaillées, int nbJoursTravaillés) {
    // SS numaralı çalışanı al
    Employe e = hashEmployes.get(SS);
    // hayali bir maaş bordrosu oluşturulur
    return new FeuilleSalaire(e, new Cotisation(3.49, 6.15, 9.39, 7.88), new ElementsSalaire(100, 100, 100, 100, 100));
  }

  // çalışan listesi
  public List<Employe> findAllEmployes() {
    if (listEmployes == null) {
      // iki ç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);
      }
    }
    // çalışan listesi oluşturulur
    return listEmployes;
  }
}
  • 11. satır: [MetierSimule] sınıfı, gerçek [metier] katmanının uyguladığı [IMetier] arayüzünü uygular.
  • 14. satır: INSEE numarasına göre indekslenmiş çalışanlar sözlüğü
  • 15. satır: Çalışan listesi
  • 27-39. satırlar: [IMetier] arayüzünün findAllEmployes yönteminin uygulanması.
  • 30-33. satırlar: iki çalışandan oluşan bir listenin oluşturulması
  • 34-36. satırlar: INSEE numarasıyla indekslenen çalışan sözlüğünün oluşturulması
  • 18-24. satırlar: [IMetier] arayüzünün calculerSalaire yönteminin uygulanması. Burada hayali bir maaş bordrosu döndürülür.

19.2. NetBeans projesi

NetBeans projesi şu şekildedir:

  • [1] dosyasında:
    • [applicationContext.xml], Spring'in yapılandırma dosyasıdır
    • [tiles.xml], Tiles adlı bir çerçeve için yapılandırma dosyasıdır.
    • [web.xml], web uygulamasının yapılandırma dosyasıdır
  • [2]: Uygulamanın farklı görünümleri
  • [3]:
    • [messages.properties]: mesaj dosyası
    • [struts.xml]: Struts yapılandırma dosyası
  • [4]'te: uygulamanın kaynak kodları. Struts eylemleri [web.actions] paketindedir.
  • [5]: simüle edilmiş [metier] katmanı
  • [6]: Kullanılan arşivler. Burada kullanılan çeşitli araçların arşivleri bulunur: Spring, Tiles, Struts 2, Struts 2 / Spring entegrasyon eklentisi, Struts 2 / Tiles entegrasyon eklentisi.
  • [7]: gerçek [metier, dao, jpa] katmanının arşivi. Bu arşiv sayesinde JPA varlıklarına, [IMetier] arayüzüne, [FeuilleSalaire] ve [ElementsSalaire] sınıflarına erişebiliriz. Tüm bu öğeler, [MetierSimule] sınıfımız tarafından kullanılmaktadır.

19.3. Proje Yapılandırması

Proje, çeşitli dosyalarla yapılandırılır:

  • Web uygulamasını yapılandıran [web.xml]
  • Struts çerçevesini yapılandıran [struts.xml]
  • [applicationContext.xml]: Spring çerçevesini yapılandırır
  • Tiles çerçevesini yapılandıran [tiles.xml]

19.3.1. Web uygulamasının yapılandırılması

[web.xml] dosyası şu şekildedir:


<?xml version="1.0" encoding="UTF-8"?>
<web-app id="pam_struts_01" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <display-name>Pam</display-name>
    <!-- Karo -->
  <context-param>
    <param-name> org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG </param-name>
    <param-value>/WEB-INF/tiles.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.apache.struts2.tiles.StrutsTilesListener</listener-class>
  </listener>
    <!-- Struts 2 -->
  <filter>
    <filter-name>struts2</filter-name>
    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>struts2</filter-name>
    <URL-pattern>/*</URL-pattern>
  </filter-mapping>
     <!-- Spring -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
</web-app>
  • 13-20. satırlar: Struts 2 filtresini yapılandırır – daha önce gördük
  • 22-24. satırlar: Spring dinleyicisini yapılandırır – daha önce görüldü
  • 9-11. satırlar: Tiles dinleyicisini yapılandırır. [org.apache.struts2.tiles.StrutsTilesListener] sınıfı, web uygulamasının başlatılmasıyla birlikte örneklenecektir. Ardından, bu sınıf kendi yapılandırma dosyasını kullanacaktır. Bu dosya, 5-8. satırlarda tanımlanmıştır. Dolayısıyla, Tiles'ın yapılandırma dosyası [WEB-INF/tiles.xml] dosyasıdır.

Sonuç olarak, Struts uygulamasının başlatılmasıyla üç sınıf örneklenir:

  • biri Struts 2 filtresi için. MVC'in C kısmını bu sınıf sağlar.
  • diğeri Spring dinleyicisi içindir. Spring, uygulamanın [métier, dao, jpa] katmanlarını örneklendirmek için [applicationContext.xml] dosyasını kullanacaktır. Spring ayrıca, önceki örnekte olduğu gibi, Application kapsamındaki verileri içerecek bir [Config] sınıfını da örneklendirecektir. Son olarak Spring, buna ihtiyaç duyan her Struts eylemine bu tek [Config] örneğine bir referans enjekte edecektir.
  • Tiles dinleyicisi için de bir tane daha. Bu çerçeve, görünümlerin yönetimini sağlayacaktır. Bu konuya yakında tekrar döneceğiz.

19.3.2. Struts çerçevesinin yapılandırılması

Struts çerçeve yapısı, aşağıdaki [struts.xml] dosyası ile yapılandırılır:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <!-- uluslararasılaştırma -->
  <constant name="struts.custom.i18n.resources" value="messages" />
  <!-- Spring entegrasyonu -->
  <constant name="struts.objectFactory.spring.autoWire" value="name" />

  
  <!-- Struts / Tiles eylemleri -->
  <package name="default" namespace="/" extends="tiles-default">
    <!-- varsayılan eylem -->
    <default-action-ref name="index" />
    <action name="index">
      <result type="redirectAction">
        <param name="actionName">Formulaire</param>
        <param name="namespace">/</param>
      </result>
    </action>
    <!-- Form eylemi -->
    <action name="Formulaire" class="web.actions.Formulaire" method="input">
      <result name="success" type="tiles">saisie</result>
      <result name="exception" type="tiles">exception</result>
    </action>
    <!-- FaireSimulation eylemi -->
    <action name="FaireSimulation" class="web.actions.Formulaire" method="calculSalaire">
      <result name="success" type="tiles">simulation</result>
      <result name="exception" type="tiles">exception</result>
      <result name="input" type="tiles">saisie</result>
    </action>
    <!-- EnregistrerSimulation eylemi -->
    <action name="EnregistrerSimulation" class="web.actions.Enregistrer" method="execute">
      <result name="error" type="tiles">erreur</result>
      <result name="simulations" type="tiles">simulations</result>
    </action>
   <!-- eylem RetourFormulaire -->
    <action name="RetourFormulaire" >
      <result type="redirectAction">
        <param name="actionName">Formulaire</param>
        <param name="namespace">/</param>
      </result>
    </action>
   <!-- eylem VoirSimulations -->
    <action name="VoirSimulations" class="web.actions.Voir">
      <result name="success" type="tiles">simulations</result>
    </action>
   <!-- hisse senedi RetirerSimulation -->
    <action name="SupprimerSimulation" class="web.actions.Supprimer" method="execute">
      <result name="erreur" type="tiles">erreur</result>
      <result name="simulations" type="tiles">simulations</result>
    </action>
   <!-- eylem TerminerSession -->
    <action name="TerminerSession" class="web.actions.Terminer" method="execute">
      <result name="success" type="redirectAction">
        <param name="actionName">Formulaire</param>
        <param name="namespace">/</param>
      </result>
    </action>
  </package>

</struts>

Struts'un çeşitli eylemlerini inceledikçe bunlar hakkında yorum yapacağız. Şu an için şu noktalara dikkat çekebiliriz:

  • 8. satır: mesaj dosyasını tanımlar
  • 10. satır: Spring bean'lerinin Struts eylemlerine enjeksiyon şeklini tanımlar. Enjeksiyon, bean'in adına göre yapılır. Spring tarafından başlatılması gereken Struts eyleminin alanı, enjekte edilecek bean'in adını taşımalıdır.
  • 25. satır: [Formulaire] eyleminin success navigasyon anahtarı için görüntülenecek görünümü tanımlar. <result> sonucunun, bizim bilmediğimiz type='tiles' özniteliğine sahip olduğunu görüyoruz. Müşteriyi bir görünüme yönlendiren redirect türünü biliyorduk. Burada tiles türündeki görünüm, Tiles çerçeve yapısı tarafından yönetilmektedir. tiles türü, [struts2-tiles-plugin-2.2.3.1.jar] arşivindeki [struts-plugin.xml] dosyasında tanımlanmıştır:
1
2
3
4
5
6
7
<struts>
    <package name="tiles-default" extends="struts-default">
        <result-types>
            <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult"/>
        </result-types>
    </package>
</struts>
  • 3-5. satırlar: tiles sonuç türünün tanımı.
  • 2. satır: Bu tür, [struts-default] paketini genişleten [tiles-default] paketinde tanımlanmıştır.
  • 14. satır: Uygulamanın tüm eylemlerinin yer alacağı [default] paketini tanımlar. tiles görünüm türünün tanımından yararlanmak için, paket [tiles-default]'i genişletir.

19.3.3. Spring çerçevesinin yapılandırılması

Spring çerçeve, aşağıdaki [WEB-INF/applicationContext.xml] dosyası ile yapılandırılır:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
  
  <!-- uygulama katmanları -->
 
<!-- web -->
  <bean id="config" class="web.Config" init-method="init">
    <property name="metier" ref="metier"/>
  </bean>
  <!-- iş mantığı -->
  <bean id="metier" class="metier.MetierSimule"/>

</beans>
  • 13. satır: [metier.MetierSimule] sınıfı tarafından örneklenen simüle edilmiş [metier] katmanı
  • 9-11. satırlar: config adlı bir bean tanımlar. Daha önce incelenen bir örnekte olduğu gibi, bu bean Application kapsamındaki bilgileri kapsüllemek için kullanılacaktır. Bu bean ile ilişkili sınıf, aşağıdaki [Config] sınıfıdır:

package web;

import java.util.List;
import jpa.Employe;
import metier.IMetier;

public class Config {

  // Spring tarafından başlatılan iş katmanı
  private IMetier metier;
  // çalışan listesi
  private List<Employe> employes;
  // hatalar
  private Exception initException;

  // oluşturucu
  public Config() {
  }

  // nesneyi başlatmak için kullanılan Spring yöntemi
  public void init() {
    // çalışan listesi isteniyor
    try {
      employes = metier.findAllEmployes();
    } catch (Exception ex) {
      initException = ex;
    }
  }

  // getter ve setter'lar
  ... 
}

config bean'inin yapılandırmasına geri dönelim:


  <bean id="config" class="web.Config" init-method="init">
    <property name="metier" ref="metier"/>
  </bean>
  <!-- iş mantığı -->
  <bean id="metier" class="metier.Metier">
    ...  
</bean>
  1. satırda, 5. satırdaki metier bean'inin, [Config] nesnesinin metier (name) adlı alanına enjekte edildiği (ref) görülebilir. metier bean'i, [metier] katmanında bir referanstır:

[metier] katmanıyla etkileşim kurmak için, [web] katmanındaki tüm Struts eylemlerinin bu katmana bir referansa ihtiyacı olacaktır. [metier] katmanına yapılan referansın, Application kapsamındaki bir veri olduğu söylenebilir. Tüm kullanıcıların tüm istekleri bu veriye ihtiyaç duyacaktır. Bu nedenle, bu referansı [Config] nesnesine yerleştiriyoruz. Ayrıca, 1. satırda, config bean'inin yapılandırmasında bir init-method özniteliği bulunmaktadır. Bu öznitelik, bean'in örneklendirilmesinden sonra çalıştırılacak bean yöntemini belirtir. Burada, [web.Config] sınıfının örneklendirilmesinden sonra, init yönteminin çalıştırılması gerektiği belirtilmektedir. Bu yöntem şöyledir:


// Spring tarafından başlatılan iş mantığı katmanı
  private IMetier metier;
  // çalışan listesi
  private List<Employe> employes;
  // hatalar
  private Exception initException;

  // yapıcı
  public Config() {
  }

  // nesneyi başlatmak için kullanılan Spring yöntemi
  public void init() {
    // çalışan listesi isteniyor
    try {
      employes = metier.findAllEmployes();
    } catch (Exception ex) {
      initException = ex;
    }
  }

init yöntemi çalıştırıldığında, sınıfın metier alanı Spring tarafından örneklenmiştir. Dolayısıyla init yöntemi, [IMetier] arayüzünün iş katmanına erişebilir (2. satır):


package metier;

import java.util.List;
import jpa.Employe;

public interface IMetier {
  // maaş bordrosunu almak
  FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravaillées, int nbJoursTravaillés );
  // çalışan listesi
  List<Employe> findAllEmployes();
}
  • 8. satır: Yöntem, bir çalışanın maaşını hesaplamaya olanak tanır
  • 10. satır: Bu yöntem, çalışan listesini almayı sağlar

Görüldüğü gibi, init yöntemi, [métier] katmanından çalışan listesini ister. Bu liste, 4. satırdaki alana kaydedilir. Bir istisna meydana gelirse, bu istisna 6. satırdaki alana kaydedilir.

Sonuç olarak, tekil [Config] nesnesi şunları içerir:

  • [métier] katmanına bir referans
  • çalışan listesi

19.4. Tiles Görünümlerinin Oluşturulması

Struts yapılandırma dosyasında gördüğümüz gibi, görünümler Tiles çerçeve yapısı tarafından oluşturulacaktır. Uygulamamızı yazmak için kesinlikle gerekli olan kısımları açıklayacağız.

Tiles, bir ana sayfadan görünümler oluşturulmasına olanak tanır. Burada [MasterPage.JSP] olarak adlandırılan bu ana sayfa, aşağıdaki JSP parçalarının birleştirilmesiyle oluşturulacaktır:

Entete.JSP
Saisie.JSP
Simulation.JSP
Simulations.JSP
Exception.JSP
Erreur.JSP

Bu JSP parçaları NetBeans projesinde tanımlanmıştır:

  

Tiles çerçeve yapısı, ana sayfaya hangi parçaların ekleneceğini tanımlamamıza olanak tanır.

[MasterPage.JSP] ana sayfası şu şekildedir:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link href="styles.css" rel="stylesheet" type="text/css"/>
    <title>
      <tiles:insertAttribute name="titre" ignore="true" />
    </title>
    <s:head/>
  </head>
  <body background="<s:url value="/ressources/standard.jpg"/>">
    <tiles:insertAttribute name="entete" />
    <hr/>
    <tiles:insertAttribute name="saisie" />
    <tiles:insertAttribute name="simulation" />
    <tiles:insertAttribute name="exception" />
    <tiles:insertAttribute name="erreur" />
    <tiles:insertAttribute name="simulations" />
  </body>
</html>

Ana sayfa, JSP parçalarının bir kaptır. Burada, ana sayfa 17. satırdan 23. satıra kadar olan altı parçanın birleşiminden oluşmaktadır. Oluşturma sırasında, ana sayfada 0 ila 6 arasında parça birleştirilebilir. Bu oluşturma işlemi, Tiles görünümlerini tanımlayan [WEB-INF/tiles.xml] dosyası tarafından yönetilir:


<?xml version="1.0" encoding="UTF-8" ?>
 
<!DOCTYPE tiles-definitions PUBLIC "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
 "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">
 
<tiles-definitions>
 
<!-- ana sayfa -->
  <definition name="masterPage" template="/MasterPage.JSP">
    <put-attribute name="entete" value="/Entete.JSP"/>
    <put-attribute name="titre"  value="Pam"/>
    <put-attribute name="saisie" value=""/>     
    <put-attribute name="simulation" value=""/>
    <put-attribute name="simulations" value=""/>
    <put-attribute name="exception" value=""/>     
    <put-attribute name="erreur" value=""/>     
  </definition>
 
<!-- giriş görünümü -->
  <definition name="saisie" extends="masterPage">
    <put-attribute name="saisie"   value="/Saisie.JSP"/>     
  </definition>

  <!-- simülasyon görünümü -->
 <definition name="simulation" extends="saisie">
    <put-attribute name="simulation"   value="/Simulation.JSP"/>     
  </definition>

<!-- simülasyonlar görünümü -->
  <definition name="simulations" extends="masterPage">
    <put-attribute name="simulations"   value="/Simulations.JSP"/>     
  </definition>
  
<!-- istisna görünümü -->
  <definition name="exception" extends="masterPage">
    <put-attribute name="exception"   value="/Exception.JSP"/>     
  </definition>
 
<!-- hata görünümü -->
 <definition name="erreur" extends="masterPage">
    <put-attribute name="erreur"   value="/Erreur.JSP"/>     
  </definition>
</tiles-definitions>
  • Yukarıdaki dosya, şu adlara sahip altı Tiles görünümünü tanımlar: masterPage (satır 9), giriş (satır 20), simülasyon (satır 25), simülasyonlar (satır 30), istisna (satır 35), hata (satır 40).
  • 9-17. satırlar: masterPage (name) adlı ve [MasterPage.JSP] (template) ana sayfasıyla ilişkili bir görünüm tanımlar. Daha önce, JSP sayfasının altı alt görünüm tanımladığını görmüştük. Ana sayfayla ilişkili bir Tiles görünümü, altı alt görünümün her biriyle ilişkili JSP parçasını belirtmelidir. Bazı alt görünümlerin değer olarak (value) boş dize aldığı görülmektedir. Bu alt görünümler, [MasterPage.JSP] ana sayfasına dahil edilmeyecektir. Dolayısıyla, masterPage olarak adlandırılan Tiles görünümü, yalnızca [Entete.JSP] alt parçacığından oluşur.
  • 20-22. satırlar: saisie (name) adlı bir görünümü tanımlar ve bu görünüm, daha önce bahsedilen masterPage adlı görünümü (extends) genişletir. Bu, söz konusu görünümün masterPage görünümündeki tüm tanımları devraldığı anlamına gelir. Tanımı aşağıdakine eşdeğerdir:

<definition name="saisie" template="/MasterPage.JSP">
    <put-attribute name="entete" value="/Entete.JSP"/>
    <put-attribute name="titre"  value="Pam"/>
    <put-attribute name="saisie" value=""/>     
    <put-attribute name="simulation" value=""/>
    <put-attribute name="simulations" value=""/>
    <put-attribute name="exception" value=""/>     
    <put-attribute name="erreur" value=""/>
    <put-attribute name="saisie" value="/Saisie.JSP"/>     
  </definition>

Bu görünümün JSP ve [MasterPage.JSP] sayfalarıyla ilişkili olduğu ve bu nedenle bu sayfanın altı alt görünümünü tanımlaması gerektiği görülmektedir. 9. satırdaki tanımın, 4. satırdakini geçersiz kıldığı görülmektedir. Dolayısıyla, saisie olarak adlandırılan Tiles görünümü, JSP ve [Entete.JSP, Saisie.JSP] parçalarından oluşmaktadır.

Bu mantığı sürdürürsek, aşağıdaki tabloyu elde ederiz:

Tiles görünümü
JSP sayfaları
masterPage
Entete.JSP
saisie
Entete.JSP, Saisie.JSP
simulation
Entete.JSP, Saisie.JSP, Simulation.JSP
simulations
Entete.JSP, Simulations.JSP
exception
Entete.JSP, Exception.JSP
erreur
Entete.JSP, Erreur.JSP

19.5. Mesaj dosyaları

Uygulama uluslararası hale getirilmiştir. Mesajlar, [messages.properties] ve [Formulaire.properties] dosyalarında bulunur.

[messages.properties] dosyası şu şekildedir:


Pam.titre=Calcul du salaire des assistantes maternelles
Pam.Erreurs.titre=Les erreurs suivantes se sont produites :
Pam.Erreurs.classe=Exception
Pam.Erreurs.message=Message
Pam.Erreur.libelle=L''erreur suivante s''est produite
Pam.Saisie.Heures.libell\u00e9=Heures travaill\u00e9es
Pam.Saisie.Jours.libell\u00e9=Jours travaill\u00e9s
Pam.Saisie.employ\u00e9=Employ\u00e9
Pam.BtnSalaire.libell\u00e9=Salaire
Pam.BtnEffacer.libell\u00e9=Effacer
Simulation.Infos.employe=Informations Employ\u00e9
Simulation.Employe.nom=Nom
Simulation.Employe.prenom=Pr\u00e9nom
Simulation.Employe.adresse=Adresse
Simulation.Employe.indice=Indice
Simulation.Employe.ville=Ville
Simulation.Employe.codePostal=Code Postal
Simulation.Infos.cotisations=Cotisations Sociales
Simulation.Cotisations.csgrds=CsgRds
Simulation.Cotisations.csgrds=Csgd
Simulation.Cotisations.retraite=Retraite
Simulation.Cotisations.secu=S\u00e9cu
Form.Infos.indemnites=Indemnit\u00e9s
Simulation.Indemnites.salaireHoraire=Salaire horaire
Simulation.Indemnites.entretienJour=Entretien/Jour
Simulation.Indemnites.repasJour=Repas/Jour
Simulation.Indemnites.cong\u00e9sPay\u00e9s=Cong\u00e9s pay\u00e9s
Simulation.Infos.Salaire=Salaire
Simulation.Salaire.salaireBase=Salaire de base
Simulation.Salaire.cotisationsSociales=Cotisations sociales
Simulation.Salaire.entretien=Indemnit\u00e9s d''entretien
Simulation.Salaire.repas=Indemnit\u00e9s de repas
Simulation.salaireNet=Salaire net
# biçimler
Format.heure = {0,time}
Format.nombre = {0,number,#0.0##}
Format.pourcent = {0,number,##0.00' %'}
Format.monnaie={0,number,##0.00' \u20ac'}
# simülasyon listesi
Pam.Simulations.titre=Liste des simulations
Pam.Simulations.num=Num\u00e9ro
Pam.Simulations.nom=Nom
Pam.Simulations.prenom=Pr\u00e9nom
Pam.Simulations.heures=Heures
Pam.Simulations.jours=Jours
Pam.Simulations.salairebase=Salaire de base
Pam.Simulations.indemnites=Indemnites
Pam.Simulations.cotisationsociales=Cotisations
Pam.Simulations.salairenet=Salaire
Pam.SimulationsVides.titre=La liste des simulations est vide
# menü
Menu.FaireSimulation=Faire la simulation
Menu.EffacerSimulation=Effacer la simulation
Menu.VoirSimulations=Voir les simulations
Menu.RetourFormulaire=Retour au formulaire de navigation
Menu.EnregistrerSimulation=Enregistrer la simulation
Menu.TerminerSession=Terminer la session
# hata mesajı
Erreur.sessionexpiree=La session a expir\u00e9
Erreur.numSimulation=N\u00b0 de simulation incorrect
# dönüştürme hatası
xwork.default.invalid.fieldvalue=Valeur invalide pour le champ "{0}".

[Formulaire.properties] dosyası şöyledir:


# çiftlerin yerel formatta olması için
double.format={0,number,#0.00##}
# hata mesajı
joursTravaill\u00e9s.error=Tapez un nombre entier compris entre 1 et 31
heuresTravaill\u00e9es.error=Tapez un nombre r\u00e9el entre 0 et 300

19.6. Stil sayfası

Tiles görünümleri aşağıdaki [styles.css] stil sayfasını kullanır:


.libelle{
  background-color: #ccffff;
  font-family: 'Times New Roman',Times,serif;
  font-size: 14px;
  font-weight: bold;;
  padding-right: 5px;
  padding-left: 5px;
  padding-bottom: 5px;
  padding-top: 5px;
}


.info{
  background-color: #99cc00;;
  padding-right: 5px;
  padding-left: 5px;
  padding-bottom: 5px;
  padding-top: 5px;
}

.titreInfos{
  background-color: #ffcc00
}

19.7. Başlangıç görünümü

Uygulamayı incelemek için, onu kullanıcının farklı eylemleri üzerinden ele alacağız. Her seferinde, bu eylemi gerçekleştiren Struts eylemini ve yanıt olarak gönderilen Tiles görünümünü inceleyeceğiz.

[struts.xml]'te şu eylemler bulunmaktadır:


  <!-- varsayılan eylem -->
    <default-action-ref name="index" />
    <action name="index">
      <result type="redirectAction">
        <param name="actionName">Formulaire!input</param>
        <param name="namespace">/</param>
      </result>
    </action>
    <!-- Form eylemi -->
    <action name="Formulaire" class="web.actions.Formulaire">
      <result name="success" type="tiles">saisie</result>
      <result name="exception" type="tiles">exception</result>
      <result name="input" type="tiles">saisie</result>
      <result name="simulation" type="tiles">simulation</result>
</action>

  • 2-8. satırlar: Uygulamanın varsayılan eylemi [Formulaire!input]'tir.

[Formulaire] sınıfı şöyledir:


package web.actions;

...
public class Formulaire extends ActionSupport implements Preparable, SessionAware {

  // Spring tarafından başlatılan yapılandırma
  private Config config;
  // çalışan listesi
  private List<Employe> employes;
  // hata listesi
  private List<Erreur> erreurs;
  // maaş bordrosu
  private FeuilleSalaire feuilleSalaire;
  // girişler
  private String comboEmployesValue;
  private Double heuresTravaillees;
  private Integer joursTravailles;
  // oturum
  private Map<String, Object> session;
  // menü
  private Menu menu;

  @Override
  public void prepare() throws Exception {
    ...
  }

  @Override
  public String input() {
  ....
  }

  // maaş hesaplaması
  public String calculSalaire() {
 ...
    }
  }

  @Override
  public void validate() {
  ...
  }

  @Override
  public void setSession(Map<String, Object> map) {
    session = map;
  }

  // alıcı ve ayarlayıcılar
  ...
}
  • 4. satır: [Formulaire] eylemi, Preparable arayüzünü uygular. Bu arayüzün tek bir yöntemi vardır: 24. satırdaki prepare yöntemi. Bu yöntem, eylemin diğer tüm yöntemlerinden önce bir kez yürütülür. Genellikle eylemin şablonunu başlatmak için kullanılır.

Eylem modeli 6-21. satırlardan oluşur:

  • 7. satır: config alanı, daha önce açıklandığı gibi Spring tarafından başlatılır. Bu alan, uygulama kapsamındaki verilere erişim sağlar:
    • [métier] katmanında bir referans
    • çalışan listesine bir referans.
    • [Config] nesnesinin oluşturulması sırasında meydana gelmiş olabilecek istisnaya bir referans
  • 9. satır: çalışan listesi. Bu liste, [Saisie.JSP] parçasında yer alan çalışan açılır menüsünü dolduracaktır.
  • 11. satır: bir hata listesi. Bu liste, [Erreur.JSP] fragmanını besleyecektir.
  • 21. satır: [Entete.JSP] parçasının menü seçenekleri listesi

[1]'te, görüntülenen menüdeki bağlantılar, [Formulaire] eyleminin menu alanı tarafından kontrol edilir.

prepare yöntemi, input yönteminden önce yürütülür. Bu yöntem şöyledir:


  @Override
  public void prepare() throws Exception {
    // yapılandırma hatası mı?
    Exception initException = config.getInitException();
    if (initException != null) {
      erreurs = new ArrayList<Erreur>();
      Throwable th = initException;
      while (th != null) {
        erreurs.add(new Erreur(th.getClass().getName(), th.getMessage()));
        th = th.getCause();
      }
    } else {
      employes = config.getEmployes();
    }
}
  • 4. satır: Spring tarafından örneklendirilen [Config] nesnesinden istisna alınır
  • 5. satır: [Config] nesnesinin oluşturulmasında bir istisna meydana gelmişse, 11. satırdaki hata listesi başlatılır. [Erreur] sınıfı şu şekildedir:

package web.entities;

import java.io.Serializable;

public class Erreur implements Serializable{
  
  public Erreur() {
  }
  
  // alanlar
  private String classe;
  private String message;

  // yapıcı
  public Erreur(String classe, String message){
    this.setClasse(classe);
    this.message=message;
  }
  
  // getter ve setter'lar
... 
}

Bu sınıf, istisna yığınını depolamak için kullanılır:

  • 11. satır: istisna sınıfı
  • 12. satır: istisna mesajı

prepare yöntemine geri dönelim:

  • 13. satır: [Config] nesnesinin çalışan listesi, eylemin employes alanında saklanır.

prepare yöntemi yürütüldükten sonra, sıra input yöntemine gelir. Bu yöntem şöyledir:


  @Override
  public String input() {
    if (erreurs == null) {
      // menü
      menu = new Menu(true, false, false, true, false, true);
      return SUCCESS;
    } else {
      // menü
      menu = new Menu(false, false, false, false, false, false);
      return "exception";
    }
}

input yöntemi, yalnızca görüntülenecek menü seçenekleri listesini belirler. [Menu] sınıfı şöyledir:


package web.entities;

import java.io.Serializable;

public class Menu implements Serializable {
  // menü öğeleri

  private boolean faireSimulation;
  private boolean effacerSimulation;
  private boolean enregistrerSimulation;
  private boolean voirSimulations;
  private boolean retourFormulaire;
  private boolean terminerSession;

  public Menu() {
  }

  public Menu(boolean faireSimulation, boolean effacerSimulation, boolean enregistrerSimulation, boolean voirSimulations, boolean retourFormulaire, boolean terminerSession) {
    this.faireSimulation = faireSimulation;
    this.effacerSimulation = effacerSimulation;
    this.enregistrerSimulation = enregistrerSimulation;
    this.voirSimulations = voirSimulations;
    this.retourFormulaire = retourFormulaire;
    this.terminerSession = terminerSession;
  }
  
  // getter ve setter'lar
...  
}
  • 8-13. satırlar: menüde 6 olası bağlantı vardır
  • 18-25. satırlar: Sınıf oluşturucu, görüntülenmesi gereken ve görüntülenmemesi gereken bağlantıları belirlemeye olanak tanır.

Menü bağlantıları, tüm Tiles görünümlerinde bulunan [Entete.JSP]'te, JSP parçasında görüntülenir. Her eylem, [Entete.JSP] menüsünün görüntülenmesini kontrol etmek için bir menu alanına sahip olacaktır.

input yöntemine geri dönelim:


  @Override
  public String input() {
    if (erreurs == null) {
      // menü
      menu = new Menu(true, false, false, true, false, true);
      return SUCCESS;
    } else {
      // menü
      menu = new Menu(false, false, false, false, false, false);
      return "exception";
    }
}
  • 3-6. satırlar: Hata listesi boşsa, [Faire la simulation, Voir les simulations, Terminer la session] menüsü görüntülenecek ve input anahtarı döndürülecektir.
  • 9-10. satırlar: Hata listesi boş değilse, menü boş olacak ve exception anahtarı döndürülecektir.

[struts.xml] içindeki [Formulaire] eyleminin yapılandırmasına geri dönelim:


    <!-- Form eylemi -->
    <action name="Formulaire" class="web.actions.Formulaire">
      <result name="success" type="tiles">saisie</result>
      <result name="exception" type="tiles">exception</result>
      <result name="input" type="tiles">saisie</result>
      <result name="simulation" type="tiles">simulation</result>
</action>
  • 5. satır: input anahtarı, saisie adlı Tiles görünümünü görüntüler
  • 4. satır: exception anahtarı, exception adlı Tiles görünümünü görüntüler

Öncelikle saisie adlı Tiles görünümünden başlayalım. Bu görünüm, JSP, [Entete.JSP] ve [Saisie.JSP] parçalarından oluşur.

[Entete.JSP] parçası şu şekildedir:

 

Kodu şöyledir:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<table>
  <tr>
    <td><h1><s:text name="Pam.titre"/></h1></td>
    <td>
      <s:if test="menu.faireSimulation">
        |<a href="javascript:doSimulation()"><s:text name="Menu.FaireSimulation"/></a><br/>
      </s:if>
      <s:if test="menu.effacerSimulation">
        |<a href="<s:url action="Formulaire!input"/>"><s:text name="Menu.EffacerSimulation"/></a><br/>
      </s:if>
      <s:if test="menu.voirSimulations">
        |<a href="<s:url action="VoirSimulations"/>"><s:text name="Menu.VoirSimulations"/></a><br/>
      </s:if>
      <s:if test="menu.retourFormulaire">
        |<a href="<s:url action="RetourFormulaire"/>"><s:text name="Menu.RetourFormulaire"/></a><br/>
      </s:if>
      <s:if test="menu.enregistrerSimulation">
        |<a href="<s:url action="EnregistrerSimulation"/>"><s:text name="Menu.EnregistrerSimulation"/></a><br/>
      </s:if>
      <s:if test="menu.terminerSession">
        |<a href="<s:url action="TerminerSession"/>"><s:text name="Menu.TerminerSession"/></a><br/>
      </s:if>
    </td>
  </tr>
</table>
  • 8-25. satırlar: menüdeki altı bağlantının görüntülenmesi [Simülasyonu Yap (8-10. satırlar), Simülasyonu Sil (11-13. satırlar), Simülasyonları Görüntüle (satır 14-16), Forma Dön (satır 17-19), Simülasyonu Kaydet (satır 20-22), Oturumu Sonlandır (satır 23-25).
  • satır 8, 11, 14, 17, 20, 23: Bağlantıların görüntülenmesi, mevcut eylemin menu alanı tarafından kontrol edilir.

[Entete.JSP] parçacığının bir HTML tablosu (satır 4-28) görüntülediği, ancak tam bir HTML sayfası olmadığı dikkatinizi çekecektir. Burada, uygulamanın tüm görünümlerinin aşağıdaki [MasterPage.JSP] ana sayfasına yerleştirildiğini unutmamak gerekir:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">

<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <link href="styles.css" rel="stylesheet" type="text/css"/>
    <title>
      <tiles:insertAttribute name="titre" ignore="true" />
    </title>
    <s:head/>
  </head>
  <body background="<s:url value="/ressources/standard.jpg"/>">
    <tiles:insertAttribute name="entete" />
    <hr/>
    <tiles:insertAttribute name="saisie" />
    <tiles:insertAttribute name="simulation" />
    <tiles:insertAttribute name="exception" />
    <tiles:insertAttribute name="erreur" />
    <tiles:insertAttribute name="simulations" />
  </body>
</html>

[Entete.JSP] parçası, normal bir HTML sayfasının içine, 17. satıra yerleştirilir.

[Saisie.JSP] parçası ise 19. satıra eklenir. Bu, şu görünümdür:

 

[Saisie.JSP] parçacığının kodu şöyledir:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">


<script language="javascript" type="text/javascript">
  function doSimulation(){
    // formu gönderme
    document.forms['Saisie'].elements['action'].name='action:Formulaire!calculSalaire'
    document.forms['Saisie'].submit();
  }  
</script>

<!-- bilgilerin girilmesi -->
<s:form name="Saisie" id="Saisie">
  <s:select name="comboEmployesValue" list="employes" listKey="SS" listValue="prenom+' ' +nom" key="Pam.Saisie.employé"/>
  <s:textfield name="heuresTravaillees" key="Pam.Saisie.Heures.libellé" value="%{#parameters['heuresTravaillees']!=null ? #parameters['heuresTravaillees'] : heuresTravaillees==null ? '' : getText('double.format',{heuresTravaillees})}"/>
  <s:textfield name="joursTravailles" key="Pam.Saisie.Jours.libellé" value="%{#parameters['joursTravailles']!=null ? #parameters['joursTravailles'] : joursTravailles==null ? '' : joursTravailles}"/>
  <input type="hidden" name="action"/>
</s:form>
  • 17. satır: Formda action özniteliği yoktur. Varsayılan olarak action='Formulaire' değerindedir.
  • 18. satır: Çalışanlar açılır menüsünün görüntülenmesi. Açılır menünün içeriği (list özniteliği), mevcut eylemin employes alanı tarafından sağlanır. Seçeneklerin value özniteliği, çalışanların SS numarası (listKey özniteliği) olacaktır. Her seçenek için görüntülenen metin, çalışanın adı ve soyadı olacaktır (listValue özniteliği). Açılır menüden seçilen çalışanın SS numarası, [Formulaire].comboEmployesvalue alanına (name özniteliği) kaydedilecektir.
  • 19. satır: Çalışılan saatlerin girildiği alan. Görüntülenen değer (value özniteliği), [Formulaire] eyleminin heuresTravaillees alanındaki değerdir ve şu biçimdedir (Formulaire.properties):

double.format={0,number,#0.00##}

Değer, [Formulaire].heuresTravaillees alanına (name özniteliği) kaydedilecektir.

  • 20. satır: çalışılan günlerin girildiği alan. Görüntülenen değer (value özniteliği), [Formulaire] eyleminin joursTravailles alanındaki değerdir.

Değer, [Formulaire].joursTravailles alanına kaydedilecektir (name özniteliği).

Sonuç olarak, hata olmadığında başlangıçta görüntülenen Tiles saisie görünümü şu şekildedir:

 

Şimdi [Formulaire] eyleminin yapılandırmasına geri dönelim:


    <!-- Form eylemi -->
    <action name="Formulaire" class="web.actions.Formulaire">
      <result name="success" type="tiles">saisie</result>
      <result name="exception" type="tiles">exception</result>
      <result name="input" type="tiles">saisie</result>
      <result name="simulation" type="tiles">simulation</result>
</action>

[Formulaire].input eyleminin, 4. satırdaki exception anahtarını da döndürebileceğini görmüştük. Bu durumda, exception adlı Tiles görünümü görüntülenir. Bu görünüm, [Entete.JSP] ve [Exception.JSP] parçalarından oluşur. [Entete.JSP] parçasını daha önce tanıtmıştık. [Exception.JSP] parçası ise şöyledir:

 

Bu, Sgbd başlatılmadığında uygulamanın 2. sürümünün başlangıç sayfasıdır. [Erreur.JSP] parçasının JSP kodu şöyledir:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<h2><s:text name="Pam.Erreurs.titre"/></h2>
<table>
  <tr class="titreInfos">
    <th><s:text name="Pam.Erreurs.classe"/></th>
    <th><s:text name="Pam.Erreurs.message"/></th>
  </tr>
  <s:iterator value="erreurs">
    <tr>
      <td class="libelle"><s:property value="classe"/></td>
      <td class="info"><s:property value="message"/></td>
    </tr>
  </s:iterator>
</table>
  • 10-14. satırlar: [Formulaire] eyleminin List<Erreur> hatalar koleksiyonu üzerinde bir yineleyici. Hatırlanacağı üzere, hata durumunda buraya bir istisna yığını depolanmıştı.

19.8. Simülasyon yapma

Başlangıç ekranı görüntülendikten sonra, [Faire une simulation] bağlantısı aracılığıyla maaş hesaplaması yapılabilir.

19.8.1. Girişlerin doğrulanması

Şu adım dizisini ele alalım:

  • [1]'e, hatalı bir giriş
  • [2]'te, gönderilen yanıt.

[Formulaire] eyleminin [struts.xml]'teki yapılandırmasını ele alalım:


    <!-- Form eylemi -->
    <action name="Formulaire" class="web.actions.Formulaire">
      <result name="success" type="tiles">saisie</result>
      <result name="exception" type="tiles">exception</result>
      <result name="input" type="tiles">saisie</result>
      <result name="simulation" type="tiles">simulation</result>
</action>

Doğrulama hatası durumunda, doğrulama yakalayıcısının input anahtarını döndürdüğü bilinmektedir. Dolayısıyla, döndürülen Tiles görünümü saisie'tir. Doğrulama süreci, hatalı alanların hata mesajlarıyla birlikte gösterilmesini sağlar.

[Formulaire] eyleminin doğrulaması, aşağıdaki [Formulaire-validation.xml] dosyası tarafından sağlanır:


<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">


<validators>
  
  <field name="heuresTravaillees" >
    <field-validator type="required" short-circuit="true">
      <message key="heuresTravaillées.error"/>
    </field-validator>
    
    <field-validator type="conversion" short-circuit="true">
      <message key="heuresTravaillées.error"/>
    </field-validator>
    
    <field-validator type="double" short-circuit="true">
      <param name="minInclusive">0</param>
      <param name="maxInclusive">300</param>
      <message key="heuresTravaillées.error"/>
    </field-validator>
  </field>
  
  <field name="joursTravailles" >
    <field-validator type="required" short-circuit="true">
      <message key="joursTravaillés.error"/>
    </field-validator>
    
    <field-validator type="conversion" short-circuit="true">
      <message key="joursTravaillés.error"/>
    </field-validator>
    
    <field-validator type="int" short-circuit="true">
      <param name="min">0</param>
      <param name="max">31</param>
      <message key="joursTravaillés.error"/>
    </field-validator>
  </field>
  
</validators>
  • 6-20. satırlar, heuresTravaillees alanının [0,300] aralığında bir gerçek sayı olup olmadığını kontrol eder.
  • 22-36. satırlar, joursTravailles alanının [0,31] aralığında bir tamsayı olup olmadığını kontrol eder.

Şimdi [struts.xml] içindeki [Formulaire] eyleminin yapılandırmasına geri dönelim:


    <!-- Form işlemi -->
    <action name="Formulaire" class="web.actions.Formulaire">
      ...
      <result name="input" type="tiles">saisie</result>
</action>

Doğrulama hatası durumunda, doğrulama yakalayıcısının input anahtarını döndürdüğü bilinmektedir. Dolayısıyla, döndürülen Tiles görünümü saisie'tir.

Bu görünümün, [Entete.JSP] ve [Saisie.JSP] parçalarından oluştuğunu hatırlatalım; burada [Entete.JSP] bir başlık ve seçenekler listesini, [Saisie.JSP] ise giriş formunu içerir. Giriş hataları olması durumunda, doğrulama süreci hatalı alanların yanına hata mesajları ekler ve ayrıca hatalı değerlerini de görüntüler. [Entete.JSP] parçası, doğrulama sürecinde hiçbir rol oynamaz. Koduna bir göz atalım:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<table>
  <tr>
    <td><h1><s:text name="Pam.titre"/></h1></td>
    <td>
      <s:if test="menu.faireSimulation">
        |<a href="javascript:doSimulation()"><s:text name="Menu.FaireSimulation"/></a><br/>
      </s:if>
      <s:if test="menu.effacerSimulation">
        |<a href="<s:url action="Formulaire!input"/>"><s:text name="Menu.EffacerSimulation"/></a><br/>
      </s:if>
      <s:if test="menu.voirSimulations">
        |<a href="<s:url action="VoirSimulations"/>"><s:text name="Menu.VoirSimulations"/></a><br/>
      </s:if>
      <s:if test="menu.retourFormulaire">
        |<a href="<s:url action="RetourFormulaire"/>"><s:text name="Menu.RetourFormulaire"/></a><br/>
      </s:if>
      <s:if test="menu.enregistrerSimulation">
        |<a href="<s:url action="EnregistrerSimulation"/>"><s:text name="Menu.EnregistrerSimulation"/></a><br/>
      </s:if>
      <s:if test="menu.terminerSession">
        |<a href="<s:url action="TerminerSession"/>"><s:text name="Menu.TerminerSession"/></a><br/>
      </s:if>
    </td>
  </tr>
</table>

Altı bağlantı, şablondaki menu alanı tarafından yapılandırılır (satır 8, 11, 14, 17, 20, 23). Bir hata oluştuğunda, bu şablon eylem tarafından güncellenmez ve sonuç olarak menüsüz bir sayfa görüntülenir. Bu sorunu gidermek için, [Formulaire] sınıfında aşağıdaki validate yöntemi bulunmaktadır:


package web.actions;

import com.opensymphony.xwork2.ActionSupport;
...
public class Formulaire extends ActionSupport implements Preparable, SessionAware {

  ...
  // menü
  private Menu menu;

  @Override
  public void prepare() throws Exception {
  ...
  }

  @Override
  public String input() {
  ...
  }

  // maaş hesaplama
  public String calculSalaire() {
  ...
  }

  @Override
  public void validate() {
    // hatalar mı var?
    if (!getFieldErrors().isEmpty()) {
      // menü
      menu = new Menu(true, false, false, true, false, true);
    }
  }

  // alıcı ve ayarlayıcılar
  ...
}
  • 27. satır: Bu satır mevcut olduğunda, validate yönteminin doğrulama süreci tarafından yürütüldüğü bilinmektedir. Bu fırsatı değerlendirerek, [Entete.JSP] parça şablonunun bir parçası olan 4. satırdaki menüyü güncelleriz.
  • 29-32. satırlar: Doğrulama hataları varsa, menüyü Tiles saisie görünümünü yeniden görüntüleyecek şekilde ayarlıyoruz. Doğrulama hatası yoksa, hiçbir işlem yapmıyoruz. Görüntülenecek görünüm şablonunu oluşturmakla görevli olan yöntem calculSalaire'tir.

19.8.2. Maaş hesaplaması

Başlıktaki JSP koduna geri dönelim:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<table>
  <tr>
    <td><h1><s:text name="Pam.titre"/></h1></td>
    <td>
      <s:if test="menu.faireSimulation">
        |<a href="javascript:doSimulation()"><s:text name="Menu.FaireSimulation"/></a><br/>
      </s:if>
      ...
    </td>
  </tr>
</table>
  • 9. satır: Kullanıcı [Faire la simulation] bağlantısına tıkladığında, doSimulation adlı JavaScript işlevi çalıştırılır. Bu işlev, [Saisie.JSP] parçasında tanımlanmıştır:

<script language="javascript" type="text/javascript">
  function doSimulation(){
    // formu gönderiyoruz
    document.forms['Saisie'].elements['action'].name='action:Formulaire!calculSalaire'
    document.forms['Saisie'].submit();
  } 
</script>

<!-- bilgilerin girilmesi -->
<s:form name="Saisie" id="Saisie">
  <s:select name="comboEmployesValue" list="employes" listKey="SS" listValue="prenom+' ' +nom" key="Pam.Saisie.employé"/>
  <s:textfield name="heuresTravaillees" key="Pam.Saisie.Heures.libellé" value="%{#parameters['heuresTravaillees']!=null ? #parameters['heuresTravaillees'] : heuresTravaillees==null ? '' : getText('double.format',{heuresTravaillees})}"/>
  <s:textfield name="joursTravailles" key="Pam.Saisie.Jours.libellé" value="%{#parameters['joursTravailles']!=null ? #parameters['joursTravailles'] : joursTravailles==null ? '' : joursTravailles}"/>
  <input type="hidden" name="action"/>
</s:form>
  • 14. satır: action adlı gizli bir alan, [Formulaire] eylemine gönderilecektir. Bu alan, formun POST kısmında yürütülmesi gereken eylemi ve yöntemi belirtmemizi sağlayacaktır. İlk örneklerden hatırlayacağınız üzere, bunlar action:Action!méthode adlı bir parametre içinde belirtilebilir. Bu parametrenin değeri önemli değildir. Yeter ki mevcut olsun.
  • 2-6. satırlar: Kullanıcı, [Entete.JSP] parçasındaki [Faire la simulation] bağlantısına tıkladığında yürütülen JavaScript işlevi.
  • 4. satır: Gizli alan action'in name özniteliği değiştirilir. Bu özniteliğin, Struts tarafından beklenen action:Action!yöntem biçiminde olması sağlanır.
  • 5. satır: 5. satırdaki Saisie adlı form gönderilir. Bunun sonucunda aşağıdaki parametre dizisi gönderilir:
comboEmployesValue=SS1&heuresTravaillees=xx&joursTravailles=yy&action:Formulaire!calculSalaire
SS1 : n° INSEE de l'employé sélectionné dans le combo
heuresTravaillees : nombre d'heures travaillées
joursTravailles : nombre de jours travaillés
action : Formulaire!calculSalaire : les éléments ci-dessus seront postés à l'action [Formulaire] puis la méthode calculSalaire de cette action sera exécutée.

[Formulaire].calculSalaire yöntemi şu şekildedir:


// maaş hesaplama
  public String calculSalaire() {
    try {
      // maaş hesaplama
      feuilleSalaire = config.getMetier().calculerFeuilleSalaire(comboEmployesValue, heuresTravaillees, joursTravailles);
      // simülasyonu oturuma ekleme
      session.put("simulation", new Simulation(0, "" + heuresTravaillees, "" + joursTravailles, feuilleSalaire));
      // menü
      menu = new Menu(true, true, true, true, false, true);
      // bitti
      return "simulation";
    } catch (Throwable th) {
      ...
    }
  }
  • 5. satır: [métier] katmanından maaş bordrosu hesaplaması istenir
  • 7. satır: Kullanıcının oturumuna Simulation türünde bir nesne eklenir. Zira, bu nesne daha sonraki bir sorguda gerekli olabilir. [Simulation] sınıfı şu şekildedir:

package web.entities;

import java.io.Serializable;
import metier.FeuilleSalaire;

public class Simulation implements Serializable{
  
  public Simulation() {
  }

  // simülasyon 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
...
}
  • 12. satır: Simülasyon numarası. Kaydedilen her yeni simülasyonda bir artırılır.
  • 13. satır: Çalışanın maaş bordrosu
  • 14. satır: Çalışanların çalışma saat sayısı
  • 15. satır: Çalışanların çalıştığı gün sayısı
  • satır 25: getIndemnites yöntemi, çalışanın toplam tazminat tutarını verir

Göreceğiz ki [Simulation] sınıfı, yapılan tüm simülasyonları içeren [Simulations.JSP] parçasının şablonudur.

[Formulaire] yöntemine geri dönelim. calculSalaire:


// maaş hesaplama
  public String calculSalaire() {
    try {
      // maaş hesaplaması
      feuilleSalaire = config.getMetier().calculerFeuilleSalaire(comboEmployesValue, heuresTravaillees, joursTravailles);
      // simülasyonu oturuma ekliyoruz
      session.put("simulation", new Simulation(0, "" + heuresTravaillees, "" + joursTravailles, feuilleSalaire));
      // menü
      menu = new Menu(true, true, true, true, false, true);
      // bitti
      return "simulation";
    } catch (Throwable th) {
 ...
  }
  • 9. satır: menünün güncellenmesi
  • 11. satır: simulation gezinme anahtarının geri gönderilmesi.

[Formulaire] eyleminin yapılandırmasına geri dön:


    <!-- Form eylemi -->
    <action name="Formulaire" class="web.actions.Formulaire">
         ...
      <result name="simulation" type="tiles">simulation</result>
</action>
  1. satır, simulation gezinme anahtarının simulation adlı Tiles görünümünü görüntülediğini gösterir. Bu görünüm, aşağıdaki JSP parçalarından oluşur: [Entete, Saisie, Simulation].

Görüntülenen görünüm şöyledir:

  • [1]'te, [Entete.JSP] parçası
  • [2]'e, [Saisie.JSP] parçası
  • [3]'e, [Simulation.JSP] parçası. Sunulan maaş bordrosunun, [metier] katmanı tarafından oluşturulan hayali maaş bordrosu olduğunu hatırlatırız.

İlk iki parça daha önce sunulmuştu. [Simulation.JSP] parçası şöyledir:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<hr/>
<!-- Çalışan bilgileri -->
<span class="titreInfos">
  <s:text  name="Simulation.Infos.employe"/>
</span>
<br/><br/>
<table>
  <!-- satır 1 -->
  <tr>
    <th class="libelle">
      <s:text name="Simulation.Employe.nom"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Employe.prenom"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Employe.adresse"/>
    </th>
  </tr>
  <!-- satır 2 -->
  <tr>
    <td class="info">   
      <s:property value="feuilleSalaire.employe.nom"/>      
    </td>
    <td class="info">
      <s:property value="feuilleSalaire.employe.prenom"/>
    </td>
    <td class="info">
      <s:property value="feuilleSalaire.employe.adresse"/>
    </td>
</table>
<table>
  <!-- satır 1 -->
  <tr>
    <th class="libelle"><s:text name="Simulation.Employe.ville"/></th>
    <th class="libelle">
      <s:text name="Simulation.Employe.codePostal"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Employe.indice"/>
    </th>
  </tr>
  <!-- satır 2 -->
  <tr>
    <td class="info">
      <s:property value="feuilleSalaire.employe.ville"/>
    </td>
    <td class="info">
      <s:property value="feuilleSalaire.employe.codePostal"/>
    </td>
    <td class="info">
      <s:property value="feuilleSalaire.employe.indemnite.indice"/>
    </td>
</table>
<!-- Prim bilgileri -->
<br/>
<span class="titreInfos">
  <s:text name="Simulation.Infos.cotisations"/>
</span>

<br/><br/>
<table>
  <!-- satır 1 -->
  <tr>
    <th class="libelle">
      <s:text name="Simulation.Cotisations.csgrds"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Cotisations.csgrds"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Cotisations.retraite"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Cotisations.secu"/>
    </th>
  </tr>
  <!-- satır 2 -->
  <tr>
    <td class="info">
      <s:text name="Format.pourcent">
        <s:param value="feuilleSalaire.cotisation.csgrds"/>
      </s:text>
    </td>
    <td  class="info">
      <s:text name="Format.pourcent">
        <s:param value="feuilleSalaire.cotisation.csgd"/>
      </s:text>
    </td>
    <td class="info">
      <s:text name="Format.pourcent">
        <s:param value="feuilleSalaire.cotisation.retraite"/>
      </s:text>
    </td>
    <td class="info">
      <s:text name="Format.pourcent">
        <s:param value="feuilleSalaire.cotisation.secu"/>
      </s:text>
    </td>
</table>
<!-- Tazminat bilgileri -->
<br/>
<span class="titreInfos">
  <s:text name="Form.Infos.indemnites"/>
</span>
<br/><br/>
<table>
  <!-- satır 1 -->
  <tr>
    <th class="libelle">
      <s:text name="Simulation.Indemnites.salaireHoraire"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Indemnites.entretienJour"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Indemnites.repasJour"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Indemnites.congésPayés"/>
    </th>
  </tr>
  <!-- satır 2 -->
  <tr>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.employe.indemnite.baseHeure"/>
      </s:text>
    </td>
    </td>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.employe.indemnite.entretienJour"/>
      </s:text>
    </td>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.employe.indemnite.repasJour"/>
      </s:text>
    </td>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.employe.indemnite.indemnitesCP"/>
      </s:text>
    </td>
  </tr>
</table>
<!-- Maaş bilgileri -->
<br/>
<span class="titreInfos">
  <s:text name="Simulation.Infos.Salaire"/>
</span>
<br/><br/>
<table>
  <!-- satır 1 -->
  <tr>
    <th class="libelle">
      <s:text name="Simulation.Salaire.salaireBase"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Salaire.cotisationsSociales"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Salaire.entretien"/>
    </th>
    <th class="libelle">
      <s:text name="Simulation.Salaire.repas"/>
    </th>
  </tr>

  <!-- satır 2 -->
  <tr>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.elementsSalaire.salaireBase"/>
      </s:text>
    </td>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.elementsSalaire.cotisationsSociales"/>
      </s:text>
    </td>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.elementsSalaire.indemnitesEntretien"/>
      </s:text>
    </td>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.elementsSalaire.indemnitesRepas"/>
      </s:text>
    </td>
  </tr>
</table>
<!-- Net maaş-->
<br/>
<table>
  <tr>
    <td class="libelle">
      <s:text name="Simulation.salaireNet"/>
    <td></td>
    <td class="info">
      <s:text name="Format.monnaie">
        <s:param value="feuilleSalaire.elementsSalaire.salaireNet"/>
      </s:text>
    </td>
  </tr>
</table>

Uzun görünüyor... ancak işlevsel olarak basit. Bu parça, çalışanın maaş bordrosunu temsil eden [Formulaire].feuilleSalaire alanının çeşitli özelliklerini görüntüler.

[Formulaire].calculSalaire yöntemine geri dönelim:


// maaş hesaplaması
  public String calculSalaire() {
    try {
      ...
      return "simulation";
    } catch (Throwable th) {
      erreurs = new ArrayList<Erreur>();
      while (th != null) {
        erreurs.add(new Erreur(th.getClass().getName(), th.getMessage()));
        th = th.getCause();
      }
      // menü
      menu = new Menu(false, false, false, false, true, true);
      return "exception";
    }
  }

Maaş hesaplaması hatalı sonuçlanabilir. Bu durum, özellikle Sgbd ile olan bağlantı kesildiğinde ortaya çıkar. Bu durumda, oluşan istisna işlenir. Bu durumla daha önce [Formulaire].input yöntemini incelerken karşılaşmıştık.

  • 7-11. satırlar: istisna yığınından Erreur nesnelerinin bir listesi oluşturulur
  • 13. satır: Menü ayarlanır
  • 14. satır: exception anahtarı döndürülür.

exception anahtarı, exception Tiles görünümünü görüntüleyecektir:


    <!-- Form eylemi -->
    <action name="Formulaire" class="web.actions.Formulaire">
      <result name="exception" type="tiles">exception</result>
      ...
</action>

Bu Tiles görünümü daha önce tanıtılmıştı. Şu şekilde görünür:

 

19.9. Simülasyonu kaydetme

Bir simülasyon yaptıktan sonra, kullanıcı bunu oturuma kaydetmek isteyebilir.

  • [1] dosyasında simülasyon kaydedilir
  • [2] dosyasında, daha önce yapılmış simülasyonların listesini içeren ve buna yeni simülasyonun eklendiği yanıt kaydedilir

[Enregistrer la simulation] bağlantısı, [Entete.JSP] parçasında yer almaktadır:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<table>
  <tr>
    <td><h1><s:text name="Pam.titre"/></h1></td>
    <td>
      ...
      <s:if test="menu.enregistrerSimulation">
        |<a href="<s:url action="EnregistrerSimulation"/>"><s:text name="Menu.EnregistrerSimulation"/></a><br/>
      </s:if>
      ...
    </td>
  </tr>
</table>

Bağlantıya tıklandığında [EnregistrerSimulation] eyleminin yürütüldüğü görülmektedir. Bu eylem, [struts.xml] dosyasında şu şekilde yapılandırılmıştır:


   <!-- eylem EnregistrerSimulation -->
    <action name="EnregistrerSimulation" class="web.actions.Enregistrer" method="execute">
      <result name="error" type="tiles">erreur</result>
      <result name="simulations" type="tiles">simulations</result>
</action>
  • 1. satır: [EnregistrerSimulation] eylemi, [Enregistrer] sınıfı ve bu sınıfın execute yöntemiyle ilişkilendirilmiştir.

[Enregistrer] sınıfı şu şekildedir:


package web.actions;

...
public class Enregistrer extends ActionSupport implements SessionAware {

  // oturum
  private Map<String, Object> session;
  // menü
  private Menu menu;

  @Override
  public void setSession(Map<String, Object> session) {
    this.session = session;
  }

  // eylemin yürütülmesi
  public String execute() {
    // oturumdaki son simülasyon alınır
    Simulation simulation = (Simulation) session.get("simulation");
    if (simulation == null) {
      return ERROR;
    }
    ...
  }

  // alıcı ve ayarlayıcılar
  ...
}
  • 4. satır: Eylem oturuma erişebilmesi gerektiğinden, SessionAware arayüzünü uygular.
  • 7. satır: oturum
  • 9. satır: menü

[Enregistrer] eylemi örneklendiğinde, execute yöntemi yürütülür. Bu yöntemin görevi, en son simülasyonu oturuma eklemektir. Bu simülasyon, yine oturumda saklanan, daha önce yapılmış simülasyonlar listesine eklenecektir.

  • 19. satır: oturumdan, oraya yerleştirilen en son simülasyon alınır.
  • 20-22. satırlar: Simülasyon bulunamazsa, muhtemelen oturumun süresi dolmuştur. Nitekim oturumun süresi, uygulamayı yapılandıran [web.xml] dosyasında belirlenebilen belirli bir süreyle sınırlıdır.
  • 21. satır: error anahtarını döndürür.

[EnregistrerSimulation] eyleminin yapılandırmasına geri dönelim:


   <!-- eylem EnregistrerSimulation -->
    <action name="EnregistrerSimulation" class="web.actions.Enregistrer" method="execute">
      <result name="error" type="tiles">erreur</result>
      <result name="simulations" type="tiles">simulations</result>
</action>

Görüldüğü gibi, error anahtarı (3. satır), erreur adlı Tiles görünümünün görüntülenmesini sağlar. Bu görünüm, [Entete.JSP] ve [Erreur.JSP] parçalarından oluşur ve şu şekilde görünür:

 

[Erreur.JSP] parçası şu şekildedir:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<h2><s:text name="Pam.Erreur.libelle"/></h2>
<h4><s:text name="Erreur.sessionexpiree"/></h4>

[Enregistrer].execute yöntemine geri dönelim:


// eylemin yürütülmesi
  public String execute() {
    // oturumdaki son simülasyon alınır
    Simulation simulation = (Simulation) session.get("simulation");
    if (simulation == null) {
      return ERROR;
    }
    // son simülasyonun numarası alınır
    Integer numDerniereSimulation = (Integer) session.get("numDerniereSimulation");
    if (numDerniereSimulation == null) {
      numDerniereSimulation = 0;
    }
    // numarayı artırma
    numDerniereSimulation++;
    // yeni numarayı oturuma kaydediliyor
    session.put("numDerniereSimulation", numDerniereSimulation);
    // simülasyon listesi alınır
    List<Simulation> simulations = (List<Simulation>) session.get("simulations");
    if (simulations == null) {
      simulations = new ArrayList<Simulation>();
      session.put("simulations", simulations);
    }
    // buna mevcut simülasyonu eklenir
    simulation.setNum(numDerniereSimulation);
    simulations.add(simulation);
    // simülasyon listesi görüntülenir
    menu = new Menu(false, false, false, false, true, true);
    return "simulations";
  }
  • 9-16. satırlar: Farklı simülasyonlar 1'den başlayarak numaralandırılır. Atanan son numara, oturumda numDerniereSimulation anahtarı altında saklanır. 9-16. satırlardaki kod, bu anahtarı alıp ona atanan değeri artırmayı içerir.
  • 18-22. satırlar: Simülasyon listesi, simulations anahtarıyla ilişkili oturumda saklanır. 18-22. satırlar, bu listenin var olup olmadığını kontrol etmek ve yoksa oluşturmaktan ibarettir.
  • 24-25. satırlar: Simülasyon listesi elde edildikten sonra, mevcut simülasyon bu listeye eklenir (25. satır). Bundan önce, mevcut simülasyona bir numara atanmıştır (24. satır).
  • 27. satır: Görüntülenecek menü belirlenir
  • 28. satır: simulations gezinme anahtarı oluşturulur.

[struts.xml] içindeki [EnregistrerSimulation] eyleminin yapılandırmasına geri dönelim:


   <!-- eylem EnregistrerSimulation -->
    <action name="EnregistrerSimulation" class="web.actions.Enregistrer" method="execute">
      <result name="error" type="tiles">erreur</result>
      <result name="simulations" type="tiles">simulations</result>
</action>
  1. satırda, simulations anahtarı, simulations adlı Tiles görünümünün görüntülenmesini sağlar. Bu görünüm, [Entete.JSP] ve [Simulations.JSP] parçalarından oluşur. Görüntülenen görünüm şöyledir:
  • [1]'te, artık çok iyi bildiğimiz [Entete.JSP] parçası.
  • [2]'te, [Simulations.JSP] parçası

[Simulations.JSP] parçası şöyledir:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!-- simülasyon listesi boş -->
<s:if test="#session['simulations']==null || #session['simulations'].size()==0">
  <h2><s:text name="Pam.SimulationsVides.titre"/></h2>
</s:if>
<!-- simülasyon listesi boş değil -->
<s:if test="#session['simulations'].size()!=0">
  <h2><s:text name="Pam.Simulations.titre"/></h2>
  <table>
    <tr class="titreInfos">
      <th><s:text name="Pam.Simulations.num"/></th>
      <th><s:text name="Pam.Simulations.nom"/></th>
      <th><s:text name="Pam.Simulations.prenom"/></th>
      <th><s:text name="Pam.Simulations.heures"/></th>
      <th><s:text name="Pam.Simulations.jours"/></th>
      <th><s:text name="Pam.Simulations.salairebase"/></th>
      <th><s:text name="Pam.Simulations.indemnites"/></th>
      <th><s:text name="Pam.Simulations.cotisationsociales"/></th>
      <th><s:text name="Pam.Simulations.salairenet"/></th>
    </tr>
    <s:iterator value="#session['simulations']">
      <s:url action="SupprimerSimulation" var="URL">
        <s:param name="id" value="num"/>
      </s:url>
      <tr>
        <td class="libelle"><s:property value="num"/></td>
        <td class="info"><s:property value="feuilleSalaire.employe.nom"/></td>
        <td class="info"><s:property value="feuilleSalaire.employe.prenom"/></td>
        <td class="info"><s:property value="heuresTravaillées"/></td>
        <td class="info"><s:property value="joursTravaillés"/></td>
        <td class="info">
          <s:text name="Format.monnaie">
            <s:param value="feuilleSalaire.elementsSalaire.salaireBase"/>
          </s:text>
        </td>
        <td class="info">
          <s:text name="Format.monnaie">
            <s:param value="indemnites"/>
          </s:text>
        </td>
        <td class="info">
          <s:text name="Format.monnaie">
            <s:param value="feuilleSalaire.elementsSalaire.cotisationsSociales"/>
          </s:text>
        </td>
        <td class="info">
          <s:text name="Format.monnaie">
            <s:param value="feuilleSalaire.elementsSalaire.salaireNet"/>
          </s:text>
        </td>
        <td class="info"><a href="<s:property value="#URL"/>">Kaldır</a></td>
      </tr>
    </s:iterator>
  </table>
</s:if>
  • 5-7. satırlar: oturumda simülasyon yoksa, şu görünüm görüntülenir:
 
  • 13-21. satırlar: Tablonun sütun başlıklarının görüntülenmesi
 
  • satır 23-55: oturumda bulunan simülasyon listesi üzerinde yineleme
  • satır 24-26: URL adlı bir URL oluşturulur (id özniteliği). Bu URL tarafından oluşturulan HTML bağlantısı şöyledir:
<a href="<a href="view-source:http://localhost:8084/pam/SupprimerSimulation.action?id=1">/pam/SupprimerSimulation.action?id=1</a>">Retirer</a>

Görüldüğü gibi, bağlantı, listeden çıkarılacak simülasyon numarasını temsil eden id parametresiyle [SupprimerSimulation] eylemini hedeflemektedir.

  • 28-54. satırlar: Simülasyon listesi üzerinde her yinelemede, geçerli simülasyonun özellikleri görüntülenir.
 

19.10. Bir simülasyonu kaldırma

Kullanıcı, simülasyon listesinden bir simülasyonu kaldırmak isteyebilir:

  • [1]'te, 1 numaralı simülasyon silinir
  • [2]'te, 1 numaralı simülasyon silinmiştir

[Retirer] bağlantısı, daha önce incelediğimiz [Simulations.JSP] parçasında yer almaktadır:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<!-- boş simülasyon listesi -->
<s:if test="#session['simulations']==null || #session['simulations'].size()==0">
  <h2><s:text name="Pam.SimulationsVides.titre"/></h2>
</s:if>
<!-- simülasyon listesi boş değil -->
<s:if test="#session['simulations'].size()!=0">
  <h2><s:text name="Pam.Simulations.titre"/></h2>
  <table>
    <tr class="titreInfos">
      ...
    </tr>
    <s:iterator value="#session['simulations']">
      <s:url action="SupprimerSimulation" var="URL">
        <s:param name="id" value="num"/>
      </s:url>
      <tr>
        ...
        <td class="info">
          <s:text name="Format.monnaie">
            <s:param value="feuilleSalaire.elementsSalaire.salaireNet"/>
          </s:text>
        </td>
        <td class="info"><a href="<s:property value="#URL"/>">Kaldır</a></td>
      </tr>
    </s:iterator>
  </table>
</s:if>
  • 16-18. satırlar: HTML bağlantısını oluşturur
<a href="<a href="view-source:http://localhost:8084/pam-01/SupprimerSimulation.action?id=2">/pam-01/SupprimerSimulation.action?id=</a>num">Retirer</a>

burada num, kaldırılacak simülasyonun numarasıdır.

[SupprimerSimulation] eylemi, [struts.xml] dosyasında şu şekilde tanımlanmıştır:


<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
    "http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>
  <!-- uluslararasılaştırma -->
  <constant name="struts.custom.i18n.resources" value="messages" />
  <!-- Spring entegrasyonu -->
  <constant name="struts.objectFactory.spring.autoWire" value="name" />

  
  <!-- Struts /Tiles eylemleri -->
  <package name="default" namespace="/" extends="tiles-default">
    ...
   <!-- eylem RetirerSimulation -->
    <action name="SupprimerSimulation" class="web.actions.Supprimer">
      <result name="erreur" type="tiles">erreur</result>
      <result name="simulations" type="tiles">simulations</result>
    </action>
   ...
  </package>

    <!-- Buraya paketler ekleyin -->

</struts>
  • 16. satır: [SupprimerSimulation] eylemi, [Supprimer] sınıfıyla ilişkilendirilmiştir. Herhangi bir yöntem belirtilmediğinden, execute yöntemi yürütülecektir. [Supprimer] sınıfı şu şekildedir:

package web.actions;

...
public class Supprimer extends ActionSupport implements SessionAware {

  // oturum
  private Map<String, Object> session;
  // silinecek simülasyon kimliği
  private String id;
  // menü
  private Menu menu;

  @Override
  public void setSession(Map<String, Object> session) {
    this.session = session;
  }

  // eylemin yürütülmesi
  public String execute() {
    // oturumdaki simülasyonlar alınır
    List<Simulation> simulations = (List<Simulation>) session.get("simulations");
    if (simulations == null) {
      // olağandışı durum - oturumun süresi dolmuş olmalı
      menu = new Menu(false, false, false, false, true, true);
      return "erreur";
    }
    // kimlik testi
    int num = 0;
    boolean erreur = false;
    try {
      num = Integer.parseInt(id);
      erreur = num <= 0;
    } catch (NumberFormatException ex) {
      // anormal
      erreur = true;
    }
    // hata mı?
    if (erreur) {
      menu = new Menu(false, false, false, false, true, true);
      return "erreur";
    }
    // silinecek simülasyon aranıyor
    for (int i = 0; i < simulations.size(); i++) {
      if (num == simulations.get(i).getNum()) {
        simulations.remove(i);
        break;
      }
    }
    // simülasyon listesi görüntüleniyor
    menu = new Menu(false, false, false, false, true, true);
    return "simulations";
  }

  // alıcı ve ayarlayıcılar
...
}
  • 4. satır: [Supprimer] eylemi, oturuma erişebilmek için [SessionAware] arayüzünü uygular.
  • 7. satır: oturum
  • 9. satır: Silinecek simülasyon numarası. Hatırlayacağımız üzere, [Supprimer] sınıfının örneklenmesi, URL Html aracılığıyla gerçekleşir:
<a href="<a href="view-source:http://localhost:8084/pam-01/SupprimerSimulation.action?id=2">/pam-01/SupprimerSimulation.action?id=</a>num">Retirer</a>

burada num, kaldırılacak simülasyon numarasıdır. Bu numara, 9. satırdaki id alanına kaydedilecektir.

  • 11. satır: İsteğe yanıt olarak görüntülenecek görünümün menüsü
  • 19. satır: İsteğe yanıtı oluşturacak olan execute yöntemi.
  • 21. satır: oturumda daha önce yapılmış simülasyonların listesi alınır
  • 22-26. satırlar: Oturumda bu listenin alınamaması, muhtemelen oturumun süresinin dolduğu anlamına gelir. Bu durumla daha önce karşılaştık. Tiles görünümünü görüntüleyen erreur anahtarını döndürüyoruz:

<!-- eylem RetirerSimulation -->
    <action name="SupprimerSimulation" class="web.actions.Supprimer">
      <result name="erreur" type="tiles">erreur</result>
      ...
</action>

erreur Tiles görünümü 19.9. paragrafında tanıtılmıştır.

  • 28-36. satırlar: 9. satırdaki id dizesinin gerçekten >0 bir tamsayı olup olmadığı kontrol edilir.
  • 38-40. satırlar: Aksi takdirde, erreur anahtarı yeniden döndürülür ve bu da erreur Tiles görünümünün görüntülenmesini sağlar
  • 43-48. satırlar: Kaldırılacak simülasyon, simülasyonlar listesinde aranır. Bulunursa silinir.
  • 50. satır: Menü, Tiles simulations görünümü için güncellenir.
  • satır 51: simulations anahtarı döndürülür. Bu anahtar, simulations Tiles görünümünü görüntüleyecektir:

<!-- RetirerSimulation eylemi -->
    <action name="SupprimerSimulation" class="web.actions.Supprimer">
      ...
      <result name="simulations" type="tiles">simulations</result>
</action>

simulations Tiles görünümü 19.9. paragrafında ele alınmıştır.

19.11. Forma geri dön

simulations Tiles görünümünden kullanıcı forma geri dönebilir:

  • [1]'te, forma geri dönme bağlantısına tıklanır
  • [2]'te boş bir form bulunur

[Retour au formulaire de simulation] bağlantısı, [Entete.JSP] parçasında tanımlanmıştır:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<table>
  <tr>
    <td><h1><s:text name="Pam.titre"/></h1></td>
    <td>
      ...
      <s:if test="menu.retourFormulaire">
        |<a href="<s:url action="RetourFormulaire"/>"><s:text name="Menu.RetourFormulaire"/></a><br/>
      </s:if>
      ...
    </td>
  </tr>
</table>
  • 10. satır: Bağlantı, [RetourFormulaire] eylemine yönlendirir. Bu eylem, [struts.xml] dosyasında şu şekilde tanımlanmıştır:

   <!-- eylem RetourFormulaire -->
    <action name="RetourFormulaire" >
      <result type="redirectAction">
        <param name="actionName">Formulaire!input</param>
        <param name="namespace">/</param>
      </result>
</action>

Bu eylemin herhangi bir sınıfa bağlı olmadığı görülmektedir. Bu eylem, istemci tarayıcısını [/Formulaire!input] eylemine yönlendirmekle yetinmektedir. Bu durumda, 19.7. paragrafında açıklanan ilk görünümün görüntülenmesi durumuyla aynı durum söz konusudur. Dolayısıyla, bu ilk görünüm olan [2]'e geri dönülür.

19.12. Simülasyon listesini görüntüle

simulation veya saisie döşeme görünümlerinden yola çıkarak, kullanıcı simülasyonları görüntülemeyi talep edebilir:

  • [1]'te, [Voir les simulations] bağlantısına tıklayın
  • [2]'te simülasyonların listesi bulunur

[Voir les simulations] bağlantısı, [Entete.JSP] parçasında tanımlanmıştır:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<table>
  <tr>
    <td><h1><s:text name="Pam.titre"/></h1></td>
    <td>
      ...
      <s:if test="menu.voirSimulations">
        |<a href="<s:url action="VoirSimulations"/>"><s:text name="Menu.VoirSimulations"/></a><br/>
      </s:if>
      ...
    </td>
  </tr>
</table>
  • 10. satır: [Voir les simulations] bağlantısı, [VoirSimulations] eylemini çağırır. Bu eylem, [struts.xml] dosyasında şu şekilde tanımlanmıştır:

   <!-- eylem VoirSimulations -->
    <action name="VoirSimulations" class="web.actions.Voir">
      <result name="success" type="tiles">simulations</result>
</action>

[VoirSimulations] eylemi, yöntem belirtilmeden [Voir] sınıfıyla ilişkilendirilmiştir. Dolayısıyla, [Voir].execute yöntemi yürütülecektir. [Voir] sınıfı şu şekildedir:


package web.actions;

import com.opensymphony.xwork2.ActionSupport;
import web.entities.Menu;

public class Voir extends ActionSupport{
  // menü
  private Menu menu=new Menu(false,false,false,false,true,true);
  // alıcı ve ayarlayıcılar

  public Menu getMenu() {
    return menu;
  }

  public void setMenu(Menu menu) {
    this.menu = menu;
  }
  
}

[Voir] eylemi tek bir şey yapar: Tiles simulations görünümü için menüyü konumlandırır (8. satır). execute yöntemi yoktur. Dolayısıyla, üst sınıf olan [ActionSupport] sınıfının yöntemi çalıştırılacaktır. Bu yöntemin, success anahtarını döndürmekten başka bir şey yapmadığı bilinmektedir.

[struts.xml]'teki işleme geri dönelim:


   <!-- eylem VoirSimulations -->
    <action name="VoirSimulations" class="web.actions.Voir">
      <result name="success" type="tiles">simulations</result>
</action>
  1. satırda, success anahtarının Tiles simulations görünümünün görüntülenmesine yol açtığı görülüyor. Bu görünüm, sayfa 161'de açıklanmıştır.

19.13. Mevcut simülasyonu silme

simulation Tiles görünümünden kullanıcı, mevcut simülasyonun silinmesini talep edebilir:

  • [1]'te mevcut simülasyon silinir
  • [2]'te, giriş formu boş olarak görüntülenir

[Effacer la simulation] bağlantısı, [Entete.JSP] parçasında tanımlanmıştır:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<table>
  <tr>
    <td><h1><s:text name="Pam.titre"/></h1></td>
    <td>
      ...
      <s:if test="menu.effacerSimulation">
        |<a href="<s:url action="Formulaire!input"/>"><s:text name="Menu.EffacerSimulation"/></a><br/>
      </s:if>
      ...
    </td>
  </tr>
</table>
  1. satırda, [Effacer la simulation] bağlantısının [Formulaire!input] eylemini tetiklediği görülüyor. Bu eylemin, başlangıç görünümü olan [2]'e yönlendirdiği biliniyor.

19.14. Mevcut oturumu sonlandırma

Tüm Tiles görünümlerinden kullanıcı oturumu sonlandırmayı talep edebilir:

  • [1]'te, simülasyonlar görünümünden başlayıp oturumu sonlandırıyoruz
  • [2]'te, giriş formu boş olarak karşımıza çıkar. Simülasyonları görüntülemek istiyoruz.
  • [3]'te simülasyon listesi artık boştur.

[Terminer la session] bağlantısı, [Entete.JSP] parçasında tanımlanmıştır:


<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>

<table>
  <tr>
    <td><h1><s:text name="Pam.titre"/></h1></td>
    <td>
      ...
      <s:if test="menu.terminerSession">
        |<a href="<s:url action="TerminerSession"/>"><s:text name="Menu.TerminerSession"/></a><br/>
      </s:if>
    </td>
  </tr>
</table>
  1. satırda, [Terminer la session] bağlantısının [TerminerSession] eylemini tetiklediği görülüyor. Bu eylem, [struts.xml] dosyasında şu şekilde tanımlanmıştır:

    <action name="TerminerSession" class="web.actions.Terminer">
      <result name="success" type="redirectAction">
        <param name="actionName">Formulaire!input</param>
        <param name="namespace">/</param>
      </result>
</action>
  • 1. satır: [Terminer] sınıfının bir örneğinin oluşturulacağı ve execute yönteminin çalıştırılacağı görülmektedir.
  • 2-5. satırlar: [Terminer].execute yönteminin yürütülmesinden sonra, ilk veri girişi ekranına yönlendirme yapılacaktır. Bu, 2 numaralı ekranı açıklamaktadır.

[Terminer] sınıfı şu şekildedir:


package web.actions;

import com.opensymphony.xwork2.ActionSupport;
import java.util.Map;
import org.apache.struts2.interceptor.SessionAware;

public class Terminer extends ActionSupport implements SessionAware {

  // oturum
  private Map<String, Object> session;
  
  @Override
  public String execute() {
    // mevcut oturumun sonlandırılması
    session.clear();
    return SUCCESS;
  }

  @Override
  public void setSession(Map<String, Object> session) {
    this.session = session;
  }
}

[Terminer] eyleminin rolü, geçerli oturumun özniteliklerini temizlemektir.

  • 7. satır: [Terminer] eylemi, oturuma erişim sağlamak için [SessionAware] arayüzünü uygular.
  • 10. satır: oturum sözlüğü
  • 13. satır: Yürütülen execute yöntemi
  • 15. satır: Oturum sözlüğünü boşaltır. Bu nedenle, oturumda bulunan simülasyon listesi kaybolacaktır. Ekran 3'te görülen durum bunu açıklamaktadır.
  • 16. satır: success anahtarını döndürür; daha önce gördüğümüz gibi, bu anahtar saisie [2] döşeme görünümünü görüntüleyecektir.

19.15. Conclusion

Simüle edilmiş bir [metier] katmanı ile çalışan vaka çalışmamızın 1. sürümünü tamamen açıklamış bulunmaktayız:

Geriye kalan tek şey, gerçek iş katmanını [web] katmanına "bağlamak".