APP下载

基于云计算以HJO为架构的企业共享型移动通讯录

2015-12-25罗伟雄时东晓曾纪霞刘岚郭柏乔

软件 2015年7期
关键词:云计算

罗伟雄++时东晓++曾纪霞++刘岚++郭柏乔

摘要:为了让企业能够把所有员工的通讯录信息进行统一管理,实现数据的高度共享,让每个用户都能自主、自动、及时地维护自己在云端的通讯录信息,以提高数据的时效性、准确性、可靠性和可用性,减轻企业对员工通讯录的维护工作量,降低维护成本。于此提出并已成功开发了以云计算技术为基础,以HJO(HTTP+JSON+OAuth)为架构的企业共享型移动通讯录,并在客户中试用得到了好评。系统利用智能移动终端使用和携带方便的特点,使系统突破了时间和地点的限制,充分显现移动应用方便、快捷等特色。

关键词:云计算;共享型;移动通讯录;HTTP;JSON;OAuth

中图分类号:TP311

文献标识码:A

DOI: 10.3969/j.issn.1003-6970.2015.07.019

0 引言

当今的通讯录可以涵盖多项内容,如:姓名、单位电话、移动电话、电子邮件、QQ等等],其准确性非常重要。而作为企业使用的通讯录更要求它具有良好的共享能力。传统的纸质通讯录成本高,携带不方便,查找速度慢,难以更新维护。而电子版通讯录大致分为远程通讯录和本地通讯录。远程通讯录就是把通讯录信息存放在云端服务器,比较典型的有Gmail、腾讯等提供的电子邮件系统中的通讯录,金山、百度等提供的云盘通讯录,这类通讯录往往是一种数据同步工具,用于把个人手机和电脑上的通讯录备份到云端,当需要时再从云端把数据恢复到手机或电脑的本地通讯录中。而手机通讯录、Outlook、Foxmail等邮件客户端上的地址簿等则属于本地通讯录,这类通信录的信息都是存放在本地的设备上。以上这些通讯录以私有化的居多,共享能力有限,而且大多要管理员维护,用户自行更新操作繁琐,其更新效率和准确性也不尽如人意。

而随着智能移动终端功能的增强和价格的下降,其普及率越来越高,据统计2014年中国智能手机用户已超过5亿。如果电子通讯录能以智能移动设备为平台,并结合云计算技术,那将会很好地解决上面的问题,同时也给用户带来更好的使用体验。基于以上的环境和需求,笔者设计和开发了一套以云计算技术为基础,以HJO(HTTP+JSON+OAuth)为架构的企业共享型云通讯录,并已投入使用。系统通过把通讯录信息云化,实现了数据的共享,消除用户对数据访问的地理局限性;通过运用HJO架构,减轻了数据的传输量,为Web应用、桌面应用和移动应用提供了统一的接口,简化了应用的开发。通过该系统用户可以便捷地使用智能移动终端设备来查询云端的通讯录信息,并能自主地维护自己的通讯录,保证了信息的准确性和共享能力,同时还降低了管理员的维护工作量。利用来电提示功能,用户不需要维护手机本身的通讯录,也能对同事的来电一目了然;使用离线数据同步技术方便了用户离线使用,节省了通讯流量。这些都给用户带来了更好的使用体验。

1 总体架构

本系统以云计算技术为基础,以HJO(HTTP+JSON+OAuth)的架构来进行系统设计。系统分为三个部分,分别是云端数据、客户端和管理端。其中云端数据分为数据存储层、数据处理层和数据访问层。该部分主要使用云计算技术对数据进行存储和处理,消除用户对数据访问的地理局限性。

(1)数据存储层。这里可以选择通用的关系型数据库作为数据持久化,如Oracle、MS SQL Server、MySQL等等。

(2)数据处理层。这是数据的逻辑处理器,主要负责数据的存取操作,对上层提供统一的数据访问接口,屏蔽下层数据库的存取操作差异。任何对数据库的操作都必须通过该层的接口实现。

(3)数据访问层。这是面向UI应用的接口层.实现对不同种类的UI应用提供统一的接口调用方式。

云端的这三个层次结构可以有效地消除底层数据库对上层应用的影响,以适应不同企业对数据存储的要求。同时也为各种不同的应用模式提供统一的调用方式,提高了系统的扩展能力。

(4)客户端。这是提供给用户访问云端数据的操作界面。根据设备的不同又分为智能终端App应用和Web网站应用。智能终端App应用使用的是Native App原生系统的开发模式。原因是系统需要读取设备的某些硬件信息,因此不适合使用基于网页的Web App开发模式。Web网站应用模式是为了让系统有更好的扩展性和延伸性。例如用户可以通过电脑或智能终端的浏览器使用本系统。另外笔者已经把Web网站应用接人微信平台,通过微信,用户便可使用该系统,这样有效提高了系统的使用率。

(5)管理端。这是提供给管理员对云端数据进行统一管理的操作界面。这里主要以Web访问方式为主。

整个系统的架构如图1所示。

2 实现方法

2.1 数据存储层

这里选择MS SQL Server 2008作为数据库。该数据库可以将结构化、半结构化和非结构化文档的数据(例如图像和音乐)直接存储到数据库中,并提供一系列丰富的集成服务,可以对数据进行查询、搜索、同步、报告和分析等操作,另外数据可以存储在服务器、PC机、移动设备等各种设备上。

系统共设计了9张数据表,用于存放用户、部门、电话和日志等信息。

Departments部门信息表

该表用于保存企业的组织和部门架构信息。其中OID为系统分配的部门编号;ParentID记录其直属上级部门的OID值,如果没有上级部门则此字段值为0;DepartmentID是由各企业自行编制的编号,主要目的是用于与其他系统同步信息。整个表的结构如表1所示。

Users用户信息表

该表用于保存用户的基本信息,每个用户占用一行。其中DepartmentID记录用户所在部门的部门编号,取自于Departments表的OID值。另外考虑到各个企业都有自己的中央认证系统,因此本系统在用户登录认证方面直接调用第三方的用户认证接口,所以在用户信息表中没有设计用户密码字段。整个表的结构如表2所示。endprint

Telephones电话号码表

该表用于保存用户的电话号码信息,每个电话号码占用一行,每个用户可以有多条记录。其中PhoneType标识该记录的电话号码是手机还是固定电话,如果为手机则填m,如果为固定电话则填t。整个表的结构如表3所示。

SimCard手机Sim卡信息表

该表用于记录用户的Sim卡信息,以便判断用户是否更换了手机卡。其中UserOID表示用户的系统编号,取之于Users表的OID值。整个表的结构如表4所示。

Managers管理员信息表

该表用于记录系统管理员信息。其中保存的密码信息必须进行加密存储。整个表的结构如表5所示。

DataChangelnfo数据修改信息

该表用于存放数据修改信息。其中TableName表示被修改的表名称,RecordOID表示所修改的记录的OID值,Action表示修改动作,插入用i表示,更新用u表示,删除用d表示。整个表的结构如表6所示。

DepartmentsLog部门信息修改日志表

该表用于记录部门信息的修改日志,即记录某条记录被修改前的原始信息,以便追踪数据的修改历史,并在发生错误时能恢复原始数据。其中Action表示记录的操作类型,插入用i表示,更新用u表示,删除用d表示。整个表的结构如表7所示。

UsersLog用户信息修改日志表

该表用于记录用户信息的修改日志,作用与DepartmentsLog类似。整个表的结构如表8所示。

TelephonesLog电话号码修改日志表

该表用于记录电话号码信息的修改日志,作用同样类似于表DepartmentsLog。整个表的结构如表9所示。

另外,客户端系统是通过读取DataChangelnfo表的信息来感知需要同步的数据并下载对应的信息。各数据表的修改信息是通过各表的Insert、Update和Delete触发器来收集的。这样做的优点是处理起来比较简单,简化了上层应用的开发。由于这里三个触发器要完成的任务都是记录哪个表的哪个记录进行了哪项操作,因此这里把三个触发器的代码写在一起。接下来就是判断当前是触发了Insert、Update还是Delete操作。逻辑上的判断是:如果存在inserted表,但不存在deleted表,则此时为Insert操作;如果同时存在inserted表和deleted表,则此时为Update操作;如果不存在inserted表,但存在deleted表,则此时为Delete操作。然后,如果是Update或Delete操作,则要先删除该记录的旧的修改信息,因为用户只需下载该记录的最终版本,因此旧的修改信息就可以删除掉。最后是把原始的记录登记在对应的日志表中,然后在DataChangelnfo表中登记该记录当前的操作类型。其核心代码如下。

判断当前是何种操作

IF EXISTS(SELECT l FROM inserted) AND NOT EXISTS(SELECT l FROM deleted)

BEGIN

SET CIAction 2'i'

SELECT ClOID 2 0ID FROM INSERTED

END

ELSE IF EXISTS(SELECT l FROM inserted) AND EXISTS(SELECT l FROM deleted)

BEGIN

SET CIAction='u'

SELECT @OID=0ID FROM INSERTED

END

ELSE IF NOT EXISTS(SELECT l FROM inserted) AND EXISTS(SELECT l FROM deleted)

BEGIN

SET @Action ='d'

SELECT @OID=0ID FROM DELETED

END

一如果是Update或Delete操作,则删除旧的修改日志

IF @Action<>il

BEGIN

INSERT INTO TelephonesLog

([Action], OID, UsersOID, PhoneType, PhoneNumber)

SELECT @Action, OID, UsersOID, PhoneType, PhoneNumber FROM DELETED

DELETE FROM DataChangelnfo

WHERE TableName=@TableName

AND RecordOID=@OID

END

——记录当前的修改的日志

INSERT INTO DataChangelnfo

(TableName, RecordOID, [Action])

VALUES

(@TableName,@OID,@Action)

2.2 数据处理层

由于不同的数据库其存取操作存在一定的差异,考虑到不同的企业所使用的数据库不尽相同,为了提高系统的适应能力,笔者首先设计了一套函数接口,然后因应不同的数据库再编写对应的操作类,而这些类继承上面的接口。这样就可以为数据访问层提供统一的接口函数,同时又屏蔽了数据存储层的操作差异。

例如用户管理模块。系统首先设计了类库DBControllerlnterface,里面声明了IUsersController接口,该接口包含了对用户数据操作的所有函数声明。如下面的代码所示。endprint

name space AddressBo ok.DB Controllerlnterface

{

///

///用户管理接口

///

public interface IUsersController

{

,//

///根据账号获取用户ID和姓名

///

///账号< /param>

///用户ID

///姓名

///

bool GetUserlnfo(string account, out int userOID, out string userName);

///

///根据手机号码获取用户ID

///

///手机号码

///用户ID

///

bool GetUserlnfo(string phoneNumber, out int userOID);

///

///检查是否存在某个账号

///

///账号< /param>

///

bo ol IsExistAccount(string account);

///

///检查是否存在某个用户ID

///

///用户ID

///

bool IsExistUserOID(int userOID);

///

///增加用户

///

///账号

///姓名

///部门编号

///

int Insert(string account, string userName, int departmentID);

///

///修改凫户

///

///用户ID

///部门编号

///

int Update(int oID, string userName, int departmentID);

///

/// Anil除用户

///

///用户 ID

///

int Delete(int oID);

///

///获取所有用户的基本信息

///

///

DataTable GetAllUsers();

///

///获取某个部门的用户基本信息

///

///部门编号

///分页索引

///分页大小

///总记录数

///

DataTable GetDepartmentUsers(int departmentID, int pageldx, int pageSize, out int recordCount);

}

}

接着系统创建了类库SQLDBController,这是实现对SQL Server数据库操作的,里面实现了UsersController类,该类继承上面的IUsersController接口并实现其方法。其核心代码如下。

name space Addres sBo ok. SQLDB Co ntroller

{

public class UsersController: IUsersController

{

public bool GetUserlnfo(string account, out int userOID, out string userName)

{

using (AddressBookEntities db=new AddressBookEntities(》

{

var data= (from record in db.Users

where record.Account==account

select record).FirstOrDefault();

if (data!=null)

{

userOID=data.OID;

userName=data.UserName;

return true;

}

else

{

userOID=0:

userName=string.Empty;

return false;

}

}

}

//其它对IUsersController接口函数的具体实现

}

}

这里使用了ADO.NET实体数据模型来连接数据库。通过该模型可以很方便的与底层数据库进行强类型的数据互操作,既方便了系统的设计也提高了数据库操作的安全性。另外对于查询到的数据集合,需要转换为DataTable类型对象,目的是便于数据访问层将其转换为JSON数据格式,因此这里使用了另一个自定义函数ConvertToDataTable。该函数是根据数据集创建数据表,然后再进行数据填充。转换时有一个需要注意的地方就是,通过ADO.NET实体数据模型查询到的数据集是包含外键关联表信息的,而且是作为一个独立的字段存在,而在这里该值是不需要的,因此进行数据转换时,需要先检测数据的类型是否为System.Data.EntityKey或System.Data.EntityState,如果是则丢弃该信息。其核心代码如下。

public class Common

{

public static DataTable ConvertToDataTable(IEnumerable varlist)

{

DataTable table=new DataTable();

ff字段名称

Propertylnfo[] oProps= null;

if (varlist==null) return table;

foreach(T rec in varlist)

{

if (oProps==null)

{

oProps=《Type)rec.GetType(》.GetProperties();

foreach (Propertylnfo piin oProps)

{

Type colType=pi.PropertyType;

//去除外键关联表

if (colType.FullName.Co ntains("AddressBo ok.SQLDBHelper"))co ntinue;

if《colType.FullName=="System.Data.EntityKey") II (colType.FullName=="System.Data.EntityState"》

continue;

if《colType.IsGenericType) && (colType.GetGenericTypeDefinitio n() ==typeof(Nullable<》》

{

colType=colType.GetGenericArguments() [0];

}

table.Columns.Add(new DataColumn(pi.Name, colType》;

}

}

DataRow row= table.NewRow();

foreach (Propertylnfo piin oProps)

{

//去除外键关联表

if (pi.PropertyType.FullName.Co ntains(”AddressBo ok. SQLDBHelper.”))co ntinue;

if《pi.PropertyType.FullName="System.Data.EntityKey")||(pi.PropertyType.FullName=="System.Data.EntityState"》

co ntinue:

row[pi.Name]=pi.GetValue(rec, null)==null? DBNull.Value: pi.GetValue(rec, null);

}

table.Rows.Add(row);

}

return table:

}

}

类似的,再创建对Oracle数据库操作的OracleDBController类库,里面同样实现了UsersController类,同样该类也继承IUsersController接口并实现其方法。要注意的是,如果使用ADO.NET实体数据模型来连接Oracle数据库,需要先安装Oracle Data Provider for .NET (ODP.NET)驱动程序。其他的操作和代码与操作SQL Server数据库的类似,这里就不再赘述。

这三个类库以及类和接口的继承关系如图2所示。这样数据访问层只要声明IUsersController接口变量,就可实现对SQL Server和Oracle数据库的存取操作,而不需要考虑具体的底层数据库的类型。同样如果需要使用其它数据库也可以按相同的方式进行编写。

2.3 数据访问层

为了统一各种UI应用的调用方式,该层采用了HJO(HTTP协议+JSON格式+OAuth2.0认证)架构模式。

HTTP协议(HypertextTransfer Protocol)是一个客户端和服务器端请求和应答的标准,它是无状态的应用层协议,由于其简捷、快速的方式,因此特别适合于分布式超媒体信息系统的应用。因此,本系统可以直接把该层部署在IIS服务器上,使用Windows Server的Web服务,这样即方便了系统的开发,也方便了系统的部署,同时由于HTTP协议是使用标准的80端口,因此也无需对网络防火墙进行特殊的配置。

JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它较XML有更高的传输效率,同一个数据使用JSON格式传输的数据量要比XML格式小很多。例如一条用户信息,使用JSON格式表示如下,只需166个字符。

[

{

"Account":"moc".

"UserName":"Micheal O'Ciardubhain".

"DepartmentID":41,

"DepartmentName":”应用外语系”,

"PhoneType":"m",

"PhoneNumber":"1 8926549871".

"OID":1003,

"UserOID":5015

}

]

而同样的记录使用XML格式来表示,如下所示,却需要330个字符,所占用的空间是JSON格式的两倍。

<?xml version="1.0"standalone="yes"?>

moc

Mic heal O'Ciardubhain

4 1

应用外语系m1892654 987 1

1003

5015

对当前的移动应用来说,用户对数据传输所占带宽还是比较敏感的,而通过使用JSON格式,可以有效减少数据传输量,节省用户带宽。因此当前特别适合使用JSON来作为移动应用的数据传输格式。

OAuth(Open Authorization)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。而OAuth2.0是OAuth协议的下一版本,它关注客户端开发者的简易性,同时为Web应用、桌面应用、手机和起居室设备提供专门的认证流程。

OAuthl.0的认证流程如下:

(1)客户端向服务器端请求临时令牌(Temp Token);

(2)客户端使用返回的Temp Token向服务器端请求认证令牌(Auth Token);

(3)客户端使用返回的Auth Token向服务器端获取访问令牌(Access Token);

(4)客户端使用返回的Access Token访问服务器上的接口。

相比之下OAuth2.0的认证流程简化如下:

(1)客户端向服务器端请求授权码(Auth Code);

(2)客户端使用返回的Auth Code向服务器端请求访问令牌(Access Token);

(3)客户端使用返回的Access Token访问服务器上的接口。

通过上面的流程可以看到,OAuth2.0节省了OAuthl.0中获取临时令牌的环节,另外出于安全考虑OAuth2.0中的授权码是有有效期的。另外OAuthl.0中每个令牌都需要加密,而OAuth2.0则通过使用https协议简化了这一步骤,这样服务器端和客户端代码都得到了简化,而且安全性更高。此外OAuth2.0考虑到客户端的多样性,因此对获取访问令牌提供了多种途径,如授权码、客户端私有证书、资源拥有者密码证书、断言证书等等。因此本系统选择使用OAuth2.0作为认证方式。endprint

通过上面的架构,即可把数据处理层提供的函数调用转换为HTIP调用,这样不管是传统的Web网站还是新兴的移动应用,都可以方便、安全地使用这些接口。

下面以用户管理模块为例进行详细的说明。

系统首先设计了Credential类,用于实现OAuth2.0认证。该类主要包括检查请求的链接是否使用HTTPS协议,产生Access Token值,校验Access Token值等功能,关键的地方是产生Access Token值。为了防止重现攻击,Access Token必须具有有效期,因此该值包含时间信息;另外系统还对Access Token进行了数字签名,目的是防止信息被非法篡改和假冒。其核心代码如下。

public static string GetAccessToken(string authKey)

{

if (authKey!=Config.Security.AuthKey) return string.Empty;

string rndString=FSMCrypt.FSMHash.GetRando mString(Config. Security.Rando mStringSize);

string hash= FSMCrypt.FSMHash.MD5(rndString, Config.Security.SALT);

string now=DateTime.Now.ToString();

string sourceString=string.Format(“{0};{1};{2}”,rndString,now, hash);

using (FSMCrypt.FSMEncryption crypt= new FSMCrypt.FSMEncryption(》

{

return

HttpUtility.UrlE nco de(c rypt.Enc rypt2(F SMCrypt.Enc ryptio nAlgo rithm.TripleDes,sourceString。

Config.Security.KEY, Config.Security.IV false, false》;

}

}

接着系统使用ASP.NET页面作为接收服务请求的通道,这样做的好处是可以更好地兼容桌面开发和移动应用开发。按照OAuth2.0的流程,每个页面的服务流程都是相同的,因此系统抽象出BasePage类,作为所有服务页面的基类。在BasePage类的Page_Lo ad事件中系统先检查当前是否使用HTTPS链接,然后再检查Access Token是否合法,都通过后再执行抽象方法Analyze。每个继承BasePage类的服务页面都需要实现Analyze方法,这是每个服务页面具体的服务功能。BasePage类的Page_Load事件的代码如下。

protected virtual void Page_Load(object sender, EventArgs e)

{

if (lAllowConnect(》

return;

else

Analyze();

}

其中AllowConnect函数就是用于检测当前请求是否使用了HTTPS链接,以及对Access Token进行合法性校验的。

前面的数据处理层因应不同的数据库设计了不同的数据处理模块,而对于服务页面就要根据相应的配置参数对接口进行实例化。为此在该层,系统实现了DB ControllerFactory工厂类,该类会自动根据配置参数产生相应的数据控制对象实例。例如要实例化上面的IUsersController接口,DBControllerFactory类会执行CreateUsersController函数,该函数会根据配置参数生成SQLDBController.UsersController实例或OracleDB Controller.UsersController实例。其核心代码如下。

public class DBControllerFactory

{

public static IUsersController CreateUsersController()

{

//获取配置是数据库类型

Config.DBStyle dbStyle=Config.GetDBStyle();

//根据配置参数返回相应的对象实例

switch (dbStyle)

{

case Config.DBStyle.SQLSERVER:

return new SQLDBController.UsersController();

case Config.DBStyle.ORACLE:

return new OracleDB Co ntroller.UsersCo ntroller();

default:

return null;

}

}

}

而服务页面对接口进行实例化时,只需调用DBControllerFactory类的相应方法即可。例如要实例化IUsersController接口,其代码如下。

IUsersController users Co ntroller= DB Co ntrollerFactory.CreateUsersController();endprint

这样不管使用哪类数据库,都无需修改任何代码,只要修改配置参数即可,有效提高了系统的适应能力和可扩展能力。

2.4 客户端

2.4.1 智能终端App应用

智能终端App应用使用了离线数据同步技术,实现了App的离线使用和数据的自动同步。这里采用了SQLite数据库作为离线数据的存储服务。SQLite是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,具有轻量级、单一文件存储、跨平台、可移植的特性,非常适合嵌入式系统。而且iOS、Android和Windows Phone系统中都有相应的类库支持,使用起来非常方便。

作为离线存储,客户端只需要保存部门信息、用户信息、电话号码信息和数据修改信息即可,对应的就是Departments、Users、Telephones和DataChangelnfo这四个表,其他表的修改日志无需存储。这四个表的结构与数据存储层中的表结构相同,这里就不再赘述。

智能终端App的主要功能如图3所示。

(1)登录。考虑到各个企业基本上都有自己的中央认证系统,因此这里可以使用企业自己的认证接口。另外,为了免除用户每次都要输入认证信息,系统还实现了自动登录功能。在首次登录时可以选择下次是否自动登录,若已选择,则第一次登录成功后,系统会把用户的相关信息保存到本地,下次打开客户端时,系统会先检查本地是否存有用户信息,若有则再检查账号是否异常,如果正常则进入系统,否则跳转到登录界面等待用户登录。其登录的流程如图4所示。

其中“检查账号是否异常”的目的是确认服务端没有暂停或删除该账号。另外除了登录之外,在用户使用其他功能之前,系统都会进行账号异常检查,以提高服务端对账号的控制能力。

(2)浏览通讯录。用户可以按组织架构来查阅用户信息。对查询到的信息可以直接拨打电话或发送短信。为了留给用户更多的控制权,用户点击拨打电话或发送短信时,系统只是打开拨号软件或短信发送软件,然后自动输入接收者的电话号码,并没有拨打电话或发送短信,这样用户可以根据需要进行调整,例如是否使用IP拨号等等。

(3)查询通讯录。用户可以按电话、姓名、账号或部门等条件来快速搜索用户信息。同样对搜索到的信息可以直接拨打电话或发送短信。为了减少用户的输入量,在输入查询条件时,系统支持自动完成功能。例如输入王字,则会自动列出所有姓王的列表让用户选择。另外系统还支持模糊查询,例如输入8632,则系统会查询所有电话号码以8632开头的信息。

(4)个人通讯录。通过该功能用户可以增、删、改自己的通讯录。修改后,数据会自动同步到云端,然后其他用户会自动下载此更新信息。为方便用户在更换手机卡后及时更新通讯录,系统实现了自动检测功能。当发现手机卡更换后会及时提醒用户,如图5所示。另外考虑到当下有不少用户有多台手机多个联系电话,因此本系统对用户的联系方式没有数量上的限制,不论有多少个联系电话都可以添加进去。

(5)来电提示。来电提示是本系统的一大特色。当有来电时系统会查询来电者的信息,如果来电号码只对应一个人,则显示其姓名和所在部门,如若对应多个人(如来电号码是某个办公室的公共电话)则只显示电话号码对应的部门名称。如图6所示。如果用户没有接通来电,系统还会记录来电者的信息,以便查看漏接的电话是哪个部门的哪位同事在哪个时间打来的

对于来电号码的查询需要注意以下问题。如果是同城的电话号码,用户在系统中登记固定电话时,一般是不会登记长途区号的,这是一种普遍的习惯,但是来电号码中却是包含长途区号的。另外我国的长途区号有3位、4位和5位,例如北京是010,深圳是0755,由于位数的不统一,因此处理起来比较繁琐。但是有一点相同的是,长途区号都是以0开头的。而对于手机来电,只会直接显示11位的号码,即使是长途,也不会在前面加0。因此可以断言,对于国内的电话,如果来电号码是以0开头的,则必定是固话,否则就是手机号码。为此检查来电的逻辑如下:首先查询系统中是否存在该完整的来电号码,如果有则显示对应信息,否则检查该号码是否以0开头,如果不是则退出,否则先去掉前3位再检查,如果依然无果则去掉前4位再检查,如此重复,直至找到此号码或剩下的号码长度小于3位为止。剩下的号码长度小于3位的原因是,我国的电话号码是没有小于3位的。在Android系统下的核心代码如下所示。

//查询电话号码信息

String info=usersTelephoneViewController.getUserInfo(phoneNumber);

//找不到该电话号码信息

if (info.isEmpty(》{

//判断是否为固话

if (phoneNumber.startsWith(“0”)){

//去掉长途区号再找

String number= phoneNumber.substring(3);

while《info=usersTelephoneViewController.getUserInfo(number》.isEmpty()

&& (number.length()>3》{

number= number.substring(l);

}

}

}

if (linfo.isEmpty(》

popWindow(info+“\r\n”+phoneNumber);

} else{

removeWindow();

}

(6)参数设置。包括设置是否启用来电提示,设置软件和通讯录更新方式等等。这样用户可以选择在哪种联网状态下才检查软件和通讯录更新,以避免消耗用户的上网流量。endprint

(7)自动同步通讯录。在设定的联网状态下,系统会启用后台线程,对比本地通讯录与云端的数据是否有差异,如有差异,则自动下载差异的数据并更新本地信息。由于差异的数据通常不多,因此同步所消耗的流量也是非常有限的。另外此过程是自动的,对于用户完全透明,不需要人工干预。

前面已提到,数据更新的信息是在数据库的触发器中记录的,因此客户端只需通过对比本地的数据版本号和服务器端的数据版本号即可获知是否有数据需要更新。这里取DataChangelnfo表中字段OID的值作为数据版本号,只要客户端的数据版本号小于服务器端的数据版本号,则客户端就会读取DataChangelnfo表中所有大于客户端数据版本号的记录,然后根据所记录的操作类型再从对应的数据表中获取更新信息或删除本地的某条记录,这样就实现了差异数据的更新操作。

(8)系统更新。与自动同步通讯录相同,在设定的联网状态下,后台线程会检查系统是否有新版本,若有则提示用户进行更新。客户端软件都有版本号,只要对比本地的软件版本号和服务器发布的版本号即可获知是否有更新。

2.4.2 Web网站应用

Web网站应用以网页的形式给用户提供服务,其扩展性非常好。例如可以嵌入各企业的门户平台,可以接人微信平台等等。但由于Web方式无法获取某些设备信息,所以此模式下无法实现手机卡检测、来电提示等特殊功能。另外Web方式只能实时获取数据,因此无法离线使用。除此之外,其他的功能与智能终端App应用方式相同。另外由于该Web网站要同时兼容PC模式和移动模式,因此在开发时需要在页面中添加声明,否则在移动设备上使用时会出现页面很小,不能自适应屏幕大小等问题。

2.5 管理端

管理端也是以网页形式提供服务。主要是供管理员对通讯录信息进行增、删、改等操作,也就是通过调用数据访问层的接口函数实现对数据信息的处理。同样为了让系统同时兼容PC模式和移动模式,也需要在页面中添加上面的声明语句。

3 结论

目前,笔者已经成功研发了这套以云计算技术为基础,以HJO(HTTP+JSON+OAuth)为架构的企业共享型移动通讯录,并已获得国家软件著作权授权。系统在笔者单位使用后受到了用户的好评。

本系统实现了通讯录信息的高度共享和自主管理的能力。用户能在不同的地点使用各种终端(如手机、平板电脑、PC机等)获取云端的数据信息。借助移动终端随身携带的特点,结合云计算技术,系统突破了时间和地域的限制,让每个用户能够随时随地地维护自己的信息,充分显现移动应用的便捷性,另外还提高了数据的时效性、准确性、可靠性和可用性,减轻了企业对员工通讯录信息的维护工作量,降低了维护成本,提高了维护的效率。利用来电提示功能,用户不需要维护手机本身的通讯录,也能对同事的来电一目了然;使用离线数据同步技术方便了用户离线使用,节省了通讯流量,这些都给使用者带来了更好的用户体验。由于系统使用了HJO架构,因此具有良好的扩展能力,后续该系统可以扩展为多企业的数据共享,甚至是以行业或地区为基础的数据共享。例如餐饮业,系统可以汇集各商家的联系方式,同时商家也可自行维护自己的信息,用户通过本系统即可以迅速查找所需餐厅的联系方式,这样即方便商家推广也方便了用户的使用。

猜你喜欢

云计算
谈云计算与信息资源共享管理
基于MapReduce的故障诊断方法
实验云:理论教学与实验教学深度融合的助推器