zoukankan      html  css  js  c++  java
  • 27-ATM+购物车程序

    1、需求

    本章作业:

    模拟实现一个ATM + 购物商城程序

    1. 额度 15000或自定义
    2. 实现购物商城,买东西加入 购物车,调用信用卡接口结账
    3. 可以提现,手续费5%
    4. 支持多账户登录
    5. 支持账户间转账
    6. 记录每月日常消费流水
    7. 提供还款接口
    8. ATM记录操作日志
    9. 提供管理接口,包括添加账户、用户额度,冻结账户等。。。
    10. 用户认证用装饰器

    示例代码 https://github.com/triaquae/py3_training/tree/master/atm

    简易流程图:https://www.processon.com/view/link/589eb841e4b0999184934329

    2、流程图

    3.评语

     

     4.我的代码

    # 软件组织结构
    atm
    │
    ├─bin       # 执行文件目录
    │  └─__init__
    │  └─__start__  # 执行文件
    │
    ├─conf      # 配置文件目录
    │  └─__init__
    │  └─__settings__
    │
    ├─core      # 核心代码
    │  └─__init__
    │  └─account.py     # 账户管理
    │  └─atm_logics.py  # atm逻辑分发
    │  └─atm_manage.py  # atm主文件
    │  └─authentication.py  # 用户认证
    │  └─db_handler.py      # 数据库操作
    │  └─log.py     # 记录日志
    │  └─main.py        # 入口文件
    │  └─shopping.py    # 购物商城主文件
    │
    ├─db        # 数据库目录
    │   └─account   # 用户账户文件目录
    │       └─alex.json
    │       └─cat.json
    │       └─jack.json
    │       └─tom.json
    │
    ├─logs      # 各种日志文件目录
    │  └─account.log    # 账户管理log
    │  └─atm.log        # atm操作log
    │  └─login.log      # 登录操作log
    │  └─shop.log       # 购物商城log
    │
    ├─README
    │
    ├─requirements.txt  # 依赖包
    │
    └─setup.py
    # 文件如何调用的?
    start.py---> main.py--->
        # 管理员
           ----> account.py
        # 普通用户
           # ATM
                ---> atm_manage.py---> atm_logics.py
           # 购物商城
                ---> shopping.py
    # -*- coding:utf-8 -*-
    import os
    import sys
    
    # 1.添加atm主目录到sys.path
    # file_path = os.path.abspath(__file__)  # 文件绝对路径
    # BASE_DIR1 = os.path.dirname(file_path)
    # BASE_DIR2 = os.path.dirname(BASE_DIR1)  # atm主目录路径
    # sys.path.append(BASE_DIR2)
    sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    
    
    # 2.导入core/main 主程序
    from core import main
    if __name__ == '__main__':
        main.run()
    start.py
    # -*- coding:utf-8 -*-
    import os
    import logging
    
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    DB_PATH = '%s\db\account\' % BASE_DIR
    
    LOG_LEVEL = logging.INFO
    LOG_PATH = '%s\logs\' % BASE_DIR
    file_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    TRADE_TYPE = {
        'withdraw': {'action': 'subtract', 'interest': 0.05},
        'transfer': {'action': 'subtract', 'interest': 0},
        'pay': {'action': 'subtract', 'interest': 0},
        'transferred': {'action': 'plus', 'interest': 0},
        'repay': {'action': 'plus', 'interest': 0},
    }
    
    ADMIN_USER = 'admin'
    ADMIN_PASSWORD = 'admin'
    settings
    # -*- coding:utf-8 -*-
    import os
    
    from conf import settings
    from .db_handler import load_account_data
    from .db_handler import save_account
    from .db_handler import save_db
    
    db_dir = settings.DB_PATH
    account_list = os.listdir(db_dir)
    
    
    def account_msg(*args):
        """查看所有账户,信用额度"""
        print("-----------
    账户  信用额度    是否冻结 ")
        for i in account_list:
            account = i.split('.json')[0]
            ret = load_account_data(account)   # db操作文件,取数据
            if ret['status'] == 0:
                if ret['data']['status'] == 0:
                    cold_status = '未冻结'
                else:
                    cold_status = '冻结'
                print("%s   %s      %s" % (ret['data']['id'], ret['data']['credit'], cold_status ))
    
    
    def account_add(account, account_logger):
        """添加新用户"""
        account_name = input('请输入要添加的用户名:').strip()
        if account_name:
            ret = load_account_data(account_name)
            if ret['status'] == 0:
                print('该账户已经存在')
            else:
                save_account(account_name)
                print('添加成功,请重新登录查看')
                account_logger.info('account:%s be added by %s'%(account_name, account))
    
    
    def account_cold(account, account_logger):
        """冻结用户"""
        account_name = input('请输入要冻结的用户名:')
        ret = load_account_data(account_name)
        if ret['status'] == 0:
            ret['data']['status'] = 1
            save_db(ret)
            print('该账户被冻结')
            account_logger.info('account:%s be frozen by %s' % (account_name, account))
        else:
            print('该账户不存在')
    
    
    def account_manage(account, account_logger, *args):
        """账户管理menu"""
        fun_dict = {
            '1': account_msg,
            '2': account_add,
            '3': account_cold,
        }
        while True:
            msg = '''
            ----account管理 ---
            1、查看所有账户及额度
            2、添加账户
            3、冻结账户
            4、退出
            '''
            print(msg)
    
            choice = input(">>>").strip()
            if choice in fun_dict:
                fun_dict[choice](account, account_logger)
            elif choice == '4':
                exit()
            else:
                print('请重新输入')
    account.py
    # -*- coding:utf-8 -*-
    
    from conf import settings
    from .db_handler import save_db
    from .db_handler import load_account_data
    
    
    def trade(amount, trade_type, account_data, logger, *args):
        """交易中心,主要修改 余额"""
    
        if trade_type in settings.TRADE_TYPE:
            interest = amount * settings.TRADE_TYPE[trade_type]['interest']  # 利息
            old_balance = account_data['data']['balance']
    
            if settings.TRADE_TYPE[trade_type]['action'] == 'plus':
                new_balance = old_balance + interest + amount
            elif settings.TRADE_TYPE[trade_type]['action'] == 'subtract':
                new_balance = old_balance - interest - amount
                if new_balance < 0:
                    balance = old_balance - interest
                    print('你可以%s %s' % (trade_type, balance))
                    return {'status': 1, 'error': '交易失败,余额不足'}
    
            # 写入文件
            account_data['data']['balance'] = new_balance
            data = save_db(account_data)
    
            # 加入日志
            logger.info('account:%s action:%s amount:%s interest:%s'
                        % (account_data['data']['id'], trade_type, amount, interest))
            return {'status': 0, 'msg': '交易成功', 'data': data}
    
        else:
            print('Trade type %s is not exist' % trade_type)
            return {'status': 1, 'error': '交易失败,交易类型不存在'}
    
    
    def msg(account_data, *args, **kwargs):
        """打印账户信息"""
        print('账号信息'.center(40, '-'))
        account_dic = account_data['data']
        for k, v in enumerate(account_dic):
            if v not in 'password':
                print('%15s : %s' % (v, account_dic[v]))
        print('End'.center(40, '-'))
    
    
    def withdraw(account_data, logger, *args, **kwargs):
        """提现操作"""
        withdraw_msg = '''
        --------余额信息-------
            额度:  %s
            余额:  %s
        ''' % (account_data['data']['credit'], account_data['data']['balance'])
        print(withdraw_msg)
    
        while True:
            withdraw_amount = input('请输入提现整数金额|b 退出:').strip()
            if len(withdraw_amount) > 0 and withdraw_amount.isdigit():
                withdraw_amount = float(withdraw_amount)
                if withdraw_amount < account_data['data']['balance']:
                    trade_res = trade(withdraw_amount, 'withdraw', account_data, logger)
                    if trade_res['status'] == 0:
                        account_data = trade_res['data']
                        print("New balance:%s" % account_data['data']['balance'])
                    else:
                        print(trade_res['error'])
    
                else:
                    print('余额不足,请重新输入')
            elif withdraw_amount == 'b':
                break
    
    
    def transfer(account_data, logger, *args, **kwargs):
        """转账操作"""
        while True:
            trans_account = input('请输入转账账户|b 退出:').strip()
            if trans_account == 'b':
                    break
            else:
                if trans_account not in account_data['data']['id']:
                    find_res = load_account_data(trans_account)
                    if find_res['status'] == 0:
                        while True:
                            trans_amount = input('转账金额|b 退出:').strip()
                            if len(trans_amount) > 0 and trans_amount.isdigit():
                                trans_account = float(trans_amount)
    
                                # 开始转账 account
                                trade_res = trade(trans_account, 'transfer', account_data, logger)
                                if trade_res['status'] == 0:
                                    # 对方账户相当于增加钱
                                    trade(trans_account, 'transferred', find_res, logger)
                                    account_data = trade_res['data']
                                    print("New balance:%s" % account_data['data']['balance'])
                                else:
                                    print(trade_res['error'])
                            elif trans_amount == 'b':
                                break
                    else:
                        print(find_res['error'])
    
                else:
                    print('this account is yours')
    
    
    def repay(account_data, logger, *args, **kwargs):
        """还款操作"""
        pay_msg = '''
        --------余额信息-------
            额度:  %s
            余额:  %s
        ''' % (account_data['data']['credit'], account_data['data']['balance'])
        print(pay_msg)
    
        while True:
            pay_amount = input('请输入还款金额|b 退出:').strip()
            if len(pay_amount) > 0 and pay_amount.isdigit():
                pay_amount = float(pay_amount)
                trade_res = trade(pay_amount, 'repay', account_data, logger)
                if trade_res['status'] == 0:
                    account_data = trade_res['data']
                    print("New balance:%s" % account_data['data']['balance'])
                else:
                    print(trade_res['error'])
    
            elif pay_amount == 'b':
                break
    atm_logics.py
    # -*- coding:utf-8 -*-
    from . import atm_logics
    
    
    def main(account_data, logger, *args, **kwargs):
        """atm模块分发器,进行分发"""
        fun_dict = {
            '1': atm_logics.msg,
            '2': atm_logics.withdraw,
            '3': atm_logics.transfer,
            '4': atm_logics.repay,
        }
    
        while True:
            msg = '''
            ----ATM ---
            1、查看信用卡信息
            2、提现
            3、转账
            4、还款
            5、返回上一层
            '''
            print(msg)
    
            choice = input(">>>").strip()
            if choice in fun_dict:
                fun_dict[choice](account_data, logger, *args, **kwargs)
            elif choice == '5':
                break
            else:
                print('请重新输入')
    atm_manage.py
    # -*- coding:utf-8 -*-
    from .db_handler import load_account_data
    
    
    def auth(*args):
        """根据account,password认证用户"""
        account, password = args
        account_data = load_account_data(account)
        if account_data['status'] == 0:
            account_data = account_data['data']
            if password == account_data['password']:
                return account_data
            else:
                return None
        else:
            return None
    authentication.py
    # -*- coding:utf-8 -*-
    import os
    import json
    
    from conf import settings
    
    
    def load_account_data(account):
        """根据输入的account,查找用户文件"""
        account_file = settings.DB_PATH + "%s.json" % account  # account文件路径
        if os.path.isfile(account_file):
            with open(account_file, 'r', encoding='utf8') as f:
                data = json.load(f)
                return {'status': 0, 'data': data}
        else:
            return {'status': -1, 'error': 'account file is not exist'}
    
    
    def save_db(account_data):
        """根据account_data,找到对应的json文件,写入文件中"""
        data = account_data['data']
        account_file = settings.DB_PATH + "%s.json" % data['id']   # account文件路径
        if os.path.isfile(account_file):
            new_file = account_file + '.new'
            with open(new_file, 'w', encoding='utf8') as f:
                json.dump(data, f)
            os.replace(new_file, account_file)
            return {'status': 0, 'data': data}
        else:
            return {'status': -1, 'error': 'account file is not exist'}
    
    
    def save_account(account):
        """写入新用户数据,创建文件"""
        data = {"expire_date": "2021-01-01",
                "credit": 15000, "status": 0,
                "id": account, "password": "abc",
                "enroll_date": "2016-01-02",
                "balance": 15000,
                "pay_day": 22}
        account_file = settings.DB_PATH + "%s.json" % account
        print(account_file)
        with open(account_file, 'w', encoding='utf8') as f:
            json.dump(data, f)
            f.flush()    # 对应新建的用户文件,如何实时刷入硬盘中
        return {'status': 0, 'data': data}
    db_handle.py
    # -*- coding:utf-8 -*-
    import logging
    
    from conf import settings
    
    
    def log_handle(log_type):
        logger = logging.getLogger(log_type)
        logger.setLevel(settings.LOG_LEVEL)
    
        log_file_name = settings.LOG_PATH + log_type + ".log"
        fh = logging.FileHandler(log_file_name)
        fh.setLevel(settings.LOG_LEVEL)
    
        logger.addHandler(fh)
        fh.setFormatter(settings.file_formatter)
        return logger
    log.py
    # -*- coding:utf-8 -*-
    
    from .authentication import auth
    from .log import log_handle
    from .shopping import main as shop_main
    from .atm_manage import main as atm_main
    from .account import account_manage
    from conf import settings
    
    atm_logger = log_handle('atm')
    login_logger = log_handle('login')
    shop_logger = log_handle('shop')
    account_logger = log_handle('account')
    
    
    def login_type(auth_type):
        def login(fun):
            if auth_type == 'user_auth':
                def inner():
                    user_obj = {
                        'is_authed': False,
                        'data': None
                    }
                    count = 0
                    while True:
                        account = input('请输入账号:').strip()
                        password = input('请输入密码:').strip()
    
                        # 普通用户
                        auth_data = auth(account, password)  # 认证
                        if auth_data:
                            if auth_data['status'] == 0:
                                user_obj['is_authed'] = True
                                user_obj['data'] = auth_data
    
                                # 登录成功,加入日志
                                login_logger.info('user %s login ' % account)
                                print('welcome to ATM & SHOP')
                                fun(user_obj, atm_logger, shop_logger)
                            else:
                                print('该用户已经被冻结')
                                login_logger.info('cold_user %s login ' % account)
                        else:
                            login_logger.info('user %s try wrong to log ' % account)
                            print('error account or password')
    
                        count += 1
                        if count == 3:
                            msg = 'user %s is try more times' % account
                            print(msg)
                            # 登录不成功,加入日志
                            login_logger.info('user %s try wrong  to log reached 3 times' % account)
                            break
                return inner
    
            elif auth_type == 'admin_auth':
                def inner():
                    admin_user = settings.ADMIN_USER
                    admin_pwd = settings.ADMIN_PASSWORD
                    count = 0
                    while True:
                        account = input('请输入账号:').strip()
                        password = input('请输入密码:').strip()
                        if account == admin_user and password == admin_pwd:
                            # 登录成功,加入日志
                            login_logger.info('user %s login ' % account)
                            print('welcome to account manage')
                            fun(account, account_logger)
                        else:
                            login_logger.info('user %s try wrong to log ' % account)
                            print('error account or password')
    
                        count += 1
                        if count == 3:
                            msg = 'user %s is try more times' % account
                            print(msg)
                            # 登录不成功,加入日志
                            login_logger.info('user %s try wrong  to log reached 3 times' % account)
                            break
                return inner
        return login
    
    
    @login_type('user_auth')
    def identity(user_obj, atm_logger, shop_logger):
        """用户认证成功"""
        atm_mall(user_obj, atm_logger, shop_logger)
    
    
    @login_type('admin_auth')
    def admin(account, account_logger):
        """管理员认证成功"""
        account_manage(account, account_logger)
    
    
    def run():
        fun_dict = {
            '1': admin,
            '2': identity,
        }
        while True:
            msg = '''
            ---------
            1.管理员
            2.普通用户
            3.退出
            '''
            print(msg)
    
            choice = input(">>>").strip()
    
            if choice in fun_dict:
                fun_dict[choice]()
            elif choice == '3':
                exit()
            else:
                print('请重新输入')
    
    
    def atm_mall(account_data, logger, logger_shop, *args, **kwargs):
        """atm——mall程序入口"""
        fun_dict = {
            '1': shop_main,
            '2': atm_main,
        }
        while True:
            msg = '''
            ----ATM & SHOP---
            1、购物商城
            2、ATM
            3、退出
            '''
            print(msg)
    
            choice = input(">>>").strip()
    
            if choice in fun_dict:
                fun_dict[choice](account_data, logger, logger_shop)
            elif choice == '3':
                exit()
            else:
                print('请重新输入')
    main.py
    # -*- coding:utf-8 -*-
    from .atm_logics import *
    
    
    def main(account_data, logger, logger_shop, *args):
        goods = [
            {"name": "电脑", "price": 1999},
            {"name": "鼠标", "price": 10},
            {"name": "游艇", "price": 20},
            {"name": "美女", "price": 998}
        ]
        shopping_cart = []
        cost = 0
    
        # 2.商品menu循环
        while True:
            print("----------商品列表 --------")
            for index, item in enumerate(goods):
                print("%s   %s  %s" % (index, item['name'], item['price']))
            choice = input("33[1;34m输入你要买的商品编号|返回上一层q:33[0m").strip()
            if choice.isdigit():
                choice = int(choice)
                if choice < len(goods):
                    shopping_cart.append([goods[choice]['name'], goods[choice]['price']])
                    print('33[1;32m>你购买了%s33[0m' % goods[choice]['name'])
                    cost += goods[choice]['price']
    
                else:
                    print('33[1;31m你输入的商品不存在33[0m')
    
            elif choice == 'q':
                if len(shopping_cart) > 0:
                    print("33[1;32m------你的购物车---------")
                    for index, item in enumerate(shopping_cart):
                        print(index, item[0], item[-1])
                    print("------------------------")
                    print("你的账单:%s33[0m" % cost)
    
                    while True:
                        choice = input('Do you want to pay? y|n :').strip()
                        if choice.lower() == 'y':
                            print('正在调用付款接口...')
                            pay_res = trade(cost, 'pay', account_data, logger)
                            if pay_res['status'] == 0:
                                print(pay_res['msg'])
    
                                # pay成功,写入日志
                                for i in shopping_cart:
                                    logger_shop.info('account:%s buy:%s cost:%s' % (account_data['data']['id'], i, cost))
                            else:
                                print(pay_res['error'])
                                print('请重新购物')
                            break
    
                        elif choice.lower() == 'n':
                            print('请重新购物')
                            break
                        else:
                            print('请重新输入')
    
                    # 支付成功,购物车清零
                    shopping_cart = []
                    cost = 0
    
                else:
                    break
    
            else:
                print('33[1;31;47m你输入的有误,请重新输入33[0m')
    shopping.py
    {"id": "alex", "pay_day": 22, "expire_date": "2021-01-01", "credit": 15000, "status": 0, "enroll_date": "2016-01-02", "balance": 11768.0, "password": "abc"}
    alex.json
    {"status": 0, "credit": 15000, "password": "abc", "pay_day": 22, "balance": 346.8999999999878, "id": "jack", "expire_date": "2021-01-01", "enroll_date": "2016-01-02"}
    jack.json
    2018-03-01 16:59:14,767 - account - INFO - account:alex1 be added by admin
    2018-03-01 16:59:21,329 - account - INFO - account:alex be frozen by admin
    2018-03-01 16:59:28,051 - account - INFO - account:jack be frozen by admin
    2018-03-01 21:45:09,287 - account - INFO - account: be added by admin
    2018-03-01 21:49:29,694 - account - INFO - account:alex be frozen by admin
    2018-03-01 21:49:47,597 - account - INFO - account:cat be added by admin
    2018-03-02 10:26:48,621 - account - INFO - account:dog be added by admin
    2018-03-02 10:34:23,346 - account - INFO - account:vvvv be added by admin
    2018-03-02 10:49:29,096 - account - INFO - account:llll be added by admin
    2018-03-02 10:53:21,614 - account - INFO - account:shengge be added by admin
    2018-03-02 10:53:54,387 - account - INFO - account:tom1 be added by admin
    acconunt.log
    2018-02-27 16:16:54,125 - atm - INFO - account:jack action:withdraw amount:100.0 interest:5.0
    2018-02-27 16:17:10,761 - atm - INFO - account:jack action:pay amount:100.0 interest:0.0
    2018-02-27 16:17:23,475 - atm - INFO - account:jack action:pay amount:100.0 interest:0.0
    2018-02-27 16:17:31,526 - atm - INFO - account:jack action:trans amount:100.0 interest:0.0
    2018-02-27 16:18:32,499 - atm - INFO - account:alex action:trans amount:100.0 interest:0
    atm.log
    2018-02-26 17:25:17,207 - login - INFO - user jack logg in 
    2018-02-26 17:31:35,451 - login - INFO - user jack logg in 
    2018-02-27 00:03:18,650 - login - INFO - user ale try wrong to log 
    2018-02-27 00:03:21,692 - login - INFO - user alex logg in 
    2018-02-27 00:05:49,870 - login - INFO - user jack logg in 
    2018-02-27 00:07:57,278 - login - INFO - user jack try wrong to log 
    2018-02-27 00:07:59,868 - login - INFO - user jack logg in 
    2018-02-27 00:15:03,256 - login - INFO - user jack logg in 
    login.log
    2018-02-28 12:09:44,197 - shop - INFO - account:jack buy:['鼠标', 10] cost:30
    2018-02-28 12:09:44,199 - shop - INFO - account:jack buy:['游艇', 20] cost:30
    2018-02-28 12:10:54,623 - shop - INFO - account:tom buy:['游艇', 20] cost:50
    2018-02-28 12:10:54,623 - shop - INFO - account:tom buy:['鼠标', 10] cost:50
    2018-02-28 12:10:54,623 - shop - INFO - account:tom buy:['游艇', 20] cost:50
    2018-03-01 21:48:25,825 - shop - INFO - account:alex buy:['电脑', 1999] cost:3027
    2018-03-01 21:48:25,825 - shop - INFO - account:alex buy:['鼠标', 10] cost:3027
    2018-03-01 21:48:25,825 - shop - INFO - account:alex buy:['游艇', 20] cost:3027
    2018-03-01 21:48:25,825 - shop - INFO - account:alex buy:['美女', 998] cost:3027
    shop.log
    作者:Liangshuo
    版本:示例版本 v1.0
    
    
    本章作业:
    模拟实现一个ATM + 购物商城程序
    额度 15000或自定义
    实现购物商城,买东西加入 购物车,调用信用卡接口结账
    可以提现,手续费5%
    支持多账户登录
    支持账户间转账
    记录每月日常消费流水
    提供还款接口
    ATM记录操作日志
    提供管理接口,包括添加账户、用户额度,冻结账户等。。。
    用户认证用装饰器
    示例代码 https://github.com/triaquae/py3_training/tree/master/atm
    简易流程图:https://www.processon.com/view/link/589eb841e4b0999184934329
    
    
    # 软件组织结构
    atm
    │
    ├─bin       # 执行文件目录
    │  └─__init__
    │  └─__start__  # 执行文件
    │
    ├─conf      # 配置文件目录
    │  └─__init__
    │  └─__settings__
    │
    ├─core      # 核心代码
    │  └─__init__
    │  └─account.py     # 账户管理
    │  └─atm_logics.py  # atm逻辑分发
    │  └─atm_manage.py  # atm主文件
    │  └─authentication.py  # 用户认证
    │  └─db_handler.py      # 数据库操作
    │  └─log.py     # 记录日志
    │  └─main.py        # 入口文件
    │  └─shopping.py    # 购物商城主文件
    │
    ├─db        # 数据库目录
    │   └─account   # 用户账户文件目录
    │       └─alex.json
    │       └─cat.json
    │       └─jack.json
    │       └─tom.json
    │
    ├─logs      # 各种日志文件目录
    │  └─account.log    # 账户管理log
    │  └─atm.log        # atm操作log
    │  └─login.log      # 登录操作log
    │  └─shop.log       # 购物商城log
    │
    ├─README
    │
    ├─requirements.txt  # 依赖包
    │
    └─setup.py
    
    
    # 文件如何调用的?
    start.py---> main.py--->
        # 管理员
           ----> account.py
        # 普通用户
           # ATM
                ---> atm_manage.py---> atm_logics.py
           # 购物商城
                ---> shopping.py
    README
    chardet==3.0.4
    ipython==2.3.1
    pyreadline==2.1
    requirements.txt

    5.演示效果

    (1)admin管理账户

      (2)普通用户购物商城

      

      (3)普通用户ATM

  • 相关阅读:
    reids 持久化
    center os 下redis安装以及基本使用
    MongoDB安装(Window)
    mysql中文乱码解决办法
    github托管代码
    MySQL表损坏修复【Incorrect key file for table】
    运维杂记-02
    配置ssh秘钥登陆
    nginx解决跨域问题
    运维杂记-01
  • 原文地址:https://www.cnblogs.com/venicid/p/8464578.html
Copyright © 2011-2022 走看看