简介本资源是一份基于Java的停车场管理系统毕业设计文档面向计算机相关专业学生及需要完成课程设计或毕设的开发人员围绕城市停车难问题给出从需求分析到系统测试的完整实现方案。压缩包内共1个docx文件约937KB内容涵盖课题背景与意义、国内外研究现状、开发环境搭建、系统分析、功能模块设计、数据库ER图与数据表设计以及测试过程。文档以Java为核心技术栈结合Mysql数据库、B/S结构、SpringBoot框架与VUE框架重点阐述用户管理、车辆信息管理、停车位管理、收费管理等模块的实现思路并包含可行性分析与系统流程分析。目前已有55人学习适合需要参考技术选型、功能划分与数据库设计思路的读者可帮助快速理解一个完整停车场管理系统的设计脉络与实现要点。1. 停车场管理系统源码拆包从车牌识别到计费这套 Java 全栈方案能跑通吗上下班高峰期停车场出口排长队收费员拿着本子手抄车牌、翻记录找入场时间——这种场景在很多中小型停车场仍然天天上演。这套基于 Java 的停车场管理系统核心就是用百度 OCR 文字识别替代人工抄牌配合 SpringBoot Vue 的前后端分离架构把车辆进出、计费、记录查询整条链路自动化。它适合两类人一是正在做课程设计或毕业设计的学生需要一套功能完整、技术栈主流的参考实现二是中小型停车场的技术负责人想评估一套低成本、可二次开发的 B/S 架构方案。系统覆盖控制台、停车场管理、车牌识别、车辆管理、停车记录、系统日志等模块后端 Java MySQL前端 Vue数据库用 Navicat 管理开发工具 IDEA VSCODE。下面从环境搭建到核心模块实现再到踩坑排查把这份资源拆开讲透。2. 开发环境搭建IDEA VSCODE MySQL 的版本对齐与依赖拉取2.1 后端 SpringBoot 工程的初始化与依赖配置这套系统的后端基于 SpringBoot 构建核心依赖包括 Web 模块、MyBatis 或 JPA 持久层、MySQL 驱动以及百度 OCR 的 SDK。我一般会在 IDEA 里用 Spring Initializr 生成骨架然后手动补全 OCR 相关依赖。常见做法是直接在pom.xml里锁定版本避免 SpringBoot 版本太高导致和 JDK 不兼容——这是热搜里频繁出现的问题很多人卡在启动报错上。!-- pom.xml 核心依赖片段 -- parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version2.7.6/version !-- 不要盲目追最新2.7.x 与 JDK8/11 兼容性最稳 -- relativePath/ /parent dependencies !-- Web 模块提供 REST 接口能力 -- dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- MySQL 驱动版本要和本地数据库匹配 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.33/version /dependency !-- MyBatis 持久层也可以用 JPA看源码里用的是哪个 -- dependency groupIdorg.mybatis.spring.boot/groupId artifactIdmybatis-spring-boot-starter/artifactId version2.3.1/version /dependency !-- 百度 OCR SDK车牌识别核心依赖 -- dependency groupIdcom.baidu.aip/groupId artifactIdjava-sdk/artifactId version4.16.16/version /dependency /dependencies这段配置里spring-boot-starter-parent的版本决定了整个工程的依赖管理基线。选 2.7.x 而不是 3.x是因为 3.x 要求 JDK17 起步而很多教学环境和服务器还停留在 JDK8 或 JDK11。MySQL 驱动用 8.0.33 是为了匹配 MySQL 8.0 的认证插件如果你本地是 MySQL 5.7驱动版本可以降到 5.1.x但连接 URL 里的参数要相应调整。百度 OCR SDK 的版本号建议去官方仓库确认最新稳定版这里给的只是一个可用的参考值。application.yml里需要配置数据库连接和 OCR 密钥server: port: 8080 # 后端服务端口前端代理要对应 spring: datasource: url: jdbc:mysql://localhost:3306/parking_db?useUnicodetruecharacterEncodingutf-8serverTimezoneAsia/Shanghai username: root password: your_password driver-class-name: com.mysql.cj.jdbc.Driver baidu: ocr: app-id: your_app_id api-key: your_api_key secret-key: your_secret_keyserverTimezone必须设成Asia/Shanghai否则停车时长计算会出现 8 小时偏差这是血泪经验。OCR 的三个密钥从百度智能云控制台申请免费额度对课程设计来说完全够用。2.2 前端 Vue 工程的依赖安装与代理配置前端用 VSCODE 打开先确认 Node.js 版本。Vue 2 和 Vue 3 的脚手架命令不同这套系统从描述看大概率是 Vue 2 Element UI 或 Vue 3 Element Plus。不管哪个版本npm install之前先检查package.json里的依赖版本尤其是vue和vue-router的大版本号要对上。# 查看 Node 版本建议 14.x 或 16.x太新的版本可能和旧版 node-sass 冲突 node -v # 安装依赖如果卡在 node-sass 编译换用 sass 替代 npm install # 启动开发服务器 npm run serve如果npm install报node-sass编译错误常见做法是把node-sass换成sassDart Sass然后把package.json里的node-sass依赖删掉样式文件里的import语法基本不用改。另一个高频问题是vue和vue-template-compiler版本不一致报错信息会直接告诉你两个版本号对齐即可。前端请求后端的接口需要在vue.config.js里配代理否则浏览器会报跨域// vue.config.js module.exports { devServer: { port: 8081, // 前端开发端口 proxy: { /api: { target: http://localhost:8080, // 后端地址 changeOrigin: true, pathRewrite: { ^/api: } } } } }changeOrigin: true是为了让后端收到的请求头里的 Host 是后端地址避免某些安全校验拦截。pathRewrite把/api前缀去掉这样后端 Controller 里不用重复写/api。2.3 MySQL 数据库的建库建表与初始数据导入数据库是这套系统的地基。从摘要描述看核心表至少包括车辆信息表、停车记录表、车位表、用户表、计费规则表。我一般会先建库再按 ER 图逐表创建最后导入初始数据。-- 建库字符集用 utf8mb4 支持中文和特殊符号 CREATE DATABASE parking_db DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; USE parking_db; -- 车辆信息表 CREATE TABLE vehicle ( id INT PRIMARY KEY AUTO_INCREMENT, plate_number VARCHAR(20) NOT NULL COMMENT 车牌号, owner_name VARCHAR(50) COMMENT 车主姓名, vehicle_type TINYINT DEFAULT 1 COMMENT 1临时车 2业主车, phone VARCHAR(20) COMMENT 联系电话, create_time DATETIME DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; -- 停车记录表 CREATE TABLE parking_record ( id INT PRIMARY KEY AUTO_INCREMENT, plate_number VARCHAR(20) NOT NULL, entry_time DATETIME NOT NULL COMMENT 入场时间, exit_time DATETIME COMMENT 出场时间, duration INT COMMENT 停车时长分钟, fee DECIMAL(10,2) COMMENT 停车费用, status TINYINT DEFAULT 0 COMMENT 0在场 1已出场 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;vehicle_type字段区分临时车和业主车计费逻辑完全不同业主车可能按月租或免费临时车按小时计费。parking_record表的status字段是关键入场时插入一条status0的记录出场时更新exit_time、duration、fee并置status1。查询在场车辆就是SELECT * FROM parking_record WHERE status0。注意plate_number字段建议加索引车牌识别后要频繁按车牌查询没索引的话数据量上来后查询会明显变慢。3. 车牌识别与计费逻辑百度 OCR 接入和停车时长计算的核心代码3.1 百度 OCR 车牌识别的调用封装与异常处理车牌识别是整个系统的入口。百度 OCR 的车牌识别接口返回 JSON包含车牌号、颜色、置信度等信息。我一般会封装一个 Service 类把 SDK 调用、结果解析、异常兜底都收在一起。Service public class PlateRecognitionService { Value(${baidu.ocr.app-id}) private String appId; Value(${baidu.ocr.api-key}) private String apiKey; Value(${baidu.ocr.secret-key}) private String secretKey; /** * 识别图片中的车牌号 * param imageBytes 图片字节数组 * return 车牌号识别失败返回 null */ public String recognizePlate(byte[] imageBytes) { AipOcr client new AipOcr(appId, apiKey, secretKey); // 设置超时避免请求卡死 client.setConnectionTimeoutInMillis(3000); client.setSocketTimeoutInMillis(5000); JSONObject response client.plateLicense(imageBytes, new HashMap()); // 检查错误码 if (response.has(error_code)) { log.warn(OCR 识别失败: {}, response.getString(error_msg)); return null; } // 解析车牌号字段名以百度官方文档为准 JSONArray wordsResult response.getJSONArray(words_result); if (wordsResult null || wordsResult.isEmpty()) { return null; } return wordsResult.getJSONObject(0).getString(number); } }setConnectionTimeoutInMillis和setSocketTimeoutInMillis必须设否则网络抖动时线程会一直挂着。错误码判断不能省百度 OCR 在图片模糊、光线不足时会返回error_code直接取words_result会抛空指针。识别失败时返回 null上层调用方决定是让用户手动输入还是重新拍照。3.2 停车时长与费用的计算逻辑计费模块的核心是根据入场时间和出场时间算时长再根据车辆类型和计费规则算费用。常见做法是把计费规则做成配置而不是硬编码。public BigDecimal calculateFee(ParkingRecord record, Vehicle vehicle) { // 出场时间减入场时间得到毫秒差 long millis Duration.between(record.getEntryTime(), record.getExitTime()).toMillis(); // 向上取整到分钟 long minutes (millis 59999) / 60000; // 业主车免费或按月租这里简化为免费 if (vehicle.getVehicleType() 2) { return BigDecimal.ZERO; } // 临时车前 30 分钟免费之后每小时 5 元不足一小时按一小时算 if (minutes 30) { return BigDecimal.ZERO; } long chargeableHours (minutes - 30 59) / 60; return new BigDecimal(chargeableHours * 5); }(millis 59999) / 60000是向上取整的写法避免停车 61 秒被算成 1 分钟。免费时长 30 分钟是常见设定具体数值应该从数据库的计费规则表里读而不是写死在代码里。chargeableHours的计算同理不足一小时按一小时算这是停车场行业的通行做法。注意Duration.between要求两个参数都不能为 null。出场时如果exit_time还没写入要先做非空校验否则直接抛异常。3.3 车辆进出场的事务控制入场和出场涉及多张表的写操作必须加事务。入场时插入停车记录、更新车位状态出场时更新停车记录、计算费用、更新车位状态。任何一步失败都要回滚。Transactional(rollbackFor Exception.class) public void handleExit(String plateNumber) { // 查在场记录 ParkingRecord record recordMapper.findActiveByPlate(plateNumber); if (record null) { throw new BizException(未找到该车辆的入场记录); } // 查出车辆信息 Vehicle vehicle vehicleMapper.findByPlate(plateNumber); // 设置出场时间 record.setExitTime(LocalDateTime.now()); // 计算费用 BigDecimal fee calculateFee(record, vehicle); record.setFee(fee); record.setStatus(1); // 更新记录 recordMapper.updateById(record); // 释放车位 parkingSpaceMapper.releaseByPlate(plateNumber); }Transactional的rollbackFor Exception.class不能省默认只回滚运行时异常业务异常如果不配就不会回滚。findActiveByPlate查询时要加status0条件否则同一辆车多次入场会查到多条记录。4. 避坑与排查这套系统跑起来最容易翻车的五个地方4.1 车牌识别返回空结果现象调用 OCR 接口后words_result为空数组或者直接返回error_code。原因图片质量不达标是最常见的。百度 OCR 对图片有最低要求分辨率太低、车牌倾斜角度过大、光线过暗或过曝都会导致识别失败。另一个原因是图片格式不对SDK 支持 JPG、PNG、BMP传 WebP 会直接报错。解决前端上传前先做一次压缩和格式转换确保最短边不低于 480px。如果是在地库等光线差的环境建议加补光灯或改用带红外补光的摄像头。代码层面识别失败后不要直接抛异常给用户而是返回一个可手动输入车牌的界面。4.2 SpringBoot 启动报数据库连接失败现象启动时抛Communications link failure或Access denied for user。原因三种可能——MySQL 服务没启动、连接 URL 里的端口不对、用户名密码错误。MySQL 8.0 还多一个坑默认认证插件是caching_sha2_password旧版驱动不支持。解决先确认 MySQL 服务在运行然后用mysql -u root -p能登录。如果驱动是 5.1.x要么升级驱动到 8.x要么在 MySQL 里执行ALTER USER rootlocalhost IDENTIFIED WITH mysql_native_password BY 密码;把认证插件改回去。4.3 前端 npm install 卡在 node-sass现象npm install执行到node-sass时长时间无响应最后报编译错误。原因node-sass是 C 原生模块需要和 Node.js 版本严格匹配版本不对就编译失败。Node 16 以上基本都会翻车。解决把package.json里的node-sass替换为sass然后删除node_modules和package-lock.json重新npm install。样式文件里的import和变量语法基本兼容个别~前缀的路径可能需要调整。4.4 停车时长计算出现负数或超大值现象出场时算出的停车时长是负数或者几万分钟。原因入场时间和出场时间的时区不一致。如果数据库存的 UTC 时间Java 取出来按本地时区解析就会差 8 小时。另一个原因是entry_time字段在插入时用了数据库默认值而exit_time用了 Java 的LocalDateTime.now()两者时区基准不同。解决统一时区。JDBC URL 里加serverTimezoneAsia/ShanghaiJava 端统一用LocalDateTime数据库字段用DATETIME而不是TIMESTAMP。如果已经出现脏数据写一个修复脚本把entry_time统一加 8 小时或减 8 小时。4.5 前后端联调时接口 404现象前端请求/api/parking/record返回 404后端日志里看不到请求。原因代理没生效或者后端 Controller 的RequestMapping路径和前端请求路径不匹配。常见的是前端配了pathRewrite去掉/api但后端 Controller 里又写了/api前缀结果变成/api/api/parking/record。解决先看浏览器 Network 面板里请求的实际 URL再对比后端启动日志里映射的路径。两边只保留一边的/api前缀。如果代理没生效检查vue.config.js修改后是否重启了开发服务器——代理配置不会热更新。5. 二次开发与验证把计费规则做成可配置用 Postman 跑通全链路这套系统跑通之后最值得做的二次开发是把计费规则从代码里抽出来做成数据库配置。原始实现里免费时长和每小时单价大概率是写死的但实际停车场运营中不同时段、不同车型的费率可能不同。我一般会加一张billing_rule表字段包括vehicle_type、free_minutes、hourly_rate、daily_cap单日封顶然后在计费方法里查表而不是用常量。CREATE TABLE billing_rule ( id INT PRIMARY KEY AUTO_INCREMENT, vehicle_type TINYINT NOT NULL COMMENT 1临时车 2业主车, free_minutes INT DEFAULT 30 COMMENT 免费时长分钟, hourly_rate DECIMAL(10,2) DEFAULT 5.00 COMMENT 每小时费率, daily_cap DECIMAL(10,2) DEFAULT 50.00 COMMENT 单日封顶, effective_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT 生效时间 ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO billing_rule (vehicle_type, free_minutes, hourly_rate, daily_cap) VALUES (1, 30, 5.00, 50.00), (2, 0, 0, 0);对应的 Java 代码改成从billingRuleMapper.findByVehicleType(vehicle.getVehicleType())取规则然后按规则计算。这样运营人员改费率不用重新部署直接改数据库就行。验证方法是用 Postman 模拟完整链路先调入场接口插入一条记录等几分钟后调出场接口检查返回的费用是否和手算一致。重点验证三个边界刚好 30 分钟、30 分 01 秒、跨天停车。跨天场景下daily_cap要生效否则停三天可能算出几百块和实际封顶规则不符。另一个值得加的验证点是并发。同一辆车如果在极短时间内被两次入场请求命中可能插入两条status0的记录。常见做法是在plate_numberstatus上建唯一索引或者在入场方法里加分布式锁。课程设计环境并发低但生产环境必须考虑。从那以后我每次拿到这类管理系统源码都强制先跑一遍「入场→等待→出场→查记录」的完整链路再去看计费边界最后才动界面。这套顺序能帮你把最核心的逻辑先验证掉不至于在样式上耗掉大半时间。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?