iOS项目技巧+封装过程

2023-10-29

前言

接手一个外包项目,发现问题颇多,下面是对整个项目封装过程的记录!

当前项目存在的问题

1: 接口前缀太多,切换环境不方便
2: 通用方法没有进行封装 -> 支付方法哪里用到写哪里
3: 扩展性和容错率太低!许多数组取值是直接根据数组下标来取的
4: 宏定义乱用 -> 用户数据没有进行封装,直接用宏来写

封装过程

1.对接口的处理

为什么不合理

之前的项目接口前缀是直接写在pch文件中,每次切换环境需要来回注释,十分的不方便。
而且pch文件本身是预编译环境,不做改动的代码才是这里的最佳选择,如果网络环境需要经常切换,存放在这里就不是很合理!

解决方案

网络环境一般为本地测试、预发布环境、正式环境。
我们可以使用三个pilst文件来对其进行封装。切换一次网络环境,只需要切换对应的plist文件即可。

好处

1.切换环境十分方便快捷,额其实这一条就够了,下面是方便切换网络环境的好处
2.在扩展方面十分方便,想想你的测试微信账号和正式账号的切换
3.方便后台和测试MM测试,想想你正在忙着撸代码呢?测试MM一会让你切换正式网络环境,一会让你切换本地环境。每次都需要重新打包,是不是很烦躁,不要怕,在APP的某一处,偷偷的用上一个点击方法,可以让她自由切换哦!
切换网络环境

图文介绍

1.创建plist文件
plist文件.png
.
2.根据场景调用对应的plist文件

- (void)setAppType:(XBApp_Type)type{
    NSString *path = nil;
    switch (type) {
        case XBApp_Type_Local:
            path =  [[NSBundle mainBundle] pathForResource:@"LocalNetworkProtocol" ofType:@"plist"];
            break;
        case XBApp_Type_Debug:
            path =  [[NSBundle mainBundle] pathForResource:@"DebugNetworkProtocol" ofType:@"plist"];
            break;
        case XBApp_Type_Release:
            path =  [[NSBundle mainBundle] pathForResource:@"ReleaseNetworkProtocol" ofType:@"plist"];
            break;
        default:  NSLog(@"-------- 警告!未选择打包模式 --------------");
            break;
    }
    _customMadeDic = [NSDictionary dictionaryWithContentsOfFile:path] ;
}

2.对通用方法的处理

对常用的方法做一些分类,比如判断字符串是否为空,判断字符串是否为电话号码,判断字符串是否为url等等….这些分类可以让你快速的开发。

3.尽量不要采取数组下标进行取值

在项目中,经常要截取一些url的参数,不要采用下标取值,正确姿势是写一个url的解析分类,获取url中对应的参数

警告:这是一个错误姿势

    NSString * string = @"https://112.112.112.112/apinew/customPage?groupId=6&sign=a7522acd73eeef8cd6f8c5c04c1b17f2&timeline=201702171414&appStartToken=&version=1.5.5";
    NSArray * ary = [string componentsSeparatedByString:@"&"];
if ([string rangeOfString:@"shop_checks"].location != NSNotFound) {
        NSString * specValue = [[ary[4] componentsSeparatedByString:@"="] lastObject];
        NSString * num = [[ary[3] componentsSeparatedByString:@"="] lastObject];
        NSString * skuProductId = [[ary[2] componentsSeparatedByString:@"="] lastObject];
        NSString * productId = [[ary[1] componentsSeparatedByString:@"="] lastObject];
}

正确的解锁姿势,写一个分类取出URL中的参数

// 将URL中得参数转化成字典
+ (NSDictionary*)getURLParameter:(NSString*)urlString{
    if (urlString.length == 0) {
        return  nil;
    }
    NSMutableDictionary *dict =[NSMutableDictionary dictionary];
    NSArray *urlArray = [urlString componentsSeparatedByString:@"?"];

    if (urlArray.count > 1) {   //如果大于1,认为有参数
        NSString *URLParString = [urlArray lastObject];

        if ([URLParString rangeOfString:@"&"].location != NSNotFound) { //多个参数
            NSArray *dictArray = [URLParString componentsSeparatedByString:@"&"];
            for (NSString *KVString in dictArray) {
                NSArray *KVArray = [KVString componentsSeparatedByString:@"="];
                for (int i = 0; i < KVArray.count; i++) {
                    if (i == KVArray.count - 1) {
                        [dict setValue:KVArray[i] forKey:KVArray[i - 1]];
                    }
                }
            }
        }else if ([URLParString rangeOfString:@"="].location != NSNotFound){ //单个参数
            NSArray *dictArray = [URLParString componentsSeparatedByString:@"="];
            for (int i = 0; i < dictArray.count; i++) {
                if (i == dictArray.count - 1) {
                    [dict setValue:dictArray[i] forKey:dictArray[i - 1]];
                }
            }
        }
    }

    return dict;
}

这只是其中一个例子,在项目中尽量不要采用数组下标取值这种操作。这种操作相对系统来说是危险的。
弊端有两方面:
1.容易造成系统崩溃
2.不容易对功能进行扩展

4.宏定义的使用

使用宏的话,尽量先对代码进行封装,再使用宏来简化代码。避免别人接手一脸懵逼的情况

警告:下面为错误示范

#define kUserId [[NSUserDefaults standardUserDefaults] objectForKey:@"userId"]
#define kuserName [[NSUserDefaults standardUserDefaults] objectForKey:@"userName"]
#define KuserLoginState [[NSUserDefaults standardUserDefaults] boolForKey:@"isLogined"]
#define kInitEntryId [[NSUserDefaults standardUserDefaults] objectForKey:@"initEntryId"]
#define kToken [[NSUserDefaults standardUserDefaults] objectForKey:@"kToken"]

这些是用户信息,完全可以使用一个模型先封装起来,后期想用宏处理的时候再用宏进行处理
正确的解锁姿势,先创建一个储存类,然后再创建一个用户类,加密可以选择SSKeychainss:

1.创建储存类

.h文件
#import <Foundation/Foundation.h>
#import "XBUserdefaultDefine.h"
#import <UIKit/UIKit.h>

@interface XBUserDefault : NSObject
+ (id)sharedWXUserDefault;

- (NSInteger)integerValueForKey:(NSString*)key;
- (BOOL)boolValueForKey:(NSString*)key;
- (NSString*)textValueForKey:(NSString*)key;
- (NSDictionary*)dicValueForKey:(NSString*)key;
- (CGFloat)floatValueForKey:(NSString*)key;
- (void)setInteger:(NSInteger)value forKey:(NSString*)key;
- (void)setBool:(BOOL)value forKey:(NSString*)key;
- (void)setFloat:(float)value forkey:(NSString*)key;
- (void)setObject:(id)object forKey:(NSString*)key;

- (void)removeObjectForKey:(NSString*)key;
- (NSArray*)allKeys;
- (BOOL)hasKey:(NSString*)key;
@end

.m文件
#import "XBUserDefault.h"

@implementation XBUserDefault
+ (id)sharedWXUserDefault{
    static dispatch_once_t predicate;
    static XBUserDefault *sharedUserDefault = nil;
    dispatch_once(&predicate, ^{
        sharedUserDefault = [[XBUserDefault alloc] init];
    });
    return sharedUserDefault;
}

- (NSInteger)integerValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults integerForKey:key];
}
- (BOOL)boolValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults boolForKey:key];
}
- (NSString*)textValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults stringForKey:key];
}
- (NSDictionary*)dicValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults dictionaryForKey:key];
}
- (CGFloat)floatValueForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [userDefaults floatForKey:key];
}
- (void)setInteger:(NSInteger)value forKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setInteger:value forKey:key];
    [userDefaults synchronize];
}
- (void)setBool:(BOOL)value forKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setBool:value forKey:key];
    [userDefaults synchronize];
}
- (void)setFloat:(float)value forkey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setFloat:value forKey:key];
    [userDefaults synchronize];
}
- (void)setObject:(id)object forKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setObject:object forKey:key];
    [userDefaults synchronize];
}
- (void)removeObjectForKey:(NSString*)key{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults removeObjectForKey:key];
    [userDefaults synchronize];
}
- (NSArray*)allKeys{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    return [[userDefaults dictionaryRepresentation] allKeys];
}
- (BOOL)hasKey:(NSString*)key{
    NSArray *allKeys = [self allKeys];
    NSInteger index = [allKeys indexOfObject:key];
    return index != NSNotFound;
}
@end

2.创建用户对象

.h文件
#import <Foundation/Foundation.h>
@interface XBUserOBJ : NSObject
+(XBUserOBJ*)sharedUserOBJ;
-(void)setUser:(NSString*)user;    //设置帐号
-(void)setPwd:(NSString*)pwd;      //设置密码
- (void)setUserID:(NSString*)userID;  //用户ID
- (NSString*)user;
- (NSString*)pwd;
- (NSString*)userID;
- (NSString*)token;
-(void)removeAllUserInfo;
@end

.m文件
#import "XBUserOBJ.h"
#import "XBUserDefault.h"
@implementation XBUserOBJ

+(XBUserOBJ*)sharedUserOBJ{
    static dispatch_once_t onceToken;
    static XBUserOBJ *sharedUserOBJ = nil;
    dispatch_once(&onceToken,^{
        sharedUserOBJ = [[XBUserOBJ alloc] init];
    });
    return sharedUserOBJ;
}
-(void)setUser:(NSString *)user{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    [userDefault setObject:user forKey:XB_Userdefault_User];
}
-(void)setPwd:(NSString *)pwd{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    [userDefault setObject:pwd forKey:XB_Userdefault_Pwd];
}
- (void)setUserID:(NSString *)userID{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    [userDefault setObject:userID forKey:XB_Userdefault_UserID];
}
//获取
-(NSString*)user{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    return [userDefault textValueForKey:XB_Userdefault_User];
}
-(NSString*)pwd{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    return [userDefault textValueForKey:XB_Userdefault_Pwd];
}
- (NSString*)userID{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    return [userDefault textValueForKey:XB_Userdefault_UserID];
}
- (void)removeAllUserInfo{
    XBUserDefault *userDefault = [XBUserDefault sharedWXUserDefault];
    [userDefault removeObjectForKey:XB_Userdefault_UserID];
    [userDefault removeObjectForKey:XB_Userdefault_UserToken];
    [userDefault removeObjectForKey:XB_Userdefault_NewUserID];
    [userDefault removeObjectForKey:XB_Userdefault_User];
    [userDefault removeObjectForKey:XB_Userdefault_Pwd];
}

公共文件
#ifndef RKXB_XBUserdefaultDefine_h
#define RKXB_XBUserdefaultDefine_h
#pragma mark  ----  用户信息存储
#define XB_Userdefault_UserID @"XB_Userdefault_UserID"
#define XB_Userdefault_UserToken @"kToken"
#define XB_Userdefault_NewUserID @"XB_Userdefault_NewUserID"
#define XB_Userdefault_NewUserToken @"XB_Userdefault_NewUserToken"
#define XB_Userdefault_User  @"XB_Userdefault_User"
#define XB_Userdefault_Pwd   @"XB_Userdefault_Pwd"
#define XB_UserDefault_Type  @"XB_UserDefault_Type"
#endif

github下载地址:https://github.com/chuheridangwu/ExampleProject

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS项目技巧+封装过程 的相关文章

  • 【封装丨优雅方法】

    封装是个老生常谈的话题了 那么如何优雅的封装呢 不要急 本文下面就讲一讲优雅封装的几种方式 如何优雅的封装 一 封装的含义 二 优雅的封装 1 使用接口和抽象类 2 使用私有变量和公有方法 3 使用静态方法和常量 4 使用注解 5 使用枚举
  • Java 前后端分离业务封装 对后端返回值进行封装 PageVO封装

    遇到前后端业务需要不一致时对Controller返回结果进行封装 后端返回结果 前后端分离后 web 端要求结果 counts 2694 pagesize 14 pages 8 page 66 items id 9009384 title
  • Java实体类中封装其他实体类并引用

    在Java开发过程中有很多情况是二个表及以上的联合操作 这是需要分清楚表的主次关系 在引用的时候有人会把二个表的数据全都封装在一个实体类中 然后在对这个实体类进行操作 但如果是三个表呢 四个表呢 还都封装在一个实体类吗 这样被封装的实体类的
  • 震惊,微信小程序可以设置网络字体!真香

    准备工作 获取字体链接 还原设计稿的时候需要用到如下特殊字体 google 的 Montserrat https fonts google com specimen Montserrat 选择这个字体 下载全部字体 将本地的字体文件上传到自
  • PCB相关知识-封装+元件属性+印制电路板PCB

    文章目录 封装Footprint 元件属性Properties 印制电路板PCB 封装Footprint 每个元器件都对应一个封装 封装相当于元器件在现实中的载体 原理图导入到PCB中的除了网络信息 还有封装信息 我们在PCB中移动摆放的就
  • python语法--面向对象基础(19)

    1 初识面向对象 1 1 面向过程 面向过程 根据业务逻辑从上到下写代码 开发过程的思路是将数据与函数按照执行的逻辑顺序组织在一起 数据与函数分开考虑 面向过程基本是由函数组成的 特点 注重步骤与过程 不注重职责分工 如果需求复杂 代码会变
  • JS 函数

    JS 函数 关键字形式的函数
  • Linux 系统安全如何设定 log 日志记录服务器

    在网上越来越多的黑客的出现 越来越多的高手出现的情况下 如何才能确保自己可以保存一份完整的 log 呢 稍微有点概念的黑客都知道 进入系统后的第一见事情就是去清理 log 而发现入侵的最简单最直接的方法就是去看系统纪录文件 现在我们来说说如
  • c++基础 面向对象:第四篇 (类和对象-封装)

    文章目录 类和对象 类和类的实例化 访问权限 成员属性私有化 封装 类和对象 c 面向对象的三大特性 封装 继承 多态 在c 中 认为万物皆对象 对象有属性和行为 类和类的实例化 在c 中 用关键字 class 去封装对象 语法 class
  • LQFP100封装尺寸图

    下图是LQFP100封装规格的参数 根据下图的参数 即可制作LQFP100的PCB封装
  • 高级面向对象技术

    封装 三种方式 工厂函数模式 构造函数模式 构造函数模式和原型结合 工厂函数模式代码示例 function factory name var obj new Object obj name name obj sayName function
  • 排阻的封装尺寸

    http arlen opcom blog 163 com blog static 33775037201011144225518 0402封装 0603封装 1 电阻封装尺寸与功率关系 通常来说 0201 1 20W 0402 1 16W
  • python学习日记【13 - 面向对象三】

    面向对象三 继承简介 方法重写 super 多重继承 多态 属性和方法 继承简介 继承是面向对象三大特性之一 通过继承我们可以使一个类获取到其他类中的属性和方法 在定义类时 可以在类名后面的括号中指定当前类的父类 超类 基类 继承提高了类的
  • Python最强知识点整理:面向对象封装案例

    面向对象封装案例 目标 封装 小明爱跑步 存放家具 01 封装 封装 是面向对象编程的一大特点 面向对象编程的 第一步 将 属性 和 方法 封装 到一个抽象的 类 中 外界 使用 类 创建 对象 然后 让对象调用方法 对象方法的细节 都被
  • VPP plugin so 的封装与解耦

    封装与解耦 每一个 plugin 封装了一个独立的功能模块 模块依赖的外部 so 接口也封装在每个 plugin 中 vpp 提供统一的使能 禁能 初始化 plugin 的框架 同时每个 plugin 对外提供的接口也使用统一的方式 大多采
  • AndroidStudio将module变为library

    文章注明出处可随意转载 请尊重别人的劳动成果 前言 在一个application当中 可能会存在多个module 有时也会有一个module包含其他module的需求 在完成这个需求时 Google了很多 全是2014年之前的一些老文章 现
  • 微信小程序实现左侧滑动导航栏

    微信小程序实现左侧滑动导航栏 1 左侧滑动导航栏图如下 2 这是我们左侧滚动栏的代码 wxml
  • 封装

    1 生活中封装 快递 外卖 电脑机箱 2 java中封装 隐藏类内部的细节 对外部提供一些访问细节的方法 3 封装例子 方法 类 属性 4 封装好处 提高代码复用性 提高代码安全性 提高代码易用性 5 实现步骤 1 隐藏内部细节 属性 2
  • 【封装】实体类(entity)

    实体类entity 一 ORM 1 1 ORM 实体类 entity 零散数据的载体 1 1 1 ORM应用 一 ORM ORM Object Relational Mapping 从数据库查询到的结果集 ResultSet 在进行遍历时
  • 3.[mybatis]的查询源码分析(执行流程、缓存、整合spring要点)

    目录 1 装饰器模式 2 sqlSession的创建 open 2 1 newExecutor 3 selectOne分析 3 1 二级缓存 3 2 一级缓存 4 数据库查询核心分析 queryFromDatabase 4 1 Simple

随机推荐

  • gcov代码覆盖率使用gcov完成代码覆盖率的测试

    Gcov作为gnu gcc工作组件之一 是一款的免费的代码覆盖率测试工具 而且可以结合lcov生成美观的html的测试报表 本文介绍一些gcov的使用方法 基本原理 一些实际中可能会遇到的问题以及解决思路 Gcov的用法 1 1 编译 Gc
  • 深度思考:老生常谈的双亲委派机制,JDBC、Tomcat是怎么反其道而行之的?

    要说双亲委派机制 还得从类加载器的类型谈起 一 类加载器的类型 类加载器有以下种类 启动类加载器 Bootstrap ClassLoader 扩展类加载器 Extension ClassLoader 应用类加载器 Application C
  • 【杭电错题】#12青年歌手大奖赛_评委会打分——最优解

    题目 青年歌手大奖赛中 评委会给参赛选手打分 选手得分规则为去掉一个最高分和一个最低分 然后计算平均得分 请编程输出某选手的得分 Input 输入数据有多组 每组占一行 每行的第一个数是n 2
  • 编程小技巧:四舍五入

    今天跟大家分享的小技巧是跟浮点数取整相关 我们知道计算机在为浮点数取整是通常是向零取整 也就是说会自动将浮点数的小数部分忽略掉 例如下面的例子 float a 3 68 int b int a 我们将变量a取整后赋值给变量b 则变量b的值为
  • 善用用户自定义信号

    kill l可以看到用户自定义信号 然后就可以在程序中注册使用此信号 通过killall 10 xxx 就可以给程序发送用户自定义信号 kill 6 可以让程序产生段错误
  • 2024王道408数据结构 P144 T10

    2024王道408数据结构 P144 T10 思考过程 这题也比较简单 首先看题目 要求我们用先序遍历求二叉树中第k个结点的值 那道理我们都懂直接开始敲代码 先建立一个计数器i和一个char类型的值ch 用来暂时存放data值 当i k时就
  • Golang vs Rust 为后端选择哪种语言?

    如果您的项目涉及 Web 开发 可分发服务器 那么建议您选择 Go 编程部分非常简单 并发模型将为您提供很多帮助 但是如果你打算开发一个 CLI 应用程序 那么你应该选择 Rust 因为它包含字符串处理和库 话虽如此 Rust 并不是最容易
  • idea-eclipse风格-快捷键大全总结

    文章目录 IDEA 快捷键风格选型 idea 快捷键总结 idea常用快捷键 与eclipse风格冲突的快捷键 代码自动提示快捷键 快速创建方法的快捷键 与eclipse使用不同 复制类的完整路径名 包名 类名 idea自身的快捷键被ecl
  • 《C#入门经典(第6版)》之如何编写简单的桌面应用程序

    1本章内容 Visual Studio 2012 的基础知识 如何编写简单的控制台应用程序 如何编写简单的桌面应用程序 VS 是一个庞大的复杂产品 可能会使初学者望而生畏 但使 用它创建简单的应用程序是非常容易的 在本章开始使用VS 时 不
  • 【从零开始学习Linux】常用命令及操作

    哈喽 哈喽 大家好 我是你们的老朋友 保护小周 本期给大家带来的是 Linux 常用命令及操作 主要有三个分类 文件操作 目录操作 网络操作 创建文件 touch 创建目录 mkdir 删除文件或目录 rm 文本编辑器 vim 查看文件内容
  • 《企业管理学》——决策与决策方法知识点总结

    第四讲 决策与决策方法 管理的核心是决策 正确的决策决胜千里 错误的决策南辕北辙 一 决策的重要性 概念及内涵 一 决策的重要性 决策是管理者从事管理工作的基础 在管理过程中 管理者会面临各种各样的问题 它们都需要管理者予以解决 在实际管理
  • Linux安装tomcat

    一 下载tomcat 打开tomcat下载页面 tomcat10下载页面 如果你 不想做代码的迁移工作 可以选择Tomcat9及其以下的版本 我们这里是为了安装Tomcat 选择Tomcat9作为演示的版本 二 解压 将下载好的Tomcat
  • HowTo如何制作一个文字冒险游戏-里篇(1)

    从一个文字冒险引擎开始 引 文字冒险游戏 顾名思义是以文字为主体的冒险游戏 其体现形式包含交互式小说 养成游戏 恋爱冒险等等 通过文字和音画表现情境戏以软件模拟情境 令玩家使用文字指令控制角色 以影响周边的情境 其运作方式可以理解成是用电脑
  • 软件测试必备知识框架图

    转载于 https www cnblogs com yinlili p 10075399 html
  • 【数据结构和算法】超多图解,超详细,堆详解

    作者 Linux猿 简介 CSDN博客专家 华为云享专家 数据结构和算法 C C 面试 刷题 Linux尽管咨询我 关注我 有问题私聊 关注专栏 图解数据结构和算法 优质好文持续更新中 欢迎小伙伴们点赞 收藏 留言 目录 一 什么是堆
  • mkdocs 部署教程

    一 安装mkdocs pip install mkdocs 二 创建项目 mkdocs new testdocs 三 文档预览 mkdocs serve 四 更换主题 下载主题 pip install mkdocs material mkd
  • IDEA,debug时出现FileNotFoundException: C:\Users\Àîê»\AppData\Local\Temp\capture83.prop (系统找不到指定的路径)的问题

    解决办法 修改你的电脑用户名 用IDEA时 运行没问题 debug就报错 原因是 你电脑C盘用户下的用户名有中文 或者其他的字符 导致找文件的时候翻译成乱码 所以出错 1 需要创建新的本地用户 点击桌面左下角win图标找到windows系统
  • 通过端口号查找进程、程序名和命令行信息

    通过端口号查找进程 程序名和命令行信息 在Linux系统中 我们经常需要根据端口号查找正在运行的进程及其相关信息 本文将介绍如何使用编程的方式通过端口号查找进程 程序名和命令行信息 在Linux中 可以使用netstat命令或ss命令来查看
  • Winform各控件详解(笔记)

    DataGridView简称DGV http www cnblogs com 08shiyan archive 2010 08 10 1796768 html
  • iOS项目技巧+封装过程

    前言 接手一个外包项目 发现问题颇多 下面是对整个项目封装过程的记录 当前项目存在的问题 1 接口前缀太多 切换环境不方便 2 通用方法没有进行封装 gt 支付方法哪里用到写哪里 3 扩展性和容错率太低 许多数组取值是直接根据数组下标来取的