文章目录
一、开发前准备
创建ATM
文件夹,并在其下创建readme.md
文件,作为说明
# 项目说明书
##项目:ATM+购物车
# 项目需求
模拟实现一个ATM + 购物商城程序
1. 额度 15000或自定义 注册功能
2. 实现购物商城,买东西加入 购物车,调用信用卡接口结账 购物功能,支付功能
3. 可以提现,手续费5% 提现功能
4. 支持多账户登录 登录功能
5. 支持账户间转账 转账功能
6. 记录日常消费 记录流水功能
7. 提供还款接口 还款功能
8. 用户认证用装饰器 登录认证装饰器
# 一个项目如何从无到有
## 一 需求分析
1. 拿到项目,会先在客户那里一起讨论需求
商量项目的功能是否能实现,周期与价格,得到一个需求文档
2. 最后在公司内部开会,得到一个开发文档
交给不同岗位的程序员进行开发
- 不同的岗位
- UI界面设计:
- 设计软件的布局,会根据软件的外观切成一张张图片
- 前端
- 拿到UI交给他的图片,然后去搭建网页
- 设计一些页面中,哪些位置需要接受数据,需要进行数据交互
- 后端
- 直接核心的业务逻辑,调度数据库进行数据的增删查改
- 测试
- 会给代码进行全面测试,比如压力测试,界面测试
- 运维
- 部署项目
## 二 程序的架构设计
1. 程序设计的好处
1. 思路清晰
2. 不会出现写一半代码时推翻重写
3. 方便自己或以后的同事更好维护
2. 三层架构设计的好处
1. 把每个功能都分为三部分,逻辑清晰
2. 如果用户更换不同的用户界面或不同的数据存储机制
都不会影响接口层的核心逻辑代码,扩展性强
3. 可以在接口层,准确的记录日志和流水
3. 三层架构
1. 用户视图层
用于与用户交互的,可以接受用户的输入,打印接口返回的数据
2. 逻辑接口层
接收用户视图层传递过来的参数,根据逻辑判断调用数据层加以处理
并返回一个结果给用户视图层
3. 数据处理层
接受接口层传递过来的参数,做数据的增删查改
## 三 分任务开发
## 四 测试
## 五 上线
用户视图层展示给用户选择的功能
1. 注册功能
2. 登录功能
3. 查看余额
4. 提现功能
5. 还款功能
6. 转账功能
7. 查看流水
8. 购物功能
9. 查看购物车
分层结构示意图
二、软件目录架构搭建
创建如下目录结构
ATM
- conf
- settings.py # 存放配置信息
- core
- src.py # 用户视图层
- db
- db_handle.py # 数据处理层
- interface
- user_interface # 逻辑接口层,专门处理用户相关逻辑接口
- bank_interface # 逻辑接口层,专门处理银行相关逻辑接口
- shop_interface # 逻辑接口层,专门处理购物相关逻辑接口
- lib
- common.py # 存放公共方法
start.py # 程序入口,项目启动文件
三、代码开发
在start.py
中
'''
程序的入口
'''
import os
import sys
# 添加环境变量
sys.path.append(os.path.dirname(__file__))
from core import src
# 开始执行项目函数
if __name__ == '__main__':
# 1. 先执行用户视图层
src.run()
在core/src.py
中
'''
用户视图层
'''
# 1.注册功能
def register():
pass
# 2.登录功能
def login():
pass
# 3.查看余额
def check_balance():
pass
# 4.提现功能
def withdraw():
pass
# 5.还款功能
def repay():
pass
# 6.转账功能
def transfer():
pass
# 7.查看流水
def check_flow():
pass
# 8.购物功能
def shopping():
pass
# 9.查看购物车
def check_shop_car():
pass
# 10.清空购物车
def clean_shop_car():
pass
# 创建函数功能字典
func_dict = {
'1':register,
'2':login,
'3':check_balance,
'4':withdraw,
'5':repay,
'6':transfer,
'7':check_flow,
'8':shopping,
'9':check_shop_car,
'10':clean_shop_car
}
# 视图层主程序
def run():
while True:
print('''
========ATM+购物车===========
1. 注册功能
2. 登录功能
3. 查看余额
4. 提现功能
5. 还款功能
6. 转账功能
7. 查看流水
8. 购物功能
9. 查看购物车
========ATM+购物车===========
''')
choice = input('请输入功能编号:').strip()
if choice not in func_dict:
print('请输入正确的功能编号')
continue
func_dict.get(choice)() # func_dict.get('1')() ---> register()
3.1 注册功能
为了方便保存用户信息,在db
目录下创建user_data
目录,用来保存以用户名.json的文件,该文件用来保存注册用户的相关信息,为了方便查找,在配置文件conf/settings.py
中配置好路径信息
# conf/settings.py
'''
存放配置信息
'''
import os
# 获取项目根目录目录路径
BASE_PATH = os.path.dirname(
os.path.dirname(__file__)
)
# 获取user_data文件夹目录路径
USER_DATA_PATH = os.path.join(
BASE_PATH,'db','user_data'
)
3.1.1 注册功能简单版
'''
用户视图层
'''
# 1.注册功能
def register():
while True:
# 1. 让用户输入用户名和密码进行校验
username = input('请输入用户名').strip()
password = input('请输入密码').strip()
re_password = input('请确认密码').strip()
# 小的逻辑处理:比如两次密码是否一致
if password == re_password:
# 2. 查看用户是否存在
import json
import os
from conf import settings
# 4.2 拼接用户的json文件路径
user_path = os.path.join(
settings.USER_DATA_PATH, f'{username}.json'
)
# 3. 若用户存在,则让用户重新输入
if os.path.exists(user_path):
print('用户已存在,请重新输入')
continue
# 4. 若用户不存在,则保存用户数据
# 4.1 组织用户的数据的字典信息
user_dic = {
'username':username,
'password':password,
'balance':15000,
# 用于记录用户流水的列表
'flow':[],
# 用于记录用户购物车
'shop_car':{},
# locked:用于记录用户是否被冻结
# False:未冻结 True:已被冻结
'locked':False
}
with open(user_path,'w',encoding='utf-8') as f:
json.dump(user_dic,f,ensure_ascii=False)
print('用户注册成功')
break
print('密码和确认密码不一致,请重新输入')
3.1.2 将功能分层
core/src.py
中
from interface import user_interface
def register():
while True:
# 1. 让用户输入用户名和密码进行校验
username = input('请输入用户名').strip()
password = input('请输入密码').strip()
re_password = input('请确认密码').strip()
# 小的逻辑处理:比如两次密码是否一致
if password == re_password:
flag,msg = user_interface.register_interface(username,password)
if flag:
print(msg)
break
print(msg)
continue
print('两次密码不一致')
interface/user_interface.py
中
'''
逻辑接口层
用户相关接口
'''
from db import db_handle
from lib import common
# 注册接口
def register_interface(username,password,balance=15000):
# 1. 查看用户是否已经存在
data = db_handle.select(username)
# 2. 若用户存在,则让用户重新输入
if data:
return False,'用户已存在'
# 3. 若用户不存在,则保存用户数据
# 3.1 组织用户的数据的字典信息
# 对密码加密
password = common.get_pwd_md5(password)
user_dic = {
'username': username,
'password': password,
'balance': balance,
# 用于记录用户流水的列表
'flow': [],
# 用于记录用户购物车
'shop_car': {},
# locked:用于记录用户是否被冻结
# False:未冻结 True:已被冻结
'locked': False
}
# 保存用户数据
db_handle.save(user_dic)
return True,f'{username}注册成功'
lib/common
中
'''
存放公共方法
'''
import hashlib
from conf import settings
# md5加密
def get_pwd_md5(password):
md5_obj = hashlib.md5()
md5_obj.update(password.encode('utf-8'))
salt = settings.SALT
md5_obj.update(salt.encode('utf-8'))
return md5_obj.hexdigest()
conf/settings.py
中
# 盐值
SALT = '我是木易'
db/db_handle.py
中
'''
数据处理层
专门用于处理数据
'''
import json
import os
from conf import settings
# 查看数据
def select(username):
# 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
# 不return,默认返回None
# 保存数据
def save(user_dic):
# 1. 拼接用户的数据字典
username = user_dic.get('username')
user_path = os.path.join(
settings.USER_DATA_PATH, f'{username}.json'
)
# 2. 保存用户数据
with open(user_path, 'w', encoding='utf-8') as f:
json.dump(user_dic, f, ensure_ascii=False)
3.2 登录功能
在core/src.py
中
# 定义全局变量 记录登录用户名
login_user = None
# 2.登录功能
def login():
while True:
# 1. 接收用户输入的用户名和密码
username = input('请输入用户名').strip()
password = input('请输入密码').strip()
# 2. 调用接口层进行处理
flag,msg = user_interface.login_interface(username,password)
# 用户登录成功,提示信息,退出循环
if flag:
print(msg)
global login_user
login_user = username
break
# 登录失败,提示信息
print(msg)
在interface/user_interface
中
# 登录接口
def login_interface(username,password):
# 1. 先查看用户是否存在
data = db_handle.select(username)
if data:
# 2. 用户存在则判断密码是否正确
# 先对密码加密
password = common.get_pwd_md5(password)
if password == data.get('password'):
return True,f'{username}登录成功'
return False,'密码错误'
# 3. 用户不存在则返回错误
return False,f'{username}用户不存在'
3.3 登录认证装饰器
在lib/common
中
from core import src
# 登录认证装饰器
def login_auth(func):
def inner(*args,**kwargs):
if src.login_user:
res = func(*args,**kwargs)
return res
print('您还未登录,请先登录!')
src.login()
return inner
3.4 查看余额功能
在core/src.py
中
from lib import common
# 3.查看余额
@common.login_auth
def check_balance():
# 直接调用查看余额接口,获取用户余额
flag,balance = user_interface.check_balance_interface(login_user)
if flag:
print(f'用户{login_user}的账户余额为:{balance}')
else:
print('这个用户出了点状况')
在interface/user_interface.py
中
# 查看余额接口
def check_balance_interface(username):
data = db_handle.select(username)
if data:
return True,data.get('balance')
return False,'哦豁,出错了
3.5 提现功能
在core/src.py
中
from interface import bank_interface
from lib import common
# 4.提现功能
@common.login_auth
def withdraw():
while True:
# 1. 让用户输入提现金额
money = input('请输入提现金额:').strip()
# 2. 判断用户输入的金额是否是数字
if not money.isdigit():
print('请重新输入,提现金额必须为数字:')
continue
# 3. 调用接口层的接口进行处理
flag, msg = bank_interface.withdraw_interface(login_user,int(money))
if flag:
print(msg)
break
else:
print(msg)
在interface/bank_interface.py
中
'''
逻辑接口层
银行相关业务接口
'''
from db import db_handle
# 提现金额接口
def withdraw_interface(username,money):
# 1. 得到用户的相关信息
data = db_handle.select(username)
if data:
# 2. 检验用户的金额是否足够
balance = int(data.get('balance'))
money = int(money*1.05) # 手续费5%
if balance >= money:
# 更新用户相关数据
balance -= money
data['balance'] = balance
# 记录流水
flow = '用户:{}提现:{}成功,手续费为{},当前可用余额为:{}'.format(username,money,money*0.05,data['balance'])
data['flow'].append(flow)
db_handle.save(data)
return True,flow
return False,'用户余额已不足'
return False,'用户出现错误'
3.6 还款功能
在core/src.py
中
from interface import bank_interface
# 5.还款功能
@common.login_auth
def repay():
while True:
# 1. 接收用户输入还款金额
money = input('请输入充值金额:').strip()
# 2. 判断金额是否是数字
if not money.isdigit():
print('请重新输入,提现金额必须为正整数:')
continue
# 3. 调用还款接口
flag, msg = bank_interface.repay_interface(login_user, int(money))
if flag:
print(msg)
break
else:
print(msg)
在interface/bank_interface.py
中
# 还款接口
def repay_interface(username,money):
# 1. 得到用户的相关信息
data = db_handle.select(username)
if data:
# 2. 更新用户金额
data['balance'] += money
# 记录流水
flow = '用户:{}充值:{}成功,当前可用余额为{}'.format(username,money,data['balance'])
data['flow'].append(flow)
# 3. 保存用户金额
db_handle.save(data)
return True, flow
return False,'用户出现错误'
3.7 转账功能
在core/src.py
中
# 6.转账功能
@common.login_auth
def transfer():
while True:
# 1. 接收用户输入的目标用户和转账金额
to_user = input('请输入对方的用户名:').strip()
money = input('请输入转账的金额:').strip()
# 2. 判断金额是否是数字
if not money.isdigit():
print('请重新输入,提现金额必须为正整数:')
continue
# 3. 不能自己给自己转账
if to_user == login_user:
print('请不要给自己转账')
continue
# 3. 调用转账接口
flag, msg = bank_interface.transfer_interface(login_user,to_user,int(money))
if flag:
print(msg)
break
else:
print(msg)
在interface/bank_interface.py
中
from db import db_handle
# 转账接口
def transfer_interface(username,to_user,money):
# 1. 判断目标用户是否存在
to_user_data = db_handle.select(to_user)
if to_user_data:
# 2. 获取用户数据信息
data = db_handle.select(username)
# 3. 判断用户金额是否足够
if data.get('balance') >= money:
# 4. 给用户做减钱操作,并保存更新数据
data['balance'] -= money
# 记录流水
flow = '给{}转账:{}成功,当前余额为{}'.format(to_user,money,data['balance'])
data['flow'].append(flow)
db_handle.save(data)
# 5. 给目标用户做加钱操作,并保存更新数据
to_user_data['balance'] += money
# 记录流水
to_user_flow = '收到{}的转账{},当前余额为{}'.format(username,money,to_user_data['balance'])
to_user_data['flow'].append(to_user_flow)
db_handle.save(to_user_data)
return True,flow
return False,'尊敬的用户:{},您当前的余额已不足,当前余额为{}'.format(username,data['balance'])
return False,'目标用户不存在'
3.8 查看流水
在core/src.py
中
# 7.查看流水
@common.login_auth
def check_flow():
# 1. 调用接口查看流水
flag, msg = bank_interface.check_flow_interface(login_user)
if flag:
for x in msg:
print(x)
else:
print(msg)
在interface/bank_interface.py
中
# 查看流水接口
def check_flow_interface(username):
data = db_handle.select(username)
if data:
if data.get('flow'):
return True,data.get('flow')
return False,'当前用户没有流水'
return False,'用户不存在'
3.9 购物功能
在core/src.py
中
from interface import shop_interface
# 8.购物功能
@common.login_auth
def shopping():
# 准备商品数据 列表套列表
shop_list = [
['商品1',1000],
['商品2',2000],
['商品3',3000],
['商品4',4000],
]
# 初始化购物车
shop_car = {}
while True:
# 1. 打印商品信息,让用户选择
print('=================欢迎来到购物商城=====================')
for index,shop in enumerate(shop_list):
shop_name,shop_price = shop
print(f'商品编号为:[{index}]',f'商品名称为:[{shop_name}]',f'商品单价为:[{shop_price}]')
print('==================24小时自助服务哦=====================')
# 2. 让用户根据商品编号进行选择
choice = input('请输入商品编号 结账请输入 y 加入购物车请输入 a').strip()
# 输入的是y 进入支付功能
if choice == 'y':
# 判断购物车是否为空
if not shop_car:
print('当前购物车为空,请先添加商品')
continue
# 调用支付接口进行支付
flag,msg = shop_interface.shopping_interface(login_user,shop_car)
if flag:
print(msg)
break
print(msg)
break
if choice == 'a':
# 判断购物车是否为空
if not shop_car:
print('当前购物车为空,请先添加商品')
continue
# 调用购物车接口
flag, msg = shop_interface.add_shop_car_interface(login_user, shop_car)
if flag:
print(msg)
break
print(msg)
break
if not choice.isdigit():
print('请输入正确的编号')
continue
choice = int(choice)
# 3. 判断choice是否存在
if choice not in range(len(shop_list)):
print('请输入正确的编号')
continue
# 4. 获取商品名称与单价
shop_name, shop_price = shop_list[choice]
# 5. 加入购物车
# 判断用户选择的商品是否重复,重复则数量+1
if shop_name in shop_car:
shop_car[shop_name][1] += 1
else:
shop_car[shop_name] = [shop_price,1]
print('************************************')
print('当前的购物车中有{}'.format(shop_car))
print('************************************')
在interface/shop_interface.py
中
'''
逻辑接口层
购物相关接口
'''
from interface import bank_interface
from db import db_handle
def shopping_interface(username,shop_car):
# 先校验逻辑,再调用银行的支付接口
# 1. 先计算总价
count = 0
for price_num in shop_car.values():
price,num = price_num
count += price*num
print(count)
# 2. 调用银行接口进行支付
flag,msg = bank_interface.pay_interface(username,count)
if flag:
return True,msg
return False,msg
def add_shop_car_interface(username,shop_car):
# 1. 获取当前用户的购物车
user_dic = db_handle.select(username)
# 2. 获取用户文件中的商品的数据
user_car = user_dic.get('shop_car')
# 3. 添加购物车
# 判断当前用户选择的商品是否已经存在
for shop_name,price_num in shop_car.items():
# 每个商品的数量
number = price_num[1]
print('number',number)
# 若商品重复,则累加商品数量
if shop_name in user_car:
user_dic['shop_car'][shop_name][1] += number
# 若不是重复的,更新到商品字典中
else:
user_dic['shop_car'].update({shop_name:price_num})
# 保存数据
db_handle.save(user_dic)
return True,'添加购物车成功'
在interface/bank_interface.py
中
# 支付接口
def pay_interface(username,count):
# 1. 获取用户信息
data = db_handle.select(username)
# 2. 获取用户余额
money = data.get('balance')
# 3. 判断余额是否足够
if money >= count:
# 进行减钱操作
data['balance'] -= count
# 添加流水
flow = '{}支付成功,支付金额为{},当前余额为{}'.format(username,count,data['balance'])
data['flow'].append(flow)
# 保存更新数据
db_handle.save(data)
return True,flow
# 余额不够
return False,'尊敬的{}您的当前余额不足,无法支付,当前余额为{}'.format(username,data['balance'])
3.10 查看购物车
在core/src.py
中
# 9.查看购物车
@common.login_auth
def check_shop_car():
flag, msg = shop_interface.check_shop_car_interface(login_user)
if flag:
for shop_name,price_num in msg.items():
print('当前购物车有{}件{},商品单价为{}'.format(price_num[1],shop_name,price_num[0]))
else:
print(msg)
在interface/shop_interface.py
中
# 查看购物车
def check_shop_car_interface(username):
# 1. 获取用户相关信息
data = db_handle.select(username)
# 2. 获取用户购物车信息
if data.get('shop_car'):
return True,data.get('shop_car')
return False,'当前购物车没有商品'
3.11 清空购物车
在core/src.py
中
# 10.清空购物车
@common.login_auth
def clean_shop_car():
flag,msg = shop_interface.clean_shop_car_interface(login_user)
print(msg)
在interface/shop_interface.py
中
# 清空购物车
def clean_shop_car_interface(username):
# 1. 先获取用户信息
data = db_handle.select(username)
# 2. 查看用户购物车是否有商品
car_data = data.get('shop_car')
if car_data:
# 3. 计算所有商品的价格
count = 0
for shop_name, price_num in car_data.items():
count += price_num[0]*price_num[1]
# 4. 判断用户余额是否足够
if data.get('balance') >= count:
# 做减钱操作
data['balance'] -= count
# 清空购物车
data['shop_car'] = {}
# 保存数据
db_handle.save(data)
return True,'购物车已清空,当前余额为{}'.format(data['balance'])
return False,'当前用户余额不足,请先充值'
return False,'当前购物车没有商品,请先添加商品'