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()



