1.定义通讯协议
基于前面介绍过的 FLask Web 网站 与 urlib 的访问网站的方法,设计一个综合应用实例。它是一个基于 Web 的学生记录管理程序。
学生的记录包括 id(学号) 、 name(姓名) 、 grade(成绩), 服务器的作用是建立与维护一个Sqllite 的学生数据库 student.db 中的学生记录表 student。
服务器建立一个 Web 网站, 同时提供查询学生记录、增加学生记录、删除学生记录等接口服务。服务器为了与客户端通信,建立一个opt 的参数如下表:
opt值 | 含 义 |
init | 初始化学生表 |
insert | 增加学生 |
delete | 删除学生 |
update | 更改学生 |
select | 查询学生 |
opt 参数值 | 获取学生记录 |
规定如下:
如果客户端向服务器发送 opt="init" ,那么服务器创建 students 表,并返回是否创建成功,如果成功就返回 {"msg":"OK"}
如果客户端向服务器发送 opt="insert" , 同时发送id , name , grade 参数,那么服务器向数据库表插入一条学生记录,并返回是否插入成功信息,如果成功就返回 {"msg":"OK"}
如果客户端向服务器发送 opt="delete" , 同时发送 id 参数,那么服务器从数据库表中删除学号为 id 的一条学生记录,并返回是否删除成功的信息,如果删除成功就返回 {"msg":"OK"}
如果客户端向服务器发送 opt="update" , 同时发送 id 参数,那么服务器从数据库表中更改学号为 id 的一条学生记录,并返回是否更改成功的信息,如果更改成功就返回 {"msg":"OK"}
如果客户端向服务器发送 opt="select" , 同时发送id 参数,那么服务器从数据库表中查询学号为 id 的一条学生记录,并返回是否查询成功的信息,如果查询成功就返回 {"msg":"OK"}
如果客户端不向服务器发送 opt 参数值,那么服务器获取所有的学生记录返回给客户端,如果成功就返回 {"msg":"OK","data":"rows"} , 其中 rows 是学生的记录行的列表。
2.服务器程序
服务器程序server.py如下:
import flask
import sqlite3
import json
# 初始化一个Flask对象,参数__name__是程序的名称
app = flask.Flask(__name__)
class StudentDB:
def __init__(self):
self.cursor = None
self.con = None
# 通过学生类打开一个数据库,采用sqlite3.connect来连接
def openDB(self):
self.con = sqlite3.connect("students.db")
# 获取Cursor游标对象,用于执行sql语句并获得结果
self.cursor = self.con.cursor()
# 关闭连接
def closeDB(self):
self.con.commit()
self.con.close()
# 创建一个学生表
def initTable(self):
res = {}
try:
self.cursor.execute("create table students (id varchar(16) "
"primary key,name varchar(16),grade int)")
res["msg"] = "OK"
except Exception as err:
res["msg"] = str(err)
return res
# 插入学生
def insertRow(self, id, name, grade):
res = {}
try:
self.cursor.execute("insert into students (id,name,grade) "
"values(?,?,?)", (id, name, grade))
res["msg"] = "OK"
except Exception as err:
res["msg"] = str(err)
return res
# 删除学生
def deleteRow(self, id):
res = {}
try:
self.cursor.execute("delete from students where id=?", (id,))
res["msg"] = "OK"
except Exception as err:
res["msg"] = str(err)
return res
# 修改学生
def updateRow(self, id):
res = {}
try:
self.cursor.execute("update students set name=?,grade=? where id=?", (id,))
res["smg"] = "OK"
except Exception as err:
res["msg"] = str(err)
return res
# 获取学生的所有信息
def selectRows(self):
res = {}
try:
data = []
self.cursor.execute("select * from students order by id")
rows = self.cursor.fetchall() # 在 Python 中使用 fetchall() 从数据库文件中提取元素
for row in rows:
# 每一个学生记录都是一个字典
d = {"id": row[0], "name": row[1], "grade": row[2]}
data.append(d)
res["msg"] = "OK"
res["data"] = data
except Exception as err:
res["msg"] = str(err)
return res
@app.route("/", methods=["GET", "POST"])
def process():
# 获取opt的值
opt = flask.request.values.get("opt") if "opt" in flask.request.values else ""
res = {}
# 创建数据库
db = StudentDB()
db.openDB()
if opt == "init":
res = db.initTable()
elif opt == "insert":
id = flask.request.values.get("id") if "id" in flask.request.values else ""
name = flask.request.values.get("name") if "name" in flask.request.values else ""
grade = flask.request.values.get("grade") if "grade" in flask.request.values else ""
res = db.insertRow(id, name, grade)
elif opt == "delete":
id = flask.request.values.get("id") if "id" in flask.request.values else ""
res = db.deleteRow(id)
elif opt == "update":
id = flask.request.values.get("id") if "id" in flask.request.values else ""
res = db.updateRow(id)
else:
res = db.selectRows()
db.closeDB()
return json.dumps(res)
if __name__ == '__main__':
app.run()
3.客户端程序
客户端程序client.py如下:
import urllib.request
import urllib.parse
import json
# 创建一个student的对象
class Student:
def __init__(self, id, name, grade):
self.id = id
self.name = name
self.grade = grade
def show(self):
# 打印方法
print("%-16s %-16s %-4d" % (self.id, self.name, self.grade))
students = []
# server的网址
url = "http://127.0.0.1:5000"
# 显示主功能界面
def main():
print("=" * 15 + "主界面" + "=" * 14)
print("*" * 10 + "1-添加学生信息" + "*" * 10)
print("*" * 10 + "2-删除学生信息" + "*" * 10)
print("*" * 10 + "3-修改学生信息" + "*" * 10)
print("*" * 10 + "4-查询学生信息" + "*" * 10)
print("*" * 10 + "5-显示所有学生信息" + "*" * 7)
print("*" * 10 + "6-初始化学生列表" + "*" * 8)
print("*" * 10 + "0-退出系统" + "*" * 13)
print("=" * 33)
# 初始化
# 如果客户端向服务端发送opt="init",那么服务器创建students表,并返回是否创建成功,如果成功就返回{"msg":"OK"}
def initialize():
st = ""
try:
content = urllib.request.urlopen(url + "?opt=init")
st = content.read()
st = json.loads(st.decode())
st = st["msg"]
except Exception as err:
st = str(err)
if st == "OK":
print("初始成功")
else:
print(st)
return st
# 插入学生记录
# 如果客户端向服务器发送opt="insert",同时发送id、name、grade参数,那么服务器向数据库表插入一条学生记录,并返回是否插入成功信息,如果如果成功就返回{"msg":"OK"}
def insertRow():
# 获取学生的学号、姓名、成绩
id = input("id=")
name = input("name=")
while True:
grade = int(input("grade="))
if 0 <= grade <= 100:
break
else:
print("无效成绩!\n请重新输入 范围:0~100")
if id != "" and name != "":
s = Student(id, name, grade)
for x in students:
if x.id == id:
print(id + "已经存在")
return
st = ""
try:
# 调用远程数据
st = "id=" + urllib.parse.quote(id) + \
"&name=" + urllib.parse.quote(name) + \
"&grade=" + str(grade)
st = st.encode()
content = urllib.request.urlopen(url + "?opt=insert", st)
st = content.read()
st = json.loads(st.decode())
st = st["msg"]
except Exception as err:
st = str(err)
if st == "OK":
insertStudent(s)
print("添加成功")
else:
print(st)
else:
print("学号、姓名不能为空")
# 插入学生记录
def insertStudent(s):
global students
i = 0
while i < len(students) and s.id > students[i].id:
i += 1
# 判断表格里面是否存在
if i < len(students) and s.id == students[i].id:
print(s.id + "已经存在")
return False
students.insert(i, s)
return True
# 删除学生记录
# 如果客户端向服务器发送opt="delete",同时发送id参数,那么服务器从数据库表中删除学号为id的一条学生记录,并返回是否删除成功的信息,如果如果成功就返回{"msg":"OK"}
def deleteRow():
global students
id = input("id=")
if id != "":
for i in range(len(students)):
if students[i].id == id:
st = ""
try:
st = "id=" + urllib.parse.quote(id)
st = st.encode()
# 找到id就调用urllib.request.urlopen
content = urllib.request.urlopen(url + "?opt=delete", st)
st = content.readline()
# 通过json解析数据
st = json.loads(st.decode())
st = st["msg"]
except Exception as err:
st = str(err)
if st == "OK":
del students[i]
print("删除成功")
else:
print(st)
break
# 更新学生信息
def updateRow():
pass
# 查询学生信息
def selectRow():
pass
# 读取学生记录
def readStudents():
global students
try:
students.clear()
content = urllib.request.urlopen(url)
data = b"" # 二进制str变量
while True:
buf = content.read(1024) # 每次读取1024字节内容,并且指针指向末尾
if len(buf) > 0:
data += buf
else:
break
data = data.decode() # 解码 UTF-8
# 反系列结构化的数据
data = json.loads(data)
if data["msg"] == "OK":
data = data["data"] # data["data"]=[row0,row1.row2...]
for d in data:
# 每个d都是一个字典
s = Student(d["id"], d["name"], d["grade"])
students.append(s)
except Exception as err:
print(err)
# 显示所有的学生
def listStudents():
global students
print("%-16s %-16s %-4s" % ("id", "name", "grade"))
for s in students:
# 调用show函数
s.show()
try:
readStudents()
while True:
main() # 打印菜单
s = int(input("请选择(0,1,2,3,4,5,6):"))
if s == 0: # 退出系统
break
elif s == 1: # 添加学生信息
insertRow()
elif s == 2: # 删除学生信息
deleteRow()
elif s == 3: # 修改学生信息
updateRow()
elif s == 4: # 查询学生信息
selectRow()
elif s == 5: # 显示所有学生信息
listStudents()
elif s == 6:
initialize() # 初始化学生列表
except Exception as exp:
print(exp)
客户端结果实例: