Skip to content

13. 练习 [IMPOTS] 配合服务 WEB

我们回到练习题 [IMPOTS],该题已在第 4.24.38 10 节中讨论过。

13.1. 服务器

我们处于以下客户端-服务器架构中:

在服务器端,我们将再次采用三层架构。[dao]层将由ImpotsMySQL类实现,该类已在第10节中与SGBD和MySQL一起使用。 [metier]层将由之前已探讨过的[ImpotsMetier]类实现。 因此,剩下的工作就是编写Web服务。该服务从客户端接收一个名为params的参数,格式为params= yes,2,200000,其中第一个元素表示纳税人是否已婚,第二个表示子女数量,第三个表示年薪。

Web服务代码如下(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

# ------------------------------------------------ 
# 税务Web服务
# ------------------------------------------------ 

# 计算税款所需的数据已放入表 mysqL TABLE
# 该表属于数据库 BASE。该表的结构如下
# 限制 decimal(10,2),coeffR decimal(6,2),coeffN decimal(10,2)
# 纳税人的参数(婚姻状况、子女数量、年薪)
# 由客户端以 params=婚姻状况, 子女数量, 年薪 的形式发送
# 结果(婚姻状况、子女数量、年薪、应缴税款)将返回给客户端
# 以 <税款>数值</税款> 的形式返回
# 若参数无效,则以 <错误>msg</错误> 的形式返回

# 服务器向客户端返回未格式化的文本
print "Content-Type: text/plain\n"

# 常量定义
USER="root"
PWD=""
HOTE="localhost"
BASE="dbimpots"
TABLE="impots"


# 创建 [metier] 层
# Python似乎不支持会话
# 在 PHP 中,本应使用会话来存储业务对象
# 在此处,我们系统地根据数据库数据构建它MySQL

# QZXW2HTML层的实例化 BW21ldGllcl0ZQX
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 标头用于确定发送文档的类型,此处为未格式化的文本。Web 服务将响应以单行文本的形式返回:
    • 若发生错误,则返回 <erreur>message</erreur>
    • <impot>valeur</impot>,其中 valeur 为税额。
  • 第 43 行:实例化 [dao] 和 [metier] 层;
  • 第 44-46 行:若实例化出现错误,脚本将发送响应并终止;
  • 第 49-53 行:获取 'params' 参数。若该参数不存在,脚本将返回响应并终止;
  • 第 56 行:将参数 'oui,2,200000' 拆分为 items 数组中的 3 个字段
  • 第58-77行:验证这3个字段的有效性。若存在错误,脚本将返回响应并终止;
  • 第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>
    # 或 <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()

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