ATM+购物车
1.项目开发流程
2.项目需求分析
3.项目架构设计(重点)
4.项目架构搭建
5.注册登录功能
内容
项目开发流程
假设我们是一家外包公司 专门给别人编写软件
1.需求分析
产品经理带着开发部门老大(架构师、研发经理)去客户公司寻求客户的需求
见客户之前架构师和研发经理会先大致了解一下客户的需求
然后琢磨出一套比较容易编写的流程
之后在于客户交谈中引导客户按照提前设想好的流程提需求
ps:这么做的目的是为了防止客户提出一些无厘头的要求!!!
2.架构设计
架构师会根据具体的业务需求选择:
开发的编程语言
项目的后端框架
项目所需的数据库(主库、从库)
项目组织结构(软件开发目录规范、自定义结构)
项目功能划分(将一个大项目拆分成多个小项目)
项目的报价(开发人员数量 天数等: 一个程序员一天按照1500+算)
3.分组开发
将项目拆分之后的多个小项目交给不同开发部门下的多个编程人员编写
每个人可能只会写很小的一部分(降低复杂度 提升开发效率 缩短开发周期)
4.项目测试
交给测试部门全面测试
语法错误千万不要提交到测试部门才被发现 这样可能会扣绩效甚至三次之后直接全铺盖走人!!!
ps:跟测试小姐姐搞好关系 这样的话很多bug都不需要提交报告 私下提醒并修改即可
5.交付上线
将项目打包给运维人员运行维护即可
6.目前行业的特点
小公司很累 但是成长速度很快(整体参与)
大公司轻松 但是成长速度缓慢(只拧螺丝)
需求分析
项目大致需求
- 额度15000或自定义
- 支持多账户登录
- 可以查看账户余额
- 可以提现(可自定义手续费比例)
- 提供还款接口
- 支持账户间转账
- 记录每月日常消费流水
- 实现购物商城,买东西加入购物车,调用信用卡接口结账
- 提供管理接口,包括添加账户、用户额度,冻结账户等
- ATM记录操作日志
- 用户认证功能
提炼项目功能
1.用户注册
2.登录功能
3.查看余额
4.余额提现
5.账户充值
6.金额转账
7.查看流水
8.添加购物车
9.查看购物车
10.结算购物车
11.管理员功能
项目大致技术栈
1.python基础核心编程
2.函数(装饰器)
3.常见内置模块
架构设计
研究常见软件架构(非常重要)
举例:
百度:百度帐户登录 需要获取用户名和密码 然后校验用户名和密码
在这里校验是基于网络将用户名和密码发送到百度的后台进行校验,后台去专门存储数据的地方校验数据
大致分为三层:浏览器 后台 数据库
ps:很多程序其实都是三层架构
第一层:用户层只做简单的数据展示
第二层:整个程序的核心层 做具体业务逻辑
第三层:数据存取
开发项目的固定结构
第一层:前端
第二层:后端
第三层:数据库
基于上述架构分析 也可以将ATM分为三层架构
展示层:只展示功能选项 基本逻辑
逻辑层:所有业务逻辑
数据层:给逻辑层提供数据存取
ATM架构牛逼之处:程序的扩展性非常的强
比如展示层等我们以后学了前端可以直接替换成页面
展示层目前是cmd操作 可以换成页面
核心逻辑层以后学了框架之后替换成框架
逻辑层目前是普通的python代码 可以换成django框架
数据存取层以后学了数据库直接替换成数据库
数据层目前是json文件 可以换成MySQL数据库
分组开发(回归正题)
1.搭建项目目录
针对启动脚本文件start.py可以放在bin目录下 也可以直接放在项目根目录
start.py
conf
settings.py
lib
common.py
core
src.py
interface
user_interface
bank_interface
shop_interface
db
log
readme
2.功能框架搭建
利用空函数
3.注册登录功能
1.start.py
# 先考虑sys.path问题 import os import sys base_dir = os.path.dirname(__file__) sys.path.append(base_dir) # sys.path.append(os.path.dirname(__file__) from core import src # 导入run功能 if __name__ == '__main__': src.run() # 确保是执行文件才可以调用run
2.conf
-----settings.py (日志文件直接拷贝即可)
"""配置文件中的变量默认全是大写""" import os # 存储到db目录下 (下列代码是跟数据存储相关的 所以可以放在第三层供外界调用 只要调用了就表示要操作数据 BASE_DIR = os.path.dirname(os.path.dirname((__file__))) DB_DIR = os.path.join(BASE_DIR,'db') if not os.path.exists(DB_DIR): # 增加程序的健壮性 os.mkdir(DB_DIR)
3.core
-----src.py
from interface import user_interface,bank_interface,shop_interface from lib import common """展示层""" """定义一个全局变量存储用户是否登录""" is_login = { 'username':None } def register(): username = input('username>>>:').strip() password = input('password>>>:').strip() confirm_pwd = input('confirm_pwd>>>').strip() if not password == confirm_pwd: print('两次密码不一致') return flag,msg = user_interface.register_interface(username,password) print(msg) def login(): username = input('username>>>:').strip() password = input('password>>>:').strip() flag,data = user_interface.login_interface(username) if flag: pwd = common.get_md5(password) if pwd == data.get('password'): is_login['username'] = username print('登录成功') else: print('密码错误') else: print(data) @common.login_auth def check_account(): flag,msg = bank_interface.check_account(is_login.get('username')) if flag: print(f'当前余额为:{msg}') else: print(msg) @common.login_auth def withdraw(): target_num = input('提现金额>>>:').strip() if target_num.isdigit(): target_num = float(target_num) flag,msg = bank_interface.withdraw_interface(is_login.get('username'),target_num) print(msg) else: print('必须是数字') @common.login_auth def repay(): repay_num = input('充值金额>>>:').strip() if repay_num.isdigit(): repay_num = float(repay_num) flag,msg = bank_interface.repay_interface(is_login.get('username'),repay_num) print(msg) else: print('必须是数字') @common.login_auth def transfer(): target_num = input('转账金额>>>:').strip() target_name = input('转账账户>>>:').strip() if target_num.isdigit(): target_num = float(target_num) flag,msg = bank_interface.transfer_interface(is_login.get('username'),target_num,target_name) print(msg) else: print('必须是数字') @common.login_auth def check_flow(): flag,msg = bank_interface.check_flow_interface(is_login.get('username')) print('+++++++') for i in msg: print(i) print('+++++++') @common.login_auth def add_shop_car(): flag,msg = shop_interface.add_car_interface(is_login.get('username')) print(msg) @common.login_auth def check_shop_car(): flag,msg = shop_interface.check_car_interface(is_login.get('username')) print(msg) @common.login_auth def clear_shop_car(): flag,msg = shop_interface.clear_car_interface(is_login.get('username')) print(msg) # 定制一个功能字典 func_dict = { '1': register, '2': login, '3': check_account, '4': withdraw, '5': repay, '6': transfer, '7': check_flow, '8': add_shop_car, '9': check_shop_car, '10': clear_shop_car } # 封装成函数便于启动脚本调用 def run(): while True: print(""" ===============ATM+购物车================= 1.用户注册 2.登录功能 3.查看余额 4.余额提现 5.账户充值 6.金额转账 7.查看流水 8.添加购物车 9.查看购物车 10.结算购物车 11.管理员功能 ===============ATM+购物车================= """) choice = input('请输入功能编号>>>:').strip() if choice in func_dict: # 获取函数名 func_name = func_dict.get(choice) # 加括号调用函数 func_name() else: print('请输入正确的功能编号')
4.db
-----db_handler.py
# 数据存取层 专门处理数据存取 import os import json from conf import settings def save(user_dict): username = user_dict.get('username') file_path = os.path.join(settings.DB_DIR,f'{username}.json') with open(file_path,'w',encoding='utf8') as f: json.dump(user_dict,f) def select(username): file_path = os.path.join(settings.DB_DIR, f'{username}.json') if os.path.exists(file_path): # 如果文件存在 则打开文件返回用户数据 with open(file_path,'r',encoding='utf8') as f : return json.load(f)
5.interface
-----user_interface.py
from db import db_handler def register_interface(username,password): # 构建用户字典 user_dict = { 'username':username, 'password':password, 'balance':15000, 'flow':[], 'shop_car':{}, 'is_lock':False, # 记录账号是否被锁定 'is_admin':False, # 记录是否是管理员 } # 调用第三层保存数据的方法 db_handler.save(user_dict) # 给第一层返回提示信息 return f'{username}用户注册成功' def check_user_interface(username): res = db_handler.select(username) if res: return '用户名已存在' def login_interface(username): res = db_handler.select(username) if res: return True,res return False,'用户名不存在'
-----bank_interface.py
from db import db_handler from lib import common logger = common.get_logger('银行业务') def check_account(username): # 根据用户名获取用户所有的数据 user_dict = db_handler.select(username) if user_dict: # 为了安全性考虑 用户只要余额 那么就返回余额即可 return True, user_dict.get('balance') return False, '用户名不存在' def withdraw_interface(username, target_num): # 1.获取当前用户的具体数据 user_dict = db_handler.select(username) # 2.比对当前用户余额是否大于提现金额 balance = user_dict.get('balance') if balance > target_num: balance -= target_num * 1.01 # 这里可以添加手续费 1% # 3.修改数据并保存 user_dict['balance'] = balance user_dict['flow'].append(f'提现金额:{target_num}和手续费:{target_num*0.01}') db_handler.save(user_dict) # 4.写入日志 info = f'{username}提现成功 提现金额为{target_num} 手续费为{target_num*0.01} 当前余额剩余:{balance}' logger.debug(info) return True, info else: return False, '余额不足 你个穷逼' def repay_interface(username, repay_num): user_dic = db_handler.select(username) user_dic['balance'] += repay_num current_balance = user_dic['balance'] user_dic['flow'].append(f'充值{repay_num}') db_handler.save(user_dic) logger.debug(f'{username}充值了:{repay_num}块钱') return True, f'充值成功,当前账户余额为{current_balance}' def transfer_interface(username, target_name, target_num): # 1.校验目标用户是否存在 target_name_dict = db_handler.select(target_name) if not target_name_dict: return False, '目标账户不存在' # 2.获取当前登录用户字典 user_dict = db_handler.select(username) # 3.先校验金额是否足够 if user_dict.get('balance') < target_num: return False, '余额不足 无法转账' # 4.双方账户增减余额即可 user_dict['balance'] -= target_num user_dict['flow'].append(f'给{target_name}转了{target_num}块钱') target_name_dict['balance'] += target_num target_name_dict['flow'].append(f'收到了{username}转过来的{target_num}块钱') db_handler.save(user_dict) db_handler.save(target_name_dict) # 5.记录日志 logger.debug(f'{username}给{target_name}转了{target_num}块钱') return True, '转账成功' def check_flow_interface(username): # 获取用户数据 user_dict = db_handler.select(username) logger.debug(f'{username}查看了自己的流水信息') # 返回用户流水 用户要什么就返回什么 不要返回整个字典 return True, user_dict.get('flow')
-----shop_interface.py
from db import db_handler from lib import common # 核心逻辑层里面专门处理购物相关的业务逻辑 logger = common.get_logger('购物业务') def check_car_interface(username): user_dict = db_handler.select(username) logger.debug(f'{username}查看了自己的购物车信息') return True, user_dict.get('shop_car') def add_car_interface(username): # 1.定义购物车数据(代码直接写死 也可以通过专门的商品文件便于后期维护更新) good_list = [ ['挂壁面', 3], ['印度飞饼', 22], ['极品木瓜', 666], ['土耳其土豆', 999], ['伊拉克拌面', 1000], ['董卓戏张飞公仔', 2000], ['仿真玩偶', 10000] ] # 11.创建一个临时存储商品数据的字典 temp_shop_car = {} # {'极品木瓜':[10,22],'印度飞饼':[100,3]} # 2.商品可以反复购买 所以这里加循环 while True: # 3.循环打印商品信息供用户选择 最好给商品添加编号 for i, j in enumerate(good_list): # i=0 j=['挂壁面', 3] print("商品编号:%s | 商品名称:%s | 商品单价:%s" % (i, j[0], j[1])) # 4.获取用户想要购买的商品编号 choice = input('请输入您想要购买的商品编号或者输入y退出添加>>>:').strip() # 12.如果是y那么修改用户购物车数据保存 if choice == 'y': user_dict = db_handler.select(username) # 修改用户购物车数据(不能直接替换 还应该考虑购物车内是否已经存在数据) real_shop_car = user_dict.get('shop_car') # {'极品木瓜':[1,22]} for good_name in temp_shop_car: if good_name in real_shop_car: real_shop_car[good_name][0] += temp_shop_car[good_name][0] else: real_shop_car[good_name] = temp_shop_car[good_name] user_dict['shop_car'] = real_shop_car # 重新写入文件 db_handler.save(user_dict) logger.debug(f'{username}用户添加购物车成功') return True,f'{username}用户添加购物车成功' # 5.校验商品编号是否是纯数字 if not choice.isdigit(): print('商品编号必须是数字') continue # 6.将用户输入的字符串类型编号转成整数类型便于后续索引取值 choice = int(choice) # 7.校验数字范围是否在商品列表的索引范围内 if not choice in range(len(good_list)): print('商品编号超出了现有的范围') continue # 8.获取用户想要购买的商品数据 target_good_list = good_list[choice] target_good_name = target_good_list[0] target_good_price = target_good_list[1] # 9.获取用户想要购买的当前商品的数量 target_num = input('请输入你想要购买的数量>>>:').strip() if target_num.isdigit(): # 数量在付钱之前 你想要多少都可以 target_num = int(target_num) # 10.确定了商量和数量 添加购物车 但是要考虑用户还可能购买其他商品 """临时购物车字典里面可能已经存在一些商品 也可能是第一次购买""" if target_good_name not in temp_shop_car: # {'极品木瓜':[1,666]} temp_shop_car[target_good_name] = [target_num, target_good_price] else: temp_shop_car[target_good_name][0] += target_num # {'极品木瓜':[1+9,666]} else: print('商品的个数必须是纯数字') def clear_car_interface(username): user_dict = db_handler.select(username) shop_car = user_dict.get('shop_car') # {'商品名称':[个数,单价]} # 定义一个总价 total_money = 0 # 3.计算商品总价(只需要字典的value 可以使用字典的内置方法values()) for good_num, good_price in shop_car.values(): # [个数,单价] total_money += good_num * good_price # 4.有了总价还需要判断用户能否买得起 balance = user_dict.get('balance') if balance > total_money: rest_money = balance - total_money user_dict['balance'] = rest_money # 5.扣钱完毕 清空购物车 user_dict['shop_car'] = {} user_dict['flow'].append(f'购物消费{total_money}') logger.debug(f'{username}疯狂消费{total_money} 账户余额{rest_money}') # 6.保存数据 db_handler.save(user_dict) return True,f'疯狂消费{total_money} 账户余额{rest_money}' return False, '钱不够 你个穷逼'
-----common.py
import hashlib from conf import settings import logging import logging.config def get_md5(password): md5 = hashlib.md5() md5.update(password.encode('utf8')) return md5.hexdigest() def login_auth(func_name): def inner(*args,**kwargs): from core import src if src.is_login.get('username'): res = func_name(*args,**kwargs) return res else: print('请先登录') src.login() return inner def get_logger(title): logging.config.dictConfig(settings.LOGGING_DIC) logger1 = logging.getLogger(title) return logger1