博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
项目:ATM+购物车(超级详解,已完结)
阅读量:3973 次
发布时间:2019-05-24

本文共 18667 字,大约阅读时间需要 62 分钟。

python基础要打牢,ATM+购物车拿来练手不错,另外也可以了解开发软件的流程。总之感觉nice()。

2020.12.31今天是2020年最后一天,意义非凡,ATM+购物车是我第一次写的比较正规庞大的项目……原谅我没做过课设,感觉其实用三层架构来写也没那么难。(不过我打算上周天和上周一写完的…执行力不够)且当跨年礼物吧…2021再继续哈哈哈哈哈。

文章目录

一、 需求分析

模拟实现一个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.1需求分析

客户提出需求,公司拿到项目

——》公司出人去(一般一个前端一个后端)和客户讨论需求、商品需求功能的可实现性、项目价格、开发周期等,得到一个需求文档
——》公司内部开会得到一个开发文档交给不同岗位的程序员开发。

- Python: 后端,爬虫        - 不同的岗位:        - UI界面设计:            - 设计软件的布局,会分局软件的外观切成一张张图片。                - 前端:            - 拿到UI交给他的图片,然后去搭建网页面。            - 设计一些页面中,哪些位置需要接收数据,需要进行数据交互。                - 后端:            - 直接核心的业务逻辑,调度数据库进行数据的增删查改。                - 测试:            - 会给代码进行全面测试,比如压力测试,界面测试(CF卡箱子)。                - 运维:            - 部署项目。

1.2程序的架构设计

1.程序设计的好处 	1)思路清晰    2)不会出现写一半代码时推翻重写的情况    3)方便自己或以后的同事更好维护		2.三层架构设计的好处    1)把每个功能都分层三部分,逻辑清晰    2)如果用户更换不同的用户界面或不同,       的数据储存机制都不会影响接口层的核心       逻辑代码,扩展性强。    3)可以在接口层,准确的记录日志与流水。        3.三层架构        一 用户视图层  用于与用户交互的,可以接受用户的输入,打印接口返回的数据。	二 逻辑接口层  接受 用户视图层 传递过来的参数,根据逻辑判断调用数据层加以处理,并返回一个结果给 用户视图层。 	三 数据处理层  接受接口层传递过来的参数,做数据的处理    - 保存数据      - 查看数据      - 更新数据    - 删除数据

程序架构图:

程序架构图

1.3分任务开发

1.4测试

1.5上线

三、软件开发目录

conf:项目的配置信息core:核心的代码db:数据interface:接口lib:共用的一些功能log:日志readme:介绍项目的功能使用等srart.py:项目的启动文件

在这里插入图片描述

四、创建用户功能字典及搭建用户视图层

core中src代码如下

# 1.注册功能def register():    ...#2.登录功能def login():    ...#3.查看余额def check_banlance():    ...#4.提现功能def withdraw():    ...#5.还款功能def repay():    ...#6.转账功能def transfer():    ...#7.查看流水def check_flow():    ...#8.购物功能def shopping():    ...#9.查看购物车def check_shop_car():    ...#10.管理员功能def admin():    ...fuc_dic = {
'1':register, '2':login, '3':check_banlance, '4':withdraw, '5':repay, '6':transfer, '7':check_flow, '8':shopping, '9':check_shop_car, '10':admin}def run(): while True: print(''' ====== ATM+购物车====== 1、注册功能 2、登录功能 3、查看余额 4、提现功能 5、还款功能 6、转账功能 7、查看流水 8、购物功能 9、查看购物车 10、管理员功能 ====== THE END====== ''') #接受用户输入 choice = input('请输入命令编号:').strip() #判断命令编号是否合法 if choice in fuc_dic: fuc_dic[choice]() else: print('请输入合法的命令编号!')

start.py代码如下

import osimport sys# 添加解释器的环境变量sys.path.append(os.path.dirname(__file__))from core import srcif __name__ == '__main__':    src.run()

五、详细写各个功能

1、注册功能

核心逻辑分析

用户在视图层输入账号和密码,将账号和密码交给逻 辑 处理层,逻辑处理层调用数据处理层的功能来判断账号和密码是否存在。存在与否,则返回相应结果给逻辑处理层(接口层),若账号密码存在,则接口层直接返回,若不存在需要接口层需要完成注册功能,接口层需要做的是组织用户的信息,然后调用数据处理层的功能将用户信息写入相应json文件并返回,最终由接口层将是否注册成功返回给用户视图层。

def register():    while True:        # 1.用户输入用户名和密码进行校验        name = input('请输入用户名:').strip()        pwd = input('请输入密码:').strip()        re_pwd = input('请确认密码').strip()        # 2.小的逻辑判断        if pwd == re_pwd:            # 调用接口层来判断是否注册成功            res,tag= user_interface.register_interface(name,pwd)            if res:                print(tag)                break            else:                print(tag)

interface中的注册接口

def register_interface(username,password,balance = 15000):    # 1.调用数据处理层中的select函数会返回用户信息字典或者None    if db_handler.select(username):        return False,'用户已存在,请重新输入!'    else:        password = common.get_pwd_md5(password)        #1.组织用户信息,准备注册        user_dic = {
'username': username, 'password': password, 'balance': balance, # 用于记录用户流水的列表 'flow': [], # 用于记录用户购物车 'shop_car': {
}, # locked:用于记录用户是否被冻结 # False: 未冻结 True: 已被冻结 'locked': False } # 2.调用数据处理层的保存函数将用户信息写入文件 #密码加密 db_handler.save(user_dic) return True, f'{username} 注册成功!'

数据处理层功能的select功能

def select(username):    # 1.接收用户名,拼接用户信息的完整json路径    user_path = os.path.join(        settings.BASE_PATH,f'{username}.json'    )    # 2.判断用户json文件是否存在    if os.path.exists(user_path):        with open(user_path,'r',encoding='utf-8') as f:            user_dic = json.load(f)            return user_dic    # 不return默认返回None

conf下的配置信息

import osBASE_PATH = os.path.dirname(    os.path.dirname(__file__))

lib中的common.py密码加密功能

# 密码加密def get_pwd_md5(pwd):    m = hashlib.md5(pwd.encode('utf-8'))    salt = 'wangxunzhidashuaibi'    m.updae(salt.encode('utf-8'))    return m.hexdegist()

2、登录功能

核心逻辑分析

用户在视图层输入账号和密码交给登录接口层,接口层调用数据处理层的功能来判断用户是否登录成功,另外加了一个用户的登录状态变量login_user用于记录用户登录状态和一个用户登录认证装饰器。

def login():    while True:        name = input('请输入你的账号:').strip()        password = input('请输入你的密码:').strip()        # 登录接口:        #登录成功返回True,登录成功        res,tag = user_interface.login_interface(name,password)        if res:            global login_user            login_user = name            print(tag)            break        else:            print(tag)

interface中的登录接口

def login_interface(name,password):    # 调用数据处理层的select功能,来校验用户登录是否成功    # 返回user_dic 或者None    res = db_handler.select(name)    if res:        # 给用户输入的密码加密        password = common.get_pwd_md5(password)        if password == res.get('password'):            return True,'登录成功!'        else:            return False,'密码错误!'    return False,'用户不存在!请重新输入!'

用户登录认证

from core import srcdef login_auth(func):    def outter(*args,**kwargs):        if src.login_user:            res = func(*args,**kwargs)            return res        else:            print('未登录,无法使用该功能!请登录!')            src.login()    return outter

3、查看余额

核心逻辑分析

用户登录后(未登录会被强制登录),查看余额,直接调用查看余额接口,查看余额接口调用数据处理层中的功能,完成任务。

@common.login_authdef check_banlance():    #直接调用查看余额接口    #返回余额    banlance = user_interface.check_balance_interface(login_user)    print(f'====用户{login_user}余额为{banlance}====')

interface查看余额接口

# 查看余额接口def check_bal_interface(username):    user_dic = db_handler.select(username)    return user_dic['balance']

4、提现功能

核心逻辑分析

用户在登录后(未登录会强制登录),在用户视图层输入提现金额,调用接口层中的提现接口,在提现接口中调用了数据处理层中的功能返回给接口层,接口层完成逻辑处理后将结果返回视图层。

记录流水和日志:要在接口层接入记录日志的功能。

原因:接口层是处理逻辑的核心所在,用户每次有提现/还款等功能都需要经过接口层。

注意:

转账要注意手续费的处理,以及用户输入的是否为数字等细节判断。

#4.提现功能@common.login_authdef withdraw():    while True:        # 1.让用户输入提现金额        money = input('请输入提现金额:').strip()        # 2.小逻辑判断:判断用户输入的是否为数字        if money.isdigit():            # 调用提现接口层            # 返回(bool,str)            flag,msg=bank_interface.withdraw_interface(login_user,money)            if flag:                print(msg)                break            else:                print(msg)        else:            print('您的输入不合法,请您输入数字,比如1220')

interface提现接口

def withdraw_interface(name,money):    #1.拿到用户信息    user_dic = db_handler.select(name)    #2.查看账户的余额    balance = user_dic.get('balance')    #判断余额是否大于提现金额和手续费    if balance >= int(money) * 1.05:        balance -= int(money) * 1.05        user_dic['balance'] = balance        #记录流水        flow =f'用户{name}提现{money}成功!' \                    f'手续费为{int(money)*0.05},余额为{balance}'        user_dic['flow'].append(flow)        #保存或者更新用户数据        db_handler.save(user_dic)        #流水既输出在屏幕上,也保存在文件中        bank_logger.info(flow)        return True,flow    else:        return False,'提现失败!请重新输入金额!'

common.py中日志功能(在接口层记录日志)

def get_logger(log_type):  # log_type ---> user    '''    :param log_type: 比如是 user日志,bank日志,购物商城日志    :return:    '''    # 1、加载日志配置信息    logging.config.dictConfig(        settings.LOGGING_DIC    )    # 2、获取日志对象    logger = logging.getLogger(log_type)    return logger

settings.py新增日志配置字典

"""logging配置"""# 定义三种日志输出格式 开始standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \                  '[%(levelname)s][%(message)s]'  # 其中name为getlogger指定的名字simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'# 定义日志输出格式 结束# ****************注意1: log文件的目录# BASE_PATH = os.path.dirname(os.path.dirname(__file__))logfile_dir = os.path.join(BASE_PATH, 'log')# print(logfile_dir)# ****************注意2: log文件名logfile_name = 'atm.log'# 如果不存在定义的日志目录就创建一个if not os.path.isdir(logfile_dir):    os.mkdir(logfile_dir)# log文件的全路径logfile_path = os.path.join(logfile_dir, logfile_name)LOGGING_DIC = {
'version': 1, 'disable_existing_loggers': False, 'formatters': {
'standard': {
'format': standard_format }, 'simple': {
'format': simple_format }, }, 'filters': {
}, 'handlers': {
# 打印到终端的日志 'console': {
'level': 'DEBUG', 'class': 'logging.StreamHandler', # 打印到屏幕 'formatter': 'simple' }, # 打印到文件的日志,收集info及以上的日志 'default': {
'level': 'DEBUG', 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件 'formatter': 'standard', 'filename': logfile_path, # 日志文件 'maxBytes': 1024 * 1024 * 5, # 日志大小 5M 'backupCount': 5, 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了 }, }, 'loggers': {
# logging.getLogger(__name__)拿到的logger配置 '': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕 'level': 'DEBUG', 'propagate': True, # 向上(更高level的logger)传递 }, },}

interface中新增bank_log日志对象

#银行流水日志对象bank_logger = common.get_logger('bank')

5、还款功能

核心逻辑分析

用户在视图层输入还款金额,由接口层进行与数据处理层进行交互,完成功能。

@common.login_authdef repay():    while True:        money = input('请输入你要还款的金额:').strip()        if money.isdigit():            if eval(money) >=0:                # 接入还款接口                flag,msg = bank_interface.repay_interface(login_user,money)                if flag:                    print(msg)                    break            else:                print('金额不能小于0!请重新输入!')        else:            print('必须输入数字!请重新输入!')

interface还款接口

def repay_interface(name,money):    #1.得到用户信息字典    user_dic = db_handler.select(name)    #2.将还款金额加入用户余额    user_dic['balance'] += eval(money)    #3.记录流水    flow = f'====用户{name}还款{money}元成功,' \           f'现有{user_dic["balance"]}元===='    bank_logger.info(flow)    #4.保存或者更新用户信息    db_handler.save(user_dic)    return True,flow

6、转账功能

核心逻辑分析

用户输入要转入的账户和金额,传入转账接口,转账接口利用数据处理层的select和save完成功能。

def transfer():    while True:        #1.接收转账对象及金额        name = input('请输入你要转账对象:').strip()        money = input('请输入你要转账金额:').strip()        #2.判断用户输入的金额是否为数字以及是否>0        if money.isdigit():            if eval(money) > 0:                flag,msg=bank_interface.transfer_interface(name,money)                if flag:                    print(msg)                    break                else:                    print(msg)            else:                print('转账金额必须大于0!')        else:            print('必须输入数字!')

转账接口

def transfer_interface(name,money):    #1.判断被转账用户是否存在    #接入数据处理层的查找功能,返回user_dic 或者None    res = db_handler.select(name)    if not res:        return False,'目标用户不存在!'    #2.获取当前用户数据    user_dic = db_handler.select(src.login_user)    #3.判断当前用户的余额是否够转账    money = eval(money)    if user_dic.get('balance') > money:        user_dic['balance'] -= money        res['balance'] += money    else:        return False,'用户的钱不够转账!'    #4.记录流水    from_log_flow = f'用户给用户{name}转账{money}元成功!'    user_dic['flow'].append(from_log_flow)    to_user_flow = f'用户接受用户{src.login_user}转账{money}元成功!'    res['flow'].append(to_user_flow)    bank_logger.info(f'用户{src.login_user}给用户{name}转账{money}元成功!')    #5.更新用户数据    db_handler.save(user_dic)    db_handler.save(res)    return True,from_log_flow

7、查看流水

核心逻辑分析

用户在视图层选择查看流水功能,调用查看流水接口,流水接口调用数据处理层的查看功能完成功能。

#7.查看流水@common.login_authdef check_flow():    #接入查看流水接口    res = bank_interface.check_flow_interface(login_user)    if res:        n = 1        for i in res:            print(f'{n}:{i}')            n+=1    else:        print('用户{name}无流水记录!')

查看流水接口

def check_flow_interface(login_user):    user_dic = db_handler.select(login_user)    return user_dic.get('flow')

8、购物功能

核心逻辑分析

用户在视图层选择购物后==》
看到商品信息==》
选择购物/支付/加入购物车==》

1.购物:需要对用户输入的指令进行判定2.支付:计算当前购物车总花费,接入支付接口,完成支付3.加入购物车:读取之前的购物车,若存在加入重复的商品	名,则数量增加,否则新增购物,最后更新购物车
#8.购物功能@common.login_authdef shopping():    # 1.打印商品信息    shop_list = []    print('============欢迎来到有趣用品商城============')    with open(r'F:\ATM+购物车\db\shoppings.txt',encoding='utf-8') as f:        n = 1 # 记录商品编号        for line in f:            shop_name,shop_price  = line.strip().split(':')            shop_price = eval(shop_price)            shop_list.append((shop_name,shop_price))            print(f'商品编号:{n},'                  f'商品名称:{shop_name},'                  f'商品单价:{shop_price}')            n+=1    print('================24小时服务================')    # 2.初始化购物车    shopping_car = {
} #3.模拟用户购物 while True: choice = input('请输入商品编号(若结账输入y 添加购物车输入n):').strip() #3.1选择结账 if choice == 'y': # 判断购物车是否为空 ==》 #空==》不能支付 #否则==》调用支付接口 if not shopping_car: print('购物车为空,无法支付!') else: #调用商品结算接口 flag,msg=shop_interface.shopping_interface(shopping_car,login_user) if flag: print(msg) break else: print(msg) elif choice == 'n': #判断购物车内是否为空 # 空==》提示用户选择商品 # 非空 ==》代表用户选择了商品加入了购物车 if not shopping_car: print('当前购物车为空,请在该购物车内添加商品!') else: #接入添加购物车接口 res = shop_interface.add_shop_car(login_user,shopping_car) if res: print('添加购物车成功!') break else: print('添加购物车失败!') else: #模拟用户选择商品 #判断用户输入的编号是否合法 if not choice.isdigit(): print('请输入数字编号!') elif not type(eval(choice)) is int: print('请输入整数编号!') elif eval(choice) > n or eval(choice) < 1: print('请输入1-{n}内的编号!') else: #获取用户所选商品的名字和单价 shop_name,shop_price = shop_list[eval(choice)-1] #采用{'name':[price,number]}形式组织购物车 if shop_name in shopping_car: shopping_car[shop_name][1]+=1 else: shopping_car[shop_name] = [shop_price,1] print(f'当前购物车{shopping_car}')

商品结算接口和添加购物车接口

#商品结算接口def shopping_interface(shopping_car,name):    #1.计算用户商品总花销    cost= 0    # 采用{'name':[price,number]}形式组织购物车    for i in shopping_car.values():        price,number = i        cost+=price*number    #2.支付    #调用银行支付接口    flag,msg=bank_interface.pay_interface(name,cost)    return flag,msg#添加购物车接口def add_shop_car(name,shopping_car):    # 获取用户购物车    use_dic = db_handler.select(name)    user_car = use_dic['shop_car']    #添加购物车    for shop_name,shop_price_num in shopping_car.items():        shop_price,shop_num  = shop_price_num        #判断商品在不在购物车里面,若在则数量增加        #否则将商品添加到购物车里        #购物车组织{商品名:[单价,数量]}        if shop_name in user_car:            use_dic['shop_car'][shop_name][1] += shop_num        else:            use_dic['shop_car'][shop_name] = [shop_price,shop_num]            #等同于use_dic['shop_car'].update({shop_name:[shop_price,shop_num]})        #更新购物车数据        db_handler.save(use_dic)        return True

支付接口

# 支付接口def pay_interface(login_user, cost):    user_dic = db_handler.select(login_user)    # 判断用户金额是否足够    if user_dic.get('balance') >= cost:        # 减钱        user_dic['balance'] -= cost        # 记录消费流水        flow = f'用户消费金额: [{cost}$]'        user_dic['flow'].append(flow)        # 保存数据        db_handler.save(user_dic)        # return True 或 return False 交给购物接口来做处理        return True    return False

9、查看购物车

核心逻辑分析

和查看余额一样,直接调用接口层,利用数据处理层查看功能完成任务。

#9.查看购物车@common.login_authdef check_shop_car():    #调用查看购物车接口    res = shop_interface.check_spc(login_user)    if res:        for i in res:            print(i)    else:        print('用户购物车内没东西!')

查看购物车接口

def check_spc(name):    user_dic = db_handler.select(name)    shop_car = user_dic['shop_car']    return shop_car

10、管理员功能

核心逻辑分析

有点像写一个小的ATM+购物车,只不过功能不一样。

管理员需要有的功能分析如下:1.添加用户2.修改用户额度3.冻结用户与写整个项目不同,管理员功能相对来说比较独立,我们在写这个功能的时候,同样采取三层架构。即管理员视图层=》管理员接口层=》管理员数据处理层,但这里处理的是用户的数据,其实也是用户数据处理层。
#添加用户def add_user():    ...#修改用户额度def change_balance():    ...#冻结用户def lock_user():    ...#管理员功能字典admin_dic={
}#管理员视图层def admin_run(): print('=====欢迎进入管理员功能区=====')

10.1搭建管理员视图层以及管理员功能字典

#管理员功能字典admin_dic={
'0':['退出',None], '1':['添加用户',add_user], '2':['修改用户额度',change_balance], '3':['冻结用户',lock_user]}#管理员视图层def admin_run(): print('=====欢迎进入管理员功能区=====') #展示管理员功能 while True: for k,v in admin_dic: print(f'{k}:{v[0]}') #管理员选择功能 choice = input('请输入您想要使用的管理员功能').strip() #判断用户输入的合法性 if choice not in admin_dic: print('请您输入合法的数字!') else: admin_dic[choice][1]()

10.2实现管理员各个功能

1、添加用户功能

#添加用户def add_user():    #相当于注册一个用户    src.register()

2、修改用户额度功能

#修改用户额度def change_balance():    #获取要修改对象的账号和所要修改的额度    while True:        name = input('请输入要修改的账号:').strip()        balance = input('请输入要修改的额度:').strip()        #判断输入额度的合法性        if not balance.isdigit():            print('输入不合法!')        else:            #修改用户的额度,调用修改用户额度接口            #修改成功返回 True和日志            flag,msg = admin_interface.change_balance(name,balance)            if flag:                print(msg)                break            print(msg)

修改用户额度接口

#修改用户额度def change_balance(name,money):    #获取用户的信息字典    #接入数据处理层查看数据:返回用户信息字典或者None    user_dic = db_handler.select(name)    if user_dic:        #修改额度        user_dic['balance'] = eval(money)        #记录流水        flow = f'管理员{src.login_user}修改{name}用户额度为{money}成功!'        admin_logger.info(flow)        #保存数据        db_handler.save(user_dic)        return True,flow    return False,'用户不存在!'

3、冻结用户功能

#冻结用户def lock_user():    while True:        name = input('请您输入要冻结的账号名').strip()        #调用冻结用户接口        flag,msg = admin_interface.lock_user_interface(name)        if flag:            print(msg)            break        print(msg)

冻结用户接口

#冻结用户def lock_user_interface(name):    #拿到用户信息字典    user_dic = db_handler.select(name)    if user_dic:        #locked:用于记录用户是否被冻结        # False: 未冻结   True: 已被冻结        user_dic['locked'] = 'True'        #记录日志        msg =f'用户{name}被冻结!'        admin_logger.info(msg)        #保存数据        db_handler.save(user_dic)        return True,msg    return False,'用户不存在!'

六、演示视频

ps:ATM+购物车项目压缩包私我

ATM+购物车

转载地址:http://afxki.baihongyu.com/

你可能感兴趣的文章
放大电路的主要性能指标?
查看>>
稳压、调压、监控、DC/DC电路大全
查看>>
放大电路的主要性能指标?
查看>>
运放电压和电流负反馈的讨论
查看>>
运放自激问题
查看>>
运放电压和电流负反馈的讨论
查看>>
终于&nbsp;整明白了中断的工作原…
查看>>
终于&nbsp;整明白了中断的工作原…
查看>>
终于&nbsp;整明白了中断的工作原…
查看>>
终于&nbsp;整明白了中断的工作原…
查看>>
2010年11月19日
查看>>
2010年11月19日
查看>>
TC35i&nbsp;单片机
查看>>
TC35i&nbsp;单片机
查看>>
AT&nbsp;命令详解
查看>>
AT&nbsp;命令详解
查看>>
AT指令发送PDU中文短信——使用串口…
查看>>
AT指令发送PDU中文短信——使用串口…
查看>>
指针的使用注意事项(个人体…
查看>>
指针的使用注意事项(个人体…
查看>>