13. تمرین [IMPOTS] با استفاده از سرویس WEB
به تمرین [IMPOTS] بازمیگردیم که پیش از این در بخشهای 4.2، 4.3، 8 و 10 پوشش داده شده است.
![]() |
13.1. سرور
ما در چارچوب معماری کلاینت-سرور زیر کار میکنیم:
![]() |
در سمت سرور، یک بار دیگر از معماری سهلایه استفاده خواهیم کرد. لایه [dao] توسط کلاس ImpotsMySQL که در نسخه دارای SGBD و MySQL در پاراگراف ۱۰ استفاده شده است، پیادهسازی خواهد شد. لایه [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)
#پارامترهای اشخاص مشمول مالیات (وضعیت تأهل، تعداد فرزندان، حقوق سالانه)
#توسط مشتری در قالب پارامترها=وضعیت تأهل، تعداد فرزندان، حقوق سالانه ارسال میشوند
#نتایج (وضعیت تأهل، تعداد فرزندان، حقوق سالانه، مالیات قابل پرداخت) به مشتری بازگردانده میشوند
# در قالب <tax>value</tax>
#یا در قالب <error>msg</error>، اگر پارامترها نامعتبر باشند
# سرور متن بدون قالببندی را به کلاینت بازمیگرداند
print "Content-Type: text/plain\n"
# تعریف ثابتها
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"
#لایه [metier] ایجاد میشود
# پایتون به نظر نمیرسد از جلسات پشتیبانی کند
#در 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(',')
# فقط باید ۳ فیلد وجود داشته باشد
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)
# پایان
یادداشتها:
- خط ۵: اشیاء از فایل impots.py وارد میشوند؛
- خط ۹: اشکالزدایی یک اسکریپت CGI میتواند مشکلساز باشد. ماژول cgitb در صورت بروز خطا، دلیل خرابی را ارسال میکند. برای این کار، خروجی استاندارد خطا (sys.stderr) باید به خروجی استاندارد (sys.stdout) (خط ۱۰) هدایت شود؛
- خط 26: هدر HTTP که نوع سند ارسالی را مشخص میکند، در این مورد متن بدون قالببندی. سرویس وب پاسخ خود را به صورت یک خط متن بازمیگرداند:
- <erreur>message</erreur> در صورت وجود خطا؛
- <impot>valeur</impot>، که در آن valeur مبلغ مالیات است.
- خط ۴۳: نمونهسازی لایههای [dao] و [metier]؛
- خطوط ۴۴–۴۶: اگر در حین نمونهسازی خطایی رخ دهد، اسکریپت پاسخ خود را ارسال کرده و متوقف میشود؛
- خطوط ۴۹–۵۳: پارامتر 'params' بازیابی میشود. اگر این پارامتر وجود نداشته باشد، اسکریپت پاسخ خود را بازمیگرداند و متوقف میشود؛
- خط ۵۶: پارامتر 'yes,2,200000' در آرایه 'items' به ۳ فیلد تقسیم میشود؛
- خطوط ۵۸–۷۷: اعتبار سه فیلد بررسی میشود. اگر خطایی وجود داشته باشد، اسکریپت پاسخ خود را ارسال کرده و متوقف میشود؛
- خط ۷۹: مالیات محاسبه میشود؛
- خط ۸۱: و برای کلاینت ارسال میشود.
در یک مرورگر وب، نتایج زیر به دست میآید:
![]() | ![]() |
13.2. یک کلاینت برنامهریزیشده
# -*- 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")
# خط متنی به شکل زیر است
# <tax>xxx</tax>
# یا <error>xxx</error>
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()



