简介:这份资源是面向计算机专业学生与Web开发学习者的停车场管理系统毕业设计文档,围绕城市停车难问题,给出从需求分析到系统实现的完整方案。内容涵盖绪论、系统分析、系统设计与实现等章节,重点讲解基于Java与Spring Boot的后端架构、HTML5与Vue.js的前端交互、MySQL数据存储,以及RESTful API、AJAX、JWT身份验证、GIS地图车位展示、短信邮件通知等关键技术,并采用MVC模式划分用户管理、车位管理、计费管理、预约管理等模块。资源包内含1个docx文档,约947KB,结构完整、目录清晰,适合作为课程设计或毕业论文的参考模板。已有136人学习,读者可借此掌握系统分析、数据库概念与逻辑结构设计、业务流程梳理等核心环节,快速搭建可运行的停车场管理项目框架。
1. 从一份毕设文档说起:这套 Web 停车场管理系统到底能跑出什么
如果你手头正躺着一份《基于 Web 停车场管理系统的设计与实现》的文档,或者你正被要求照着它把代码落地,那这篇笔记就是写给你的。我拿到这份文档的第一反应不是看摘要,而是直接翻到第 3 章的数据库表结构——因为一个停车场系统能不能跑起来,八成取决于表设计得合不合理。这份文档用的是 JSP + Java + MySQL 的经典组合,开发工具是 MyEclipse2014,数据库 MySQL 5.5,服务器 Tomcat,整体走 B/S 架构和 MVC 模式。说白了,这是一套典型的 J2EE 课程设计级项目,但它把停车场业务里最核心的几条线——固定车主、临时车辆、IC 卡、车位状态——都串起来了。适合谁?适合正在做类似课设、想找一个能跑通全流程的参考实现的人,也适合想拿它当模板改造成小区或园区停车管理 Demo 的开发者。下面我按“先看懂结构、再动手跑通、最后避开坑”的顺序,把这份文档拆成能复现的步骤。
2. 系统骨架与数据库:六张表撑起固定车主和临时车辆两条线
2.1 模块划分与 MVC 分层逻辑
文档里把系统拆成六大模块:系统信息管理、车位信息管理、IC 卡信息管理、固定车主停车管理、临时车辆停车管理、系统功能操作。这个划分不是拍脑袋来的,它对应的是停车场日常运营里最频繁的几类操作。系统信息管理管的是角色和用户,也就是谁能登录、能干什么;车位信息管理管的是车位编号、所属区域、车位状态;IC 卡信息管理管的是发卡和卡与车主、车位的绑定;固定车主和临时车辆这两块是业务核心,区别在于计费方式和出场逻辑;系统功能操作就是改密码和退出。
MVC 在这里的作用很实际:JSP 负责视图层,Servlet 或 Action 负责控制层,JavaBean 和 DAO 负责模型层。为什么要这么分?因为停车场系统里“车位状态”这个数据会被多个页面同时读写——车位管理页要改,固定车主入场时要占,临时车辆入场时也要占。如果视图层直接连数据库,改一处就得动好几个 JSP,耦合度一高,后面加个“预约车位”功能就得翻遍所有页面。MVC 把数据操作收在 DAO 里,视图只负责展示,控制层只负责调度,这样改计费规则时只需要动模型层。
2.2 数据库表结构与字段含义
文档第 3.3.2 节给出了六张核心表,我把它们整理成一张对照表,方便你建库时直接抄:
| 表名 | 核心字段 | 用途说明 |
|---|---|---|
| 用户表 | User_id, Role_id, User_name, Real_name, User_pwd, User_phone | 登录认证与角色绑定 |
| IC 卡信息表 | Card_id, Seat_id, User_name, User_Sex, User_addr, Car_num | 卡与车主、车位、车牌的绑定 |
| 车位信息表 | Seat_id, Seat_num, Seat_area, Seat_state, Seat_tag | 车位基础信息与占用状态 |
| 临时停车管理表 | temp_id, Car_id, Car_num, Entry_date, Entry_time, Out_date, Out_time, Temp_money | 临时车辆出入场与费用 |
| 固定停车管理表 | fixed_id, car_id, entry_date, entry_time, Out_date, Out_time, Fixed_money | 固定车主出入场与包周计费 |
| 角色表 | Role_id, Role_name | 角色定义,配合用户表做权限 |
建表时有个细节要注意:文档里把日期和时间拆成了两个字段(Entry_date 和 Entry_time),而不是用一个 DATETIME。这种设计在课程设计里很常见,好处是查询时按日期分组统计方便,坏处是计算停车时长时得先把两个字段拼起来。我一般会建议保留这种拆分,但在 Java 层写一个工具方法把 date + time 转成 LocalDateTime,避免每次算费用都写重复的字符串拼接。
2.3 固定车主与临时车辆的计费逻辑差异
固定车主的计费规则文档写得很明确:车辆停留达到一周,系统提示收费四百元,超过一周按周累加。这个逻辑落在代码里就是一个判断:出场时间减去入场时间,除以 7 天,取整后乘以 400。临时车辆则是按停留时间实时计算,文档没有给出具体费率,但根据常见做法,可以按小时阶梯计费,比如首小时 5 元,之后每小时 2 元,不足一小时按一小时算。
这里有个容易翻车的地方:固定车主的“一周”是按自然周还是按 7×24 小时?文档写的是“停留时间达到一周”,我理解成 7×24 小时。如果你按自然周算,周一入场周日出场可能不满 7 天却跨了周,费用就对不上。所以代码里统一用 Duration.between(entry, exit).toDays() 来判断,不要用 Calendar 的 WEEK_OF_YEAR。
3. 从零跑通:环境搭建、建库建表和核心功能实现
3.1 开发环境准备与项目导入
文档指定的环境是 MyEclipse2014 + JDK + Tomcat + MySQL 5.5。如果你现在用 IDEA 或 Eclipse 新版,问题不大,但要注意 MyEclipse2014 默认的 JDK 版本较低,项目编译级别可能卡在 1.6 或 1.7。我建议统一升到 JDK 1.8,因为后面算时间用 LocalDateTime 需要 Java 8 以上。
导入步骤大致是:先在 MyEclipse 里新建一个 Web Project,把文档对应的源码包解压后覆盖 WebRoot 和 src 目录;然后在项目属性里把 Build Path 的 JRE 改成你本机的 JDK 1.8;接着在 Tomcat 的 server.xml 里确认端口没被占用,默认 8080 就行。数据库连接配置一般在 src 下的 db.properties 或 jdbc.properties 里,把 url、username、password 改成你本机 MySQL 的。
# db.properties 示例 jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/parking_db?useUnicode=true&characterEncoding=utf8 jdbc.username=root jdbc.password=your_password这里注意 MySQL 5.5 和 8.0 的驱动类名不一样,5.5 用 com.mysql.jdbc.Driver,8.0 用 com.mysql.cj.jdbc.Driver。如果你本机装的是 8.0,只改驱动类名还不够,url 后面要加 serverTimezone=Asia/Shanghai,否则连接会报时区错误。
3.2 建库建表 SQL 与初始数据
根据文档的表结构,我整理了一份可直接执行的建表 SQL。字符集统一用 utf8,因为车主姓名和地址可能包含中文。
CREATE DATABASE parking_db DEFAULT CHARACTER SET utf8; USE parking_db; -- 用户表 CREATE TABLE t_user ( User_id INT(11) NOT NULL AUTO_INCREMENT, Role_id INT(11) NOT NULL, User_name VARCHAR(50) NOT NULL, Real_name VARCHAR(50) NOT NULL, User_pwd VARCHAR(50) NOT NULL, User_phone VARCHAR(50) DEFAULT NULL, PRIMARY KEY (User_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 车位信息表 CREATE TABLE t_seat ( Seat_id INT(11) NOT NULL AUTO_INCREMENT, Seat_num VARCHAR(50) NOT NULL, Seat_area VARCHAR(50) DEFAULT NULL, Seat_state VARCHAR(50) DEFAULT '空闲', Seat_tag VARCHAR(50) DEFAULT NULL, PRIMARY KEY (Seat_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- IC 卡信息表 CREATE TABLE t_card ( Card_id INT(11) NOT NULL AUTO_INCREMENT, Seat_id INT(11) DEFAULT NULL, User_name VARCHAR(50) DEFAULT NULL, User_Sex VARCHAR(50) DEFAULT NULL, User_addr VARCHAR(50) DEFAULT NULL, Car_num VARCHAR(50) DEFAULT NULL, PRIMARY KEY (Card_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 临时停车管理表 CREATE TABLE t_temp_parking ( temp_id INT(11) NOT NULL AUTO_INCREMENT, Car_id INT(11) DEFAULT NULL, Car_num VARCHAR(50) DEFAULT NULL, Entry_date VARCHAR(50) DEFAULT NULL, Entry_time VARCHAR(50) DEFAULT NULL, Out_date VARCHAR(50) DEFAULT NULL, Out_time VARCHAR(50) DEFAULT NULL, Temp_money VARCHAR(50) DEFAULT NULL, PRIMARY KEY (temp_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- 固定停车管理表 CREATE TABLE t_fixed_parking ( fixed_id INT(11) NOT NULL AUTO_INCREMENT, car_id INT(11) DEFAULT NULL, entry_date VARCHAR(50) DEFAULT NULL, entry_time VARCHAR(50) DEFAULT NULL, Out_date VARCHAR(50) DEFAULT NULL, Out_time VARCHAR(50) DEFAULT NULL, Fixed_money VARCHAR(50) DEFAULT NULL, PRIMARY KEY (fixed_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;建完表后,先插一条管理员账号,否则登录页进不去。用户表里 Role_id 可以先用 1 表示管理员,2 表示普通操作员。
INSERT INTO t_user (Role_id, User_name, Real_name, User_pwd, User_phone) VALUES (1, 'admin', '系统管理员', 'admin123', '13800000000');3.3 登录与车位管理功能实现要点
登录功能的流程是:JSP 页面提交用户名和密码到 Servlet,Servlet 调用 DAO 的 findByUsername 方法,查到用户后比对密码,成功则把用户信息放进 session,跳转到主页面。这里有个安全上的小改进:文档里密码是明文存储的,实际做的时候至少加个 MD5 或 SHA-256,虽然课设不查这个,但养成习惯没坏处。
车位管理的核心是“新增车位”和“车位状态切换”。新增车位时,Seat_state 默认设为“空闲”。当固定车主入场时,根据 IC 卡绑定的 Seat_id 把对应车位的 Seat_state 改成“占用”;出场时再改回“空闲”。临时车辆入场时,需要先查一张空闲车位表,分配一个空闲车位,同时把状态改成“占用”。这个逻辑如果写在 JSP 里会非常乱,我一般会抽一个 SeatService,把“占用”和“释放”做成两个方法,控制层只调方法。
// SeatService.java 片段 public boolean occupySeat(int seatId) { String sql = "UPDATE t_seat SET Seat_state='占用' WHERE Seat_id=? AND Seat_state='空闲'"; // 执行更新,返回影响行数是否大于 0 } public boolean releaseSeat(int seatId) { String sql = "UPDATE t_seat SET Seat_state='空闲' WHERE Seat_id=?"; // 执行更新 }注意 occupySeat 的 SQL 里带了 AND Seat_state='空闲',这是为了防止两个请求同时抢同一个车位。虽然课设并发量几乎为零,但这个写法能让你在答辩时多一个亮点。
4. 避坑与排查:从登录失败到计费对不上的五条血泪经验
4.1 中文乱码:表单提交后姓名变问号
现象:新增车主时,姓名和地址里的中文在数据库里显示为 ???。 原因:JSP 页面、Servlet 请求解析、数据库连接三层里有一层没设 UTF-8。 解决:JSP 页面顶部加 <%@ page contentType="text/html;charset=UTF-8" %>;Servlet 里在取参数前加 request.setCharacterEncoding("UTF-8");数据库连接 url 加 characterEncoding=utf8。三层都设了,乱码基本绝迹。
4.2 数据库连接报时区错误
现象:启动 Tomcat 后访问登录页,后台抛异常,提示 The server time zone value '?D1ú±ê×?ê±??' is unrecognized。 原因:MySQL 8.0 的驱动要求显式指定时区,而文档环境是 MySQL 5.5,没这个问题。 解决:把 jdbc.url 改成 jdbc:mysql://localhost:3306/parking_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai。如果你还在用 5.5,加不加都行,但加上不碍事。
4.3 固定车主出场计费金额为 0
现象:固定车主设置出场后,Fixed_money 字段是 0 或者空。 原因:计算费用时直接用了字符串截取日期,没有把 date 和 time 拼成完整时间,导致 Duration 算出来是负数或零。 解决:写一个工具方法,把 entry_date + " " + entry_time 和 out_date + " " + out_time 分别用 SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 解析成 Date,再算毫秒差。注意文档里日期格式可能是 yyyy-MM-dd,时间格式是 HH:mm:ss,拼接时中间要加空格。
4.4 临时车辆出场后车位没释放
现象:临时车辆结算完成后,车位信息表里对应车位的 Seat_state 还是“占用”。 原因:结算逻辑只更新了临时停车表的出场时间和费用,忘了调 releaseSeat。 解决:在临时车辆出场的 Service 方法里,结算费用之后紧接着调 seatService.releaseSeat(seatId)。顺序不能反,先释放再结算的话,如果结算抛异常,车位就白白空出来了。
4.5 Tomcat 启动报端口占用
现象:启动 Tomcat 时控制台报 Address already in use: JVM_Bind。 原因:8080 端口被其他程序占了,常见的是另一个 Tomcat 实例没关干净,或者某个开发工具内置了服务器。 解决:Windows 下用 netstat -ano | findstr 8080 找到 PID,再到任务管理器里结束对应进程。或者直接改 Tomcat 的 conf/server.xml,把 Connector port 改成 8081。
5. 进阶技巧:把计费逻辑抽成策略模式,以及一份可复用的测试清单
5.1 用策略模式替换 if-else 计费
文档里固定车主和临时车辆的计费是两套独立逻辑,分别写在各自的 Servlet 或 Service 里。如果你后面要加“月租车主”“VIP 车主”或者“节假日费率”,继续堆 if-else 会很难维护。我一般会抽一个 FeeStrategy 接口,固定车主和临时车辆各实现一个类,控制层根据车辆类型调对应的策略。
public interface FeeStrategy { BigDecimal calculate(LocalDateTime entry, LocalDateTime exit); } public class FixedFeeStrategy implements FeeStrategy { @Override public BigDecimal calculate(LocalDateTime entry, LocalDateTime exit) { long days = Duration.between(entry, exit).toDays(); long weeks = days / 7; if (days % 7 != 0) weeks += 1; // 不足一周按一周算 return new BigDecimal(weeks * 400); } } public class TempFeeStrategy implements FeeStrategy { @Override public BigDecimal calculate(LocalDateTime entry, LocalDateTime exit) { long hours = Duration.between(entry, exit).toHours(); if (hours <= 1) return new BigDecimal(5); return new BigDecimal(5 + (hours - 1) * 2); } }这样改的好处是,新增计费规则时只需要加一个实现类,不用动原来的代码。参数上注意:固定车主的 weeks 计算里,如果 days 正好是 7 的倍数,weeks 就是 days/7;如果不是,要向上取整。临时车辆的 hours 用 toHours() 会截断分钟,比如停了 1 小时 59 分,toHours() 返回 1,按 1 小时算,这符合“不足一小时按一小时”的常见规则。
5.2 一份可复用的功能验证清单
跑通系统后,别急着关掉,按下面这张清单过一遍,能省掉答辩时被问住的尴尬:
| 验证项 | 操作步骤 | 预期结果 |
|---|---|---|
| 登录失败 | 输入错误密码 | 提示“用户名或密码错误”,不跳转 |
| 新增车位 | 填写车位编号和区域 | 车位列表出现新记录,状态为“空闲” |
| 固定车主入场 | 选择 IC 卡号,提交 | 对应车位状态变“占用”,固定停车表新增记录 |
| 固定车主出场 | 点击设置出场 | 费用按周计算,车位状态变“空闲” |
| 临时车辆入场 | 填写车牌和临时卡号 | 分配空闲车位,临时停车表新增记录 |
| 临时车辆结算 | 点击结算 | 费用按小时计算,车位释放 |
| 修改密码 | 输入旧密码和新密码 | 旧密码失效,新密码可登录 |
这张表我每次做完类似系统都会跑一遍,尤其是“固定车主出场”和“临时车辆结算”这两项,最容易因为日期格式或车位释放顺序出问题。
5.3 导出 Excel 的简易实现
文档提到固定车主停车信息可以导出 Excel。如果不想引入 POI 这种重依赖,可以用最简单的 CSV 格式代替,Excel 也能直接打开。写一个 Servlet,把查询结果按逗号拼接,设置 response 的 content-type 为 application/vnd.ms-excel,文件名用 URLEncoder 编码一下防止中文乱码。
response.setContentType("application/vnd.ms-excel;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("停车信息.csv", "UTF-8")); PrintWriter out = response.getWriter(); out.println("车位ID,IC卡ID,入场日期,入场时间,出场日期,出场时间,费用"); for (FixedParking fp : list) { out.println(fp.getFixedId() + "," + fp.getCarId() + "," + fp.getEntryDate() + "," + fp.getEntryTime() + "," + fp.getOutDate() + "," + fp.getOutTime() + "," + fp.getFixedMoney()); } out.flush(); out.close();注意 CSV 里如果字段本身包含逗号,要用双引号包起来,不过停车信息里一般不会出现逗号,所以这个简易版够用了。
从那以后我每次拿到类似的管理系统文档,都会先把数据库表结构抄出来建一遍,再跑一遍功能验证清单,最后才去看代码。这套习惯帮我省掉了至少三次答辩前夜才发现计费逻辑对不上的返工。希望帮到你。
本文还有配套的精品资源,点击获取