说明:本文章是本人于2019年大四的毕业设计节选,两年后再来回顾,发现当时还是比较稚嫩,现在看来,当时在程序设计架构方面存在些许问题。(2021-04-10突然想把毕设公开)

摘 要

  随着经济的发展以及技术的进步,各种新技术、新材料的应用,使得停车场车辆出入管理系统的各种管理功能逐渐完善,可靠性逐步提高。现如今,在绝大多数停车场管理系统中使用了现代电子系统控制技术,同时使得管理更加智能、便捷。所以在此推出停车场车辆出入管理系统以便管理进出车辆,更好地服务于现代社会人们快节奏的生活步伐,完全替代时下人工管理所造成的诸多问题。
  本系统除了管理车辆的进出场外,同时也为用户设计了一些其他的管理功能。本系统将权限分为管理员以及普通员工,功能方面有车辆出入库功能、车位管理功能、停车费计算功能、过卡免收费功能、进出场记录查询功能、数据同步功能、员工上下班签到签退功能、登录系统功能以及用户管理功能。本系统主要采用C/S架构,编程语言是C/C++,编程工具用Qt,服务器用阿里云的Ubuntu系统。
  本文将对停车场车辆出入管理系统设计与实现进行详细以及全面地分析。将介绍了系统所使用的相关技术,以及明确系统的可行性和需求,提出总体设计的方案,详细说明系统功能的实现方法,具体分析系统测试过程中遇到的主要问题。

关键词:出行;停车场;车辆出入;C/S;Qt

ABSTRACT

  With the development of the economy and the advancement of technology, the application of various new technologies and new materials has gradually improved the various management functions of the parking lot vehicle access management system and gradually improved the reliability. Today, modern electronic system control technology is used in most parking management systems, while making management smarter and more convenient. Therefore, the parking lot vehicle access management system is introduced here to manage the entry and exit of vehicles, better serve the fast-paced life of people in modern society, and completely replace the problems caused by the current manual management.
  In addition to the management of vehicles in and out of the field, the system also designed some other management functions for users.This system divides the authority into the administrator and the ordinary staff, the function aspect has the vehicle to enter the storehouse function, the parking space management function, the parking fee calculation function, passes the card to be free to charge the function, enters the exit record inquiry function, the data synchronization function, the staff to work and work to sign in the check-out function, the login system function and the user management function.This system mainly USES C/S architecture, programming language is C/C++, programming tools with Qt, server with ali cloud Ubuntu system.
  This paper makes a comprehensive analysis of the vehicle access management system in the parking lot.This paper introduces the relevant technology used in the system, clarifies the feasibility and requirements of the system, proposes the overall design scheme, explains the implementation method of the system function in detail, and analyzes the main problems encountered in the process of system testing in detail.

Keywords: Travel; The parking lot;Vehicle access; C/S; Qt

目 录

摘 要
ABstract
第一章 前言

1.1研究本课题的背景
1.2 国内外研究现状
1.2.1国外停车场管理发展状况
1.2.2国内停车场管理发展状况
1.3研究本课题的意义
1.4研究方法
1.4.1 文献研究法
1.4.2 调查法
1.4.3 观察法
1.5研究内容和结构说明
第二章 系统分析
2.1可行性分析
2.1.1 经济可行性
2.1.2 技术可行性
2.1.3 硬件可行性
2.1.4 操作可行性
2.2 需求分析
2.2.1 功能需求
2.2.2 性能需求
2.2.3 用户需求
2.2.4 数据库需求
2.3系统建模
2.3.1 用例模型分析
2.3.2 用例阐述
2.4系统过程设计
2.4.1 员工使用系统活动图
2.4.2 车位管理活动图
2.4.3 结算管理活动图
2.4.4 车主VIP信息管理活动图
2.4.5 个人信息管理活动图
2.4.6 车辆进出场记录查询活动图
2.4 本章小结
第三章 系统设计
3.1系统架构设计
3.1.1 客户端内部架构
3.2系统功能设计
3.3 功能模块动态建模
3.3.1 车辆出入管理顺序图
3.3.2 员工登入系统与退出系统顺序图
3.4 系统业务逻辑设计
3.3.1 系统登录注册等功能服务程序
3.3.2 车位信息管理功能服务程序
3.3.3 车辆出入库功能服务程序
3.3.4 车主VIP服务程序
3.3.5 车辆进出场记录查询服务程序
3.5 数据库设计
3.5.1 数据模型分析
3.5.2 数据库表及结构设计
3.5 本章小结
第四章 系统实现
4.1 系统流程图
4.2 系统功能模块
4.2.1 模拟控制车辆进出场与信息显示模块
4.2.2 管理员管理账号模块
4.2.3 登录系统模块
4.2.4 客户端车辆进出场记录界面显示模块
4.2.4 车位管理模块
4.2.5 结算管理模块
4.2.6 车辆进出场记录查询模块
4.2.7 车主VIP账户管理模块
4.2.8 员工签到签退模块
4.2.9 个人信息管理模块
4.3 系统部分核心代码
4.3.1 界面布局
4.3.2 功能界面初始化
4.3.3 各功能界面的信号槽绑定
4.4 系统正则表达校验
4.4.1 车牌号码正则表达式
4.4.2 手机号码正则表达式
4.4.3 身份证号码正则表达式
4.5 本章小结
第五章 系统测试
5.1 系统测试目的
5.2 系统测试内容
5.3 本章小结2
总 结
参考文献

第一章 前言

  生活在即将全面奔向小康的中国特色社会主义社会里的我们,出门的方式更加多种多样,并且更加“高级”了。但是现阶段互联网行业不景气,许多互联网公司不是倒闭就是大量裁员。例如曾风靡一时的OfO小黄车,由于各种因素,已经不再是共享单车的巨头。为什么会有发生这样的事情?是竞争、是运气、是国人的素质……。随着越来越多的城市因为交通拥堵和停车可用性不足而陷入困境,智能停车行业也在不断发展。虽然传感器技术的部署仍然是智能停车发展的核心,但各种其他技术创新也可以实现更具适应性的系统。包括摄像头、无线通信、数据分析、感应回路、智能停车计时器和高级算法。

1.1研究本课题的背景

  我国作为人口第一大国,不管是天然资源还是人工生产的资源,人均平摊下来少得可怜,这也就是为什么我国还是发展中国家的主要原因之一。日前,我国乃至世界的人数与日俱增,在吃、穿、住、行的必须“活动”中,“行”也是多种多样的。例如乘车出行,你可以打出租、软件叫车、坐公交以及自己开车等,在一些非一线城市里,如果上下班不是很堵车的话完全可以自己开车来代步。更别说一线城市了,从上下班高峰期的堵车情况就能看出车主们对于停车位的需求,由此,停车场也会随之增多,形式各异。按地理位置来说可分为地面、地上、地下等,按收费来说除了收费、免费外还可继续细分划时间收费,可谓是花样繁多。

1.2 国内外研究现状

  随着世界的发展和我国经济的增长,汽车保有量越来越大,停车场的需求也越来越严重,交通压力也需要停车管理系统来减轻交通压力。国外同样也是如此,但是不同的是,国外的系统使用率相对我国更加多或更加智能。

1.2.1国外停车场管理发展状况

  目前,国外的停车场车辆出入管理系统基本上不使用现金,大多使用电子钱包。此外,许多国外停车场管理系统都配备了停车位引导系统和停车位查询系统等智能设备,使停车场管理系统的功能更加完善和丰富。对于许多国内停车场,仍然需要支付现金停车费。目前,一些国外停车设备制造商可以实现“网络化存储”停车管理系统。管理系统可以统一分配停车位资源,统一交易结算。停车用户可以通过家庭网络预留停车位,支付停车费,并检查旅行目的地的各种停车信息。这种新型的停车场管理适应了网络在人们日常生活中越来越受欢迎的趋势。停车场管理系统的范围和功能得到了极大的扩展和扩展。当然,虽然停车管理系统使用了大量先进技术,但系统成本非常高,技术难以实现。系统的高维护成本给实施和普及带来了实际障碍。

1.2.2国内停车场管理发展状况

  最初的国内停车场管理系统是在引进和消化吸收国外同类系统的基础上逐步发展起来的[1]。发展初期,由于有许多关键设备国内无法生产,因此停车场管理系统硬件大多采用国外产品,所以这一阶段的国内停车场管理系统带有更多“集成”的意味[1]。近些年来,我国停车场车辆出入管理系统已逐步发展起来。但其仍处于初级应用阶段,大多数系统并未充分考虑我国实情,因此会出现许多问题。在我国,技术设备已成为制约管理系统发挥管理功能的瓶颈。例如,一些管理系统使用非常先进的自动牌照识别技术,该技术旨在实现用于车辆访问的无人和非实物收费的工作模式。但是,在实际应用过程中,这种新技术往往无法克服目前一些车牌污垢,生锈和安装位置不当的情况,使管理系统无法自动识别,导致系统暂停异常。为了使系统正常工作,通常需要有管理人员。

1.3研究本课题的意义

  停车场车辆出入管理系统是一种安装在计算机中的软件,用于控制停车场车辆出入以及管理停车,帮助相关人员解决停车问题。停车场车辆出入管理系统软件具有收费,缓解交通压力,智能停车等各种功能。随着该软件的发展和高交通压力,停车场车辆出入管理系统将具有更多的功能。停车场车辆出入管理系统用于停车收费,随着需求和技术的发展,停车管理系统的功能越来越复杂,一些停车管理系统具有引导功能甚至一些停车场车辆出入管理系统可以帮助城市减少交通压力。新型的停车场车辆出入管理系统将车辆进入和退出数据详细记录在计算机系统中,因此可以消除人为错误的发生并落入个人口袋中。在防盗方面发挥有效作用。车辆进出记录,除了图像对比功能外,还可以有效防止车辆被盗和更换。减少人员管理,降低人工成本。

1.4研究方法

1.4.1 文献研究法

  为了解停车场车辆出入系统的实际情况,本人将查阅许多相关研究成果以及理论资料。将通过前人已研究过的成果和结论,从而考虑自己的系统将如何更加适应我国现有国情以及复杂情况。更好地消除现存的缺陷以及获取更多的市场的需求,促进停车场车辆出入管理系统的发展。

1.4.2 调查法

  本人将通过走访各个停车场闸门的形式来了解各个不同的停车场管理系统的功能。和通过资料来了解我国大中型城市中的停车场内是否配备了电子管理系统。这些管理系统有的功能单一,仅显示进出场记录界面,有的功能不全,多出入口无法联机查询。对于上述情况,本人准备将自己的停车场车辆出入管理系统的功能打造得更全面,更符合现实。

1.4.3 观察法

  本人目前在实习,每天早出晚归都需要开共享汽车去上班,因此会经过许多停车场,了解到他们的收费情况。本人准备每次进出商业停车场以及自己学校停车场时仔细观察车辆过闸时人员与系统的操作。对于多出入口的停车场,将从不同角度进行观察。

1.5研究内容和结构说明

  论文阐述了开发基于Linux系统以及Windows系统的停车场车辆出入管理系统的背景、研究本课题的意义、国内外的研究现状、系统的可行性分析、需求分析以及功能分析。并且结合了相关图表对系统的总体框架和详细设计进行了说明。同时也对系统的数据库表进行了分析。

第二章 系统分析

  本章将对停车场车辆出入管理系统进行系统分析。将从可行性、需求上进行分析。同时会对系统建模、用例阐述以及系统过程设计进行描述。详细全面的系统分析将解决开发中遇到的不必要的难题,规划好要做什么,要怎么做。

2.1可行性分析

2.1.1 经济可行性

  关于经济可行性,可从开发角度以及客户使用角度两个方面讨论。从开发角度来说,需要的硬件设备有可以上网的电脑,性能不做太多要求。本系统需要一台云服务器,本人在阿里云上选购的云服务器ECS,搭载Ubuntu系统,服务端程序就运行在其上。当然,若在实际生产环境中,客户需要自己购买服务器;从客户使用角度来说,关于本系统的硬件设备只需要一台能上网的基本配置的电脑,其他硬件设施如高清拍照摄像头、电机闸门等另算,这都是停车场的标配。综上看来,对于开发人员开发一套本系统来说是很实惠的。

2.1.2 技术可行性

  本系统兼容Linux系统以及Windows系统,正是得益于Qt这款开发软件。用以客户端和服务器的架构,即C/S架构。本系统主要在虚拟机Linux-Ubuntu系统上开发,后期配置Windows系统,可作为辅助验证,因为本人习惯在Linux下开发,也是以后的发展趋势。关于为什么主打选择Linux,其过去主要作为服务器运行,但经过几年的发展,其用户界面有了很大的改善,如今Linux
已经成为美观易用,用户友好的桌面操作系统,在某些方面,Linux甚至赶超Windows和Mac成为用户首选[9]。

2.1.3 硬件可行性

  在前文2.1.1“经济可行性”中已经提及到了硬件相关。对于用户来说,其只需要配置一台普通电脑即可安装本系统。如果用户想更换运行环境,也可以使用专门嵌入到Android系统的平板来进行触屏操作。当然,除了用电脑安装本系统外,还需要有闸门与摄像头,这都是基本配置。

2.1.4 操作可行性

  本系统操作非常简单,只需要基本的鼠标操作以及键盘输入,对于会用电脑的人来说根本不需要太多教学。系统的主界面仿照Ubuntu-Linux系统,将功能按钮放置在左侧成列,各个图标可直观看出对应的功能,可以说是不会用电脑的人都会操作。

2.2 需求分析

2.2.1 功能需求

  本系统包含有管理员注册员工账号、注销员工账号功能,个人信息管理、车位管理、车主VIP信息管理、结算管理、进出场记录查询以及员工上下班签到管理功能。核心功能在看不见的车辆进出场时客户端与服务端的交互,这是本系统实现的重点以及难点。

2.2.2 性能需求

  为了确保本系统可以长时间稳定的运行,停车场车辆出入管理系统须满足如下性能需求:

(1)系统的可兼容性以及可扩充性

(2)系统响应的精确性以及及时性

(3)系统的易维护性以及易操作性

(4)系统的安全性

2.2.3 用户需求

  本系统角色仅有两种,一种是拥有绝对权限的管理员,一种是权限较低的员工。管理员和普通员工的功能并不完全相同,有管理员能做而普通员工不能做的,这涉及到重要信息读写;有普通员工能做的而管理员不能做的,这涉及到普通员工考勤。

  管理员:注册员工账号、注销员工账号,个人信息管理、车位管理、车主VIP信息管理、结算管理、进出场记录查询。

  普通员工:个人信息管理、车位信息查看、车主VIP信息管理、结算信息查看、进出场记录查询、上下班签到签退。

2.2.4 数据库需求

  本系统将在服务程序运行的平台搭建数据库。完全满足客户端无需直接操作数据库,这才是标准的C/S架构。本系统的数据库将存储各种信息,包括停车场管理员以及员工用户信息、在线车辆车牌及数量信息、VIP车主详细信息、车辆出入记录信息等。本系统会对数据库表的读写操作非常平凡,因此需要一个性能、存储速度都非常好的数据库。

2.3系统建模

2.3.1 用例模型分析

  本系统中的参与者仅有两类,其一是管理员,另一个是普通员工。管理员独有的活动有管理员工账号,可对员工账号进行增删改查,还有车位管理、结算管理。普通员工独有的活动有上下班签到签退。这二者共同的活动有车主VIP信息管理、进出场记录管理、个人信息管理。由此可得系统总用例图,如图2.1系统总用例图所示。
在这里插入图片描述

图2.1 系统总用例图
### 2.3.2 用例阐述

(1)员工使用系统用例阐述

  员工使用系统是指管理员分配的员工账号密码后,用此账号密码可登录进入系统,随后做一些列常规操作。如表2.1员工使用系统用例阐述所示。

表2.1员工使用系统用例阐述

用例名称员工使用系统
用例描述对系统常规功能的使用,如车主VIP信息管理,个人信息管理、进出场记录管理等
参与者员工
用例名称员工使用系统
状态账号密码录入数据库表
前置条件员工成功登录进入系统并签到
后置条件签退成功
基本操作流程 不可操作流程1)员工登录系统,服务端验证身份信息 2)员工进行各种功能操作 3)签退退出系统 登录系统失败

(2)车位管理用例阐述

  车位管理功能里的更新车位功能仅对管理员开放。因此普通员工在此模块下使用本功能只能进行简单的查询在停车辆车牌号操作。下表将以管理员的视角进行车位管理用例阐述,如表2.2车位管理用例阐述表

表2.2 车位管理用例阐述

用例名称车位管理
用例描述修改总停车位数量
参与者管理员
状态账号密码录入数据库表
前置条件管理员成功登录进入系统并进入车位管理功能界面
后置条件退出系统
基本操作流程 不可操作流程1)管理员登录系统,服务端验证身份信息 2)进入此功能界面,查看在停车辆 3)根据实际情况修改停车位数量 登录系统失败

(3)结算管理用例阐述

  结算管理功能同样是只有管理员才能对计费规则进行操作,普通员工只能进行查看当前营收与当前计价规则。结算管理用例阐述表如表2.3所示。

表2.3结算管理用例阐述

用例名称结算管理
用例描述修改按时间阶段计价规则
用例名称结算管理
参与者管理员
状态账号密码录入数据库表
前置条件管理员成功登录进入系统并进入结算管理功能界面
后置条件退出系统
基本操作流程 不可操作流程1)管理员登录系统,服务端验证身份信息 2)进入此功能界面,查看计价规则 3)根据实际情况更新阶段收费规则 登录系统失败

(4)车主VIP信息管理用例阐述

  车主VIP信息管理功能没有权限要求。管理员和普通员工可用此模块给需要长期在此停车场停车的车主办理VIP账户。车主VIP信息管理用例表如表2.4所示。

表2.4车主VIP信息管理用例

用例名称车主VIP信息管理
用例描述为车主注册账号、查询余额、更换车牌、更换手机
参与者管理员、普通员工
状态账号密码录入数据库表
前置条件管理员成功登录进入系统并进入车主VIP信息管理功能界面
后置条件退出系统
基本操作流程 不可操作流程1)管理员登录系统,服务端验证身份信息 2)进入此功能界面,注册车主信息 3)根据实际情况修改车主信息 登录系统失败

(5)个人信息管理用例阐述

  个人信息管理功能也是对本系统所有角色开放。此功能用于用户修改自己的密码或手机号码。个人信息管理用例表如表2.5所示。

表2.5个人信息管理用例

用例名称个人信息管理
用例描述用户自行修改密码或手机号码
用例名称个人信息管理
参与者管理员、普通员工
状态账号密码录入数据库表
前置条件管理员成功登录进入系统并进入个人信息管理功能界面
后置条件退出系统
基本操作流程 不可操作流程1)管理员登录系统,服务端验证身份信息 2)进入此功能界面,修改个人信息 3)根据实际情况修改个人信息 登录系统失败

(6)车辆进出场记录查询管理用例阐述

  交易记录查询管理功能没有权限要求,此功能也称车辆进出场记录。管理员和普通员工可用此模块查询已完成的车辆进出场记录。交易记录查询管理用例表如表2.6所示。

表2.6车辆进出场记录查询管理用例

用例名称车辆进出场记录查询管理
用例描述查询车辆进出场记录
参与者管理员、普通员工
状态账号密码录入数据库表
前置条件管理员成功登录进入系统并进入车辆进出场记录管理功能界面
后置条件退出系统
基本操作流程 不可操作流程1)管理员登录系统,服务端验证身份信息 2)进入此功能界面,查询记录信息 3)根据实际情况查询车辆进出场记录信息 登录系统失败

2.4系统过程设计

2.4.1 员工使用系统活动图

  停车场闸门看守员工在登录本系统后,须进行签到,此功能为拓展接口,可为考勤管理预留。签到之后则可点击界面上的按钮分别对车位管理、结算管理、车主VIP信息管理、个人信息管理、交易记录查询、签退进行操作。员工使用系统活动图如图2.2所示。
在这里插入图片描述

图2.2 员工使用系统活动图

2.4.2 车位管理活动图

  由于车位管理功能涉及到权限不同从而使用功能的内容不同,因此下图描述的是管理员的车位管理活动图,从而省去了签到签退功能。车位管理活动图如图2.3所示。在这里插入图片描述

图2.3 车位管理活动图

2.4.3 结算管理活动图

  结算管理也因权限不同而使用的内容不同。只有管理员才能够进行按时间阶段进行计价方案更改。结算管理活动图如图2.4所示。在这里插入图片描述

图2.4 结算管理活动图

2.4.4 车主VIP信息管理活动图

  车主VIP信息管理的所有功能无权限不同要使用不同,但是为了节省绘图空间,这里仍然以管理员的角度出发,如图2.5所示。在这里插入图片描述

图2.5 车主VIP信息管理活动图

2.4.5 个人信息管理活动图

个人信息管理功能活动图如图2.6所示。在这里插入图片描述

图2.6 个人信息管理活动图

2.4.6 车辆进出场记录查询活动图

车辆进出场记录查询活动图如图2.7所示。在这里插入图片描述

图2.7 车辆进出场记录查询活动图

2.4 本章小结

  本章进行了系统分析,通过可行性分析与需求分析后对本系统有了感性的认知。随后对本系统的过程的重要功能进行了活动图描述。本章省去了用例图,以活动图作为代表,将各个系统功能模块进行展示。更加直观地体现了系统各功能的活动流程,为系统设计以及系统实现做好铺垫。

第三章 系统设计

  对系统进行了系统需求分析后,下面的工作就是针对系统的需求进行功能设计。系统功能的设计是建立在需求分析的基础上的。用户有怎样的需求、市场有怎样的需求,就要设计相应的功能来实现其需求。

3.1系统架构设计

  本系统所设计的基于Linux或Windows系统的停车场出入管理系统,架构为C/S架构。作为一个典型的客户端-服务器模式,本系统将服务程序以及所有数据资料放置在阿里云ECS服务器上,可以在本地用SSH工具远程连接置服务器。数据库的读写操作均由服务程序完成。服务器系统为Ubuntu系统,CPU为1核,内存2G,出网带宽1Mbps,公网IP为47.106.103.130,私有IP为172.18.42.118,客户端连接公网IP和端口置服务程序。大致架构如下图
3.1 所示。
在这里插入图片描述

图3.1 系统架构

3.1.1 客户端内部架构

  本系统最直观的展现就是客户端程序,界面是由两部分组成,顶部栏显示当前时间和当前用户,下面则显示功能业务界面。这样做的目的是减少界面切换响应,将统一的显示固定下来。在Qt里使用QStackWidget将各功能界面依次入栈,每个界面均有按钮可切换至其他界面,使用Qt里信号槽的特性进行界面跳转。

3.2系统功能设计

  本系统主要的功能对系统的管理员注册员工账号、注销员工账号功能,个人信息管理、车辆管理、VIP车主管理、结算管理、交易记录查询以及员工上下班签到管理等功能。管理员注册、注销员工账号功能为一个单独的软件,但是隶属于本系统,从该软件注册的账号,可使用注册通过的用户名与密码登录停车场车辆出入管理系统(后称管理系统);个人信息管理是用户登录管理系统后,可修改个人的密码或手机号码,此功能对管理员与普通员工功能权限一致;车辆管理功能会涉及到权限不同从而功能不同,普通员工只能进行查看今日出入情况和检索在停车辆车牌号,管理员多出的功能是更新车位数量;VIP车主管理功能无权限之分,在这个功能模块中,使用者可注册车主信息,为其进行余额充值、更换车牌、更换手机号以及根据身份证号查询其信息等;结算管理功能有权限之分,普通员工仅限查看收费规则以及查看今日营收信息,管理员则可以更新收费规则,即时生效;交易记录查询功能无权限之分,在此功能模块下,可按时间段、车牌号、时间段以及车牌号查询该停车场车辆进出场记录以及缴纳的费用,同时会显示查询的这些记录中缴费的总数额,另外还支持导出记录生产txt文件;员工签到签退功能是为考勤管理设计的,在普通员工登入系统后,首先会要求员工签到,只有在员工签到之后才能使用其他功能,员工如需退出本系统时,需要签退,签退后才会被允许退出本系统。系统的总体功能图如图3.2所示。
在这里插入图片描述

图3.2 系统总体功能结构图

3.3 功能模块动态建模

  此小节将使用顺序图来描述本系统的重点功能,其实真正的复杂功能是系统内部自行运行,对操作者来说是看不见的,操作者唯一使用的就是切换各种功能模块。

3.3.1 车辆出入管理顺序图

  不管是普通员工还是管理员登录进入本系统后,车辆出入管理功能就在后台启动。当车辆进入本系统所管理的停车场时,系统本地客户端会检测该车辆车牌是否已存在本停车场,如果已存在,则说明车辆不合法,不予进入。当车辆车牌合法后,客户端将车牌号以及当前进场时间上传至服务端,服务端收到后会将信息存储至数据库表中,并将成功信息返送给客户端,客户端才可控制闸门抬杆。当车主需要将车子开走时,即离开本停车场时,客户端会将该车辆车牌号以及当前出场时间上传至服务端,服务端程序会拿该车牌号去数据库表里比对,从而提取出该车辆进场时间,将刚才获得的出场时间与进场时间作差可获得停车时长。服务端整理好该车的数据后发送给客户端,客户端则会根据停车时间以及结算规则计算出停车费用。如果车主是VIP用户,则可从余额里自动扣除费用后开闸放行,若车主不是VIP用户,则需手动缴纳费用后才可放行。车辆出入管理顺序图如图3.3所示。在这里插入图片描述

图3.3 车辆出入管理顺序图

3.3.2 员工登入系统与退出系统顺序图

  作为一个停车场车辆出入管理系统,其功能不仅在于车辆,由于用户的特殊性,本系统需要作出必要的考勤功能,因此本系统提供了一个员工进入系统签到与退出系统签退的功能。员工登入系统与退出系统顺序图如图3.4所示。在这里插入图片描述

图3.4 员工登入系统与退出系统顺序图

3.4 系统业务逻辑设计

  在3.1中提到了本系统的架构模式,是C/S架构模式。本系统分为客户端程序和服务端程序,客户端程序有两个,一个是管理员专属的为员工分配账号的程序,另一个则是本系统直观上的“管理系统”程序,下称客户端程序。客户端程序与服务端程序实时交互,通过发送任务命令加对应反馈的方式进行交互。客户端必须接入网络才可与服务程序交互,服务端上的数据库用于存储必要的数据,以供后续业务查询、更新等操作。服务端上的服务程序不是一个,而是单独的功能模块对应相应的服务程序,通过不同的端口号区分,在阿里云ESC服务器上,服务程序有五个,下面介绍各个服务程序与客户端的业务交互逻辑。

3.3.1 系统登录注册等功能服务程序

  该服务程序的端口号为2019,用于管理员使用账号管理软件分配或删除员工账号以及验证用户登录。具体接受命令有登录、注册、注销、修改密码、修改手机号码、查询账户以及退出登录功能。由于本系统拥有两种角色,因此在登录时,客户端程序会要求选择角色,即是管理员还是员工。一个停车场有一个或多个出入口,本系统为每个停车场提供了唯一编号,若是在一个停车场里面的客户端,都会要求填写客户端ID。客户端程序会进行基本的账号密码长度以及其与客户端ID有无进行检查,通过检查后会将其发送至对应的服务程序。服务程序收到信息后会判断任务类型,取出其中需要的字段,由于是登录操作,服务程序首先会判断是什么角色,如果是管理员,则直接在数据库表中检索账号与密码,匹配成功后则返回成功信息至客户端,客户端收到后即进入主界面;如果是普通员工,则服务程序首先会检查该账号和密码是否在数据库表中匹配,通过后就会检查该账号是否在线,如果在线,则直接返回给客户端,客户端将不予该账号再次登录本系统,提示相关错误,如果不在线,则可让客户端进入签到界面。当普通员工要退出本系统时需要进行签退操作,此时客户端会向服务程序发起退出请求,服务程序则将该账号从在线用户数据库表中移除。该服务程序的注册、注销以及查询账号功能仅对管理员开放,这些任务消息在另一个独立的客户端软件中。

3.3.2 车位信息管理功能服务程序

  该服务程序的端口号为2020,其功能相对简单,有查询车位信息、更改总车位数量以及更新占有车位数量。虽然从表面上看起来只有仅仅三个功能,但是其中查询车位信息以及更新占有车位数量是在一个多出入口停车场同步的必要功能与方法。在客户端启动后,会定时查询对应的客户端ID的车位信息,同时本地实时更新车位情况;在有车辆进入或驶离停车场时,更新占有车位数量功能将被触发。即当A出入口有车辆进入时,总车位会减一,此时所有出入口的显示都必须立刻更新车位状况,这就需要无时无刻客户端都与服务端在进行车位信息查询的原因。还有一个更改总车位数量的功能仅限管理员使用,例如停车场车位扩建或临时封闭一些停车位,则需要管理员来进行车位数量更改,此时需要控制一个逻辑的地方就是,更改的总车位数量不能低于在停车位数量也不能为负值,这需要服务程序去做控制。

3.3.3 车辆出入库功能服务程序

  该服务程序的端口号为2021,其是本系统的核心服务程序,是业务逻辑的重心。当车辆进场时,客户端将车牌信息(含时间以及模式)发送至服务程序,服务程序首先会拿车牌号去在停车辆表里比对,若存在该车牌号,则说明该停车场内已有此车牌号的车辆,那就不能让该车辆进入停车场,就向客户端返回失败信息。若不存在该车牌号,则将该车牌号插入在在停车辆表中,然后向客户端返回成功信息,此时车辆才得以入场;车辆出场时,客户端将车辆信息发送至服务程序,由于是出场,服务器从在停车辆表里直接将车牌号删除,无需查询有无该车牌,但在删除之前,需要将进场的时间戳提取出来,将进出场时间等信息打包在返回给客户端的信息中,同时拿该车牌号去车主VIP表中检索,如果在车主VIP表中存在该车牌号,则将返回消息的VIP标志置为1。将信息发送给客户端,客户端按计费规则计算出需缴费用,最后将所有情况(车牌号、进场时间、出场时间、停留时间、VIP标志、缴费额度、客户端ID)再发送给服务程序,服务程序将信息记录在信息记录表中。如果是VIP车主,则将车主VIP表里车牌号对应的余额与缴纳费用作差,更新车主VIP余额。

3.3.4 车主VIP服务程序

  该服务程序的端口号为2022,其功能模块基本上相当于一个小型增、改、查系统,包含了车主信息注册、余额充值、车牌号更换、手机号码更换、账号信息查询以及查询所有VIP车主身份证号。当某车主常用本系统管理的停车场时,可向闸门员工申请注册成为VIP车主,VIP车主所绑定的车辆车牌号在时出本系统所管理的停车场时可以进行自动余额缴费。注册的条件是身份证号码作为唯一区别号、手机号码、车牌号以及充值额度,车主VIP注册主要以人为本,不以车牌号为主,即注册好车辆信息后,车主可在使用期间要求更改手机号或车牌号。目前只考虑一人一车的情况,注册了VIP可在本软件管理的所有停车场生效。当余额低于扣款阈值时,则自动缴费功能失效,需要车主手动缴费或充值余额扣费后才可放行。在进行车主信息录入或修改时,客户端会对所有输入值进行校验,即看身份证号、手机号码、车牌号以及余额(是否5的倍数)输入是否合法,其中车牌号的校验除了本地校验无误外(例如湘A66666则不行),还需要在服务端从数据库里校验是否已经存在车主注册该车牌号,目的就是要确保一人一车。

3.3.5 车辆进出场记录查询服务程序

  该服务程序的端口号是2023,用于客户端上传与查询进出场交易记录。其只操作一个数据表,在车辆出场前一刻,客户端将该车在本系统所管理的停车场的停车信息上传至服务程序,服务程序则将信息存储至数据库表。客户端对该服务程序所操作的命令除了上传记录外还有提取记录功能,可按时间段查询(客户端会控制最后时间不得超过查询时间),可按车牌号查询其所有记录,亦可按车牌号以及时间段查询该车辆的停车记录。当查询到记录后,服务端会将数据发送至客户端,客户端会在软件界面显示各条记录,并将这些记录的缴费额度进行累加,得出当前记录营收总数。当数据显示后,员工可将进出场记录导出成文本文件,会在软件目录生成以当前时间命名的文本文件,供财务查账等。

3.5 数据库设计

  本系统数据库使用的SQLite3数据库。SQLite,是一款轻型的数据库,其是遵守ACID的关系型数据库管理系统,它被包含在一个相对小的C库中[8]。是由纯C语言开发的数据库。它的设计目标是应用于嵌入式系统的,而且已经使用在了很多嵌入式产品中,由于是C语言开发,它占用资源非常的低,在嵌入式设备中,只需要几百K的内存就足够支持其运行。它能够支持Windows/Linux/Unix等操作系统,同时能够与许多不同的程序语言相结合。因此在这个项目中,我使用SQLite3数据库来作为本系统的数据库。

3.5.1 数据模型分析

  通过对停车场出入管理系统的分析,得出本系统总体E-R图。如图3.5所示。在这里插入图片描述

图3.5 总体E-R图

3.5.2 数据库表及结构设计

  该系统在数据库中定义了6张表,其中包含:登录注册表(login_register_X)、在线用户表(OnlineUsers)、停车信息表(Car_space_info)、车主信息表(Driver_Info)、出入场信息记录表(In_Out_Record)、在停车辆表(OnlineCars)。下面详细介绍所有表的结构:

(1)登录注册表(login_register_X):该表保存的字段有用户名、密码、手机号、性别、权限,其作用是验证员工登录系统是否合法,表后的“X”是客户端ID编号。

(2)在线用户表(OnlineUsers):该表保存的字段有用户名与客户端ID,客户端ID的作用是区分不同停车场的系统,该表的作用是存储在线用户,目的是为了防止统一系统登录两个同样的用户。

(3)停车信息表(Car_space_info):该表保存的字段有客户端ID、所有车位、占用车位,该表描述了该客户端所在的停车场的车位总数以及停车数量信息。

(4)车主信息表(Driver_Info):该表保存了司机信息,分别有身份证号、手机号、车牌号、余额,其作用是在该表内的车主信息在进出本系统管理的停车场时可自动从余额里缴费。

(5)出入场信息记录表(In_Out_Record):该表保存的字段有车牌号、车辆入场时间戳、车辆出场时间戳、车辆停车时间、所缴纳的费用、VIP标志、客户端ID,该表的作用是用于后期核验与查询记录。

(6)在停车辆表(OnlineCars):该表保存的字段有车牌号、入场时间戳、客户端ID,其作用是临时保存在停的车辆,防止重复车牌号入场,另一个作用是在车辆出场时,系统可从该表中提取入场时间,这样就能计算出车辆在停时间。

详细的数据库表设计见表3.1-3.6。

登录注册表(login_register_X),见表3.1。

表3.1 登录注册表
字段名数据类型是否允许为空是否主键备注
usernamevarchar(16)not null用户名称
passwordvarchar(16)not null用户密码
tel_phonechar(11)not null用户手机号
sexintegernot null用户性别
adminintegernot null用户权限

在线用户表(OnlineUsers),见表3.2。

表3.2 在线用户表
字段名数据类型是否允许为空是否主键备注
usernamevarchar(16)not null用户名称
CIDintegernot null客户端ID

停车信息表(Car_space_info),见表3.3。

表3.3 停车信息表
字段名数据类型是否允许为空是否主键备注
CIDintegernot null客户端ID
all_spaceintegernot null总停车位
字段名数据类型是否允许为空是否主键备注
occupy_spaceintegernot null已占用停车位

车主信息表(Driver_Info),见表3.4。

表3.4 车主信息表
字段名数据类型是否允许为空是否主键备注
IdCardchar(18)not null身份证号码
tel_phonechar(11)not null手机号码
licence_platevarchar(10)not null车牌号码
balanceintegernot null余额

出入场信息记录表(In_Out_Record),见表3.5。

表3.5 出入场信息记录表
字段名数据类型是否允许为空是否主键备注
licence_platevarchar(10)not null车牌号码
In_timeintegernot null入场时间戳
Out_timevarchar(10)not null出场时间戳
Stay_timeintegernot null车辆停留时间
Moneyintegernot null停车费用
Vip_flageintegernot nullVIP标志
CIDintegernot null客户端ID

在停车辆表(OnlineCars),见表3.6。

表3.6 在停车辆表
字段名数据类型是否允许为空是否主键备注
licence_platevarchar(10)not null车牌号码
In_timeintegernot null入场时间戳
CIDintegernot null出场时间戳

3.5 本章小结

  本章从系统架构、系统功能模块、系统业务逻辑以及数据库的设计等方面描述了系统在设计阶段取得的进展。
当然本系统在数据库设计方面还也存在许多不足之处,即数据库里的表都没有主外键关系,但是我的数据库表只需要用来存储数据就足矣了。

第四章 系统实现

  本章将围绕系统的运行环境、系统的流程图和系统的几个主要模块的实现进行详细的介绍。本系统的主要模块分为管理员注册员工账号、注销员工账号模块,个人信息管理模块、车辆管理模块、VIP车主管理模块、结算管理模块、交易记录查询以及员工上下班签到管理模块等。

4.1 系统流程图

以下流程图将大概勾勒出使用本系统的大致流程,如图4.1系统流程图。在这里插入图片描述

图4.1 系统流程图

4.2 系统功能模块

4.2.1 模拟控制车辆进出场与信息显示模块

  本系统在真实情况下会涉及到硬件设施以及图像识别算法。为了更方便的模拟车辆出入停车场,本系统增加了两个功能。功能一是模拟车牌识别,直接以填充车牌的方式进行车辆出入停车场;功能二是展示车辆信息,入场与出场时均会显示在界面上。此二功能即模拟实现了作摄像头车牌识别与LED显示屏,为真实环境预留接口。模拟车辆出入库的车牌填充会对车牌号进行正则校验,校验通过后,发送服务器进行车牌号检索。如发现此停车场已存在同样的车牌号,则视为非法车牌并禁止入场;当车辆出场时,同样会检查车牌号是否正确,然后上送服务器进行检索,若车牌不存在则报错,此时需人工干预。模拟控制车辆进出场界面如图4.2所示。在这里插入图片描述

图4.2 模拟控制车辆进出场界面图

模拟LED信息显示界面如图4.3所示。在这里插入图片描述

图4.3 模拟LED信息显示界面图

4.2.2 管理员管理账号模块

  本系统的账号由管理员来分配,在本人构思本系统时,很好的想了一下什么是“系统”。系统不是一个独立的软件,也不是一个孤立的客户端与服务端,系统它是一套体系,因此我为本系统新增了一个为管理软件客户端分配账号的程序软件。软件登录进入后的界面如图4.4管理员管理账号界面图所示。在这里插入图片描述

图4.4 管理员管理账号界面图

账号管理功能的类图如图4.5所示。在这里插入图片描述

图4.5 功能类图

4.2.3 登录系统模块

  登录模块是系统的必备模块,也是系统的“门面”,使用本系统的任何功能的前提只有通过登录模块进入。由于账号都是管理员分配,因此没有忘记密码一说,忘记了密码直接找管理员重新初始化账号即可。由于本系统的特殊性,即一个停车场会有多个客户端软件,因此同一停车场的不同客户端需要填写客户端ID,在同一个客户端ID下即可同步车辆出入信息以及车位信息。除了填写客户端ID之外还需要选择角色,即是管理员还是普通员工。登录界面如图4.6登录界面显示图所示。在这里插入图片描述

图4.6 登录界面显示图

登录功能类图如图4.7所示。在这里插入图片描述

图4.7 登录功能类图

4.2.4 客户端车辆进出场记录界面显示模块

  此功能模块是管理员登录后或普通员工登录签到后看到的第一个模块。该界面模块实时记录和显示了本停车场的进出场信息。其中包括车牌号、进场或出场、进场时间、出场时间、总停时间以及费用。对于进场车辆只显示车牌号、进场以及进场时间,对于出场车辆则显示所有信息。车辆进出场记录界面如图4.8所示。在这里插入图片描述

图4.8 车辆进出场记录界面图

车辆进出场记录界面显示模块类图如图4.9所示。在这里插入图片描述

图4.9 车辆进出场记录界面显示模块类图

4.2.4 车位管理模块

  管理员使用车位管理功能可管理本停车场的车位数量以及查询在停车辆车牌号。而普通员工只能进行车牌号查询操作。普通员工进入此功能界面无法看到“更新”按钮。管理员车位管理界面如图4.10所示。在这里插入图片描述

图4.10 管理员车位管理界面图

车位管理模块类图如图4.11所示。在这里插入图片描述

图4.11 车位管理模块类图

4.2.5 结算管理模块

  此功能模块对普通员工而言仅限查看作用,可查看时间端收费详情与当前营收。对管理员而言,除了有普通员工的功能之外,还可以自行设置计价标准。目前系统对管理员设置计价规则还未做控制,这是后续升级需要处理的事情。结算管理界面图如图4.12所示。
在这里插入图片描述

图4.12 结算管理界面图

结算管理模块类图如图4.13所示。在这里插入图片描述

图4.13 结算管理模块类图

4.2.6 车辆进出场记录查询模块

  车辆进出场记录查询功能共有三种查询模式。此功能模块权限对所有角色开放,其目的是为了针对性的查询进出场记录。可为后期补发票、对账或查询总营收,也可以做数据分析,发现潜在车主用户。在查询到记录后还可导出成文本文件,可用于文本打印等操作。车辆出场记录查询界面如图4.14所示。在这里插入图片描述

图4.14 车辆进出场记录查询界面图

车辆进出场记录查询功能类图如图4.15所示。
在这里插入图片描述

图4.15 车辆进出场记录查询功能类图

4.2.7 车主VIP账户管理模块

  车主VIP账户管理模块可以算是一个小的注册、修改与查询功能的集合。不管是管理员还是普通员工,在此功能模块下的权限都是一样的。车主VIP账户管理模块界面如图4.16所示。在这里插入图片描述

车主VIP账户管理功能类图如图4.17所示。
在这里插入图片描述

图4.17 车主VIP账户管理功能类图

4.2.8 员工签到签退模块

  员工签到签退功能只对普通员工角色开放,管理员无法进入此功能模块。员工登录本系统客户端后,首先会跳转至此功能界面进行签到,方可使用其他功能;员工退出本系统或点击了退出按钮没有签退的情况下,系统会自动跳转至此功能界面进行签退操作。此功能模块为考勤管理预留接口,统计员工在线时长。员工签退界面图如图4.18所示。在这里插入图片描述

图4.18 员工签退界面图

车主VIP账户管理功能类图如图4.19所示。在这里插入图片描述

图4.19 员工签到签退界面图

4.2.9 个人信息管理模块

  个人信息管理模块可以说是一个简化版的“车主VIP账户管理模块”。其作用是当前用户自行选择修改自己的密码或是手机号码。密码与手机号码本地会做正则校验,符合长度方可上送服务器进行更换。个人信息修改界面如图4.20所示。
在这里插入图片描述

图4.20 个人信息修改界面

个人信息修功能类图如图4.21所示。
在这里插入图片描述

图4.21 个人信息修功能类图

4.3 系统部分核心代码

  由于本系统客户端使用Qt开发,因此其信号槽机制可得以很好的展现。在客户端的实现中,有一个PManagergui类,其里面实现了各个界面以及网络处理等功能的信号槽绑定,以及各个界面的初始化工作。PManagergui类图如图4.22所示。
在这里插入图片描述

图4.22 PManagergui类图

4.3.1 界面布局

  实现界面布局的函数是initManager函数,此函数的作用是配置客户端界面布局,随后调用initPage函数初始化各功能界面模块以及connectAll函数进行信号槽的绑定。

initManager函数代码如下:

void PManagergui::initManager()
{
	//分配一个栈Widget空间,设置名字为“widgetList”,设置界面大小
	p_wgtList = new QStackedWidget( this );
	p_wgtList->setObjectName( "widgetList" );
	
	p_wgtList->setGeometry( 0, 60, PAGE_WIDTH, PAGE_HEIGHT_SUB );
	p_wgtList->setMaximumSize( PAGE_WIDTH, PAGE_HEIGHT_SUB ); 
	p_wgtList->setMinimumSize( PAGE_WIDTH, PAGE_HEIGHT_SUB );

    //为p_TitleBar对象分配空间,设置p_TitleBar的位置以及大小,设置p_wgtList的位置 
	p_TitleBar = new PTitlebar( this );
	
	p_TitleBar->setGeometry( 0, 0, 1250, 60 );
	p_wgtList->setGeometry( 0, 60, PAGE_WIDTH, PAGE_HEIGHT_SUB );
	
	//为space_loop对象分配空间	
	space_loop = new PSpace_loop();	
	initPage();          //初始化各界面模块	
	connectAll();        //绑定各个类的信号槽	
	this->show();        //显示本类的界面	
	Car_IO->show();      //显示进出场控制界面	
	Show_some->show();   //显示信息展示界面	
	
	//如果是管理员,直接进入主界面,否则进入签到界面	
	if( 1 == G_Admin )	
	{	
		switchPage( E_PAGE_MAIN, NULL );	
	}	
	else	
	{	
		switchPage( E_PAGE_STAFF_SIGN, NULL );	
	}
}

4.3.2 功能界面初始化

实现各个功能模块界面初始化的函数是initPage函数,其将本系统所有功能的模块类依次放入QStackWidget中。initPage函数如下:

void PManagergui::initPage()
{
	//为Car_IO、Show_some对象分配空间
    Car_IO = new Car_in_out(); 
	Show_some = new Show();
	//为主界面功能对象分配空间并将其插入到栈Widget中
    p_wgtMain = new MainUi();
	p_wgtList->insertWidget( E_PAGE_MAIN, p_wgtMain );
	//为车辆管理功能对象分配空间并将其插入到栈Widget中
    p_wgtCarManage = new PCarmanage();
	p_wgtList->insertWidget( E_PAGE_CARMANAGE, p_wgtCarManage );
	//为车辆管理功能对象分配空间并将其插入到栈Widget中
    p_wgtMoneyManage = new PMoneyManage();
	p_wgtList->insertWidget( E_PAGE_MONEYMANAGE, p_wgtMoneyManage );
	//为车辆进出场记录功能对象分配空间并将其插入到栈Widget中
    p_wgtIO_Record = new PIO_Record();
	p_wgtList->insertWidget( E_PAGE_IO_RECORD, p_wgtIO_Record );
	//为车主VIP信息管理功能对象分配空间并将其插入到栈Widget中
    p_wgtDriver_Vip = new PDriver_Vip();
	p_wgtList->insertWidget( E_PAGE_DRIVER_VIP, p_wgtDriver_Vip	);
	//为员工签到功能对象分配空间并将其插入到栈Widget中
    p_wgtStaff_sign = new PStaff_Sign();
    p_wgtList->insertWidget( E_PAGE_STAFF_SIGN, p_wgtStaff_sign );
	//为个人信息修改功能对象分配空间并将其插入到栈Widget中
    p_wgtInfo_Change = new PChangeinfo();
    p_wgtList->insertWidget( E_PAGE_INFO_CHANGE, p_wgtInfo_Change);
}

4.3.3 各功能界面的信号槽绑定

  本系统客户端的实现使用了大量的信号与槽,分有页面跳转类信号槽与功能信号槽。分别由connectPage函数和connectManager函数实现。由于connectManager代码量过多,因此不在正文部分展示,详情请见附录。connectPage函数代码如下:

void PManagergui::connectPage()
{
    connect( p_wgtMain, &PBasewgt::sigDispPage, this, &PManagergui::slotDispPage );
	connect( p_wgtCarManage, &PBasewgt::sigDispPage, this, &PManagergui::slotDispPage );
	connect( p_wgtMoneyManage, &PBasewgt::sigDispPage, this, &PManagergui::slotDispPage );
    connect( p_wgtIo_Record, &PBasewgt::sigDispPage, this, &PManagergui::slotDispPage );
    connect( p_wgtDriver_Vip, &PBasewgt::sigDispPage,this, &PManagergui::slotDispPage );
    connect( p_wgtStaff_sign, &PBasewgt::sigDispPage, this, &PManagergui::slotDispPage );
    connect( p_wgtInfo_Change, &PBasewgt::sigDispPage,this, &PManagergui::slotDispPage );
}

在上述代码中,各个类的信号函数都是sigDispPage,其对应的槽函数均是PManagergui
类的slotDispPage函数。在Qt中,信号函数是没有实现的,slotDispPage槽函数的实现如下:

void PManagergui::slotDispPage(EnumPage ePage, const QString strData)
{
	//切换界面 
	switchPage( ePage, strData ); 
}

slotDispPage函数调用了switchPage函数,switchPage函数实现如下:

void PManagergui::switchPage( EnumPage ePage, const QString sData)
{
	//设置当前界面
	p_wgtList->setCurrentIndex( ePage );
	//强转成其基类对象
	PBasewgt *pCurWgt = ( PBasewgt * )p_wgtList->currentWidget();
    pCurWgt->init( sData );
}

4.4 系统正则表达校验

  本系统客户端需要对车牌号码、手机号码、身份证号码、账号等进行本地校验,因此必须使用正则表达式。

4.4.1 车牌号码正则表达式

  车牌号正则表达式:"^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-Z0-9]{4}[A-Z0-9挂学警港澳]{1}$",此表达式全面的校验了我国的各种车牌号。

4.4.2 手机号码正则表达式

  手机号码正则表达式:"^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\\d{8}$",此表达式基本上包括了我国三大运行商以及部分网络电话字段的手机号码校验,但是无法验证真实性,只能验证是否是手机号码格式。

4.4.3 身份证号码正则表达式

  身份证号码正则表达式:"^[1-9][\\d{5}(18|19|([23]\\d))\\d{2}((0[1-9])|(10|11|12))((0-2]

[1-9])|10|20|30|31)\\d{3}[0-9Xx]$",此正则表达式只是折中版本的校验,满足15位和18位身份证校验的基本需求。不过仍然存在一些不足,例如地址码判定不够精确以及2月31日的号码也能通过,这方面还需要人工核验。后续可升级为读身份证信息提取身份证号码。

4.5 本章小结

  本章对系统架构进行了简单描述,以及对系统各功能模块实现的界面贴图和其对应的类图进行了描述与展示。同时对系统部分核心代码进行了展示与介绍以及客户端校验输入控制做了相关正则表达式的展示。

第五章 系统测试

5.1 系统测试目的

  测试是保证程序错误尽可能少的发生或发生的几率减小的一种手段,没有完美的程序保证不出问题。测试也不是为了去修复这些错误,而是去发现错误、找出错误原因,随后才是去解决错误。为了保证停车场车辆出入管理系统核心功能以及必要功能正常运行,更加需要详细测试,多方面考虑,从实际情况入手。

5.2 系统测试内容

测试用例名称:系统登录测试

功能描述:进入系统客户端

前提条件:系统所在平台能连上网络,可以ping通公网IP:47.106.103.130

系统登录测试用例表,如表5.1所示。

表5.1系统登录测试用例表
输入/动作期望的结果实际的结果
不输入客户端编号,输入无误的用户名,输入此用户名所对应的正确密码,点击按钮进行登录提示无CID提示无CID
不输入客户端编号,不输入用户名,输入此用户名所对应的正确密码,点击按钮进行登录提示请输入账号或密码提示请输入账号或密码
输入不存在的客户端编号,输入无误的用户名,输入此用户名对应的正确密码,点击按钮进行登录提示不存在此CID提示不存在此CID
输入无误的客户端编号,输入长度短于6个字符的用户名,输入字符长度范围无误的密码,点击按钮进行登录提示账号或密码过短提示账号或密码过短
输入无误的客户端编号,输入长度长于16个字符的用户名,输入字符长度范围无误的密码,点击按钮进行登录提示账号或密码过长提示账号或密码过长
输入无误的客户端编号,输入字符长度范围无误的用户名,输入长度短于8个字符的密码,点击按钮进行登录提示账号或密码过短提示账号或密码过短
输入无误的客户端编号,输入字符长度范围无误的用户名,输入长度长于16个字符的密码,点击按钮进行登录提示账号或密码过长提示账号或密码过长
输入无误的客户端编号,输入错误的用户名,输入此用户名对应的正确密码,点击按钮进行登录提示用户名或密码错误提示用户名或密码错误
输入无误的客户端编号,输入无误的用户名,输入错误的密码,点击按钮进行登录提示用户名或密码错误提示用户名或密码错误
输入/动作期望的结果实际的结果
输入无误的客户端编号,输入无误的用户名,输入此用户名对应的正确密码,选择错误的角色,点击按钮进行登录提示用户名或密码错误提示用户名或密码错误
输入无误的客户端编号,输入无误的用户名,输入此用户名对应的正确密码,选择无误的角色,点击按钮进行登录是管理员则直接进入主界面,是员工则进入签到界面是管理员则直接进入主界面,是员工则进入签到界面
输入无误的客户端编号,输入无误的已在线的账号,输入此用户名对应的正确密码,选择无误的角色,点击按钮进行登录提示该用户已在线提示该用户已在线
输入无误的客户端编号,输入无误的账号,输入此用户名对应的正确密码,选择无误的角色,断开网络,点击按钮进行登录提示无法连接至服务器提示无法连接至服务器
测试者测试日期测试结果(P/F)
邓子康2019-04-18P

测试用例名称:系统主界面测试

功能描述:系统主界面展示并记录了车辆出入的状况

前提条件:登录进本系统,并且保持网络连接

系统主界面测试用例表,如表5.2所示。

表5.2系统主界面测试用例表
输入/动作期望的结果实际的结果
车辆入场主界面显示该车辆车牌号入场记录主界面显示该车辆车牌号入场记录
车辆出场主界面显示该车辆车牌号进出场完整记录主界面显示该车辆车牌号进出场完整记录
切换至其他功能界面,车辆出入场,后切回主界面正确显示记录正确显示记录
点击“清除”按钮界面的数据被清空界面的数据被清空
测试者测试日期测试结果(P/F)
邓子康2019-04-19P

测试用例名称:车位管理测试

功能描述:停车场车位数量管理

前提条件:登录进本系统,并且保持网络连接

车位管理测试用例表,如表5.3所示。

表5.3车位管理测试用例表
输入/动作期望的结果实际的结果
管理员进入此功能界面,在输入框输入非数字字符,点击“更新”按钮提示请输入数字提示请输入数字
管理员进入此功能界面,在输入框输入负数,点击“更新”按钮请输入大于零的数字请输入大于零的数字
输入/动作期望的结果实际的结果
管理员进入此功能界面,在输入框输入小数,点击“更新”按钮提示错误数字提示错误数字
管理员进入此功能界面,在输入框输入的数字小于已停车位数量提示错误数字提示错误数字
管理员进入此功能界面,在输入框输入的无误的大于已停车位数量的数字界面更新显示总车位数量,并提示更新成功界面更新显示总车位数量,并提示更新成功
任意角色进入此功能界面,在输入框输入的无误的大于已停车位数量的数字界面更新显示总车位数量,并提示更新成功界面更新显示总车位数量,并提示更新成功
测试者测试日期测试结果(P/F)
邓子康2019-04-19P

测试用例名称:结算管理测试

功能描述:控制时区段计价规则,查看当前营收状况

前提条件:登录进本系统,并且保持网络连接

结算管理测试用例表,如表5.4所示。

表5.4结算管理测试用例表
输入/动作期望的结果实际的结果
普通员工进入此功能界面,不显示“确认”按钮不显示“确认”按钮不显示“确认”按钮
车辆缴费出库后,点击此功能按钮,界面能够正确显示当前累计营收金额正确显示当前累计营收金额正确显示当前累计营收金额
此功能界面能够正确显示区间计费规则正确显示区间计费规则正确显示区间计费规则
管理员进入此功能界面,能够正确显示区间计费规则正确显示区间计费规则正确显示区间计费规则
管理员进入此功能界面,填入非数字字符至价格设置框,按“确认”按钮提示请输入数字提示请输入数字
管理员进入此功能界面,填入小数数字至价格设置框,按“确认”按钮提示请输入无误的数字提示请输入无误的数字
管理员进入此功能界面,填入无误的数字至价格设置框,按“确认”按钮提示价格设置成功提示价格设置成功
测试者测试日期测试结果(P/F)
邓子康2019-04-20P

测试用例名称:进出场记录查询测试

功能描述:查询系统管理的停车场的进出场

前提条件:登录进本系统,并且保持网络连接,进入此功能界面

进出场记录查询测试用例表,如表5.5所示。

表5.5进出场记录查询测试用例表
输入/动作期望的结果实际的结果
选择开始日期和结束日期,选择“按时间”选项,点击确认按钮界面显示该时间跨度内的所有进出场记录界面显示该时间跨度内的所有进出场记录
输入/动作期望的结果实际的结果
选择开始日期和结束日期,选择“按车牌”选项,不填入车牌号,点击确认按钮提示请输入车牌号提示请输入车牌号
选择开始日期和结束日期,选择“按车牌”选项,填入不合法的车牌号,点击确认按钮提示请输入无误的车牌号提示请输入无误的车牌号
选择开始日期和结束日期,选择“按车牌”选项,填入有记录录的车牌号,点击确认按钮界面显示该车牌号在本停车场的进出场记录界面显示该车牌号在本停车场的进出场记录
选择开始日期和结束日期,选择“按时间和车牌”选项,填入有记录录的车牌号,点击确认按钮界面显示该车牌号在本停车场以及选择时间段内的的进出场记录界面显示该车牌号在本停车场以及选择时间段内的的进出场记录
查询到交易记录后,点击“导出文件”按钮在程序路径下生成当前日期的记录文件在程序路径下生成当前日期的记录文件
测试者测试日期测试结果(P/F)
邓子康2019-04-20P

测试用例名称:车主VIP账户管理测试

功能描述:对VIP车主的账户进行管理

前提条件:登录进本系统,并且保持网络连接,进入此功能界面

车主VIP账户管理测试用例表,如表5.6所示。

表5.6车主VIP账户管理测试用例表
输入/动作期望的结果实际的结果
点击“查询”按钮界面显示所有VIP车主身份证号界面显示所有VIP车主身份证号
选择“注册”选项,不填入任何数据,按“确认”按钮提示请填入数据提示请填入数据
选择“注册”选项,填入不合法的“身份证号码”,按“确认”按钮提示身份证号码不正确提示身份证号码不正确
选择“注册”选项,填入合法的身份证号码,填入不合法的车牌号,按“确认”按钮提示车牌号不合法提示车牌号不合法
选择“注册”选项,填入合法的身份证号码,填入合法的车牌号,填入不合法的电话号码,按“确认”按钮提示电话号码不合法提示电话号码不合法
选择“注册”选项,填入合法的身份证号码,填入合法的车牌号,填入合法的电话号码,填入小与零的余额,按“确认”按钮提示请输入大于零的数字提示请输入大于零的数字
选择“注册”选项,填入合法且未注册的身份证号码,填入合法的车牌号,填入合法的电话号码,填入无误的数字余额,按“确认”按钮提示注册成功提示注册成功
选择“充值”选项,填入已注册的车主身份证号码,填入无误的数字余额,按“确认”按钮提示充值成功提示充值成功
输入/动作期望的结果实际的结果
选择“更换车牌号”选项,填入已注册的车主身份证号码,填入正确车牌号,按“确认”按钮提示更换车牌号成功提示更换车牌号成功
选择“查询信息”选项,填入已注册的车主身份证号码,按“确认”按钮对应的框内显示查询到的数据对应的框内显示查询到的数据
点击“清除”按钮如果界面有手动输入的数据或查询到的数据,全部清空如果界面有手动输入的数据或查询到的数据,全部清空
测试者测试日期测试结果(P/F)
邓子康2019-04-20P

测试用例名称:员工签到功能测试

功能描述:员工上班考勤接口

前提条件:登录进本系统,并且保持网络连接

员工签到功能测试用例表,如表5.7所示。

表5.7员工签到功能测试用例表
输入/动作期望的结果实际的结果
普通员工登录跳转至此功能界面跳转至此功能界面
管理员点击此功能按钮提示是管理员提示你是管理员
普通员工在此功能界面,未签到,点击其他功能按钮界面不切换,提示请签到界面不切换,提示请签到
普通员工在此功能界面,签到界面显示签到时间并自动跳转至主界面界面显示签到时间并自动跳转至主界面
普通员工在未签退的情况下按退出键跳转至此功能界面跳转至此功能界面
签到后,在此功能界面点击签退按钮显示签退时间,在岗时间,并在程序路径下生成员工签退到记录显示签退时间,在岗时间,并在程序路径下生成员工签退到记录
签退后,点击其他功能按钮界面无反应界面无反应
签退后,点击“退出”按钮退出系统,程序结束运行退出系统,程序结束运行
测试者测试日期测试结果(P/F)
邓子康2019-04-20P

测试用例名称:个人信息修改测试

功能描述:更换个人账号密码或手机号

前提条件:登录进本系统,并且保持网络连接登录进本系统,并且保持网络连接,进入此功能界面

个人信息修改测试用例表,如表5.8所示。

表5.8个人信息修改测试用例表
输入/动作期望的结果实际的结果
选择“修改密码”选项,不输入任何数据提示请输入数据提示请输入数据
选择“修改密码”选项,输入长度短于8个字符的密码,点击确认按钮提示输入密码过短提示输入密码过短
选择“修改密码”选项,输入长度长于16个字符的密码,点击确认按钮提示输入密码过长提示输入密码过长
选择“修改密码”选项,输入字符长度范围无误的密码,点击确认按钮提示更改密码成功提示更改密码成功
选择“修改手机号”选项,不输入任何数据提示请输入数据提示请输入数据
选择“修改手机号”选项,输入长度不为11的字符,点击确认按钮提示输入的号码不是11位提示输入的号码不是11位
选择“修改手机号”选项,输入非手机号的11个字符,点击确认按钮提示非法手机号提示非法手机号
选择“修改手机号”选项,输入合法的手机号,点击确认按钮提示更改手机号码成功提示更改手机号码成功
测试者测试日期测试结果(P/F)
邓子康2019-04-20P

测试用例名称:多客户端管理同一停车场测试

功能描述:多出入口同步数据

前提条件:两个或两个以上员工账号使用同一客户端ID登录本系统

多客户端管理同一停车场测试用例表,如表5.9所示。

表5.9多客户端管理同一停车场测试
输入/动作期望的结果实际的结果
A出入口客户端某车辆入场,B出入口客户端查询总车位数量空闲车位数量减一空闲车位数量减一
A出入口客户端某车辆出场,B出入口客户端查询总车位数量空闲车位数量加一空闲车位数量加一
差一辆车停满停车场,A出入口客户端某车辆入场后,B出入口客户端某车辆也入场B出入口提示车位已满B出入口提示车位已满
测试者测试日期测试结果(P/F)
邓子康2019-04-20P

5.3 本章小结

  本章主要记录了本系统的功能测试,对各个数据输入以及动作细节进行严格测试。在测试期间发现了一些缺陷,本人对其及时进行了修复,在修复后本系统军通过了这些测试。本人在写这些测试用例时,才真正意识到测试是一件枯燥但是却是最重要的工作,也是产品质量的保障。

总 结

  本次毕业设计选择开发“停车场车辆出入管理系统”的原因是因为自己在公司实习期间上下班都开共享汽车,开车就需要去找停车位,找不到停车位的话就只能将车停在停车场,因此每天进出停车场闸门的时候本人就在想这个管理系统要如何实现。那时共享汽车风靡长沙,不过在编写此论文时本人开的那家共享汽车已经早已倒闭。本人认为这是一件挺悲哀的事情,也能反应出一个道理,不是什么行业火爆,做它它就会成功,这里面存在优胜劣汰,你追我赶。
  本系统的优点是对于服务程序的按功能分布式架构,即一个客户端内不同的功能会与不同的服务程序交互。这样做的好处是服务程序要崩溃的话不会一次性全部崩溃,另一个好处是分散服务程序压力,功能点对点通信。本系统真正做到服务程序在云端,即本人的服务程序是在阿里云上的一台Ubuntu系统上并且拥有公网IP,因此无论你在何处,只要能ping通这个公网IP,你就能使用本系统。本系统的缺点是部分服务程序开久了后会崩溃调,前期发现服务程序存在一点bug,不过已做修复,但是这个修复只能保持一段时间,过久了还是会崩溃,后续还要做出错处理机制。
  在此次毕业设计中,本人一直在公司实习,同时也在做公司的项目。本人发现毕业设计的系统对公司开发的项目来说简直是小巫见大巫。本系统若真是用于实际环境,则会暴露出更多的问题,原因还是在于个人能力有限。大学四年以来,本人发一个规律,即每一次的专业课课程设计的小组的人员数量一次比一次少,到了毕业设计之时,就是自己一个人。在本次毕业设计中,本人承担了一个项目的所有角色,体会到了从小组成员分工到一个人独立完成的困难。不过这也是很好的,自己亲力亲为,从架构设计到整体实现,整个过程虽然辛苦,但是收获了许多。

参考文献

[1] 刘文利.国内停车场管理系统的现状与发展趋势[J].中国新技术新产品,2011

[2] 宁秋平.非接触IC卡停车场管理系统设计[D] .硕博学位论文,2005

[3] 谭浩强.C程序设计(第二版)[M].清华大学出版社,1999

[4] Stephen Prate(美) 张海龙、袁国忠译.C++ Primer Plus(第六版) [M].人民邮电出版社,2017

[5] Matthew、Stones (英) 陈建、宋健建译.Linux程序设计(第四版) [M].人民邮电出版社,2016

[6]高林,周海燕. 管理信息系统与案例分析 [M].人民邮电出版社,2004

[7] Grant Allen、Mike Owens(美) 杨谦、刘义宣、谢志强译.SQLite权威指南[M].电子工业出版社,2016

[8] 倪继利.QT及Linux操作系统窗口设 [M].电子工业出版社, 2006

[9] Linden(美) 徐波译.C专家编程 [M].人民邮电出版社,2002

[10] Kenneth A.Reek(美) 徐波译.C和指 [M].人民邮电出版社,2008

[11] Richard Stevens、Steve Rago(美).Unix环境高级编程第三版[M].人民邮电出版社,2016

[12]王维波、栗宝娟、侯春望.Qt5.9C++开发指南 [M].人民邮电出版社,2018

[13] Andrew Koenig、Barbara Moo(美) 黄晓春译.C++沉思录 [M].人民邮电出版社,2008

[14]张海藩.软件工程导论(第五版) [M] .清华大学出版社,2008

[15]李红等.管理信息系统开发与应用 [M].电子工业出版社,2014

附录A:系统部分源代码
user.c

#include "server.h"
/* user.c
 *本程序的作用是验证登录信息以及用户注册,将一直挂在后台运行
 *当客户端发送数据过来时,通过判断标志来确认是注册还是登录
 *注册则将信息分别写入对应的数据库存储
 *登录则将信息拿到数据库比对
 * 成功或失败均给客户端发送相应信息
 */
void *login_register(void *arg);
pthread_mutex_t mutex; 
sqlite3 *db = NULL;

void main()
{
	int listen_fd, conn_fd;
	struct sockaddr_in servaddr, cliaddr;
	socklen_t fixed_size = sizeof(cliaddr);
	struct thread_info t_info[MAX];
	pthread_t tid;
	int i = 0;

	int on = 1;
    setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	pthread_mutex_init(&mutex, NULL);
	listen_fd = socket(AF_INET, SOCK_STREAM, 0);
	bzero(&servaddr, sizeof(servaddr));

	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(SER_PORT_1);
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

	bind(listen_fd, (struct sockaddr *)&servaddr, fixed_size);

	listen(listen_fd, MAX);

	while(1)
	{
		if(i >= (MAX - 1))
		{
			i = 0;
		}
		conn_fd = accept(listen_fd, (struct sockaddr *)&cliaddr, &fixed_size);
		printf("Connected\n");
		t_info[i].cliaddr = cliaddr;
		t_info[i].conn_fd = conn_fd;

		pthread_create(&tid, NULL, login_register, (void *)&t_info[i]);
		pthread_detach(tid);
		i++;
	}

	sqlite3_close(db);
}

void *login_register(void *arg)
{
	int n, i, j;
	struct thread_info *t_info = (struct thread_info*)arg;
	struct login_register_info info;
	struct message mess;
	char username[17] = {0};   
	char password[17] = {0}; 
	char tel_phone[12] = {0}; 
	int sex;  
	int admin;
	int CID;
	
	char *errmsg = NULL;
	char buff[512] = {0};
	char **result = NULL;
	int row = 0, col = 0;
	int ret = 0;
	int flag = 0;

	bzero(&mess, sizeof(mess));
	
	pthread_mutex_lock(&mutex);
	ret = sqlite3_open("../Database/Graduation_Project.db", &db);

	if(ret)
	{
		fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
		sqlite3_close(db);
		return (void *)0;
	}

	while(1)
	{
		n = read(t_info->conn_fd, &info, sizeof(info));
		if(n == 0)
		{
			break;
		}

		memcpy(username, info.username, 16);
		memcpy(password, info.password, 16);
		memcpy(tel_phone, info.tel_phone, 11);
		sex = info.sex;
		admin = info.admin;
		CID = info.CID;
		
		FILE *fp = fopen("../Files/Data_config.txt", "r");
		
		while(!feof(fp))
		{
			bzero(buff, sizeof(buff));
			fgets(buff, sizeof(int), fp);
			if(CID == atoi(buff)) //存在CID
			{
				ret = 1;
			}
		}
		
		fclose(fp);	
		mess.flag = -1;	
		if(ret == 1)
		{
			ret = 0;
		}
		else
		{
			write(t_info->conn_fd, &mess, sizeof(mess));
			break;
		}
		
		if(info.flag == 1)//注册
		{
			if(select_all(CID, db, buff, &result, &errmsg, &row, &col, LOGIN_REGISTER) < 0)
			{
				break;
			}
		
			for(i = col; i < (row + 1) * col; i += col)
			{
				if(strcmp(username, result[i]) == 0)  //已存在用户
				{
					ret = Register_Error_1;
					mess.flag = ret;
					write(t_info->conn_fd, &mess, sizeof(mess));
					sqlite3_free_table(result);
					goto there;
				}
			}
			
			bzero(buff, sizeof(buff));
			sprintf(buff, "insert into login_register_%d values('%s', '%s', '%s', %d, %d);",
					CID, username, password, tel_phone, sex, admin);
			
			if(sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
			{			
				printf("%s\n", errmsg);
				ret = Register_Error_2;
				mess.flag = ret;
				write(t_info->conn_fd, &mess, sizeof(mess));
				sqlite3_free(errmsg);
				break;
			}

			ret = Register_Succ;
			mess.flag = ret;
			write(t_info->conn_fd, &mess, sizeof(mess));
			sqlite3_free_table(result);
			break;
		}
		else if(info.flag == 2)//登录
		{	
			//查询所有
			if(select_all(CID, db, buff, &result, &errmsg, &row, &col, LOGIN_REGISTER) < 0)
			{
				break;
			}
		
			if(admin == 1)
			{
				for(i = col; i < (row + 1) * col; i += col)
				{//用户名以及密码匹配
					if(strcmp(username, result[i]) == 0 && strcmp(password, result[i + 1]) == 0 && strcmp("1", result[i + 4]) == 0)
					{
				    	ret = Login_Succ;
						mess.flag = ret;
						write(t_info->conn_fd, &mess, sizeof(mess));
												
						sqlite3_free(errmsg);
						sqlite3_free_table(result);						
						goto there;
					}
				}
				
				ret = Login_Error_2;
				mess.flag = ret;
				write(t_info->conn_fd, &mess, sizeof(mess));
				sqlite3_free_table(result);
				break;
			}
			else
			{
				for(i = col; i < (row + 1) * col; i += col)
				{//用户名以及密码匹配
					if(strcmp(username, result[i]) == 0 && strcmp(password, result[i + 1]) == 0 &&  strcmp("1", result[i + 4]) != 0)
					{
						//放入在线用户数据库表
						bzero(buff, sizeof(buff));
						sprintf(buff, "insert into OnlineUsers values('%s', %d);", username, CID);
						if(sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
						{//失败
							ret = Login_Error_3;
							mess.flag = ret;
							write(t_info->conn_fd, &mess, sizeof(mess));
							sqlite3_free(errmsg);
							goto there;
						}				
						
						ret = Login_Succ;
						mess.flag = ret;
						write(t_info->conn_fd, &mess, sizeof(mess));
						sqlite3_free(errmsg);
						sqlite3_free_table(result);
						goto there;
					}
				}
				
				ret = Login_Error_1;
				mess.flag = ret;
				write(t_info->conn_fd, &mess, sizeof(mess));
				sqlite3_free_table(result);
				break;
			}	
			
		}
		else if(info.flag == 3)//更改密码
		{
			//查询所有
			if(select_all(CID, db, buff, &result, &errmsg, &row, &col, LOGIN_REGISTER) < 0)
			{
				break;
			}
			
			for(i = col; i < (row + 1) * col; i += col)
			{//修改密码只允许当前登录用户修改
				if(strcmp(username, result[i]) == 0)
				{
					ret = 1;
					break;
				}
			}
			
			bzero(buff, sizeof(buff));
			if(ret == 1)
			{
				sprintf(buff, "update login_register_%d set password = '%s' where username = '%s';", CID, password, username);
				if(sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
				{
					sqlite3_close(db);
					ret = Change_Pass_Error_2;
					mess.flag = ret;
					write(t_info->conn_fd, &mess, sizeof(mess));
					sqlite3_free(errmsg);
					break;
				}
			}
			else
			{
				ret = Change_Pass_Error_1;
				mess.flag = ret;
				write(t_info->conn_fd, &mess, sizeof(mess));
				sqlite3_free_table(result);
				break;
			}
			
			ret = Change_Pass_Succ;
			mess.flag = ret;
			write(t_info->conn_fd, &mess, sizeof(mess));
	        sqlite3_free_table(result);
			break;
		}
		else if(info.flag == 4)//更改手机号
		{
			//查询所有
			if(select_all(CID, db, buff, &result, &errmsg, &row, &col, LOGIN_REGISTER) < 0)
			{
				break;
			}
			
			for(i = col; i < (row + 1) * col; i += col)
			{
				if(strcmp(username, result[i]) == 0)
				{
					ret = 1;
					break;
				}
			}
			
			bzero(buff, sizeof(buff));
			if(ret == 1)
			{
				sprintf(buff, "update login_register_%d set tel_phone = '%s' where username = '%s';", CID, tel_phone, username);
				if(sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
				{
					ret = Change_Tel_Error_2;
					mess.flag = ret;
					write(t_info->conn_fd, &mess, sizeof(mess));
					sqlite3_free(errmsg);
					break;
				}
			}
			else
			{
				ret = Change_Tel_Error_1;
				write(t_info->conn_fd, &ret, 4);
				sqlite3_free_table(result);
				break;
			}
			
			ret = Change_Tel_Succ;
			mess.flag = ret;
			write(t_info->conn_fd, &mess, sizeof(mess));
	        sqlite3_free_table(result);
			break;
		}
		else if(info.flag == 5)//注销
		{
			//查询所有
			//先查在不在线
			if(select_all(CID, db, buff, &result, &errmsg, &row, &col, ONLINEUSERS) < 0)
			{
				break;
			}
			for(i = col; i < (row + 1) * col; i += col)
			{//存在用户名则不行
				if(strcmp(username, result[i]) == 0)
				{	
					ret = Delete_Error_3;
					mess.flag = ret;
					write(t_info->conn_fd, &mess, sizeof(mess));
					sqlite3_free_table(result);
					goto there;
				}
			}
			
			bzero(buff, sizeof(buff));
			if(select_all(CID, db, buff, &result, &errmsg, &row, &col, LOGIN_REGISTER) < 0)
			{
				break;
			}
			
			for(i = col; i < (row + 1) * col; i += col)
			{//找出用户名然后删掉
				if(strcmp(username, result[i]) == 0)
				{	
					if(strcmp("1",  result[i + col - 1]) == 0)
					{
						ret = -1;
						break;
					}
					ret = 1;
					break;
				}
			}

			if(ret == -1)
			{//不能删除管理员
				ret = Delete_Error_2;
				mess.flag = ret;
				write(t_info->conn_fd, &mess, sizeof(mess));
				sqlite3_free(errmsg);
				break;
			}
			
			bzero(buff, sizeof(buff));
			if(ret == 1)
			{
				sprintf(buff, "delete from login_register_%d where username = '%s';",CID, username);
				if(sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
				{
					ret = Delete_Error_4;
					mess.flag = ret;
					write(t_info->conn_fd, &mess, sizeof(mess));
					sqlite3_free(errmsg);
					break;
				}
			}
			else
			{
				ret = Delete_Error_1;
				mess.flag = ret;
				write(t_info->conn_fd, &mess, sizeof(mess));
				sqlite3_free_table(result);
				break;
			}
			
			ret = Delete_Succ;
			mess.flag = ret;
			write(t_info->conn_fd, &mess, sizeof(mess));
	        sqlite3_free_table(result);
			break;
		}
		else if(info.flag == 6)//查询
		{
			//查询所有
			if(select_all(CID, db, buff, &result, &errmsg, &row, &col, LOGIN_REGISTER) < 0)
			{
				break;
			}
	
			mess.flag = 100 + row;
			
			//创建一个空的文档(对象)
			cJSON *json = cJSON_CreateObject();		
			cJSON *array = NULL;
			cJSON_AddItemToObject(json, "Usernames", array = cJSON_CreateArray());
						
			for(i = col; i < (row + 1) * col; i += col)
			{
				cJSON_AddItemToArray(array, cJSON_CreateString(result[i]));
			}
						
			//将json结构格式化到缓冲区
			char *buf = cJSON_Print(json);

			memcpy(mess.mess, buf, strlen(buf));
			
			free(buf);
			buf = NULL;
			//释放json结构所占用的内存
			cJSON_Delete(json);
			write(t_info->conn_fd, &mess, sizeof(mess));

			sqlite3_free_table(result);
			break;			
		}
		else if(info.flag == 7)//退出登录
		{
			if(select_all(CID, db, buff, &result, &errmsg, &row, &col, LOGIN_REGISTER) < 0)
			{
				break;
			}
		
			for(i = col; i < (row + 1) * col; i += col)
			{
				if(strcmp(username, result[i]) == 0)  //已存在用户
				{
					ret = 1;
				}
			}
			
			if(ret != 1) //不存在该用户
			{
				ret = Exit_Error_1;
				mess.flag = ret;
				write(t_info->conn_fd, &mess, sizeof(mess));
				sqlite3_free(errmsg);
				goto there;
			}
			
			//从在线用户数据库表中删除用户名
			bzero(buff, sizeof(buff));
			sprintf(buff, "delete from OnlineUsers where username = '%s';", username);
			if(sqlite3_exec(db, buff, NULL, NULL, &errmsg) != SQLITE_OK)
			{//失败
				ret = Exit_Error_2;
				mess.flag = ret;
				write(t_info->conn_fd, &mess, sizeof(mess));
				sqlite3_free(errmsg);
				goto there;
			}
			
			sqlite3_free(errmsg);
			ret = Exit_Succ;
			mess.flag = ret;
			write(t_info->conn_fd, &mess, sizeof(mess));
			
			sqlite3_free_table(result);
			break;
		}
		else
		{
			break;
		}
	}
	there:
	sqlite3_close(db);
	pthread_mutex_unlock(&mutex);
	close(t_info->conn_fd);
	return (void *)0;
}

server.h

#ifndef __SERVER_H_
#define __SERVER_H_

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sqlite3.h>
#include <time.h>
#include <pthread.h>
#include "cJSON.h"

#define MAX                   	500  //客户端最大连接数

//反馈代码
//用户服务器
#define Register_Succ         		1001
#define Register_Error_1           -1001
#define Register_Error_2           -1002
#define Login_Succ              	2001
#define Login_Error_1              -2001
#define Login_Error_2              -2002
#define Login_Error_3              -2003
#define Change_Pass_Succ      	    3001
#define Change_Pass_Error_1        -3001
#define Change_Pass_Error_2        -3002
#define Change_Tel_Succ       	    4001
#define Change_Tel_Error_1         -4001
#define Change_Tel_Error_2         -4002

#define Delete_Succ           		5001
#define Delete_Error_1             -5001
#define Delete_Error_2             -5002
#define Delete_Error_3             -5003
#define Delete_Error_4             -5004
#define Exit_Succ             		7001         
#define Exit_Error_1               -7001  
#define Exit_Error_2               -7002  

//车位服务器
#define Select_Succ           		1011
#define Update_All_Succ       		2011
#define OVER_Error                 -2011
#define Update_Error               -2012
#define Update_Succ             	3011    

//车辆出入服务器 
#define Insert_Succ          		1021 
#define Has_Exsist                 -1021 
#define Move_Succ               	2021  
#define Move_Error_1               -2021  
#define Move_Error_2               -2022  

#define Rec_Up_Succ             	3021  
#define Rec_Up_Error               -3021  
#define Select_Licence_Succ  	    4021

//车主VIP服务器
#define Insert_Vip_Succ       		1031
#define Exsist_IdCard              -1031
#define Exsist_Licence             -1032
#define Exsist_Tel                 -1033
#define Insert_Vip_Error           -1034
#define Recharge_Succ         		2031
#define Driver_Not_Exsist     		2031
#define Recharge_Error             -2032
#define Update_Licence_Succ   		3031
#define Update_Licence_Error       -3031
#define Update_Tel_Succ       		4031
#define Update_Tel_Error           -4031
#define Select_IdCards_Succ  		5031
#define Select_VipInfo_Succ   		6031
#define IdCard_Not_Exsist          -6031

//进出场记录服务器
#define Select_LRecord_Succ   		1041
#define Licence_Not_Exsist         -1041
#define Select_LRecord_Error       -1042
#define Select_TRecord_Succ     	2041
#define Select_TRecord_Error       -2041
#define Select_LTRecord_Succ        3041
#define Select_LTRecord_Error      -3041

#define LOGIN_REGISTER          0     
#define ONLINEUSERS             1
#define CAR_SPACE_INFO          2
#define CAR_IN_OUT              3
#define DRIVER_VIP              4
#define Car_RECORD_INFO         5

#define SER_PORT_1            2019
#define SER_PORT_2            2020
#define SER_PORT_3            2021
#define SER_PORT_4            2022
#define SER_PORT_5            2023

struct login_register_info
{
	int flag;               //标志位
    char username[17];      //用户名(最多16个字节数据,最少3个)
    char password[17];      //密码(最多16个字节数据,最少6个)
    char tel_phone[12];     //电话号码
    int sex;                //性别
	int admin;              //权限     1:超级管理员  0:普通用户
	int CID;                //客户端ID
};

//车位结构体
struct Car_space
{
	int flag;
	int all_space;
	int occupy_space;
	int CID;
};

//车辆信息结构体
struct Car_info
{
	int flag;                //标志位
	char licence_plate[10];	 //车牌号
	int	in_time;             //进场时间戳
	int out_time;            //出场时间戳
    int Vip_flag;            //会员标志(车牌充值车主)
	int money;               //缴费额度
	int stopping_time;       //停车时间(秒钟计量)
	int CID;                 //客户端ID
};

//车主VIP注册结构体
struct Driver_ETC
{
	int flag;                //标志位
	char licence_plate[10];	 //车牌
	char tel_phone[12];      //电话
	char IdCard[19];         //身份证号码
	int balance;             //余额
	int CID;        		 //客户端ID 
};

#define SIZE (2048 * 950)
//服务器向客户端发送专用
struct message
{
	int flag;                //标志位
	char mess[SIZE];         //携带信息
};

struct thread_info
{
	struct sockaddr_in cliaddr;
	int conn_fd;
};

//查询所有且得到结果集
int select_all(int CID, sqlite3 *db_user, char *buff, char ***result, char **errmsg, int *row, int *col, int flag);
//用户线程函数
void *login_register(void *arg);
//主程序处理线程函数
void *Main_pro(void *arg);
#endif

Server.c

#include "server.h"

//查询所有且得到结果集
int select_all(int CID, sqlite3 *db_user, char *buff, char ***result, char **errmsg, int *row, int *col, int flag)
{
	int ret = 0;
	
	if(flag == LOGIN_REGISTER)
	{
		sprintf(buff, "select *from login_register_%d;", CID);
	}
	
	if(flag == ONLINEUSERS)
	{
		strncpy(buff, "select *from OnlineUsers;", sizeof("select *from OnlineUsers;"));
	}
	
	if(flag == CAR_SPACE_INFO)
	{
		strncpy(buff, "select *from Car_space_info;", sizeof("select *from Car_space_info;"));
	}

	if(flag == CAR_IN_OUT)
	{
		strncpy(buff, "select *from OnlineCars;", sizeof("select *from OnlineCars;"));
	}
	
	if(flag == DRIVER_VIP)
	{
		strncpy(buff, "select *from Driver_Info;", sizeof("select *from Driver_Info;"));
	}
	
	if(flag == Car_RECORD_INFO)
	{
		strncpy(buff, "select *from In_Out_Record;", sizeof("select *from In_Out_Record;"));
	}
	
	if(sqlite3_exec(db_user, buff, NULL, NULL, errmsg) != SQLITE_OK)
	{
		sqlite3_close(db_user);
		sqlite3_free(errmsg);
		return -1;
	}
			
	//得到结果集
	sqlite3_get_table(db_user, buff, result, row, col, errmsg);
	
	return 0;
}
void PManagergui::connectManager()
{
    connect(p_wgtMain, &PBasewgt::sigExitSystem, this, &PManagergui::slotExitSystem);
    connect(p_wgtCarManage, &PBasewgt::sigExitSystem, this, &PManagergui::slotExitSystem);
    connect(p_wgtMoneyManage, &PBasewgt::sigExitSystem, this, &PManagergui::slotExitSystem);
    connect(p_wgtIo_Record, &PBasewgt::sigExitSystem, this, &PManagergui::slotExitSystem);
    connect(p_wgtDriver_Vip, &PBasewgt::sigExitSystem, this, &PManagergui::slotExitSystem);
    connect(p_wgtStaff_sign, &PBasewgt::sigExitSystem, this, &PManagergui::slotExitSystem);
    connect(p_wgtInfo_Change, &PBasewgt::sigExitSystem, this, &PManagergui::slotExitSystem);

    connect(Car_IO, &Car_in_out::signal_car_io, p_wgtMain, &MainUi::slotCar_info);
    connect(space_loop, &PBasewgt::sigSer_process, space_loop, &PSpace_loop::slotSer_process);
    connect(p_wgtMain, &PBasewgt::sigSer_process, p_wgtMain, &MainUi::slotSer_process);
    connect(p_wgtCarManage, &PBasewgt::sigSer_process, p_wgtCarManage, &PCarmanage::slotSer_process);
    connect(p_wgtMoneyManage, &PBasewgt::sigSer_process, p_wgtMoneyManage, &PMoneyManage::slotSer_process);
    connect(p_wgtIo_Record, &PBasewgt::sigSer_process, p_wgtIo_Record, &PIO_Record::slotSer_process);
    connect(p_wgtDriver_Vip, &PBasewgt::sigSer_process, p_wgtDriver_Vip, &PDriver_Vip::slotSer_process);
    connect(p_wgtStaff_sign, &PBasewgt::sigSer_process, p_wgtStaff_sign, &PStaff_Sign::slotSer_process);
    connect(p_wgtInfo_Change, &PBasewgt::sigSer_process, p_wgtInfo_Change, &PChangeinfo::slotSer_process);
    connect(p_wgtMain, &MainUi::sigUpload_Occupy, space_loop, &PSpace_loop::slotUpload_Occupy);
    connect(p_wgtMain, &MainUi::sigShow, Show_some, &Show::slotshow_carinfo);
    connect(p_wgtMain, &MainUi::sigCalcMoney, p_wgtMoneyManage, &PMoneyManage::slotCalcMoney);
}
Logo

快速构建 Web 应用程序

更多推荐