前言
本期项目是停车场管理系统,主要包括数据监控大盘、车辆管理、黑名单管理、停车管理、车位管理、预约管理、日志管理、用户管理、角色管理。尽可能的把停车场功能做全,然后以企业级的开发标准来完成整个前后端代码,无论是用来作为毕业设计还是拿来学习,相信对初学者都会有很大帮助。
(想要源码和视频教程的同学私信我~~~)
工程架构
应用分层
上面的分层架构摘自阿里巴巴java开发手册,我对此做了一些调整,实际分层结构如下:
领域模型
-
DO(DataObject):与数据库表结构一一对应,通过DAO层向上传输数据源对象
-
BO(BusinessObject):业务对象。由Service层输出的封装业务逻辑的对象
-
VO(View Object):显示层对象,通常是Web向模板渲染引擎层传输的对象
BO和VO领域模型又分为BoRequest(输入模型)、BoResponse(输出模型)、VoRequest(输入模型)、VoResponse(输出模型)
技术栈
前端:vue + element
后端:jdk1.8 + springboot + redis + mysql
系统设计
接口设计
整个项目接口采用的目前互联网比较流行的restful风格设计,每个接口、每个参数都有详细的文档说明。因为企业中开发必然是团队协作,必然前后端分离的开发模式,你得先把接口定义出来,然后前端可以和后端同步开发。还有一种就是对外提供接口,比如你们隔壁团队也想调用你这个服务的接口,但是你两排期是同一周,这时候你得先把接口定义出来给人家,然后大家同步开发,开发完了之后再进行联调。
运行效果
系统登录
dashboard
首页数据大盘,按最近7天饼图占比、最近30天折线图走势、最近一年柱状图分析、最近7天各个时间段占比分析全方位可视化分析数据。
车辆管理
黑名单管理
对于一些漏缴费、不按规定停车、多次预约停车位却毁约的车辆,我们可以添加黑名单,加黑后的车辆将不被允许进入停车场。
停车管理
车辆入库后会生成一条停车记录,此时状态是'已入库'和'未支付',等车辆出口后,系统会根据车位的每小时停车费*实际停车实际(按小时计算,超出一小时按一小时收费)。这里大家需要注意,真实的停车场收费都是摄像头拍照的,比如车子出库的时候,摄像头会拍摄车牌,然后生成收费信息,当你缴费后就可以出库了。这里我们是管理后台,系统并没有接入摄像头设备,所以出库需要人工点击出库按钮。(也可以接入支付宝扣费接口和摄像头接口,这样我们的系统就跟真实的停车管理系统一样了~)
Excel导出
所有模块都支持数据导出Excel,方便进行数据分析
停车记录导出
车位数据导出
车位管理
预约管理
车主可以提前预约,预约后将优先安排车辆入库停车
日志管理
日志管理默认是开给管理员的,在系统中的所有操作都会被记录,在系统出现异常时也便于管理员进行问题排查。
用户管理
默认也是只有管理员拥有用户管理菜单的权限,可以新建/编辑用户、分配用户角色、禁用/启用等操作
编辑用户信息
角色管理
极其灵活的权限管理,系统中的所有按钮都可以单独分配权限,你可以给A角色只分配了查询和导出权限,也可以给B角色分配查询、编辑、新建权限,还可以给C角色只分配查询权限。可以满足几乎所有的业务需求,大家可以自由发挥定义权限组合。
页面不存在时提示页面
普通读者登录
系统默认会创建两个角色,一个是超管角色,另一个则是普通用户角色(当然角色大家可以按前面说的自定义)。普通用户登录,比如停车管理菜单,普通用户就只有查询的权限,其他的新增、编辑、删除、导出和出库权限都没有。截图如下:
个人信息修改
密码修改
管理员创建完用户之后的默认密码是“123456”,用户可以登录系统自己修改密码
权限设计
权限基于security和spring-session实现。权限可以分为认证和授权,认证其实就是登录,用户登录时会进行账号密码的校验,校验成功后会,会把session存入redis中。授权指的是用户是否拥有访问后端资源的权限,每个新用户在创建后都会分配角色,角色其实就是一个权限集合,这里的权限可以理解为访问后端一个个接口(资源)的权限。
这里权限设计的非常灵活,细粒度到按钮级别,比如新增、删除、修改、查询、借阅动作,普通用户可能就只有查询权限,管理员则拥有新增、删除、修改的权限。普通用户即使通过接口直接访问后端的修改或者删除接口,后端也会返回授权失败错误,因为后端每个需要权限的接口都打了权限标识,只有拥有资源权限用户才能访问。
比如下面的车辆修改接口,只有拥有“CAR_UPDATE”这个权限标识的用户才能访问这个接口,否则返回“未授权”的错误。
@PutMapping("/{id}") @PreAuthorize("hasAuthority(T(com.senior.book.console.api.security.Authority).BOOK_UPDATE.name())") public Result<Boolean> update(@PathVariable("id") Long id, @Valid @RequestBody BookUpdateVoRequest request) { }
日志方案
日志采用lombok注解+slf4j+log4j2的实现方案,基于profile实现了多环境的日志配置,因为不同环境的日志打印策略是不一样,比如开发环境我可能需要打印到console控制台,需要debug级别的日志以便于本地开发调试,测试环境可能就需要打印到日志文件里,线上环境可能需要打印到文件的同时将日志发送到kafka然后收集到es中,这样当线上部署了多台机器后我们查日志不用一台一台机器去查日志了,因为都收集到es了,我们只需要登录kibana去搜索,这样就非常方便。这里说到的kafka+es+kibana这样一套日志解决方案也是目前互联网公司比较常用的一套解决方案。如果你动手能力够强,你可以本地搭一套kafka、es、kibana,然后只需要在配置文件中加入几行配置就实现了这么一套企业级的日志解决方案(默认是输出到日志文件)。
下面是部分关键配置,如果要配置kafka,只需要在<Appenders>标签中配置<Kafka>配置即可
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="WARN" xmlns:xi="http://www.w3.org/2001/XInclude"> <Properties> <Property name="LOG_FILE">system.log</Property> <Property name="LOG_PATH">./logs</Property> <Property name="PID">????</Property> <Property name="LOG_EXCEPTION_CONVERSION_WORD">%xwEx</Property> <Property name="LOG_LEVEL_PATTERN">%5p</Property> <Property name="LOG_DATE_FORMAT_PATTERN">yyyy-MM-dd HH:mm:ss.SSS</Property> <Property name="CONSOLE_LOG_PATTERN">%clr{%d{${LOG_DATE_FORMAT_PATTERN}}}{faint} %clr{${LOG_LEVEL_PATTERN}} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} </Property> <Property name="FILE_LOG_PATTERN">%d{${LOG_DATE_FORMAT_PATTERN}} ${LOG_LEVEL_PATTERN} ${sys:PID} --- [%t] %-40.40c{1.}:%L : %m%n${sys:LOG_EXCEPTION_CONVERSION_WORD} </Property> </Properties> <Appenders> <xi:include href="log4j2/file-appender.xml"/> </Appenders> <Loggers> <logger name="com.senior.park" level="info"/> <Root level="info"> <AppenderRef ref="FileAppender"/> </Root> </Loggers> </Configuration>