此项目自2017年伊始一直持续到2018年3月份,此项目一共两个人开发,我和我的另一个同事。这个项目并不是严格意义上的纯oc项目,它混合加入了c++ 的编码工作,原因是底层的socket封装是使用c++进行的,而我们需要封装远程访问数据库的一些增删改查操作,此外还需要进行长连接的一些测试工作。
这个项目是一个移动版的OA协同办公软件,类似微信企业版,所以大部分的重点就在与即时通讯的开发与调试。我的同事主要负责整个聊天系统的开发,而我就是负责协同办公的一些业务流程开发,比如公文审批系统、人事考勤系统等。
我具体负责以下代码工作的开发,
- 远程访问数据库的增删改查封装。为什么要封装?不是有现成的库吗?例如FMDB之类的?正是应为底层使用了c++ 开发,原有的一些库更本就不满足需求,应为这个是需要和c++混合开发的项目,其中我们需要根据我们查询的字段是一个还是多个进行区分,因为一个字段的查询是直接返回查询结果的,而多字段的查询是key和value是分开的,换句话说就是返回的结果中key和value是没有映射关系的,所以为了项目以后可以直接根据key值取到value的值,在这里需要分开处理。 以下是(MNSqlDBProvider.mm)的部分代码
nRet = dbProvider.ExecuteQuery(client, 0, sqlS, &memory);
if (nRet == 0) {
//sql语句执行成功
if (memory.UnzipMemory() == 0) {
dbRewsult.ExtractResult(&memory);
//获取查询数据库的结果
NSMutableDictionary *dict = dbRewsult.GetMfidlds();
NSMutableArray *muArray = dbRewsult.GetMuArray();
//多字段查询处理结果
if (keyArray.count > 1) {
self.info = dict;
self.infoArray = muArray;
if ([dict count] == 0) {
return 0;//不存在信息
}
return 1;
}
//只查询一个字段处理结果
if ([[dict objectForKey:key] isEqualToString:@"0"]) {
//不存在
self.info = dict;
self.infoArray = muArray;
return PHONE_NO_EXICT;//==0
}else{
//不为0,并不代表查询结果存在,需进一步解析
self.info = dict;
self.infoArray = muArray;
return PHONE_EXICT;//==1
}
}else{
//解压失败
NSLog(@"%s 解压失败",__func__);
}
return 0;
}else{
client->Close();
client->Open();
return nRet;
}
- 获取各个服务器的IP和Prot。这里我实现了一个叫MNServerConfig的单例类,用于根据中心服务器的IP和Prot来获消息服务器、文件服务器、数据服务器的各自IP和Prot。这个吃了不少亏,在项目开始的时候各个服务的IP的端口都是写死的了,随着项目的开发和服务器的不断升级,需要经常修改服务器的IP和端口号,这样我们就非常麻烦的需要一个个的去修改。在项目进行到中期的时候,服务器也比较稳定了我就写成根据中心服务器的IP来获取其他服务器的IP,这样就省力多了。对了,获取到所有服务器的IP和Prot后就需要本地进行保存,这样就不用每次打开应用都再去获取一边了。这里我直接保存到本地磁盘上名为company_ip.plist的文件。部分代码:
NSFileManager *fm = [NSFileManager defaultManager];
AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
NSString *ipPath = [delegate.loginFilePath stringByAppendingPathComponent:FILE_IP_NAME];
if (![fm fileExistsAtPath:ipPath]) {
NSString *sql = [NSString stringWithFormat:@"SELECT ZJMC,GWIP,GWDK,DXDM FROM t_icobjectserver"];
NSString *key = @"ZJMC,GWIP,GWDK,DXDM";
ICSocketClient client = ICSocketClient();
const char *ip = [W_CENTER_SERVER_IP UTF8String]; //中心服务器的ip
client.SetServerIP(ip);
client.SetServerPort(W_CENTER_PORT);
client.Open();
NSInteger nRet = [self.mnSqlDBProvider dbExecuteQueryInSocket:&client sqlStr:sql key:key];
client.Close();
if (nRet != 0) {
[self configIPAndPort:self.mnSqlDBProvider.infoArray];
if (![self saveIPAndProt:self.mnSqlDBProvider.infoArray]) {
NSLog(@"本地存储IP失败,请检查");
}
}
}else{
NSLog(@"从本地获取ip");
NSArray *ipInfo = [NSKeyedUnarchiver unarchiveObjectWithFile:ipPath];
[self configIPAndPort:ipInfo];
}
- 登录与注册。用户群体分为三大类,公司、团队、散户。每一种类的业务属性不一样从而导致注册方式不一样,,比如注册类型为公司的话就需要上传公司的营业证照进行审核并绑定一个管理员,管理员拥有公司的最高操作权限,可以添加删除公司的员工并赋予员工一定的管理权利,还可以把员工分配到每一个部门里。团队的是只需要绑定管理员帐号,添加自己团队的人员即刻。散户,顾名思义就是一些不在公司和团队里的人员,这些人只需要绑定自己的手机号就可以进行登录,不过登记去后只能和认识的人聊天。自然而然的登录就分为三类了,根据登录的类别不一样,所获得权限不一样。
这里有一些细节,
a、 一个手机号绑定一个帐号,一个人可以拥有不同身份的帐号,领导要求每次登录都要记住登录的帐号以及帐号所属的类型,如果下次登录的是公司类型的帐号就要自动给出这个帐号上次登录所属的公司名称,注意,这里一个帐号可以加入多个公司。
b、在登录的成功的时候就需要开启socket长连接,为了保持长连接需要在AppDelegate里面进行连接,不能在登录控制器里面连接。
- 人事系统。人事系统包括集团公司组织架构、部门人事列表、人员的考勤记录、请假流程的设计等。公司的组织架构分为三种,国内的全资子公司、国内的合资公司,国内的项目合作公司以及海外分公司。种类的不同代表着公司在该系统中的权重不同。部门人事列表有点类似QQ分组列表一样,可以进行分组操作,在组内可以下设二级部门,对人员可以进行增删操作。人员的考勤实现手机自动打卡上下班,借助百度地图实现在公司园区坐标里在规定时间内由服务器向手机端推送签到消息进行打卡操作,打卡时自动上传当前经纬度以及打卡时间,有服务器归纳总结一个月的考情记录并发送给人事部。如果没有收到打卡信息或者打卡失败,可以手动进入系统进行打卡操作。请假系统的开发需要考勤记录的配合。请假有发起者和审批者两种角色,一个人可以只是一种角色也可以拥有两种角色。
请假大致流程如下
- 公文系统。公文系统整体流程有点类似与请假流程,不一样的是公文有多个步骤需要流通,比如拟稿、校验、审核、定稿、发文等,其中步骤并不是单线一直流通的,其中可能有些步骤需要循环往复的流通才可能往下一步骤进行,并且在流转的过程可能需要不同的人员进行审核操作,这相比于请假复杂多了。
总结
其实项目早已结束,至于为什么我这么晚才来总结,那可能就要问我们领导了。这也算是我真正意义上的iOS项目吧,看着项目从0到0.8的我内心有好多要说的,不是技术上的原因,我一直认为阻碍项目的发展的永远不是技术问题而往往是人的因素。在这个项目开发的过程中,我们没有产品经理、没有UI设计师、没有数据库管理人员等,所有的操作全凭自己完成...最重要的是所有的需求都是我们大领导一个人提出的,没错,一个人!你能想象到你没有接触到实体业务,全凭领导一张嘴说,你就完成了整个项目的80%,你可想而知整个开发过程是有多么的痛苦...有些功能你开发了将近一个月的时间,拿给领导看过之后,领导说他又有新想法了...所有的都要推倒从做,就比如公文系统,那种心情真的是不好受!
代码的编写工作其实占用整个项目的生命周期是最短的,前期的需求分析以及业务逻辑的梳理是占用做多的。一个好的开发规范就是前期做好项目分析需求,这样就可以极大避免后期的推倒从做事件。