13. Übung [IMPOTS] mit einem Dienst WEB
Wir kehren zur Übung [IMPOTS] zurück, die bereits in den Abschnitten 4.2, 4.3, 8 und 10 behandelt wurde.
![]() |
13.1. Der Server
Wir befinden uns in der folgenden Client-Server-Architektur:
![]() |
Auf der Serverseite werden wir erneut eine dreischichtige Architektur verwenden. Die Schicht [dao] wird durch die Klasse ImpotsMySQL implementiert, die bereits in der Version mit SGBD und MySQL in Abschnitt 10 verwendet wurde. Die Schicht [metier] wird durch die bereits behandelte Klasse [ImpotsMetier] implementiert. Es bleibt also nur noch, den Webdienst zu schreiben. Dieser erhält von seinen Clients einen Parameter params in der Form params= ja,2,200000, wobei das erste Element angibt, ob der Steuerzahler verheiratet ist oder nicht, das zweite die Anzahl seiner Kinder und das dritte sein Jahresgehalt.
Der Webdienst lautet wie folgt (impots_web_01):
#!D:\Programme\ActivePython\Python2.7.2\python.exe
# -*- coding=Utf-8 -*-
# Import des Moduls „Impots*“
from impots import *
import cgi,cgitb,re
# Anzeige von Debugging-Informationen zulassen
cgitb.enable()
sys.stderr=sys.stdout
# ------------------------------------------------
# Der Webdienst der Steuerbehörde
# ------------------------------------------------
# Die für die Steuerberechnung erforderlichen Daten wurden in die Tabelle mysqL TABLE
# der Datenbank BASE. Die Tabelle hat folgende Struktur
# Grenzwerte decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# die Parameter der steuerpflichtigen Personen (Familienstand, Anzahl der Kinder, Jahresgehalt)
# werden vom Kunden in der Form „params=Familienstand, Anzahl der Kinder, Jahresgehalt“ übermittelt
# Die Ergebnisse (Familienstand, Anzahl der Kinder, Jahresgehalt, zu zahlende Steuer) werden an den Kunden zurückgesendet
# in der Form <Steuer>Wert</Steuer>
# oder in der Form <Fehler>Meldung</Fehler>, wenn die Parameter ungültig sind
# Der Server sendet unformatierten Text an den Client zurück
print "Content-Type: text/plain\n"
# Definition der Konstanten
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"
# die Schicht [metier] wird erstellt
# Python scheint keine Unterstützung für Sitzungen zu bieten
# In PHP hätte man eine Sitzung verwendet, um das Geschäftsobjekt zu speichern
# Hier wird es systematisch aus den Daten der Datenbank erstellt MySQL
# Instanziierung der Schicht [metier]
try:
metier=ImpotsMetier(ImpotsMySQL(HOTE,USER,PWD,BASE,TABLE))
except (IOError, ImpotsError) as infos:
print ("<erreur>Une erreur s'est produite : {0}</erreur>".format(infos))
sys.exit()
# die vom Client an den Server gesendete Zeile wird abgerufen
params=cgi.FieldStorage().getlist('params')
# Wenn keine Parameter vorhanden sind, wird ein Fehler ausgegeben
if not params:
print "<erreur>Le parametre [params] est absent<erreur>"
sys.exit()
# Der Parameter „params“ wird ausgewertet
items=params[0].strip().lower().split(',')
# Es dürfen nur 3 Felder vorhanden sein
if len(items)!=3:
print "<erreur>[%s] : nombre de parametres invalide</erreur>" % (params[0])
sys.exit()
# Der erste Parameter (Familienstand) muss „ja“ oder „nein“ lauten
marie=items[0].strip()
if marie!="oui" and marie != "non":
print "<erreur>[%s] : 1er parametre invalide</erreur>\n"% (params[0])
sys.exit()
# Der zweite Parameter (Anzahl der Kinder) muss eine ganze Zahl sein
match=re.match(r"^\s*(\d+)\s*$",items[1])
if not match:
print "<erreur>[%s] : 2ieme parametre invalide</erreur>\n"% (params[0])
sys.exit()
enfants=int(match.groups()[0])
# Der dritte Parameter (Gehalt) muss eine ganze Zahl sein
match=re.match(r"^\s*(\d+)\s*$",items[2])
if not match:
print "<erreur>[%s] : 3ieme parametre invalide</erreur>\n"% (params[0])
sys.exit()
salaire=int(match.groups()[0])
# Die Steuer wird berechnet
impot=metier.calculer(marie,enfants,salaire)
# Das Ergebnis wird zurückgegeben
print "<impot>%s</impot>\n" % (impot)
# Ende
Hinweise:
- Zeile 5: Die Objekte aus der Datei impots.py werden importiert;
- Zeile 9: Das Debuggen eines CGI-Skripts kann problematisch sein. Das Modul cgitb gibt im Fehlerfall den Grund für den Absturz aus. Dazu muss die Standard-Fehlerausgabe (sys.stderr) in die Standardausgabe (sys.stdout) umgeleitet werden (Zeile 10);
- Zeile 26: Der HTTP-Header, der die Art des gesendeten Dokuments festlegt, in diesem Fall unformatierter Text. Der Webdienst sendet seine Antwort in Form einer einzigen Textzeile zurück:
- <erreur>message</erreur>, wenn ein Fehler vorliegt;
- <impot>valeur</impot>, wobei valeur den Steuerbetrag angibt.
- Zeile 43: Instanziierung der Schichten [dao] und [metier];
- Zeilen 44–46: Bei einem Fehler bei der Instanziierung sendet das Skript seine Antwort und wird beendet;
- Zeilen 49–53: Der Parameter „params“ wird abgerufen. Fehlt er, sendet das Skript seine Antwort und wird beendet;
- Zeile 56: Der Parameter „oui,2,200000“ wird im Array „items“ in drei Felder zerlegt;
- Zeilen 58–77: Die Gültigkeit der drei Felder wird überprüft. Liegt ein Fehler vor, sendet das Skript seine Antwort und wird beendet;
- Zeile 79: Die Steuer wird berechnet;
- Zeile 81: und an den Kunden gesendet.
In einem Webbrowser erhält man folgende Ergebnisse:
![]() | ![]() |
13.2. Ein programmierter Client
# -*- coding=utf-8 -*-
import httplib,urllib,re
# Konstanten
HOST="localhost"
URL="/cgi-bin/impots_web_01b.py"
data=("oui,2,200000","non,2,200000","oui,3,200000","non,3,200000","x,y,z,t","x,2,200000", "oui,x,200000","oui,2,x");
# Anmeldung
connexion=httplib.HTTPConnection(HOST)
# Nachverfolgung
#connexion.set_debuglevel(1)
# Es wird eine Schleife über die an den Server zu sendenden Daten durchlaufen
for params in data:
# Die Parameter müssen vor dem Senden an den Server kodiert werden
parametres = urllib.urlencode({'params': params})
# Senden der Anfrage
connexion.request("POST",URL,parametres)
# Verarbeitung der Antwort (Textzeile)
reponse=connexion.getresponse().read()
lignes=reponse.split("\n")
# Die Textzeile hat das folgende Format
# <impot>xxx</impot>
# oder <Fehler>xxx</Fehler>
impot=re.match(r"^<impot>(\S+)</impot>\s*$",lignes[0])
if impot:
print "params=%s, impot=%s" % (params,impot.groups()[0])
else:
erreur=re.match(r"^<erreur>(.+)</erreur>\s*$",lignes[0])
if erreur:
print "params=%s, erreur=%s" % (params,erreur.groups()[0])
else:
print lignes
# Verbindung wird geschlossen
connexion.close()



