Skip to content

13. Вправа [IMPOTS] із використанням сервісу WEB

Повернемося до вправи [IMPOTS], яку вже розглядали в розділах 4.2, 4.3, 8, 10.

13.1. Сервер

Ми розглядаємо таку архітектуру «клієнт-сервер»:

На стороні сервера ми знову будемо використовувати трирівневу архітектуру. Рівень [dao] буде реалізовано класом ImpotsMySQL, який використовувався у версії з SGBD та MySQL у розділі 10. Рівень [metier] буде реалізовано класом [ImpotsMetier], який ми вже розглядали. Отже, залишається лише написати веб-сервіс. Він отримує від своїх клієнтів параметр params у формі params= yes,2,200000, де перший елемент вказує, чи одружений платник податків, другий — кількість його дітей, третій — його річний оклад.

Веб-сервіс має такий вигляд (impots_web_01):


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

# -*- coding=Utf-8 -*-
# імпорт модуля класів Impots*
from impots import *
import cgi,cgitb,re

# дозволено відображення інформації для налагодження
cgitb.enable()
sys.stderr=sys.stdout

# ------------------------------------------------ 
# веб-сервіс податків
# ------------------------------------------------ 

# дані, необхідні для розрахунку податку, розміщено в таблиці mysqL TABLE
#, що належить до бази даних BASE. Таблиця має таку структуру
# межі decimal(10,2), coeffR decimal(6,2), coeffN decimal(10,2)
# параметри платників податків (сімейний стан, кількість дітей, річний заробіток)
# надсилаються клієнтом у форматі params=сімейний стан, кількість дітей, річний заробіток
# результати (сімейний стан, кількість дітей, річний заробіток, сума податку до сплати) надсилаються клієнту
# у форматі <податок>значення</податок>
# або у форматі <помилка>повідомлення</помилка>, якщо параметри недійсні

# сервер повертає клієнту неформатований текст
print "Content-Type: text/plain\n"

# визначення констант
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"


# створюється шар [metier]
# Здається, Python не підтримує сесії
# у PHP для збереження бізнес-об’єкта використовували б сесію
# тут його систематично створюють на основі даних з бази даних MySQL

# інстанціювання шару [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()

# отримуємо рядок, надісланий клієнтом на сервер
params=cgi.FieldStorage().getlist('params')
# якщо параметрів немає, то виникає помилка
if not params:
  print "<erreur>Le parametre [params] est absent<erreur>"
  sys.exit()

# обробляємо параметр params  
items=params[0].strip().lower().split(',')
# має бути лише 3 поля
if len(items)!=3:
  print "<erreur>[%s] : nombre de parametres invalide</erreur>" % (params[0])
  sys.exit()
# перший параметр (сімейний стан) повинен мати значення «так» або «ні»
marie=items[0].strip()
if marie!="oui" and marie != "non":
  print "<erreur>[%s] : 1er parametre invalide</erreur>\n"% (params[0])
  sys.exit()
# другий параметр (кількість дітей) має бути цілим числом
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])
# третій параметр (зарплата) повинен бути цілим числом
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])
# розраховується податок
impot=metier.calculer(marie,enfants,salaire)
# повертається результат
print "<impot>%s</impot>\n" % (impot)
# кінець

Примітки:

  • рядок 5: імпортуються об’єкти з файлу impots.py;
  • рядок 9: налагодження скрипту CGI може бути складним. Модуль cgitb у разі помилки надсилає причину збою. Для цього потрібно перенаправити стандартний вивід помилок (sys.stderr) на стандартний вивід (sys.stdout) (рядок 10);
  • рядок 26: заголовок Http, який визначає тип надсиланого документа, у даному випадку — неформатований текст. Веб-сервіс повертає свою відповідь у вигляді одного рядка тексту:
    • <erreur>message</erreur>, якщо сталася помилка;
    • <impot>valeur</impot>, де valeur — сума податку.
  • рядок 43: інстанціювання шарів [dao] та [metier];
  • рядки 44–46: у разі помилки під час створення екземплярів скрипт надсилає відповідь і завершується;
  • рядки 49–53: отримується параметр «params». Якщо його немає, скрипт надсилає відповідь і завершується;
  • рядок 56: параметр «oui,2,200000» розбивається на 3 поля в масиві items;
  • рядки 58–77: перевіряється правильність трьох полів. Якщо є помилка, скрипт надсилає відповідь і завершується;
  • рядок 79: обчислюється податок;
  • рядок 81: і надсилається клієнту.

У веб-браузері отримуємо такі результати:

13.2. Програмований клієнт


Програма (client_impots_web_01)


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

import httplib,urllib,re

# константи
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");

# вхід
connexion=httplib.HTTPConnection(HOST)
# відстеження
#connexion.set_debuglevel(1)
# цикл обробки даних, що надсилаються на сервер
for params in data:
    # параметри потрібно кодувати перед відправкою на сервер
    parametres = urllib.urlencode({'params': params})
    # відправлення запиту
    connexion.request("POST",URL,parametres)
    # обробка відповіді (текстовий рядок)
    reponse=connexion.getresponse().read()
    lignes=reponse.split("\n")
    # рядок тексту має вигляд
    # <impot>xxx</impot>
    # або <помилка>xxx</помилка>
    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
# завершення з'єднання
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