——ATM项目 叠加未完善
1.项目的架构图

二 程序的架构设计
1、程序设计的好处
1)思路清晰
2)不会出现写一半代码时推翻重写
3)方便自己或以后的同事更好维护
2、三层架构设计的好处
1)把每个功能都分层三部分,逻辑清晰
2)如果用户更换不同的用户界面或不同,
的数据储存机制都不会影响接口层的核心
逻辑代码,扩展性强。
3)可以在接口层,准确的记录日志与流水。
3、三层架构
一 用户视图层
用于与用户交互的,可以接受用户的输入,打印接口返回的数据。
二 逻辑接口层
接受 用户视图层 传递过来的参数,根据逻辑判断调用数据层加以处理,
并返回一个结果给 用户视图层。
三 数据处理层
接受接口层传递过来的参数,做数据的
- 保存数据 save()
- 查看数据 select()
- 更新数据
- 删除数据
三.项目各功能具体流程
1.在用户视图层,接收用户输入的数据,交给接口层处理
2.逻辑接口层接收到用户视图层传来的数据,进行核心逻辑校验
3.在2的校验过程中,数据处理层会接到逻辑接口层传来的阐述,并对数据进行增删改查
4.数据处理层将处理完的数据传回给逻辑接口层并完成校验
5.完成校验的逻辑接口层将结果返回给用户视图层给用户一个回应
以登录功能为例:
1.用户输入用户名和密码,用户视图层将得到数据传给逻辑接口层进行判断
2.逻辑层查询数据层查看用户名是否存在,若存在则继续校验密码,不存在则返回结果给用户视图层,让用户重新输入
3.逻辑层继续校验密码,查询数据层数据,判断该用户名的密码与输入的密码是否一致,若不一致则返回密码不一致,若一致则返回登陆成功
四.ATM部分代码
用户视图层
from interface import user_interface from interface import bank_interface from interface import shop_interface from lib import common have_login = 0 # 注册功能 def register(): while True: user_name = input('请输出账号').strip() password = input('请输出密码').strip() password_two = input('请再次输入密码输出密码').strip() if not password.isdigit(): print('密码请输入数字哦') elif password == password_two: flag, msg = user_interface.register_interface(user_name, password) if flag: print(msg) break else: print(msg) print('再来一次') # 登录功能 def login(): while True: user_name = input('请输出账号').strip() password = input('请输出密码').strip() flag, msg = user_interface.user_login(user_name, password) if flag: global have_login have_login = user_name print(msg) break else: print(msg) # 查看余额 @common.logins def check_balance(): check=user_interface.check_money(have_login) print(f'{have_login},余额为{check}') # 提现功能 @common.logins def withdraw(): while True: money=input('请输入提现的金额') flag,msg=bank_interface.takemoney(have_login,money) if flag: print(msg) break else: print(msg) # 还款功能 @common.logins def repay(): money=input('请输入你想还款的数额') msg=bank_interface.up_interface(have_login,money) print(msg) # 转账功能 @common.logins def transfer(): to_name=input('请输入需要转移账户的姓名') to_money=input('请输入转账的金额') flag,msg=bank_interface.transfer_money(have_login,to_name,to_money) if flag: print(msg) else: print(msg) # 查看流水 @common.logins def check_flow(): flow=bank_interface.check_funwater(have_login) if flow: for i in flow: print(i) else: print('当前用户无流水') # 购物功能 shopping_car = {} # {‘商品名字‘:[’价格','数量']} @common.logins def shopping(): res_list=[ ['涛哥抱枕',10000], ['macbook',10000], ['雷克萨斯',30000] ] while True: global shopping_car for index,shop in enumerate(res_list): shop_name,shop_price=shop print('' f'商品编号{index}', f'商品名称{shop_name}', f'商品单价{shop_price}' '') #初始化购物车 choice=input('请输入商品编号').strip() choice_pay_or_addcar=input('添加购物车y:直接支付:n') if not choice.isdigit(): print('请输入数字') choice=int(choice) #判断choice是否存在列表中 if choice not in range(len(res_list)): print('请输入正确编号') continue #获取名称单价 shop_name,shop_price=res_list[choice] #------> 0-->['涛哥抱枕',10000],1-->['macbook',10000],2--->['雷克萨斯',30000](直接解压出来) #加入购物车------》y # 判断用户选择的商品是否重复添加添加过购物车否则默认为一 # {‘商品名字‘:[’价格','数量']} if choice_pay_or_addcar == "y": msg=shop_interface.add_car_interface(have_login,shopping_car) #有问题 shopping_car = {} # {‘商品名字‘:[’价格','数量']} print(msg) break #进支付功能接口 if choice_pay_or_addcar == 'n': if shop_name in shopping_car: shopping_car.get("shop_car")[shop_name][1]+=1 shopping_car[shop_name]=[shop_price,1] flag,msg=shop_interface.pay_interface(have_login,shopping_car) if flag: shopping_car = {} # {‘商品名字‘:[’价格','数量']} print(msg) break else: print(msg) break # 查看购物车 @common.logins def review_shopping_car(): msg=shop_interface.get_shopcar(have_login) print(msg) # 管理员 def admin(): pass new_dic = { '0': exit, '1': register, '2': login, '3': check_balance, '4': withdraw, '5': repay, '6': transfer, '7': check_flow, '8': shopping, '9': review_shopping_car, '10': admin, } def run(): while True: print(''' 0、退出 1、注册功能 2、登录功能 3、查看余额 4、提现功能 5、还款功能 6、转账功能 7、查看流水 8、购物功能 9、查看购物车 10、管理员功能 ''') choice = input('请输入编号').strip() if not choice.isdigit(): print('请输入正确数字') continue elif choice not in new_dic: print('你输入的数字有误') else: new_dic[choice]()
逻辑接口层
银行接口
from db import db_handler
from lib import common
bank_log=common.add_log("用户银行")
# 取钱
def takemoney(username, money):
user_dic = db_handler.judeg(username)
# 判断取钱的数量账户余额是否充足
account_mony = user_dic.get('balance')
number = int(money) * 1.05
haha = int(money) * 0.05
if account_mony >= number:
account_mony -= int(number)
user_dic['balance'] = account_mony
#记录流水
bank_log.info(f'{username}提取成功{money},手续费{int(haha)}')
res=f'{username}提取成功{money},手续费{int(haha)}'
user_dic.get('flow').append(res)
db_handler.save(user_dic)
return True, res
else:
return False, '账户余额不足请及时充值'
# 还款
def up_interface(username, money):
user_dic = db_handler.judeg(username)
if user_dic:
user_dic = db_handler.top_up(user_dic, money)
bank_log.info(f'{username},充值{money}成功')
res=f'{username},充值{money}成功'
user_dic.get('flow').append(res)
db_handler.save(user_dic)
return res
# 金钱转移
def transfer_money(usnaem, to_name, to_money):
user_dic = db_handler.judeg(usnaem)
to_user_dic = db_handler.judeg(to_name)
if to_user_dic:
user_money = user_dic.get('balance')
if eval(to_money) <= user_money:
user_money -= eval(to_money)
user_dic['balance'] = user_money
to_user_dic['balance'] += eval(to_money)
res=f'用户{usnaem}转账{to_name}金额{to_money}成功',f'用户{to_name}获得转账金额{to_money}成功'
bank_log.info(res)
user_dic.get('flow').append(res)
db_handler.save(user_dic)
db_handler.save(to_user_dic)
return True,res
else:
return False,f'金额不足请及时充值'
else:
return False,f'您转账的用户不存在'
#流水接口
def check_funwater(user):
user_dic=db_handler.judeg(user)
user_dic.get('flow')
return user_dic.get('flow')
购物接口
'''
购物接口interface
'''
from db import db_handler
from lib import common
shop_log=common.add_log('用户交易')
# 购物支付接口
def pay_interface(user_name,shopping_car): #{‘商品名字‘:[’价格','数量']}
'''
结账功能
:param user_name:
:param shopping_car:
:return:
'''
user_dic=db_handler.judeg(user_name)
for i in shopping_car:
res=shopping_car[i]
price=res[0]*res[1]
if user_dic["balance"] >= price:
user_dic['balance']-=price
shop_log.info(f'{user_name}购买{i}支付成功{price}元')
res = f'{user_name}购买{i}支付成功{price}元'
user_dic.get('flow').append(res)
db_handler.save(user_dic)
return True,res
else:
return False,'余额不足'
#添加购物车
def add_car_interface(username,shopping_car):
user_dic=db_handler.judeg(username)
user_dic.get('shop_car').update(shopping_car)
shop_log.info('添加购物车成功')
db_handler.save(user_dic)
return '添加购物车成功'
#查询购物车接口
def get_shopcar(usernaem):
user_dic=db_handler.judeg(usernaem)
res=user_dic.get("shop_car")
return res
用户接口
from db import db_handler
from lib import common
user_log=common.add_log('用户注册')
#用户注册
def register_interface(user_name,password,balance=15000):
user_dic=db_handler.judeg(user_name)
if user_dic:
return False,'用户存在'
#加密操作
password=common.pwd_md5(password)
user_dic = {
'username': user_name,
'password': password,
'balance': balance,
# 用于记录用户流水
'flow': [],
# 用于记录购物车
'shop_car': {},
# locked:用于记录用户是否被冻结
# false:未冻结
'locked': False
}
db_handler.save(user_dic)
user_log.info(f'{user_name}用户注册成功')
return True,f'{user_name}用户注册成功'
#用户登录
def user_login(username,password):
user_dic=db_handler.judeg(username)
if user_dic:
password=common.pwd_md5(password)
if password==user_dic.get("password"):
user_log.info(f'{username}登录成功')
return True,f'{username}登录成功'
else:
return False,'账号密码错误'
return False,'用户不存在'
#用户余额查询
def check_money(username):
user_dic=db_handler.judeg(username)
res=user_dic.get("balance")
return res
数据处理层
|--user_data(用户数据)
|----|--------用户数据文件.json
|----|--------用户数据文件.json
|-----|--------用户数据文件.json
db_handle
import json import os from conf import settings #查看用户是否存在(存在返回字典用于今后调用此接口的能拿到字典内容 不存在自动返回None 其他都是返回True) def judeg(user_naem): user_path=os.path.join(settings.USER_PATH,f'{user_naem}.json') if os.path.exists(user_path): with open(user_path,mode='r',encoding='utf8')as f: res=json.load(f) return res #保存数据 def save(user_dic): username=user_dic.get('username') userpath=os.path.join(settings.USER_PATH,f'{username}.json') with open(userpath,mode='w',encoding='utf8')as f: json.dump(user_dic,f,ensure_ascii=False)#字典内就可以输入中文了 #还款 def top_up(user_dic,money): user_dic['balance']+=int(money) return user_dic
lib公用方法
common
import hashlib
import logging.config
from conf import settings
# 登入认证装饰器
def logins(func):
from core import src
def wrapper(*args,**kwargs):
if src.have_login:
res=func(*args,**kwargs)
return res
else:
print('您还未登入无法享受服务请登录吧')
src.login()
return wrapper
#加密加盐
def pwd_md5(password):
res=hashlib.md5()
res.update('天王盖地虎'.encode('utf8'))#记得编编码处理uodate() md5今晚再练习几遍
res.update(password.encode('utf8'))
res.update('宝塔阵河妖'.encode('utf8'))
return res.hexdigest() #提取追后全部列表结果的加密程序
#添加日志功能
def add_log(user_type):
'''
各个接口添加日志
:param user_type:
:return:
'''
# 加载日志配置信息
logging.config.dictConfig(
settings.LOGGING_DIC
)
# 获取日志对象
logger=logging.getLogger(user_type)
print(logger)
return logger
日志log
conf \ settings
import os #文件基础路劲 BASE_PATH=os.path.dirname(os.path.dirname(__file__)) #获取文件数据库路径 USER_PATH=os.path.join(BASE_PATH,'db','user_data') """ logging配置 """ import os # 1、定义三种日志输出格式,日志中可能用到的格式化串如下 # %(name)s Logger的名字 # %(levelno)s 数字形式的日志级别 # %(levelname)s 文本形式的日志级别 # %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有 # %(filename)s 调用日志输出函数的模块的文件名 # %(module)s 调用日志输出函数的模块名 # %(funcName)s 调用日志输出函数的函数名 # %(lineno)d 调用日志输出函数的语句所在的代码行 # %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示 # %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数 # %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒 # %(thread)d 线程ID。可能没有 # %(threadName)s 线程名。可能没有 # %(process)d 进程ID。可能没有 # %(message)s用户输出的消息 # 2、强调:其中的%(name)s为getlogger时指定的名字 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \ '[%(levelname)s][%(message)s]' simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s' test_format = '%(asctime)s] %(message)s' BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # log文件的目录 LOG_PATH = os.path.join(BASE_DIR,'log','a1.log') LOG_PATH_TWO=os.path.join(BASE_DIR,'log','a2.log') # 3、日志配置字典 LOGGING_DIC = { 'version': 1, 'disable_existing_loggers': False, #设置日志的格式 'formatters': { 'standard': { 'format': standard_format }, 'simple': { 'format': simple_format }, 'test': { 'format': test_format }, }, 'filters': {}, # handlers是日志的接收者,不同的handler会将日志输出到不同的位置 'handlers': { #打印到终端的日志 'console': { 'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, #打印到文件的日志,收集info及以上的日志 'default': { 'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,日志轮转 'formatter': 'standard', # 可以定制日志文件路径 'filename':LOG_PATH, # 日志文件 'maxBytes': 1024*1024*5, # 日志大小 5M 'backupCount': 5,#指定文件最多备份几份 'encoding': 'utf-8',# 日志文件的编码,再也不用担心中文log乱码了 }, 'other': { 'level': 'DEBUG', 'class': 'logging.FileHandler', # 保存到文件 'formatter': 'test', 'filename': LOG_PATH_TWO, 'encoding': 'utf-8', }, }, # loggers是日志的产生者,产生的日志会传递给handler然后控制输出 'loggers': { #logging.getLogger(__name__)拿到的logger配置 '用户交易': { 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制) 'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递 }, '': { 'handlers': ['default','other'], 'level': 'DEBUG', 'propagate': False, }, }, }
log下
a1
a2 #等日志文件
start(开始文件)
from core import src if __name__ == '__main__': src.run()
readme
#**项目说明书** ##项目:ATM+购物车 # 项目需求: 1.额度15000或自定义 --> 注册功能 2.实现购物商城,买东西加入购物车,调用信用卡接口结账 --> 购物功能、支付功能 3.可以提现,手续费5% --> 提现功能 4.支持多账户登录 --> 登录功能 5.支持账户间转账 --> 转账功能 6.记录日常消费 --> 记录流水功能 7.提供还款接口 --> 还款功能 8.ATM记录操作日志 --> 记录日志功能 9.提供管理接口,包括添加账户、用户额度,冻结账户等。。。 ---> 管理员功能 10.用户认证用装饰器 --> 登录认证装饰器 ## "用户视图层" 展示给用户选择的功能 1、注册功能 2、登录功能 3、查看余额 4、提现功能 5、还款功能 6、转账功能 7、查看流水 8、购物功能 9、查看购物车 10、管理员功能 # 一个项目是如何从无到有 ## 一 需求分析 1.拿到项目,会先在客户那里一起讨论需求, 商量项目的功能是否能实现,周期与价格,得到一个需求文档。 2.最后在公司内部需要开一次会议,最终得到一个开发文档, 交给不同岗位的程序员进行开发。 - Python: 后端,爬虫 - 不同的岗位: - UI界面设计: - 设计软件的布局,会分局软件的外观切成一张张图片。 - 前端: - 拿到UI交给他的图片,然后去搭建网页面。 - 设计一些页面中,哪些位置需要接收数据,需要进行数据交互。 - 后端: - 直接核心的业务逻辑,调度数据库进行数据的增删查改。 - 测试: - 会给代码进行全面测试,比如压力测试,界面测试(CF卡箱子)。 - 运维: - 部署项目。 ## 二 程序的架构设计 ### 1、程序设计的好处 1)思路清晰 2)不会出现写一半代码时推翻重写 3)方便自己或以后的同事更好维护 ### 2、三层架构设计的好处 1)把每个功能都分层三部分,逻辑清晰 2)如果用户更换不同的用户界面或不同, 的数据储存机制都不会影响接口层的核心 逻辑代码,扩展性强。 3)可以在接口层,准确的记录日志与流水。 ### 3、三层架构 #### 一 用户视图层 用于与用户交互的,可以接受用户的输入,打印接口返回的数据。 #### 二 逻辑接口层 接受 用户视图层 传递过来的参数,根据逻辑判断调用数据层加以处理, 并返回一个结果给 用户视图层。 #### 三 数据处理层 接受接口层传递过来的参数,进行数据处理 - 保存数据 save() - 查看数据 select() - 更新数据 - 删除数据 ## 三 分任务开发 ## 四 测试 ## 五 上线 # 统计代码 file ---> settings ---> Plugins --->
A-用户视图层 B-逻辑接口层 C-数据处理层
注册功能:
A接受用户输入数据,进行小逻辑判断,判断俩次密码输入是否一致,不一致让用户重新输,一致就将用户名和密码传给B,
B把数据传给C,C进行数据查找,有就返回给B字典,没就返回None,B根据返回的结果进行处理,如果返回的是字典就将用
户已经存在的结果返回给A,A打印结果给用户;如果是None就让C把用户数据进行保存,然后返回将结果返回给A,A打印给
用户结果。
登录功能:
A接受用户输入数据,将数据传给B,B将数据传给C,C进行数据查找返回结果给B,如果是None,B就将结果返回给A,A打印结果
给用户,如果返回是字典,就判断密码是否一致,然后将结果返回给A,A打印结果给用户
查询余额:
因为有登录装饰器,能使用该功能的用户已经登录,使用该功能时,A将全局变量的中的用户名传给B,B把数据传给C进行数据
查找,查找完的结果给B,B将用户的金额返回给A,A打印结果给用户
提现功能:
因为有登录装饰器,能使用该功能的用户已经登录,A接受用户传入的数据后给B,B通过把登录的用户传给C进行数据的查找,将
查找的结果返回给B,B过去用户金额,和提现金额进行比对,若用户提现金额加手续费大于用户余额,则返回给A用户金额不足;若
用户余额大于用户提现金额加手续费,则进行数据处理,将余额减去提现金额加手续费,让后将数据传给C,让C进行保存覆盖以前的
数据,B还将结果返回给A,A打印给用户结果

浙公网安备 33010602011771号