资讯动态

SpringBoot+Vue智能停车场管理系统实战:从需求到部署全流程解析

发布时间:2026/10/18 18:40:43 来源:尧图企业网站定制
这套基于SpringBootVue的智能停车场管理系统是我在练手前后端分离项目时从零搭出来的完整作品。从最初只想做一个能管理车位的小工具到后面衍生出用户端、管理端、计费、支付、统计报表一路改下来踩了不少坑也积累了不少能直接用的经验。如果你正准备自己动手做一套类似的系统或者正在找能支撑项目答辩、实训演示的完整案例这篇内容完全可以作为一个整体参考。系统本身定位很明确解决传统停车场人工收费效率低、车位状态不透明、出场排队时间长、运营数据难统计这几个老问题。技术栈选用SpringBootVue是当前中小型管理系统里非常成熟的一套组合。后端SpringBoot负责业务逻辑和数据持久化前端Vue负责交互和展示前后端通过RESTful接口对接职责清晰也方便后期拆分扩展。项目中除了源码还配了说明文档、部署文档和配套讲解资源照着走基本能把环境跑起来。1. 需求拆解停车场管理系统到底要管哪些事1.1 痛点分析传统停车场差在哪做系统之前我专门去观察了几个线下停车场的管理流程。传统模式下车主入场拿卡或扫牌出场时人工计算费用、收费抬杆高峰期排队是常态。管理员最头疼的不是收钱而是不知道场内到底有多少空位不知道某辆车停了多久更不知道一天的总收入是多少所有数据都靠交接班时的纸质记录去核对。从技术角度看这些痛点完全可以抽象成几个核心问题车辆身份如何识别车位状态如何实时更新费用如何按规则自动计算订单如何生成和核销。把这几个问题拆开系统设计就有方向了。至于智慧大屏、手机端缴费、月卡管理通通是锦上添花先把基础闭环跑通才最重要。1.2 功能模块梳理从用户到管理员的完整闭环做需求梳理时建议不要一上来就画大而全的功能图而是按角色和核心流程走一遍。这个系统我最终拆成了两个端。用户端主要面向普通车主功能包括实时查看剩余车位、在线缴费、查询停车记录、月卡充值。这个端不需要太复杂核心是“查车位”和“缴费”两个动作。管理端面向停车场运营人员功能包括车位管理、车辆入场/出场登记、订单管理、收费规则配置、月卡管理、数据统计报表。管理端承载了系统的主要业务逻辑后面的设计重心也基本都在这边。两个端共用的底层能力是车辆管理、订单管理、支付流水记录、权限控制。这样梳理下来模块边界很清楚前端只负责展示和交互后端负责状态流转和计算。1.3 技术选型为什么非用SpringBootVue不可很多初学者会纠结要不要上微服务要不要用更“新”的框架。我的观点很直接这种体量的系统SpringBootVue就是性价比最高的选择没有之一。SpringBoot的优势在于约定优于配置内置Tomcat一个jar包就能跑开发期不用为环境折腾太久。配合MyBatis-Plus做数据操作分页、条件构造器、自动填充这些能力几乎开箱即用。Vue这边选择Vue2还是Vue3都行我建议如果是从零学直接学Vue3的组合式API配套的Element Plus组件库做后台界面效率很高。选这套组合还有一个关键原因前后端分离让部署变得灵活。前端可以丢到Nginx里做静态资源服务后端单独跑一个进程互不影响。对单体应用来说这样的分离已经足够干净。2. 数据库与后端设计把“车位”理解成一个状态机2.1 核心表结构设计车辆、车位、订单、用户数据库是这类管理系统的地基。我设计表时没有追求过度范式化而是从业务场景出发保证查询方便、可解释性强。核心表就四张车辆表、车位表、订单表、用户表另外加了一张月卡表做扩展。车位表是重点。它包含车位编号、区域、类型普通/充电桩/无障碍、状态空闲/占用/锁定。车位状态必须冗余一个字段在表里不要只通过订单表去推算否则高并发下查询压力会很大。车辆表保存车牌号和车主信息入场时通过车牌号关联车辆。没有匹配的车辆时先创建一个临时车辆记录出场时再补全信息。订单表记录入场时间、出场时间、应收金额、实收金额、支付状态。这里有个细节金额用分存储避免浮点数误差展示时再转换为元。用户表一方面存管理员账号另一方面存普通车主账号用role字段区分角色。权限控制不用做太细admin和user两种角色就够用。2.2 后端分层与接口约定后端代码结构我习惯分成四层controller、service、mapper、entity。这个项目还额外加了一个common包放统一返回结果、异常处理、工具类。统一返回结果的约定很重要。我用的结构是{ code: 200, message: 操作成功, data: {} }所有接口都返回这个结构前端拿到code为200才处理data这样错误处理逻辑能统一。异常统一用RestControllerAdvice捕获避免把Spring的默认错误页直接甩给前端。接口命名按REST风格比如POST /api/auth/login 登录GET /api/parking/spaces 车位列表POST /api/parking/entry 车辆入场POST /api/parking/exit 车辆出场GET /api/orders 订单分页查询POST /api/pay/create 创建支付单开发时建议先用Postman把接口跑通再和前端联调。我习惯把所有接口的边界情况参数缺失、数据不存在、重复请求都先测一遍省得后面前端一调就报错定位半天才发现是后端校验没做。2.3 身份认证与权限控制项目用的是JWT做认证Spring Security做权限拦截。登录成功后后端签发一个token前端每次请求带上后端解析token拿到用户信息。实现时需要注意两个坑。第一个是token过期时间的设置不要设得太长建议普通用户12小时管理员8小时过期后前端要跳转回登录页。第二个是Spring Security的放行规则登录接口、静态资源、后端健康检查接口要放行其余接口都需要认证。权限控制不用搞得过于复杂。在controller上使用PreAuthorize(hasRole(ADMIN))只让管理员访问后台管理接口用户端接口只要求登录即可。这样简单直接又满足了基本的安全需求。3. 核心功能实操从配置文件到接口调通的完整路径3.1 车牌识别对接别怕没有相机也能跑起来车牌识别是智能停车系统的门面功能。现实中停车场会部署道闸相机相机识别到车牌后把结果传给后端。自己做项目时不一定有真实硬件但可以通过两种方式模拟一种是前端上传车辆照片调用第三方OCR接口识别车牌另一种更简单提供一个手动录入车牌的入口同时预留识别接口的位置。我用的是混合方案。真实场景下相机厂商通常提供HTTP回调接口入场时把识别结果POST到系统系统根据车牌号判断是临时车还是月卡车然后落库。没有相机时管理端手动选择“模拟识别”手动输入车牌号系统走同样的逻辑。对接第三方OCR时最需要注意的是接口调用的异常处理。网络超时、图片格式不对、识别结果为空都要有兜底逻辑。我比较推荐把车牌识别封装成一个独立的service后续换识别服务商时只需要改这一个文件的实现。3.2 计费引擎把每一个时间段都算清楚计费规则是停车场系统的核心难点。不同的停车场费率差别很大有的是按小时收费有的是前半小时免费然后阶梯计费还有过夜封顶。设计计费引擎时我是这么做的把费率配置做成一张表支持首小时单价、续时单价、每日封顶金额、免费时长、跨日是否重新计费这几个字段。计费时传入入场时间、出场时间和费率配置输出应收金额。核心计算逻辑用伪代码表示大概是public BigDecimal calculateFee(LocalDateTime entryTime, LocalDateTime exitTime, FeeRule rule) { long minutes Duration.between(entryTime, exitTime).toMinutes(); long freeMinutes rule.getFreeMinutes(); if (minutes freeMinutes) { return BigDecimal.ZERO; } long billableMinutes minutes - freeMinutes; // 按小时数向上取整 long hours (billableMinutes 59) / 60; // 如果设置日封顶先按天计算封顶 BigDecimal fee rule.getFirstHourPrice() .add(rule.getSubsequentHourPrice().multiply(BigDecimal.valueOf(hours - 1))); // 封顶限制 if (rule.getDailyCap() ! null fee.compareTo(rule.getDailyCap()) 0) { fee rule.getDailyCap(); } return fee; }这里有一个非常关键的点时长计算必须用毫秒级的时间戳差不能直接拿字符串时间相减。而且入场和出场时间必须统一使用后端系统时间不能依赖前端传的时间否则用户改一下本地时间就能逃费。3.3 车位状态流转入场和出场的原子操作车位从空闲到占用再到空闲这就是一个状态机。入场时要做三步把车位状态改为占用、写入一条入场记录、如果是月卡车检查有效期。出场时要做四步计算费用、生成订单、更新车位状态、记录支付流水。这些操作如果分开执行很容易出现数据不一致。比如入场时车位状态更新了但入场记录没写成功车位上就会显示有车实际却没有记录。我最终用Transactional把整个入场、出场流程包起来任何一个环节失败都整体回滚。高并发场景下还需要考虑接口的幂等性。比如出场接口被前端重复点击就会生成两笔订单。解决方式有两种在订单表加唯一约束用车牌号出场时间作为唯一键或者在接口层做防重同一个订单号只能成功处理一次。我用了第二种用订单号去查询已经存在就直接返回已有的订单信息不重复创建。3.4 支付流程与订单核销支付我采用的方案是生成支付二维码用户扫码后完成“模拟支付”。没有接真实支付渠道但把支付的核心流程走通了。前端点击“去支付”后后端创建支付单生成一个支付二维码二维码内容包含订单号和金额。用户扫码后跳到支付确认页点击“确认支付”模拟支付成功。后端在支付成功回调里做订单状态更新。这里有一个经验支付结果一定要通过服务端主动查询或回调来确认不能直接信任前端传的支付成功状态。我在模拟方案里也是通过一个查询接口去确认支付单状态确保订单的金额和状态是服务端生成的避免被篡改。前端支付页的轮询逻辑可以这样写每2秒查询一次支付状态支付成功后跳转到结果页。注意轮询要及时停止否则用户离开页面后还在发请求。4. 前端Vue实现管理后台和用户端一次说清4.1 前端工程结构设计前端用的Vue Cli创建通过代理解决开发环境的跨域。src目录下按views、components、router、utils、api拆分。views下面再按角色分子目录admin和user方便权限过滤。依赖方面用axios做请求封装element-ui做组件库vuex做状态管理echarts做图表。axios拦截器里统一加token响应处理里统一判断code401时清除token并跳转登录页。这个封装每一位初学者都必须掌握能省掉大量重复代码。4.2 关键页面实现实时车位图、收费记录、统计报表实时车位图是管理端的招牌页面。我用的是canvas手绘车位示意图每个车位是一个矩形色块绿色表示空闲红色表示占用蓝色表示充电桩车位。后端提供一个获取所有车位状态的接口前端定时轮询每5秒刷新一次。展示时车位编号、所属区域、当前状态都要在色块上标出来管理员一眼就能看到哪里有空位。收费记录页面就是订单列表关键字段是车牌号、入场时间、出场时间、金额、支付状态。列表用分页加载筛选条件包括日期范围、支付状态、车牌号关键字。这里要注意日期范围查询在后端SQL中要注意索引优化否则数据量大之后会慢。统计报表页面我放了三张图近7天收入柱状图、今日车位利用率饼图、不同时段入场车辆数折线图。图表数据全部来自后端接口不要在前端做复杂的汇总计算前端只负责把后端返回的聚合结果渲染出来。4.3 与后端的跨域对接开发时最容易出问题的就是跨域。我的做法是前后端配合处理后端在配置类里允许特定来源的跨域请求前端在vue.config.js里配置devServer的proxy。module.exports { devServer: { proxy: { /api: { target: http://localhost:8080, changeOrigin: true } } } }这样前端请求/api开头的地址都会代理到后端服务浏览器的同源策略就不会拦截。生产环境部署时前端资源由Nginx托管Nginx再配置一个反向代理转发/api请求到后端服务同样能解决跨域问题。后端CORS配置只需要放在开发环境用于直连调试生产环境有了代理后反而不需要放开跨域安全性更高。5. 部署上线一步一步把项目跑起来5.1 环境准备与初始化部署这台演示环境我用的是一台2核4G的云服务器。系统是CentOS 7。需要安装的软件包括JDK 8、Maven 3.6、MySQL 5.7、Nginx 1.18、Node.js 14。数据库初始化是最先要做的操作。建议不要直接把建表和插入语句在命令行里盯着跑而是准备一份初始化SQL脚本包含建库、建表、初始管理员账号、基础费率数据。脚本要能够重复执行所以加上了DROP TABLE IF EXISTS方便重置。5.2 后端打包与启动后端打包前先检查application.yml里的数据库地址、账号密码、端口是否和服务器一致。我用的是Maven打包命令是mvn clean package -DskipTests打包后target目录下会生成一个parking.jar。直接用java命令启动java -jar parking.jar --spring.profiles.activeprod这样就能从外部指定prod配置不用重新打包。为了让服务在后台运行我用了nohupnohup java -jar parking.jar parking.log 21 查看日志用tail -f parking.log日志里出现“Started ParkingApplication”说明启动成功。生产环境建议再用systemd管理这个进程方便开机自启和异常重启。5.3 前端构建与Nginx配置前端构建前要把src/utils/request.js里的请求地址改成服务器域名。构建命令是npm install npm run build构建完成后dist目录就是静态文件。把dist上传到服务器比如放在/usr/share/nginx/html/parking然后修改Nginx配置server { listen 80; server_name your_domain; location / { root /usr/share/nginx/html/parking; index index.html; try_files $uri $uri/ /index.html; } location /api/ { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }try_files那行一定要加否则前端路由刷新后会出现404。接口转发也要配置正确否则页面能打开但数据加载不出来。5.4 数据库初始化脚本我建议把初始化脚本分成三个文件建库脚本、表结构脚本、基础数据脚本。这样后期想要重置数据可以单独清空数据而不是动表结构。基础数据脚本里一定要包含管理员账号和默认费率。管理员密码不要用明文先通过工具生成BCrypt加密串再插入数据库。我吃过一次亏直接明文存密码项目被同学扫了一遍发现漏洞后来才改用BCrypt加密。6. 踩坑实录与常见问题排查6.1 时区问题导致时间差8小时这个问题几乎百分百会遇到。MySQL连接串中如果没有设置serverTimezone默认情况下插入的时间会比真实时间少8小时。解决方式是在JDBC连接串中加入?serverTimezoneAsia/ShanghaiuseUnicodetruecharacterEncodingutf8useSSLfalse同时数据库连接层的驱动高版本也要兼容。我在做这个项目时把时间类型统一用LocalDateTime并且在实体上加了JsonFormat(pattern yyyy-MM-dd HH:mm:ss, timezone GMT8)保证后端返回前端的格式正确。6.2 跨域配置失效有段时间前端请求一直报跨域但我明明在后端加了CORS配置。排查后发现是Spring Security的拦截器在CORS配置之前就拦截了请求。正确的做法是在SecurityConfig里添加cors()并且让CORS过滤器优先于认证过滤器。如果不生效可以把自定义的CORS配置类上的Configuration注释检查一下有没有被扫描到。6.3 高并发下超卖的坑模拟并发测试时发现多个请求同时入场后同一个车位被分配给了两辆车。原因就是车位状态的查询和更新不是原子操作。后来我在SQL层面加了一个条件更新UPDATE parking_space SET status OCCUPIED WHERE id ? AND status FREE如果影响行数为0说明车位已经被占用直接返回车位已满。这样就用数据库的原子性解决了竞态问题。之后再配合事务基本不会出问题。6.4 部署后前端404问题前端页面部署到Nginx后直接访问域名首页是正常的但刷新某个子路由就出现404。原因就是前端路由是history模式Nginx没有配置try_files来把非真实路径的请求回退到index.html。按照前面Nginx配置加上try_files就能解决。这个问题如果不遇到你可能永远想不到但遇到了就知道有多坑。6.5 文件上传大小限制如果系统需要上传车辆照片SpringBoot默认的最大文件大小是1MB很容易超限。需要在application.yml中调整spring: servlet: multipart: max-file-size: 10MB max-request-size: 10MB这个配置虽然不起眼但如果没有设置上传车辆照片时会出现“FileSizeLimitExceededException”异常接口直接报错很影响体验。7. 项目扩展与我的实操心得7.1 可以从哪些方向升级这个系统跑通基础功能后可以做的扩展方向非常多。如果接入真实硬件比如道闸相机、地磁传感器、LED余位屏就能把“智能”两个字做实。支付方面可以申请商户号对接微信支付或支付宝支付把模拟支付替换成真实支付回调。另外可以做缓存优化车位状态和余位数量用Redis存储配合TTL设置能大幅提升查询性能。如果再引入消息队列处理支付回调通知系统架构的完整度又能上一个台阶。对于学习性质的模拟项目来说这些扩展点可以作为能力进阶的方向。7.2 几个值得坚持的编码习惯写这个项目时有几个习惯帮了大忙。第一个是每个接口都写清晰的注释包括入参、出参、异常情况写代码时思路会清楚很多。第二个是命名要规范类名、方法名、表名、字段名全部用有意义的英文短语不要用拼音缩写自己都看不懂。第三个是定期备份数据库在开发阶段每天导出一份SQL出了问题随时恢复。第四个尤为重要前后端开发前一定要把接口文档定好哪怕是先写在纸上。我在联调阶段最痛苦的就是接口参数对不上前端说传了token后端说没收到header折腾半天才发现是字段名写错了。接口先对齐后面开发效率会高很多。7.3 一套完整的交付物应该包含什么如果是用于项目演示、实训作业一定要把交付物整理齐全。除了源码之外说明文档、部署指南、演示视频、答辩PPT都值得花时间做。说明文档里写清项目背景、功能设计、数据库设计、核心代码讲解部署文档则把环境搭建到最终启动的每一步记录下来让人照着能跑起来。这其实是很多朋友容易忽略的地方。代码写得再漂亮部署不了或者别人看不懂展示效果会大打折扣。我在写这个项目时专门把部署文档更新了好几个版本把踩过的坑都补了进去后面再部署或者换服务器照着文档走基本一遍过。最后再分享一个小技巧做这类管理系统一定要从真实业务场景出发去设计不要为了炫技堆技术。拿这个停车场系统来说用户真正关心的是能不能快速找到车位、出场时能不能快速缴费管理员关心的是今天收入多少、哪里车位多、哪里车位少。把这些核心问题解决了系统就算成功了一大半。技术只是工具业务理解才是项目价值的真正体现。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑