目录

项目实现思路

ATM项目

ATM架构设计
三层架构
core目录下的src.py(浏览器) (展示层)
interface目录下的多个py文件(框架) (核心逻辑层)
db目录下db_handler.py(数据库服务) (数据处理层)

优先实现功能

在src.py的展示层写面条版的函数,先实现主题功能,暂时别想着优化

拆分函数

如下图是一个用户注册功能函数:



我们要做的是将其到interface、db构成三层架构

拆分到哪?

核心逻辑层 有user bank shop admin等文件,负责不同的功能, 将跟user相关的代码(登录、注册) 放入相应的user_innerface.py文件

然后如果在innerface层下需要进行数据操作,就调用db层的函数。

请注意:展示层只能访问逻辑层,不能访问数据层。

项目路径展示

项目启动文件 start.py

项目启动文件start.py可以放在项目根路径,也可以放在bin文件夹下。

该文件首先要做的第一件事就是使用os.path.dirname获取将当前项目路径,并将其导入sys.path。

然后就是调用展示层文件src.py。

使用if name == __name__:标志这个文件是启动文件。



请无视飘红,这是pycharm的小bug,实际程序是可以运行的。

配置文件 setting.py



配置文件应该存放的是一些不会变动的信息,如项目的根路径、数据库的路径、日志的存放位置。

当其他模块要用这些路径的时候的时候,从配置文件导入即可。注意当数据库db不存在时,settings.py会进行创建,所以在第三层一定要导入settings.py。

日志配置字典

可以先别急着实现日志功能,中后期再添加日志。

关于日志模块的配置信息,应该写在settings.py文件内,并且封装成函数方便调用:

日志函数

日志函数属于公共功能,应该放在common.py。

在每个接口文件的开头都放一个logger,方便调用,下面拿bank接口文件举例:



所有这个文件内产生的日志,都是银行日志。

展示层 src.py

用户注册

获取用户输入

获取用户输入包括 获取用户名和获取密码

可自行添加:退出、输入两次密码比对

这两个功能逻辑简单,可以放在展示层

md5加密

使用hashlib对用户输入的密码进行md5加密,将密文保存到数据层,下次用户登录直接比对密文。

展示层只调用加密函数,加密函数应该存放于lib/common.py路径下:

调user功能接口

将用户名、密文输入user接口函数:



接口函数在核心逻辑层,在user_interface.py文件内:



逻辑层调用数据层的select函数,检查用户是否注册。再建立用户信息字典,最后调用数据层的save函数,输入用户信息字典,保存数据。

用户登录

基本流程

1.获取用户输入

2.md5加密

3.调user功能接口

调user功能接口:

接口返回值一致性

这个接口返回两个值:登录状态,信息

请注意之前注册接口的返回值只有一个值,这样我们每次调接口都要查看到底有几个返回值,容易混淆。为了保持接口返回值一致性,应该都改成返回两个值

将用户名和密文传入login_interface函数:

这里需要注意的是,每次传入的参数,都需要进行校验,保证传入干净的数据。

登录成功修改全局字典

当登录成功后,会修改全局字典:

将全局字典'username'键的值从空改成当前用户。



全局字典对应的是cookies。也就是你登录网站之后,网站会给你返回一个通行证,浏览器帮你把这个通行证存在本地。下一次登录就拿出来给网站看,也就不需要重新输入用户名密码了。

还有一个原因就是,使用的用户多了之后,如果放在第二层、第三层则会增大服务器的开销,所以放在第一层让用户承担开销,更为合理。

登录校验装饰器

由于我们希望只有登录的用户,才能使用更多功能,所以要给其他函数添加装饰器。



只有当全局字典是有值的,才会执行被装饰函数。还记得吗,登录成功会将全局字典的值改为当前用户。

循环导入

装饰器理论上应该放入common.py,因为登录检验的逻辑不是我们应该给用户展示的,但是放入common.py容易引起循环导入:

查看余额

从全局字典获取当前用户名

调bank功能接口

这个功能比较简单,先调用bank接口(之前是user接口),再调用select函数得到用户信息字典,返回用户的余额数据即可。

余额提现

从全局字典获取当前用户名

调bank功能接口



传入用户名、提现金额两个参数。

接口函数在逻辑层:

判断用户输入是否是整数或小数

对用户输入的数字,我们要进行校验,可以将校验的代码封装成函数,放在common.py。需要用的时候直接调用。这里建议在第二层做校验用户输入,第一层只能输入数据。

手续费 免费额度

在用户提现时收取一定手续费,手续费的数据应该放在settings.py下,便于管理。

免费额度的意思是:在免费额度内,用户提现不需要手续费,如果超过额度,就需要手续费。

以支付宝为例:每个用户有2万元的免费额度,超出后按照0.1%收取手续费。

实现思路:可以在用户信息字典中添加一个键值对,存放该用户的提现免费额度。

账户充值

与余额提现很相似,故省略。

repay:



repay_interface:

用户转账

转账相对来说,比前面复杂一点点,需要指名给谁转账:

转账逻辑

关于转账需要注意:

  1. 不能转账给自己
  2. 确认被转账的人存在
  3. 确认用户余额足够转账
  4. 确认转账之后当前用户金额减少
  5. 确认被转账用户金额增加

查看流水

在发生充值、提现、转账、购物车结算,这种涉及到账户余额变化的事件时,要将金额变动的信息加入用户信息字典。只要有钱的变动,就应该有流水信息。



所以应该在上述函数中,都添加一些代码,将流水信息添加到用户字典。

添加时间信息 转账流水

查看流水,就是将用户信息字典的流水信息拿出来展示,这个功能实现很简单,不再赘述。

也可以给流水添加时间信息:



注意转账功能的流水,既需要给当前用户添加流水,也需要给被转账的用户添加流水。

日志也可以实现这个功能,建议后期再添加日志。

添加购物车

核心逻辑

user_data = {'shop_car': {'印度飞饼': [20, 22]}}  # 现在的字典
swap_dict = {'印度飞饼': [100, 22], '仿真玩偶': [1, 10000]} # 临时字典
for good in swap_dict: # 1.键一个一个取出来
if good in user_data.get('shop_car'): # 2.如果商品在user-data中
user_data.get('shop_car').get(good)[0] += swap_dict.get(good)[0] # #3.修改数量的值
else:
user_data.get('shop_car')[good] = [swap_dict.get(good)[0], swap_dict.get(good)[1]] # 如果不存在就新增键值对
print(user_data)

展示商品

用户需要先查看商品,才能添加购物车。可以在逻辑层写一个展示商品的函数。商品数据也可以放在逻辑层。商品数据也可以保存在文件,做成配置项,从settings导入。

使用临时字典

什么叫临时字典?在添加购物车时,我们运行用户循环添加,直到用户输入q则停止添加。如果不使用临时字典,则用户每次添加,都会进行一次数据层的文件写入。使用临时字典,则是将数据保存在字典中,等到用户输入q,再将字典中的数据一次性写入文件。总得来说就是减少了写入的次数。

展示临时字典

因为临时字典是在程序运行中临时存在的,所以无法通过查看文件中的用户信息,来看到临时字典里的东西。

只能及时展示,每次循环临时字典都会变动。

查看购物车

调用shop接口查看用户字典即可,很简单,不再赘述。购物车是空的时候,要进行提示。

清空购物车

主要逻辑

从用户字典读出当前购物车信息,对商品价格进行计算,比对余额是否充足,将余额减去商品价格,最后将购物车清空,记录金额变动的流水,最后写入用户信息字典。

管理员功能

校对用户信息字典

管理员用户也是用户,只不过他有一个键值对比较特殊is_admin:true。已经登录的用户想使用管理员功能,就要先进行用户字典中数据值的校对,如果is_admin == true则可以使用管理员功能。说明一点,对于普通的用户注册,它们的信息字典从创建开始默认:is_admin:false。也可以设置只有管理员用户才有这个键值对。



调用接口函数查看当前用户是不是管理员:



确认is_admin这个键的值:

校对全局变量

给全局变量字典扩充一个键值对:



登录成功后,会将这两个键值对的值都进行修改。如果是管理员登录则会将'is_admin'修改为true。

此时获取当前全局变量字典的信息,就可以进行是否为管理员的校验了。

有参装饰器

装饰器要能区分哪些是普通函数,哪些是管理员函数。所以要外界传一个参数,告诉装饰器现在装饰的是普通函数还是管理员函数。如果是管理员函数就多加一个分支,如果是普通函数就按照原来进行。



先校验用户是否登录,再校验当前功能函数级别。

如果这个函数是普通函数(装饰器传参为normal),则直接执行。

如果这个函数是管理员函数(type=='admin'),则校验全局字典的is_admin键值对。如果是True,则继续执行。

如果is_admin == false则是普通用户,就走else不然其使用管理员函数。

给函数装上有参装饰器:



这样看起来确实更加清晰推荐使用,但是装饰器获取的还是全局变量字典的值(cookies),全局变量在展示层,理论上用户可以修改,所以我觉得应该还是有安全隐患。但是也不钻牛角尖了,就这样了!!而且使用有参装饰器和全局字典就可以少写一个校验admin的接口函数。

冻结用户

冻结用户之前,管理员先要能查看所有的用户吧,所以要在数据层写一个查看所有用户的函数。



db目录大概是这样:



这个函数返回用户名的列表:



在接口层改用户的is_lock键值对:



在登录函数添加判断是否锁定的逻辑:

查看文件的函数

可以扩展这个查看文件的函数,给他传入参数(一个目录,文件后缀名),他给你返回一个此目录下所有你指定后缀名的文件。比如指定txt,就给你返回目录下所有文本文件。

解冻用户

会冻结难道不会解冻吗?

提示:获取db目录所有被冻结的用户名单

def unlock_user():
cold_user = []
user_list = db_handler.check_file()
# 1.获取所有被冻结的用户
for user in user_list:
user_data_dict = db_handler.select(user)
cold_massage = user_data_dict.get('is_lock')
if cold_massage:
cold_user.append(user)
else:
continue
# 2.展示被冻用户
for num, user in enumerate(cold_user):
print(f'编号{num},用户名:{user}')
while True:
# 3.解冻
admin_choice = input(f'请输入要冻结的用户编号>>>')
if admin_choice.lower() == 'q':
break
if not admin_choice.isdigit():
print('输入错误')
continue
admin_choice = int(admin_choice)
if admin_choice not in list(range(len(cold_user))):
print('超出范围')
continue
user_name = cold_user[admin_choice]
user_data_dict = db_handler.select(user_name)
user_data_dict['is_lock'] = False
print(f'解冻{user_name}成功')
db_handler.save(user_data_dict)

逻辑层 interface

对传入数据进行校验

逻辑层会接受到用户传入的数据,为了安全性,我们必须对传入数据进行校验。

数据层 db_handler.py

数据层的优化

数据层总是需要用到项目路径(base_path)、数据库路径(db_path),这两个路径都是不变的。

在每个函数内都写很麻烦,我们可以将其放入配置文件conf/setting.py

优化前:



放入配置文件:

(当db不存在就创建)



在数据层(db_hander.py)导入即可form conf import setting

数据层的select函数



注意:当用户存在,返回用户信息的字典,当用户不存在,返回None。

数据层的save函数



ensure_ascii参数保证写入的时候不会把中文转成unicode编码,增强可读性。

common文件到底有什么?

  1. 加密
  2. 用户登录装饰器
  3. 用户输入校验
  4. 日志函数

ATM购物车项目总结的更多相关文章

  1. 阶段性项目 ATM+购物车项目

    ATM + 购物车https://www.cnblogs.com/kermitjam/articles/10687180.html readme 内容前戏: 一个项目是如何从无到有的. 一 需求分析 ...

  2. ATM + 购物车项目

    ''' 存放配置文件 ''' import os #获取项目根目录 BASE_PATH=os.path.dirname(os.path.dirname(__file__)) #获取用户目录 USER_ ...

  3. ATM+购物车项目流程

    目录 需求分析 架构设计 功能实现 搭建文件目录 conf配置文件夹 lib公共功能文件夹 db数据文件夹 interface业务逻辑层文件夹 core表现层文件夹 测试 最外层功能(src.py) ...

  4. ATM购物车+三层结构项目设计

    ATM购物车项目 模拟实现一个ATM + 购物商城程序. 该程序实现普通用户的登录注册.提现充值还款等功能,并且支持到网上商城购物的功能. 账户余额足够支付商品价格时,扣款支付:余额不足时,无法支付, ...

  5. ATM购物车程序项目规范(更新到高级版)

    ATM购物车程序(高级版) 之前的低级版本已经删除,现在的内容太多,没时间把内容上传,有时间我会把项目源码奉上! 我已经把整个项目源码传到群文件里了,需要的可以加主页qq群号.同时群内也有免费的学习资 ...

  6. python以ATM+购物车剖析一个项目的由来及流程

    ATM+购物车 一个项目是如何从无到有的 ''' 项目的由来,几个阶段 0.采集项目需求 1.需求分析 2.程序的架构设计 3.分任务开发 4.测试 5.上线运行 ''' 需求分析: # 对项目需求进 ...

  7. 项目: ATM+购物车

    ATM+购物车 项目文件: 介绍 以下为文件夹层次和内容: readme.md 1. 需求 模拟银行取款 + 购物全过程 1.注册 2.登录 3.提现 4.还款 5.转账 6.查看余额 7.查看购物车 ...

  8. day19 十九、ATM+购物车

    项目:ATM+购物车 作业需求:模拟实现一个ATM + 购物商城程序1.额度 15000或自定义 2.实现购物商城,买东西加入 购物车,调用信用卡接口结账 3.可以提现,手续费5% 4.每月22号出账 ...

  9. Python 入门基础16 -- ATM + 购物车

    ATM + 购物车 1.需求分析 2.设计程序以及程序的架构 设计程序的好处: - 扩展性强 - 逻辑清晰 3.分任务开发 4.测试 黑盒: 白盒: 对程序性能的测试 5.上线运行 # Tank -- ...

  10. Python实战之ATM+购物车

    ATM + 购物车 需求分析 ''' - 额度 15000或自定义 - 实现购物商城,买东西加入 购物车,调用信用卡接口结账 - 可以提现,手续费5% - 支持多账户登录 - 支持账户间转账 - 记录 ...

随机推荐

  1. Elasticsearch之集群角色类型

    角色划分 在Elasticsearch中,有很多角色,常用的角色有如下: Master Node:主节点 Master eligible nodes:合格节点 Data Node:数据节点 Coord ...

  2. 国产电脑可较为流畅运行的Windows系统

    系统是Windows2003,内置了WPS和IE8,使用QEMU TCG运行,速度慢,凑合能用. 使用前先sudo apt install qemu-system-x86,把压缩包中的2003.qco ...

  3. CentOS 7.9 安装 rocketmq-4.9.2

    一.CentOS 7.9 安装 rocketmq-4.9.2 地址: https://rocketmq.apache.org https://github.com/apache/rocketmq ht ...

  4. P2680 [NOIP2015 提高组] 运输计划 (树上差分-边差分)

    P2680 题目的大意就是走完m条路径所需要的最短时间(边权是时间), 其中我们可以把一条边的权值变成0(也就是题目所说的虫洞). 可以考虑二分答案x,找到一条边,使得所有大于x的路径都经过这条边(差 ...

  5. 洛谷P7960 [NOIP2021] 报数 (筛法)

    禁止报的数的生成规则与埃式筛法类似,考虑用筛法预处理可以报出的数字列表和不可报出的数字,从而 O(1) 回答每一组询问. 用check函数判断数字中是否含有7,用nx[i]记录数字i的下一个合法数. ...

  6. SpringBoot(三) - Slf4j+logback 日志,异步请求,定时任务

    1.Slf4j+logback 日志 SpringBoot框架的默认日志实现:slf4j + logback: 默认日志级别:info,对应了实际生产环境日志级别: 1.1 日志级别 # 常见的日志框 ...

  7. python2与python区别汇总

    目录 输入与输出 range使用区别 字符编码区别 输入与输出 python2与python3中两个关键字的区别 python2中 input方法需要用户自己提前指定数据类型 写什么类型就是什么类型 ...

  8. List接口中的常用方法

    void add(int index, Object ele):在index位置插入ele元素boolean addAll(int index, Collection eles):从index位置开始 ...

  9. java连接数据库加载驱动到java项目

    java连接数据库 package com.cook.zheng; import java.sql.Connection; import java.sql.DriverManager; public ...

  10. 创建Vue工程常用的命令

    创建一个vue项目的步骤 1.创建一个名称为myapp的工程 vue init webpack myapp 2.进入工程目录 cd myapp 3.安装 vue-router npm install ...