system: [SYSTEM]

user: 2. 系统设计与实现 2.1. 系统结构设计目标 系统的客户端使用eclipse的IDE作为开发工具，开发的任务主要是客户端显示界面的设计与实现、客户端数据控制逻辑的设计与实现、客户端网络访问和客户端输入控制。 系统的服务器端使用Myeclipse结合MySQL作为开发工具，服务器端需要实现的功能包括：接收客户端的数据请求并且将请求数据转换为服务器端的编码格式、为各个数据处理功能设计程序接口、实现各个数据处理功能、使用Hibernate技术 [ 2 ] 简化数据库与服务器之间的相互访问。 根据系统结构和实际的需求，“快递代取”系统设计 [ 3 ] 的目标是： 1) 实现用户在系统中快速注册 2) 支持用户管理个人信息 3) 用户发单消息群发 4) 实现发单用户与接单用户一对一绑定 5) 客户端为用户提供服务，服务器端做业务处理 “快递代取”系统的功能分布结构图如图1所示。 基于上述目的，“快递代取”系统客户端与服务器端具体的功能如图2所示。 2.2. 系统功能 1) 用户注册功能 为了能够更加方便的管理用户信息和为用户提供更加优质的服务，用户第一次使用本系统时必须先进行注册，用户将注册时需要将必要信息填写完整。由系统审核通过后，该用户将在本系统中拥有自己的个人账户。只有拥有账户的用户才能够登陆本系统，使用本系统。 2) 用户登录功能 在本系统注册过的用户，可以凭借注册的用户名以及密码登录到系统中。登陆后的用户才可以使用本系统的发单、接单等其他功能。 图1. 软件功能分布图 图2. “快递代取”系统客户端与服务器端具体功能 3) 用户修改资料功能 为了方便用户能够管理自己的基本信息，系统提供用户资料修改功能。该功能能够让用户修改自己的一部分个人信息并保存到后台服务器中。用户使用用户资料修改功能不能修改个人财富等系统控制的信息，以此保证用户使用本软件的公平性。 4) 发单功能 发单功能是本系统的核心功能之一。每当用户需要别人帮忙代取快递时，用户可以点击发单按钮，填写所取快递的基本信息并将该任务发送到社区，等待其他人承接该任务。 5) 接单功能 接单功能也是本系统的核心功能。用户在空闲时或者去取自己快递时，可以在社区中查找自己能够帮别人代取的快递，承接该用户的订单，以此方法来获取虚拟金币(在用户需要别人代取快递时需要支付给接单者虚拟金币以此作为答谢)。 6) 查看接、发单历史记录功能 用户可以利用此功能查看自己曾经帮别人代取快递或者要求别人帮忙代取快递的详细记录，以便用户更好的了解自己的账户使用状况。 虚拟金币的设置保证了用户使用本软件的公平性。每一个用户可以通过帮别人代取快递而达到不用自己每次都要到校外取快递的目的。 2.3. 系统模块与实现 2.3.1. 客户端 系统客户端是与用户直接接触的，因此在设计用户端软件功能结构时要站在用户的角度要充分考虑用户体验。决定用户体验的两个重要因素分别是界面布局和软件运行流畅性。保证前者的关键在于在设计软件功能时保证功能之间的层次关系清晰明了，而保证后者的关键在于选择适合的开发技术。 基于以上论述，可以得到系统客户端的功能结构如图3所示。 2.3.2. 服务器端 系统的服务器端承担了系统中近70%的逻辑运算，是整个系统的核心。服务器端虽不需要向外界显示任何信息，但其能否正常运行却是系统能否向外界显示正确信息的关键。服务器端的设计使用分层结构设计思想，保证层与层之间留有固定的接口，这样即可以将各层的逻辑分开设计，减少编写代码的复杂度，又方便日后技术发展后对服务器端的优化。 服务器端的功能结构如图4所示。 2.4. 关键技术与算法 2.4.1. 客户端关键技术与算法 客户端针对每个界面功能的不同，都对应着不同的逻辑控制代码。另外，网络数据传输使用TCP/IP协议，在数据进入传输控制层之前使用JSON对其进行封装，当数据离开传输控制层之后解析封装的JSON，得到传输的具体数据。客户端逻辑控制程序使用模块化设计思想，减少控制逻辑之间的耦合度。 客户端逻辑控制部分全部基于以下几个技术开发的，下面主要对开发技术做进一步详细说明： 1) 线程的使用 [ 4 ] [ 5 ] ： 在Android开发平台下，为了保障主进程的安全性，客户端的主进程是不允许直接访问网络的，所以每当客户端有访问网络的需求时，必须开启一个新的线程服务进而访问网络，向服务器发送服务请求。 图3. 客户端功能结构图 图4. 服务器端功能结构图 在客户端发送的请求中，所有的程序变量和JavaBean都使用JSON.toJSONString方法，封装成JSON [ 6 ] 对象后才向网络发送。当服务器接收到客户端的请求后，首先解析JSON对象，根据解析后的数据执行相应的服务并向客户端返回字节流，客户端在请求不超时的前提下读取字节流并使用utf-8编码标准将字节流转换为字符串，进而转换成客户端程序中的变量。 用户数据在客户端的流向如图5所示。 2) SharePreference的使用： SharePreference是简单的持久化设置，它将所要共享的数据保存在一个xml文件中，这样其他的界面就可以通过程序的上下文获取该变量。 SharePreference的工作原理如图6所示。 客户端的某一个界面若想将本界面的某个变量共享到其他界面，该变量需调用SharePreference方法，这样该界面会作为根界面，其他界面可以根据上下文Context对象getSharePrefere方法得到共享变量的值。 3) Bundle的使用： Bundle用非持久化的方法将数据信息传递到另一个上下文中。例如在本系统中，用户查看完自己的个人信息之后可以随时修改，这时就需要将前一界面的数据放到修改界面，此时使用Bundle最为合适。 4) 界面与程序之间数据的传递： 界面与程序之间数据的传递包含两个方向的传递 [ 7 ] 。 第一是界面向程序传递数据。用户在客户端界面输入的数据需要进行合法性验证、类型转换才可以在控制逻辑程序上下文中使用。在本系统中，对用户输入合法性的验证是使用正则表达式对输入数据进行检验。如果输入数据不符合正则表达式规定的标准则不允许改数据进入控制逻辑的上下文，用户需要 图5. 客户端数据流向图 图6. SharePreference方法原理图 重新输入。对于类型装换，逻辑控制程序可以通过FindViewById方法获取经过正则表达式检验合格的数据，再使用toString()等方法将其转换为程序变量。 第二是程序将数据写到界面上。相比界面向程序传递数据，由于逻辑控制程序中的数据一定是合法的，所以程序向界面传递数据并不需要检验数据的合法性，因此只需要调用Adapter即可将程序变量显示在界面上。 正则表达式：正则表达式是判断即将写入程序的变量是否合法的一个方法，使用正则表达式对输入信息进行合法性检验充分保障了系统的安全性。 图7是数据在界面与程序之间的转换关系。 2.4.2. 服务器端关键技术与算法 软件系统的服务器端使用分层结构设计，过滤器层、servlet层、数据库访问层、SessionFactory层分别有自己的任务，每层都是调用下层的方法，向上层提供服务，提高层内部的内聚，减少层之间的耦合，提高系统的运行效率，最终实现服务器端的整体功能。 下面按照从下往上的顺序依次介绍各主要层。 1) SessionFactory层： SessionFactory是初始化Hibernate时调用的，在与数据库建立连接时，它充当了数据代理的角色，并且他还负责创建每一个Session对象。在框架技术中，SessionFactory已经是封装比较完善的一个类，在本系统中直接使用了Hibernate [ 8 ] [ 9 ] 中自带的SessionFactory类。SessionFactory层数是服务器端分层结构的最底层，它封装了对数据库具体操作的行为，只为数据库操作层提供一组接口，方便数据库操作层的调用。 图7. 正则表达式运行流程图 2) 数据库操作层： 数据库操作层调用SessionFactory层的接口向servlet层提供服务。 数据库操作层的构成如图8所示。 其主要由两大模块组成，第一个模块是对用户数据的操作，第二个模块是对快递信息的操作。这两个模块都继承了BaseHibernateDAO这个函数来实现对数据库的基本操作(包括增加数据、查询数据、修改数据、更新数据等)。 两个模块中每个模块都有接口和接口的实现两类class文件，接口是向上层提供服务的，上层函数调用接口实现某一功能时不需要知道这些接口是如何实现的，而接口的实现则是实现该功能的具体逻辑以及对下层接口的调用。 3) Servlet层(单元测试)： Servlet层主要的功能是：①接收前面客户端发出的请求；②调用相应的数据库操作层的接口来向客户端提供服务；③将数据库操作层返回的数据发送回前面用户端。 Servlet层是服务器端接收并处理客户端业务请求的核心控制层，它只调用下层(数据库操作层)为它提供的接口，不向上层(过滤器层)提供接口服务。解析和封装JSON数据在本层中是主要任务，但值得注意的是，在本层解析数据前一定要先经过过滤器层将数据转化为utf-8的编码格式才能正确的对数据进行解析。这也是服务器端最高层，过滤器层必要性的体现。 本系统中servlet层的具体逻辑如图9所示。 单元测试：单元测试是测试后台服务器端代码时使用的虚拟前端请求，在真实的使用环境中和前后端统一综合测试时不用修改代码，不影响系统运行。 4) 过滤器层： 过滤器层主要是使前面的客户端与后面的服务器端之间使用统一的编码格式，以此解决中文乱码的问题。本系统中，约定客户端与服务器端都是用utf-8的编码格式，所以当服务器端接收到客户端发来的数据请求后，过滤器层会通过与客户端之间的沟通将数据格式变为utf-8的编码格式。