Skip to content

13. Oefening [IMPOTS] met een service WEB

We keren terug naar de oefening [IMPOTS] die al is behandeld in de paragrafen 4.2, 4.3, 8 en 10.

13.1. De server

We bevinden ons in de volgende client-serverarchitectuur:

Aan de serverzijde gaan we opnieuw een drielaagse architectuur gebruiken. De laag [dao] wordt geïmplementeerd door de klasse ImpotsMySQL die in de versie met de SGBD en MySQL in paragraaf 10 werd gebruikt. De laag [metier] wordt geïmplementeerd door de klasse [ImpotsMetier] die we al hebben besproken. Het enige wat nu nog rest, is het schrijven van de webservice. Deze ontvangt van zijn clients een parameter params in de vorm params= ja,2,200000, waarbij het eerste element aangeeft of de belastingplichtige al dan niet gehuwd is, het tweede het aantal kinderen en het derde het jaarsalaris.

De webservice is als volgt (impots_web_01):


#!D:\Programs\ActivePython\Python2.7.2\python.exe

# -*- coding=Utf-8 -*-
# module met de klassen Impots* importeren
from impots import *
import cgi,cgitb,re

# we staan het weergeven van debug-informatie toe
cgitb.enable()
sys.stderr=sys.stdout

# ------------------------------------------------ 
# de webdienst voor belastingen
# ------------------------------------------------ 

# de gegevens die nodig zijn voor de berekening van de belasting zijn in de tabel mysqL TABLE
# die deel uitmaakt van de database BASE. De tabel heeft de volgende structuur
# limieten decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# de parameters van de belastingplichtigen (burgerlijke staat, aantal kinderen, jaarsalaris)
# worden door de klant verzonden in de vorm params=burgerlijke staat, aantal kinderen, jaarsalaris
# de resultaten (burgerlijke staat, aantal kinderen, jaarsalaris, te betalen belasting) worden teruggestuurd naar de klant
# in de vorm <belasting>waarde</belasting>
# of in de vorm <fout>msg</fout>, als de parameters ongeldig zijn

# de server stuurt onopgemaakte tekst terug naar de klant
print "Content-Type: text/plain\n"

# definitie van de constanten
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"


# de laag [metier] wordt aangemaakt
# Python lijkt geen ondersteuning te bieden voor sessies
# in PHP zou men een sessie hebben gebruikt om het bedrijfsobject op te slaan
# hier wordt het systematisch opgebouwd op basis van de gegevens uit de database MySQL

# instantiëring van de laag [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()

# we halen de regel op die door de client naar de server is verzonden
params=cgi.FieldStorage().getlist('params')
# als er geen parameters zijn, dan is er een fout
if not params:
  print "<erreur>Le parametre [params] est absent<erreur>"
  sys.exit()

# de parameter 'params' wordt verwerkt  
items=params[0].strip().lower().split(',')
# er mogen slechts 3 velden zijn
if len(items)!=3:
  print "<erreur>[%s] : nombre de parametres invalide</erreur>" % (params[0])
  sys.exit()
# de eerste parameter (burgerlijke staat) moet ja/nee zijn
marie=items[0].strip()
if marie!="oui" and marie != "non":
  print "<erreur>[%s] : 1er parametre invalide</erreur>\n"% (params[0])
  sys.exit()
# de tweede parameter (aantal kinderen) moet een geheel getal zijn
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])
# de derde parameter (salaris) moet een geheel getal zijn
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])
# de belasting wordt berekend
impot=metier.calculer(marie,enfants,salaire)
# het resultaat wordt teruggestuurd
print "<impot>%s</impot>\n" % (impot)
# einde

Opmerkingen:

  • regel 5: de objecten uit het bestand impots.py worden geïmporteerd;
  • regel 9: het debuggen van een CGI-script kan problematisch zijn. De module cgitb geeft bij een fout de oorzaak van de crash door. Hiervoor moet de standaardfoutuitvoer (sys.stderr) worden omgeleid naar de standaarduitvoer (sys.stdout) (regel 10);
  • regel 26: de HTTP-header die de aard van het verzonden document bepaalt, in dit geval onopgemaakte tekst. De webservice stuurt zijn antwoord terug in de vorm van één enkele tekstregel:
    • <erreur>message</erreur> als er een fout is;
    • <impot>valeur</impot>, waarbij valeur het belastingbedrag is.
  • regel 43: instantiëren van de lagen [dao] en [metier];
  • regels 44-46: als er een fout optreedt bij het instantiëren, verstuurt het script zijn antwoord en wordt het beëindigd;
  • regels 49-53: de parameter 'params' wordt opgehaald. Als deze ontbreekt, stuurt het script zijn antwoord en wordt het beëindigd;
  • regel 56: de parameter 'ja,2,200000' wordt opgesplitst in 3 velden in de array items;
  • regels 58-77: de geldigheid van de drie velden wordt gecontroleerd. Als er een fout is, verstuurt het script zijn antwoord en wordt het beëindigd;
  • regel 79: de belasting wordt berekend;
  • regel 81: en naar de klant verzonden.

In een webbrowser krijgt men de volgende resultaten:

13.2. Een geprogrammeerde klant


Het programma (client_impots_web_01)


# -*- coding=utf-8 -*-

import httplib,urllib,re

# constanten
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");

# verbinding
connexion=httplib.HTTPConnection(HOST)
# opvolging
#connexion.set_debuglevel(1)
# we doorlopen de gegevens die naar de server moeten worden verzonden
for params in data:
    # de parameters moeten worden gecodeerd voordat ze naar de server worden verzonden
    parametres = urllib.urlencode({'params': params})
    # het verzoek wordt verzonden
    connexion.request("POST",URL,parametres)
    # verwerking van het antwoord (tekstregel)
    reponse=connexion.getresponse().read()
    lignes=reponse.split("\n")
    # de tekstregel heeft de volgende vorm
    # <impot>xxx</impot>
    # of <fout>xxx</fout>
    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
# verbinding verbreken
connexion.close()

13.3. Résultats

1
2
3
4
5
6
7
8
params=oui,2,200000, impot=22504.0
params=non,2,200000, impot=33388.0
params=oui,3,200000, impot=16400.0
params=non,3,200000, impot=22504.0
params=x,y,z,t, erreur=[x,y,z,t] : nombre de parametres invalide
params=x,2,200000, erreur=[x,2,200000] : 1er parametre invalide
params=oui,x,200000, erreur=[oui,x,200000] : 2ieme parametre invalide
params=oui,2,x, erreur=[oui,2,x] : 3ieme parametre invalide