26、ATM项目的编写流程
1、搭建项目的目录规范
- ATM 项目根目录
- readme.md 项目的说明书
- start.py 项目启动文件
- conf 配置文件
- settings.py
- lib 公共方法文件
- common.py
- core(用户视图层) 存放用户视图层代码文件
- src.py
- interface(逻辑接口层) 存放核心业务逻辑代码
- user_interface.py 用户相关的接口
- bank_interface.py 银行相关的接口
- shop_interface.py 购物相关的接口
- db(数据处理层) 存放数据与数据处理层代码
- db_handler.py 数据处理层代码
- user_data 用户数据
- log 存放日志文件
2.1、启动项的编写
启动文件——start文件——先将解释器添加到环境变量
sys.path.append(
os.path.dirname(__file__)
)
2.2、启动文件——start文件——导入用户视层图
from core import src
2.3、启动文件——start文件——编写开启项目启动函数
if __name__ == '__main__':
2.4、启动文件——start文件——先执行用户视层图
src.run()
3.1、获取项目根目录路径
BASE_PATH = os.path.dirname( os.path.dirname(__file__) )
3.2、获取user_data文件夹目录路径
USER_DATA_PATH = os.path.join( BASE_PATH, 'db', 'user_data')
4.2.13、用户视图层core——src.py——视图层主程序的编写
def run(): while True: print(''' ===== ATM + 购物车 ===== 1、注册功能 2、登录功能 3、查看余额 4、提现功能 5、还款功能 6、转账功能 7、查看流水 8、购物功能 9、查看购物车 10、管理员功能 ========= end ========= ''')
4.2.13、用户视图层core——src.py——各种功能的空函数
# 1、注册功能 def register(): # 2、登录功能 def login(): # 3、查看余额 @common.login_auth def check_balance(): # 4、提现功能 @common.login_auth def withdraw(): # 5、还款功能 @common.login_auth def repay(): # 6、转账功能 @common.login_auth def transfer(): # 7、查看流水 @common.login_auth def check_flow(): # 8、购物功能 @common.login_auth def shopping(): # 9、查看购物车 @common.login_auth def check_shop_car(): # 10、管理员功能(考试额外加分项) @common.login_auth def admin():
4.2.12、用户视图层core——src.py——创建函数功能字典
func_dic = {
'1': register,
'2': login,
'3': check_balance,
'4': withdraw,
'5': repay,
'6': transfer,
'7': check_flow,
'8': shopping,
'9': check_shop_car,
'10': admin,
}
4.2.13.1、用户视图层core——src.py——视图层主程序的编写——让用户选择功能编号
choice = input('请输入功能编号: ').strip()
4.2.13.2、用户视图层core——src.py——视图层主程序的编写——判断功能编号是否存在
if choice not in func_dic: print('请输入正确的功能编号!') continue
4.2.13.3、用户视图层core——src.py——视图层主程序的编写——调用选择的函数功能
func_dic.get(choice)()
4.2.2、用户视图层core——src.py——注册功能
从interface中调用到user_interface
form interface import user_interface
def register(): while True: username = input('请输入用户名: ').strip() password = input('请输入密码: ').strip() re_password = input('请确认密码: ').strip() if password == re_password:
4.2、用户视图层core——src.py——将数据接口的模块导入
from interface import user_interface from interface import bank_interface from interface import shop_interface from lib import common
6.4.2.2、逻辑接口层interface——user_interface.py——注册接口——判断用户是否存在
保存数据时需要做加密处理
def register_interface(username, password, balance=15000): # 2)查看用户是否存在 # 2.1) 调用 数据处理层 中的 select函数,会返回 用户字典 或 None user_dic = db_handler.select(username) # {user: user, pwd: pwd...} or None # 若用户存在,则return,告诉用户重新输入 if user_dic: # return (False, '用户名已存在!') return False, '用户名已存在!'
7.1.1、公共文件lib——common.py——md5加密
import hashlib # md5加密 def get_pwd_md5(password): md5_obj = hashlib.md5() md5_obj.update(password.encode('utf-8')) salt = '一二三四五,Egon上山打老鼠!' md5_obj.update(salt.encode('utf-8')) return md5_obj.hexdigest()
6.4.2.1、逻辑接口层interface——user_interface.py——注册接口——给用户输入的密码做一次加密
# 3)若用户不存在,则保存用户数据 # 做密码加密 password = common.get_pwd_md5(password) # 3.1) 组织用户的数据的字典信息 user_dic = { 'username': username, 'password': password, 'balance': balance, # 用于记录用户流水的列表 'flow': [], # 用于记录用户购物车 'shop_car': {}, # locked:用于记录用户是否被冻结 # False: 未冻结 True: 已被冻结 'locked': False } # 3.2)保存数据 db_handler.save(user_dic) msg = f'{username} 注册成功!' # 3.3)记录日志 user_logger.info(msg) return True, msg
注册接口将会传递一个username,给数据处理层,去确定是否已经被注册
5.2.1、数据处理层db——db_handler.py——查看数据
需要从settings调用地址
使用os内置函数
import os
from conf import settings
# 1) 接收接口层传过来的username用户名,拼接用户json文件路径
user_path = os.path.join(
settings.USER_DATA_PATH, f'{username}.json'
)
# 2)校验用户json文件是否存在
if os.path.exists(user_path):
# 3) 打开数据,并返回给接口层
with open(user_path, 'r', encoding='utf-8') as f:
user_dic = json.load(f)
return user_dic
5.2.2、数据处理层db——db_handler.py——保存数据
使用json函数
import json
# 保存数据(添加新数据或者更新数据) def save(user_dic): # 1) 拼接用户的数据字典 username = user_dic.get('username') # 根据用户的名字,拼接 用户名.json 文件路径 user_path = os.path.join( settings.USER_DATA_PATH, f'{username}.json' ) # 2) 保存用户数据 with open(user_path, 'w', encoding='utf-8') as f: # ensure_ascii=False让文件中的中文数据,显示更美观 json.dump(user_dic, f, ensure_ascii=False)
4.2.3.1、用户视图层——core——src.py——让用户输入用户名与密码
、登录功能 def login(): # 登录视图 while True: # 1) 让用户输入用户名与密码 username = input('请输入用户名: ').strip() password = input('请输入密码: ').strip()
需要通过接口层的登录接口验证账户是否存在
6.4.3、用户接口层——interface——user_inteerface——登录接口
# 登录接口 def login_interface(username, password): # 1) 先查看当前用户数据是否存在 # {用户数据字典} or None user_dic = db_handler.select(username) # 2) 判断用户是否存在 if user_dic: # 若有冻结用户,则需要判断是否被锁定 if user_dic.get('locked'): return False, '当前用户已被锁定' # 给用户输入的密码做一次加密 password = common.get_pwd_md5(password) # 3) 校验密码是否一致 if password == user_dic.get('password'): msg = f'用户: [{username}] 登录成功!' user_logger.info(msg) return True, msg else: msg = f'用户: [{username}]密码错误!' user_logger.warn(msg) return False, msg msg = f'用户: [{username}]用户不存在,请重新输入!!' return False, msg
通过登录功能验证后,继续编写登录功能
4.2.3.2、用户视图层——core——src.py——调用接口层,将数据传给登录接口
# 2) 调用接口层的注册接口,将用户名与密码交给接口层来进行处理 # res ---> (False, '用户名已存在!') # res = user_interface.register_interface( # flag, msg ---> (flag---> False, msg --> '用户名已存在!') # (True, 用户注册成功), (False, 注册失败) flag, msg = user_interface.register_interface( username, password ) # 3) 根据flag判断用户注册是否成功,flag控制break的结束 if flag: print(msg)
global login_user
login_user = username break else: print(msg)
7.1.2、公共文件lib——common.py——登录认证装饰器
def login_auth(func): from core import src def inner(*args, **kwargs): if src.login_user: res = func(*args, **kwargs) return res else: print('未出示证明,无法享受美好的功能服务!') src.login() return inner