Skip to content

11. Steuerberechnung: Übung mit einem Webservice und einer dreischichtigen Architektur

Wir werden die IMPOTS-Übung (siehe Abschnitte 4.2, 4.3, 6) noch einmal aufgreifen und sie in eine Client/Server-Anwendung umwandeln. Das Server-Skript wird in drei Komponenten unterteilt:

  • eine Schicht namens [DAO] (Data Access Objects), die die Interaktion mit der MySQL-Datenbank übernimmt
  • eine Schicht namens [business], die die Steuer berechnet
  • eine [Web]-Schicht, die die Kommunikation mit Web-Clients übernimmt.

Das Client-Skript [1]:

  • sendet die drei für die Steuerberechnung erforderlichen Informationen ($married, $children, $salary) an das Server-Skript
  • zeigt die Antwort des Servers auf der Konsole an

Das Server-Skript [2] besteht aus der [Web]-Schicht des Servers.

  • Zu Beginn einer neuen Client-Sitzung füllt es Arrays mit Daten aus der MySQL-Datenbank [dbimports]. Dazu greift es auf die [DAO]-Schicht zurück. Die so erstellten Arrays werden in der Client-Sitzung abgelegt, damit sie in nachfolgenden Client-Anfragen verwendet werden können.
  • Wenn ein Client eine Anfrage stellt, übergibt er die drei Informationen ($married, $children, $salary) an die [Business-Logik]-Schicht, die die Steuer $tax berechnet.
  • Das Server-Skript gibt die berechnete Steuer $tax zurück.

11.1. Das Client-Skript (clients_impots_05_web)

Das Client-Skript fungiert als Client des Webdienstes zur Steuerberechnung. Es sendet (POST) Parameter im folgenden Format an den Server:

params=$married,$children,$salary wobei

  • $married die Zeichenfolge „yes“ oder „no“ ist,
  • $children die Anzahl der Kinder ist,
  • $salary das Gehalt des Steuerpflichtigen ist

Es ruft die drei oben genannten Parameter aus einer Textdatei [data.txt] im Format (verheiratet, Kinder, Gehalt) ab:

oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000

Das Client-Skript

  • liest die Textdatei [data.txt] Zeile für Zeile
  • sendet die Zeichenfolge params=$married,$children,$salary an den Webdienst zur Steuerberechnung
  • und ruft die Antwort vom Dienst ab. Diese Antwort kann zwei Formen annehmen:
<erreur>message d'erreur</erreur>
<impot>montant de l'impôt</impot>
  • speichert die Antwort des Servers in einer Textdatei [results.txt] in einem der beiden folgenden Formate:
marié:enfants:salaire:erreur
marié:enfants:salaire:impôt

Der clientseitige Skriptcode lautet wie folgt:


<?php
 
// tax client
// error management
ini_set("display_errors", "off");
 
// ---------------------------------------------------------------------------------
// a class of utility functions
class Utilitaires {
 
  function cutNewLinechar($ligne) {
    ...
  }
 
}
 
// main -----------------------------------------------------
// definition of constants
$DATA = "data.txt";
$RESULTATS = "resultats.txt";
// server data
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/impots_05_web.php";
 
// taxable person parameters (marital status, number of children, annual salary)
// were placed in the $DATA text file, one line for each taxpayer
// results (marital status, number of children, annual salary, tax payable) 
// or (marital status, number of children, annual salary, error msg) are placed in
// the $RESULTATS text file, with one result per line
 
// utility class
$u = new Utilitaires();
 
// opening taxpayer data files
$data = fopen($DATA, "r");
if (!$data) {
  print "Impossible d'ouvrir en lecture le fichier des données [$DATA]\n";
  exit;
}
 
// open results file
$résultats = fopen($RESULTATS, "w");
if (!$résultats) {
  print "Impossible de créer le fichier des résultats [$RESULTATS]\n";
  exit;
}
 
// the current line of the taxpayer data file is used
while ($ligne = fgets($data, 100)) {
  // remove any end-of-line marker
  $ligne = $u->cutNewLineChar($ligne);
  // we retrieve the 3 fields married:children:salary which form $ligne
  list($marié, $enfants, $salaire) = explode(",", $ligne);
  // tax calculation
  list($erreur, $impôt) = calculerImpot($HOTE, $PORT, $urlServeur, $cookie, array($marié, $enfants, $salaire));
  // enter the result
  $résultat = $erreur ? "$marié:$enfants:$salaire:$erreur" : "$marié:$enfants:$salaire:$impôt";
  fputs($résultats, "$résultat\n");
  // following data
}
// close files
fclose($data);
fclose($résultats);
 
// end
print "Terminé...\n";
exit;
 
function calculerImpot($HOTE, $PORT, $urlServeur, &$cookie, $params) {
  // connects client to ($HOTE,$PORT,$urlServeur)
  // sends the $cookie cookie if it is non-empty. $cookie is passed by reference
  // sends $params to the server
  // exploits the single line returned by the server
 
  // open a connection on port 80 of $HOTE
  $connexion = fsockopen($HOTE, $PORT);
  // mistake?
  if (!$connexion)
    return array("erreur lors de la connexion au serveur ($HOTE, $PORT)");
  // protocol HTTP headers must end with an empty line
  // POST
  fputs($connexion, "POST $urlServeur HTTP/1.1\n");
  // Host
  fputs($connexion, "Host: localhost\n");
  // Connection
  fputs($connexion, "Connection: close\n");
// send cookie if non-empty
  if ($cookie) {
    fputs($connexion, "Cookie: $cookie\n");
  }////if
  // now we send the client instruction after encoding it
  $infos = "params=" . urlencode(implode(",", $params));
  // on indique quel type d'informations on va envoyer
  fputs($connexion, "Content-type: application/x-www-form-urlencoded\n");
  // send the size (number of characters) of the information to be sent
  fputs($connexion, "Content-length: " . strlen($infos) . "\n");
  // send an empty line
  fputs($connexion, "\n");
  // we send the news
  fputs($connexion, $infos);
  // the web server response is displayed
  // and we take care to recover any cookie
  while ($ligne = fgets($connexion, 1000)) {
    // cookie - only on 1st response
    if (!$cookie) {
      if (preg_match("/^Set-Cookie: (.*?)\s*$/", $ligne, $champs)) {
        $cookie = $champs[1];
      }//if
    }
    // as soon as there is an empty line, the HTTP response is terminated
    if (trim($ligne) == "") {
      break;
    }
  }////while
  // read line result
  $ligne = fgets($connexion, 1000);
  // close the connection
  fclose($connexion);
  // result calculation
  $erreur="";
  $impôt="";
  if (preg_match("/^<erreur>(.*?)<\/erreur>\s*$/", $ligne, $champs)) {
    $erreur = $champs[1];
  } else {
    if (preg_match("/^<impot>(.*?)<\/impot>\s*$/", $ligne, $champs)) {
      $impôt = $champs[1];
    }else{
      $erreur="résultat du serveur non exploitable";
    }
  }
  // return
  return array($erreur, $impôt);
}

Kommentare

Der clientseitige Skriptcode enthält Elemente, die wir bereits kennen:

  • Zeilen 9–15: Die Klasse [Utilities] wurde in Version 3, Abschnitt 6 eingeführt
  • Zeilen 17–68: Das Hauptprogramm ähnelt dem in Version 1, Abschnitt 4.2. Es unterscheidet sich lediglich in der Steuerberechnung, Zeile 56.
  • Zeile 56: Die Funktion zur Steuerberechnung akzeptiert die folgenden Parameter:
    • $HOST, $PORT, $serverURL: werden für die Verbindung zum Webdienst verwendet
    • $cookie: ist das Sitzungs-Cookie. Dieser Parameter wird per Referenz übergeben. Sein Wert wird von der Steuerberechnungsfunktion festgelegt. Beim ersten Aufruf hat er keinen Wert. Danach hat er einen.
    • array($married, $children, $salary): stellt eine Zeile aus der Datei [data.txt] dar

Die Steuerberechnungsfunktion gibt ein Array mit zwei Ergebnissen zurück ($error, $tax), wobei $error eine mögliche Fehlermeldung und $tax der Steuerbetrag ist.

  • Zeilen 70–134: Dies ist ein klassischer HTTP-Client, wie wir ihn schon oft gesehen haben. Beachten Sie folgende Punkte:
  • Zeile 83: Die Parameter ($married, $children, $salary) werden über eine POST-Anfrage an den Server gesendet
  • Zeilen 89–91: Wenn der Client über eine Sitzungs-ID verfügt, sendet er diese an den Server
  • Zeile 93: Erstellung des Parameters „params“
  • Zeile 101: Der Parameter `params` wird gesendet
  • Zeilen 104–115: Der Client liest alle vom Server gesendeten HTTP-Header, bis er auf die Leerzeile stößt, die das Ende der Header markiert. Er nutzt diese Gelegenheit, um die Sitzungs-ID aus der Antwort auf seine erste Anfrage abzurufen.
  • Zeilen 123–125: Verarbeitung jeder Zeile im Format <error>message</error>
  • Zeilen 126–128: Wir verfahren ebenso mit jeder Zeile der Form <tax>amount</tax>
  • Zeile 133: Das Ergebnis wird zurückgegeben

11.2. Der Webdienst zur Steuerberechnung

Hier interessieren uns die drei Skripte, aus denen der Server besteht:

Das entsprechende NetBeans-Projekt sieht wie folgt aus:

In [1] besteht der Server aus den folgenden PHP-Skripten:

  • [impots_05_entites] enthält die vom Server verwendeten Klassen
  • [impots_05_dao] enthält die Klassen und Schnittstellen der [dao]-Schicht
  • [impots_05_metier] enthält die Klassen und Schnittstellen der [business]-Schicht
  • [impots_05_web] enthält die Klassen und Schnittstellen der [dao]-Schicht

Zunächst stellen wir zwei Klassen vor, die von den verschiedenen Schichten des Webdienstes verwendet werden.

11.2.1. Die Webservice-Entitäten (impots_05_entities)

Die MySQL-Datenbank [dbimpots] enthält eine Tabelle [impots] mit den Daten, die zur Berechnung der Steuer benötigt werden [1]:

Wir speichern die Daten aus der MySQL-Tabelle [impots] in einem Array von Tranche-Objekten, wobei Tranche die folgende Klasse ist:


<?php
 
// a tax bracket
class Tranche {
 
  // private fields
  private $limite;
  private $coeffR;
  private $coeffN;
 
  // getters and setters
  public function getLimite() {
    return $this->limite;
  }
 
  public function setLimite($limite) {
    $this->limite = $limite;
  }
 
  public function getCoeffR() {
    return $this->coeffR;
  }
 
  public function setCoeffR($coeffR) {
    $this->coeffR = $coeffR;
  }
 
  public function getCoeffN() {
    return $this->coeffN;
  }
 
  public function setCoeffN($coeffN) {
    $this->coeffN = $coeffN;
  }
 
  // manufacturer
  public function __construct($limite, $coeffR, $coeffN) {
    $this->setLimite($limite);
    $this->setCoeffR($coeffR);
    $this->setCoeffN($coeffN);
  }
 
  // toString
  public function __toString(){
    return "[$this->limite,$this->coeffR,$this->coeffN]";
  }
}

Die privaten Felder [$limite, $coeffR, $coeffN] werden verwendet, um die Spalten [limites, coeffR, coeffN] einer Zeile in der MySQL-Tabelle [impots] zu speichern.

Zusätzlich verwendet der Servercode eine benutzerdefinierte Ausnahme, die Klasse ImpotsException:

1
2
3
4
5
6
7
class ImpotsException extends Exception {

  public function __construct($message, $code=0) {
    parent::__construct($message, $code);
  }

}
  • Zeile 1: Die Klasse [ImpotsException] erweitert die in PHP 5 vordefinierte Klasse [Exception]
  • Zeile 3: Der Konstruktor der Klasse [ImpotsException] akzeptiert zwei Parameter:
    • $message: eine Fehlermeldung
    • $code: ein Fehlercode

11.2.2. Die [dao]-Schicht (impots_05_dao)

Die [dao]-Schicht ermöglicht den Zugriff auf Datenbankdaten:

Die [dao]-Schicht verfügt über folgende Schnittstelle:

1
2
3
4
5
6
// dao interface
interface IImpotsDao {

// renders an array of Slice entities
  function getData();
}

Die Schnittstelle IImpotsDao stellt nur die Funktion getData bereit. Diese Funktion speichert die verschiedenen Zeilen der MySQL-Tabelle [dbimpots.impots] in einem Array von Tranche-Objekten.

Die Implementierungsklasse sieht wie folgt aus:


<?php
 
// dao layer
// dependencies
require_once "impots_05_entites.php";
// constants
define("TABLE", "impots");
 
// -----------------------------------------------------------------
// abstract implementation
abstract class ImpotsDaoWithPdo implements IImpotsDao {
 
// private fields
  private $dsn;
  private $user;
  private $passwd;
  private $tranches;
 
// getters and setters
  public function getDsn() {
    return $this->dsn;
  }
 
  public function setDsn($dsn) {
    $this->dsn = $dsn;
  }
 
  public function getUser() {
    return $this->user;
  }
 
  public function setUser($user) {
    $this->user = $user;
  }
 
  public function getPasswd() {
    return $this->passwd;
  }
 
  public function setPasswd($passwd) {
    $this->passwd = $passwd;
  }
 
  // manufacturer
  public function __construct($dsn, $user, $passwd) {
    // save parameters
    $this->setDsn($dsn);
    $this->setUser($user);
    $this->setPasswd($passwd);
    // retrieve data from SGBD
    // connects ($user,$pwd) to base $dsn
    try {
      // connection
      $connexion = new PDO($dsn, $user, $passwd, array(PDO::ATTR_PERSISTENT => true));
      // read table $TABLE
      $requête = "select limites,coeffR,coeffN from " . TABLE;
      // executes the $requête request on the $connexion connection
      $statement = $connexion->prepare($requête);
      $statement->execute();
      // query result evaluation
      while ($colonnes = $statement->fetch()) {
        $this->tranches[] = new Tranche($colonnes[0], $colonnes[1], $colonnes[2]);
      }
      // disconnect
      $connexion=NULL;
    } catch (PDOException $e) {
      // return with error
      throw new ImpotsException($e->getMessage(), 1);
    }
  }
 
  public function getData(){
    return $this->tranches;
  }
}
  • Zeile 5: Die Implementierung der Schnittstelle [IImpotsDao] erfordert die im Skript [impots_05_entities] definierten Klassen.
  • Zeile 11: Definition einer abstrakten Klasse. Eine abstrakte Klasse ist eine Klasse, die nicht instanziiert werden kann. Eine abstrakte Klasse muss abgeleitet werden, um instanziiert werden zu können. Eine Klasse kann als abstrakt deklariert werden, weil sie nicht instanziiert werden kann (einige ihrer Methoden sind nicht definiert) oder weil wir sie nicht instanziieren wollen. Hier wollen wir die Klasse [ImpotsDaoWithPdo] nicht instanziieren. Wir werden abgeleitete Klassen instanziieren.
  • Zeile 11: Die Klasse [ImpotsDaoWithPdo] implementiert die Schnittstelle [IImpotsDao]. Sie muss daher die Methode getData definieren. Diese Methode befindet sich in den Zeilen 72–74.
  • Zeile 14: $dsn (Data Source Name) ist eine Zeichenkette, die das DBMS und die verwendete Datenbank eindeutig identifiziert.
  • Zeile 15: $user identifiziert den Benutzer, der eine Verbindung zur Datenbank herstellt
  • Zeile 16: $passwd ist das Passwort für den oben genannten Benutzer
  • Zeile 17: $tranches ist das Array von Tranche-Objekten, in dem die MySQL-Tabelle [dbimpots.impots] gespeichert wird.
  • Zeilen 45–70: Der Klassenkonstruktor. Dieser Code wurde bereits in Version 4, Abschnitt 8.2 behandelt. Beachten Sie, dass die Erstellung des [ImpotsDaoWithPdo]-Objekts fehlschlagen kann. In diesem Fall wird eine [ImpotsException] ausgelöst.
  • Zeilen 72–74: Die Methode [getData] der Schnittstelle [IImpotsDao].

Die Klasse [ImpotsDaoWithPdo] eignet sich für jedes DBMS. Der Klassenkonstruktor in Zeile 45 erfordert die Kenntnis des Datenquellennamens der Datenbank. Diese Zeichenfolge hängt vom verwendeten DBMS ab. Wir haben uns dafür entschieden, vom Benutzer der Klasse nicht zu verlangen, diesen Datenquellennamen zu kennen. Für jedes DBMS gibt es eine spezifische Klasse, die von [ImpotsDaoWithPdo] abgeleitet ist. Für das MySQL-DBMS ist dies die folgende Klasse:


class ImpotsDaoWithMySQL extends ImpotsDaoWithPdo {
 
  public function __construct($host, $port, $base, $user, $passwd) {
    parent::__construct("mysql:host=$host;dbname=$base;port=$port", $user, $passwd);
  }
 
}
  • In Zeile 3 fordert der Konstruktor nicht den Datenquellennamen an, sondern lediglich den Namen des DBMS-Hosts ($host), dessen Listening-Port ($port) und den Datenbanknamen ($base).
  • Zeile 4: Der Datenquellenname für die MySQL-Datenbank wird gebildet und zum Aufruf des Konstruktors der übergeordneten Klasse verwendet.

Beachten Sie, dass Sie zur Anpassung an ein anderes DBMS einfach die entsprechende, von [ImpotsDaoWithPdo] abgeleitete Klasse schreiben müssen. In jedem Fall muss der für das verwendete DBMS spezifische Datenquellenname gebildet werden.

11.2.3. Die [business]-Schicht (impots_05_metier)

Die [business]-Schicht enthält die Logik zur Steuerberechnung:

Die [business]-Schicht verfügt über die folgende Schnittstelle:


<?php
 
// business interface
interface IImpotsMetier {
  public function calculerImpot($marié, $enfants, $salaire);
}

Die Schnittstelle [IImpotsMetier] stellt nur eine Methode bereit, die Methode [calculateTax], die die Steuer eines Steuerpflichtigen anhand der folgenden Parameter berechnet:

  • $married: eine Zeichenkette mit dem Wert „yes“ oder „no“, je nachdem, ob der Steuerzahler verheiratet ist oder nicht
  • $children: die Anzahl der Kinder des Steuerzahlers
  • $salary: das Gehalt des Steuerzahlers

Die [web]-Schicht stellt diese Parameter bereit.

Die Implementierung der Schnittstelle [IImpotsMetier] sieht wie folgt aus:


// dependencies
require_once "impots_05_dao.php";
 
// ------------------------------------------------------------------
// implementation class
class ImpotsMetier implements IImpotsMetier {
 
  // dao layer
  private $dao;
   // object array [Slice]
  private $data;
 
  // getter and setter
  public function getDao() {
    return $this->dao;
  }
 
  public function setDao($dao) {
    $this->dao = $dao;
  }

  public function setData($data){
    $this->data=$data;
  }
 
  public function __construct($dao) {
    // retrieve the data needed to calculate taxes
    $this->setDao($dao);
    $this->setData($this->dao->getData());
  }
 
  public function calculerImpot($marié, $enfants, $salaire) {
    // $marié : yes, no
    // $enfants : number of children
    // $salaire: annual salary
    // number of shares
    $marié = strtolower($marié);
    if ($marié == "oui")
      $nbParts = $enfants / 2 + 2;
    else
      $nbParts=$enfants / 2 + 1;
    // an additional 1/2 share if at least 3 children
    if ($enfants >= 3)
      $nbParts+=0.5;
    // taxable income
    $revenuImposable = 0.72 * $salaire;
    // family quotient
    $quotient = $revenuImposable / $nbParts;
    // is set at the end of the limit table to stop the following loop
    $N = count($this->data);
    $this->data[$N - 1]->setLimite($quotient);
    // tAX CALCULATION
    $i = 0;
    while ($i < $N and $quotient > $this->data[$i]->getLimite()) {
      $i++;
    }
    // because $quotient has been placed at the end of the $limites array, the previous loop
    // cannot exceed the table $limites
    // now we can calculate the tax
    return floor($revenuImposable * $this->data[$i]->getCoeffR() - $nbParts * $this->data[$i]->getCoeffN());
  }
 
}
  • Zeile 2: Die [business]-Schicht benötigt Klassen aus der [DAO]-Schicht sowie Entitäten (Tranche, ImpotsException).
  • Zeile 6: Die Klasse [ImpotsMetier] implementiert die Schnittstelle [IimpotsMetier].
  • Zeilen 9–11: Die privaten Felder der Klasse:
    • $dao: Verweis auf die [dao]-Schicht
    • $data: Array von Objekten vom Typ [Tranche], bereitgestellt von der [dao]-Schicht
  • Zeilen 26–30: Der Konstruktor der Klasse initialisiert die beiden vorherigen Felder. Er erhält als Parameter eine Referenz auf die [dao]-Schicht.
  • Zeilen 32–61: Implementierung der Methode [calculerImpot] der Schnittstelle [IimpotsMetier]. Diese Methode wurde in Version 1 eingeführt (Abschnitt 4.2).

11.2.4. Die [web]-Schicht (impots_05_web)

Die [business]-Schicht enthält die Logik zur Steuerberechnung:

Die [Web]-Schicht besteht aus dem Webdienst, der auf Web-Clients reagiert. Erinnern Sie sich daran, dass diese Clients eine Anfrage an den Webdienst senden, indem sie den folgenden Parameter übermitteln: params=married,children,salary. Dies ist ein Webdienst, der denjenigen ähnelt, die wir in den vorherigen Abschnitten erstellt haben. Sein Code lautet wie folgt:


<?php
 
// business layer
require_once "impots_05_metier.php";
 
// error management
ini_set("display_errors", "off");
 
// uTF-8 header
header("Content-Type: text/plain; charset=utf-8");
 
// ------------------------------------------------------------------------------
// tax web service
// definition of constants
$HOTE = "localhost";
$PORT = 3306;
$BASE = "dbimpots";
$USER = "root";
$PWD = "";
// the data required to calculate the tax has been placed in the mysql table IMPOTS
// belonging to the $BASE database. The table has the following structure
// limits decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
// taxable person parameters (marital status, number of children, annual salary)
// are sent by the customer in the form params=marital status, number of children, annual salary
// results (marital status, number of children, annual salary, tax payable) are returned to the customer
// in the form <impot>impot</impot>
// or as <error>error</error>, if parameters are invalid
 
// retrieve the [business] layer in the session
session_start();
if (!isset($_SESSION['metier'])) {
// instantiation of the [dao] layer and the [business] layer
  try {
    $_SESSION['metier'] = new ImpotsMetier(new ImpotsDaoWithMySQL($HOTE, $PORT, $BASE, $USER, $PWD));
  } catch (ImpotsException $ie) {
    print "<erreur>Erreur : " . utf8_encode($ie->getMessage() . "</erreur>");
    exit;
  }
}
$metier = $_SESSION['metier'];
 
// retrieve the line sent by the client
$params = utf8_encode(htmlspecialchars(strtolower(trim($_POST['params']))));
$items = explode(",", $params);
// there must be only 3 parameters
if (count($items) != 3) {
  print "<erreur>[$params] : nombre de paramètres invalides</erreur>\n";
  exit;
}//if
// first parameter (marital status) must be yes/no
$marié = trim($items[0]);
if ($marié != "oui" and $marié != "non") {
  print "<erreur>[$params] : 1er paramètre invalide</erreur>\n";
  exit;
}//if
// the second parameter (number of children) must be an integer
if (!preg_match("/^\s*(\d+)\s*$/", $items[1], $champs)) {
  print "<erreur>[$params] : 2ième paramètre invalide</erreur>\n";
  exit;
}//if
$enfants = $champs[1];
// the third parameter (salary) must be an integer
if (!preg_match("/^\s*(\d+)\s*$/", $items[2], $champs)) {
  print "<erreur>[$params] : 3ième paramètre invalide</erreur>\n";
  exit;
}//if
$salaire = $champs[1];
// tax calculation
$impôt = $metier->calculerImpot($marié, $enfants, $salaire);
// return the result
print "<impot>$impôt</impot>\n";
// end
exit;
  • Zeile 4: Die [Web]-Schicht benötigt die Klassen aus der [Business]-Schicht
  • Zeilen 30–40: Der Verweis auf die [Business]-Schicht ist auf die Sitzung beschränkt. Wenn wir uns daran erinnern, dass diese [Business]-Schicht einen Verweis auf die [DAO]-Schicht hat und dass letztere die DBMS-Daten speichert, können wir erkennen, dass:
    • die erste Anfrage des Clients einen Zugriff auf das DBMS auslöst
    • dass nachfolgende Anfragen desselben Clients die von der [DAO]-Schicht gespeicherten Daten verwenden. Daher erfolgt kein Zugriff auf das DBMS.
  • Zeile 34: Aufbau einer [Business]-Schicht, die mit einer für das MySQL-DBMS implementierten [DAO]-Schicht zusammenarbeitet
  • Zeilen 35–37: Behandlung eines möglichen Fehlers im vorherigen Vorgang. In diesem Fall wird eine <error>message</error>-Zeile an den Client gesendet.
  • Zeile 43: Abrufen des vom Client gesendeten Parameters „params“.
  • Zeilen 46–49: Überprüfung der Anzahl der in „params“ gefundenen Elemente
  • Zeilen 51–55: Überprüfung der Gültigkeit der ersten Information
  • Zeilen 56–60: Dasselbe für die zweite Information
  • Zeilen 62–66: Gleiches gilt für die dritte
  • Zeile 69: Die [Business]-Schicht berechnet die Steuer.
  • Zeile 71: Sende das Ergebnis an den Client

Ergebnisse

Zur Erinnerung: Der Client [client_impots_web_05] verwendet die folgende Datei [data.txt]:

oui,2,200000
non,2,200000
oui,3,200000
non,3,200000
oui,5,50000
non,0,3000000

Anhand dieser Zeilen (verheiratet, Kinder, Gehalt) fragt der Client den Steuerberechnungsserver ab und schreibt die Ergebnisse in die Textdatei [results.txt]. Nach Ausführung des Clients sieht der Inhalt dieser Datei wie folgt aus:

oui:2:200000:22504
non:2:200000:33388
oui:3:200000:16400
non:3:200000:22504
oui:5:50000:0
non:0:3000000:1354938

wobei jede Zeile das Format (verheiratet, Kinder, Gehalt, berechnete Steuer) hat.