资讯详情

资讯详情

Java+Swing+MySQL停车场管理系统:从建表到计费的实战指南

简介一款基于Java Swing与MySQL的停车场管理系统完整项目面向Java初学者、课程设计及毕业设计人群旨在解决停车位管理、车辆出入登记与收费统计等实际问题帮助提升桌面端GUI编程和数据库结合能力。压缩包共79个文件涵盖25个Java源码、47个编译后class文件、1个SQL建表脚本、1个JAR依赖包、IDE工程配置及界面预览图整体大小仅2.08MB体积紧凑且目录结构明确便于直接导入开发环境运行。上线以来已有2351人学习/下载参照性较强。项目在实现上运用了Swing组件库构建用户界面采用MVC分层组织模型、视图与控制逻辑并通过JDBC完成对MySQL数据库的操作具体模块包括车位信息管理、车辆进出管理、用户管理和交易记录管理数据库涉及车位表、车辆表、用户表与交易表的关联设计。同时代码中包含事件驱动处理、多线程并发控制、输入验证与SQL注入防护等安全措施对理解桌面应用整体开发流程颇有帮助。1. JavaSwingMysql停车场管理系统毕业设计常客也是桌面端最难得的练手项目很多人第一眼看到“JavaSwingMysql停车场管理系统”这个标题会下意识觉得它只是又一个课设模板。但如果你真把 Swing 当玩具把 MySQL 当存档工具那这项目写出来大概率是个黑匣子——能跑但一上线就露馅。停车场管理系统本质上要解决三件事车辆进出记录、按时长计费、剩余车位实时管理。这三件事恰好把 Java 桌面开发里最核心的几块技能串起来了面向对象的实体设计、JDBC 数据库访问、Swing 的事件驱动 UI以及最让人头疼的并发与时间边界问题。做这个项目的人可能是正在找 java 面试题的应届生也可能是想把课设做出真实业务逻辑的在校生。不管哪种我建议你把它当成一个“迷你进销存”来做而不是只写一个能交差的 CRUD。本文会带你从表结构设计走到界面布局把计费规则、排障思路和验证手段都拆开讲保证你照着做能复现做完能讲清楚。2. 开建前先想明白选型、工程骨架与运行环境的三个关键决策2.1 为什么是 Swing 而不是 JavaFX别被“过时”带偏了很多人在动手前会纠结Swing 是不是太老了JavaFX 是不是更好就这个项目的定位来说Swing 反而是最稳的选择。Java 面试题里问桌面开发问的也多是 Swing 的组件模型和事件监听而不是 JavaFX 的 FXML 和属性绑定。Swing 的 MVC 结构足够朴素——JTable 是 ViewTableModel 是 Controller 和 Model 的中介业务逻辑塞在普通类里这种结构对于“停车场管理系统”这种数据表不超过五张的小体量项目反而是最容易维护的。另一个现实原因是运行环境。这个系统大概率要跑在 Windows 教室或实验室的机器上这些机器可能装的是老 JDKJavaFX 在 JDK 8 以后才被拆出去你还得额外配置模块路径。Swing 是 JDK 自带的东西装上 JDK 就能跑。这里有个血泪经验JDK 别装最新版推荐 JDK 8 或 JDK 11 LTS。JDK 8 对 Swing 的向后兼容最好JDK 11 也能跑但有些旧版 JDBC 驱动在 JDK 11 上会有模块访问警告。我一般会用 JDK 8配 MySQL 5.7 或 8.0 都行踩坑最少。2.2 数据库选型与安装要点MySQL 5.7 还是 8.0MySQL 的选择主要看你的环境。MySQL 5.7.44 是 5.7 系列的最终版稳定性经过了多年验证配置文件存在my.ini字符集默认是 latin1所以在建库时务必显式指定 utf8mb4。MySQL 8.0 的功能更多比如窗口函数、公用表表达式CTE但这些在这个项目里其实用不太上。它能用上的是更严格的默认认证插件 caching_sha2_password。这个插件会坑到一部分老驱动——mysql-connector-java 5.x 连 8.0 会报认证错误。我的建议是如果你是照着 mysql 安装教程一步步配的 8.0就务必用 mysql-connector-java 8.0.x 驱动如果你用的是 5.7驱动用 5.1.49 就好。驱动 jar 包放在项目的lib目录下编译和运行都要把lib加进 classpath这一条对新手的意义比想象中大。安装完成后建议先做三件事第一在 Windows 服务里把 MySQL 设为手动启动避免开机自启拖慢机器第二用客户端工具确认 root 能登录第三建一个专用数据库而不是用 root 连业务代码。root 用户跑业务查询在课设里常见但在 mysql 项目实战里是禁忌——一旦 SQL 写错把系统表删了后悔药是没有的。2.3 工程骨架包结构决定你答辩时能不能讲清楚这个系统的代码量不大但包结构不好后期改需求会非常痛苦。我常用的分层是这样的parking/ ├── Main.java // 程序入口 ├── db/ │ ├── DBUtil.java // JDBC 连接管理 │ └── DBConfig.java // 数据库参数配置 ├── entity/ │ ├── Car.java // 车辆实体 │ ├── ParkingRecord.java // 停车记录实体 │ └── User.java // 操作员实体 ├── dao/ │ ├── ParkingRecordDAO.java // 数据访问 │ └── UserDAO.java ├── service/ │ └── ParkingService.java // 计费等业务逻辑 └── ui/ ├── LoginFrame.java // 登录界面 ├── MainFrame.java // 主界面 └── CarDialog.java // 车辆进出录入弹窗实体类只放字段和 getter/setter不写任何业务逻辑DAO 只做 SQL 的封装service 层负责计费、车位状态更新这类跨表操作。UI 层只调用 service不直接写 SQL。这样分层之后你回答 java 面试题里“怎么降低耦合”这类问题时就能直接拿自己的项目举例。记得把数据库密码写在DBConfig.java里但千万不要把这个文件提交到 git 公开仓库这种失误在简历上属于硬伤。3. 表结构设计与 JDBC 连接先把数据模型立稳计费才不会翻车3.1 三张核心表车辆信息、停车记录、操作员停车场管理系统最少需要三张表车辆表、停车记录表、操作员表。车辆表存固定车辆月租车停车记录表存每一次进出的流水操作员表存登录账号。一个常见的设计错误是把车辆信息和停车记录合成一张表理由是“反正每辆车只查一次进出记录”。但停车场有固定车和临时车之分固定车可以提前录入临时车则要先进场再生成记录。合成一张表你会发现临时车的车牌号、车主姓名这些字段只能留空查统计报表时 SQL 越写越长最后完全没法看。MySQL 的 create table 语句里我习惯给所有表都加上create_time和update_time两个 datetime 字段前者在插入时取NOW()后者在更新时取NOW()。这俩字段在前端界面上可以不显示但排查数据问题时是救命稻草。车辆表建议以车牌号作为唯一键的一部分因为同一辆车的入场记录有多条车辆表本身则用自增主键。停车记录表的外键car_id关联车辆表主键同时冗余一个plate_number字段。冗余的理由是当临时车进场时车辆表和记录表是同时插入的car_id需要先插入车辆表再查询出主键而直接带车牌号可以省掉这一步。这个取舍在数据量小于百万时毫无问题分享给爱较真的同学时你可以用“读多写少、避免 join”来解释。操作员表不要明文存密码。即便这是课设也应该用 MD5 加密存储。JDK 自带的MessageDigest就能算 MD5不需要引第三方库。登录校验时把用户输入的密码做同样转换再比对。3.2 建表 SQL 与自增主键的坑下面给一套干净的建表脚本字符集统一 utf8mb4引擎用 InnoDB。MySQL 事务处理依赖 InnoDBMyISAM 不支持行级锁并发写记录的时候容易出问题CREATE DATABASE IF NOT EXISTS parking DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci; USE parking; CREATE TABLE car ( id INT AUTO_INCREMENT PRIMARY KEY, plate_number VARCHAR(20) NOT NULL UNIQUE, owner_name VARCHAR(50) DEFAULT , phone VARCHAR(20) DEFAULT , car_type TINYINT DEFAULT 1 COMMENT 1-临时车 2-月租车, create_time DATETIME DEFAULT NOW(), update_time DATETIME DEFAULT NOW() ON UPDATE NOW() ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE parking_record ( id INT AUTO_INCREMENT PRIMARY KEY, car_id INT NOT NULL, plate_number VARCHAR(20) NOT NULL, entry_time DATETIME NOT NULL, exit_time DATETIME DEFAULT NULL, duration_minutes INT DEFAULT NULL, total_fee DECIMAL(8,2) DEFAULT 0, status TINYINT DEFAULT 1 COMMENT 1-停在场内 0-已离场, create_time DATETIME DEFAULT NOW(), INDEX idx_plate_entry (plate_number, entry_time), CONSTRAINT fk_record_car FOREIGN KEY (car_id) REFERENCES car(id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; CREATE TABLE operator ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(30) NOT NULL UNIQUE, password_hash VARCHAR(64) NOT NULL, role TINYINT DEFAULT 1 COMMENT 1-管理员 2-收费员, create_time DATETIME DEFAULT NOW() ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO operator (username, password_hash) VALUES (admin, MD5(admin123));表里的idx_plate_entry联合索引很关键因为管理人员查“某车牌的历史进出记录”是最常见的查询没有这个索引数据量过万后会明显卡顿。ON UPDATE NOW()这个写法值得记住——MySQL 8.0 也支持能省掉 DAO 里手动更新update_time的代码。MD5 的 hash 值是 32 位十六进制所以password_hash用VARCHAR(64)给它留了余量。3.3 JDBC 连接管理DriverManager 还是连接池这个项目不推荐引入 MyBatis 或 Hibernate理由是过度设计。但 DAO 层如果用裸的DriverManager每执行一条 SQL 都建立一次物理连接性能属实浪费。常见做法是写一个极简连接池或者直接用DriverManager配静态单例。我一般会写一个DBUtil类内部持有一个LinkedListConnection作为空闲连接池最大连接数设为 5用后归还。这样代码量不大又能扛住 Swing 界面里连点按钮的并发查询。public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/parking?useSSLfalseserverTimezoneAsia/ShanghaicharacterEncodingutf8; private static final String USER parking_app; private static final String PASSWORD your_password; private static LinkedListConnection pool new LinkedList(); static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { throw new ExceptionInInitializerError(MySQL驱动未找到请检查lib目录); } } public static synchronized Connection getConnection() throws SQLException { if (pool.isEmpty()) { return DriverManager.getConnection(URL, USER, PASSWORD); } return pool.removeFirst(); } public static synchronized void close(Connection conn) { if (conn ! null) { pool.addLast(conn); } } }注意URL里的三个参数useSSLfalse是因为本地开发没有配置 SSL 证书不关掉会有一堆告警serverTimezoneAsia/Shanghai是必须的否则 MySQL 8.0 的时区偏移会导致java.sql.Timestamp转换后差 8 小时characterEncodingutf8是配合 MySQL 5.7 的老写法。连接池的核心是“用后归还”而不是“用后关闭”所以close方法的实现是把连接塞回链表。如果某条 SQL 抛了异常连接可能处于不可用状态这时应该真正关闭它而不是归还——这个边界很多初学者会漏。4. 核心业务与界面实现从登录到计费全流程附关键代码4.1 登录界面与操作员拦截登录界面用JFrame加JTextField、JPasswordField、JButton就够了。验证逻辑写在UserDAO里先按用户名查出password_hash再用MessageDigest对输入的密码做 MD5比对两个字符串。不要在 SQL 里直接写WHERE username ? AND password MD5(?)因为一旦 SQL 出错错误日志会打印整个 SQL密码等于裸奔。public boolean login(String username, String password) { String sql SELECT password_hash FROM operator WHERE username ?; try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { ps.setString(1, username); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { String hash rs.getString(password_hash); return hash.equals(md5(password)); } } } catch (SQLException e) { e.printStackTrace(); } return false; }注意try-with-resources的写法它会自动关闭ResultSet、PreparedStatement和Connection。这里的Connection是从连接池拿的关闭它时会把连接归还给池子。为什么ResultSet也要单独关闭因为Statement关闭时不一定马上释放结果集占用的游标资源显式关闭更稳妥。登录失败时弹JOptionPane.showMessageDialog提示“用户名或密码错误”不要区分“用户不存在”和“密码错误”防止遍历用户名。4.2 主界面布局JTabbedPane 分成四个页签主界面用JTabbedPane分成四个页签车辆入场、车辆出场、在场车辆、统计报表。这个结构逻辑清晰也方便扩展——加一个“月租车管理”页签不需要改动现有页签代码。入场页签的顶部是一个“车牌号输入框 入场按钮”下面是一张JTable显示最近入场的车辆。出场页签的核心是一个“根据车牌查询记录”的按钮查询结果显示在表格里选中一行再点“结算出场”。在场车辆页签每次打开时刷新显示status 1的记录。JTable必须配合DefaultTableModel使用不要直接往JTable构造器里塞二维数组。原因很简单DefaultTableModel有addRow、removeRow、setValueAt方法后续增删数据很顺手而直接构造的表格模型是只读的你要刷新数据就得重新创建JTable对象界面会闪烁。我一般把表格刷新的代码封装成refreshTable(String sql, Object... params)方法每次查询后清空 old rows 再逐行添加public void refreshTable(String sql, Object... params) { DefaultTableModel model (DefaultTableModel) table.getModel(); model.setRowCount(0); try (Connection conn DBUtil.getConnection(); PreparedStatement ps conn.prepareStatement(sql)) { for (int i 0; i params.length; i) { ps.setObject(i 1, params[i]); } try (ResultSet rs ps.executeQuery()) { ResultSetMetaData meta rs.getMetaData(); int colCount meta.getColumnCount(); while (rs.next()) { Object[] row new Object[colCount]; for (int i 1; i colCount; i) { row[i - 1] rs.getObject(i); } model.addRow(row); } } } catch (SQLException e) { e.printStackTrace(); } }这个方法胜在通用整个系统里所有跟“查询列表”相关的 UI 都能复用。ResultSetMetaData可以动态读取列数SQL 里SELECT的列变动时Java 代码不用跟着改。列名与表头的映射建议在创建JTable时写死而不是用meta.getColumnName()直接拿英文列名否则界面上会显示plate_number而不是“车牌号”。4.3 入场逻辑事务边界定在“写两张表”这里入场操作的业务规则是先查车辆表有没有这辆车没有就新建然后插入一条entry_time NOW()的停车记录状态设为在场最后把界面上的剩余车位减一。这三个步骤必须放在同一个事务里否则会出现“车辆建了但记录没插入”或者“记录插了但剩余车位没更新”的中间状态。Connection默认是自动提交的事务需要先setAutoCommit(false)操作完成后commit()异常时rollback()。因为DBUtil的close方法会把连接归还到池里所以事务方法里不要用 try-with-resources 包裹Connection——一旦正常关闭事务就提交了一旦异常关闭连接被归还但事务没回滚状态就乱了。正确写法是手动控制public boolean carEntry(String plateNumber) { String findCarSql SELECT id, car_type FROM car WHERE plate_number ?; String insertCarSql INSERT INTO car (plate_number, car_type) VALUES (?, 1); String insertRecordSql INSERT INTO parking_record (car_id, plate_number, entry_time, status) VALUES (?, ?, NOW(), 1); Connection conn null; try { conn DBUtil.getConnection(); conn.setAutoCommit(false); int carId; int carType 1; try (PreparedStatement ps conn.prepareStatement(findCarSql)) { ps.setString(1, plateNumber); try (ResultSet rs ps.executeQuery()) { if (rs.next()) { carId rs.getInt(id); carType rs.getInt(car_type); } else { // 插入临时车返回自增主键 try (PreparedStatement ps2 conn.prepareStatement(insertCarSql, Statement.RETURN_GENERATED_KEYS)) { ps2.setString(1, plateNumber); ps2.executeUpdate(); try (ResultSet keys ps2.getGeneratedKeys()) { keys.next(); carId keys.getInt(1); } } } } } // 月租车直接放行临时车检查余额 if (carType 2) { // 这里可以扩展月租有效期检查 } try (PreparedStatement ps3 conn.prepareStatement(insertRecordSql)) { ps3.setInt(1, carId); ps3.setString(2, plateNumber); ps3.executeUpdate(); } conn.commit(); return true; } catch (SQLException e) { if (conn ! null) { try { conn.rollback(); } catch (SQLException ignored) {} } e.printStackTrace(); return false; } finally { if (conn ! null) { try { conn.setAutoCommit(true); // 恢复默认状态再归还 DBUtil.close(conn); } catch (SQLException e) { e.printStackTrace(); } } } }这段代码里最值得讲的是Statement.RETURN_GENERATED_KEYS。在 MySQL 的 InnoDB 下自增主键的生成是由auto-inc锁控制的如果不显式获取生成的主键你可能要再查一次SELECT id FROM car WHERE plate_number ?这会引入一个极小的时间窗如果另一个线程同时插入同车牌的车你拿到的主键可能就是别人的。用getGeneratedKeys()拿到的才是本次插入真正生成的值。这段逻辑改成mybatisplus根据java实体类生成创建表的sql语句的模式也能对应上——实体类的主键注解本质上就映射了这个自增策略。4.4 出场计费按分钟计费与整点向上取整的取舍出场逻辑的核心是计费。按月租车直接不收费按临时车需要计算entry_time到NOW()的差额然后套费率。最常见的费率表是“首小时 5 元之后每小时 3 元不足一小时按一小时算”。这个规则用 Java 时间 API 写比用 SQL 算更直观。DATEDIFF 这类函数在 MySQL 排序或分组时挺方便但计费这种跟业务强相关的逻辑放在 service 层便于单元测试。public BigDecimal calculateFee(LocalDateTime entryTime, LocalDateTime exitTime) { long minutes Duration.between(entryTime, exitTime).toMinutes(); if (minutes 0) { throw new IllegalArgumentException(出场时间早于入场时间); } if (minutes 60) { return new BigDecimal(5.00); } long extraHours (minutes - 60 59) / 60; // 向上取整 BigDecimal fee new BigDecimal(5.00) .add(new BigDecimal(extraHours).multiply(new BigDecimal(3.00))); return fee; }这段代码的变量extraHours计算方式值得单独讲一句(minutes - 60 59) / 60是整数向上取整的标准技巧。重点来了——MySQL 的排序和比较比如 mysql 排序或者一个车牌有多条记录时选最新入场的 SQL跟这里的计费逻辑完全无关。出场扣费时只要更新parking_record表的exit_time、duration_minutes、total_fee并把status置为 0再让剩余车位加一。整个过程又是一个事务只不过这次只写一张表可以用try-with-resources简化。这里提醒一个容易被忽略的点计费时用LocalDateTime而不是java.util.Date。JDK 8 的java.time包是线程安全的DateTimeFormatter可以明确指定yyyy-MM-dd HH:mm:ss不会踩SimpleDateFormat的线程坑。Swing 是单线程事件模型一般不会并发操作日期但面试题喜欢问这些这个细节能体现你是写过工程项目的人。5. 避坑清单五个让新手项目当场翻车的真实问题5.1 界面假死Swing 的 EDT 线程到底是什么现象点击“查询所有车辆”后整个窗口拖不动、按钮没反应过几秒才恢复数据量大时直接卡死。原因你把数据库查询放在 Swing 事件回调线程EDT里。EDT 负责绘制所有组件它被一个耗时的executeQuery阻塞后就没空处理鼠标事件和重绘请求了表现就是界面假死。解决耗时操作放后台线程。最简单的做法是new Thread(() - refreshTable(sql)).start()但线程里不能碰任何 Swing 组件所以更规范的做法是用SwingWorkerVoid, ObjectSwingWorkerVoid, Object worker new SwingWorker() { Override protected Void doInBackground() { // 在这里执行DAO查询不碰UI ListCar list carDAO.findAll(); // 把结果放到中间变量 resultList list; return null; } Override protected void done() { // 回到EDT安全地更新JTable refreshTableFromList(resultList); } }; worker.execute();doInBackground()在后台线程跑done()会被系统调度回 EDT 执行。这个模式适用于所有耗时操作按车牌查历史记录、生成报表、批量导入。如果你用的是线程池记得统一关闭否则程序退出时 JVM 可能不退出。5.2 中文乱码连接串和表结构的双重坑现象JTextField里输入“鲁B12345”存进 MySQL 后变成“???12345”或者界面上读出来是乱码。原因两个层面。第一连接 URL 里没有characterEncodingutf8驱动用了默认编码跟数据库字符集不一致第二表或库的字符集是 latin1即使 URL 对了也是乱码。解决连接 URL 一定要带characterEncodingutf8MySQL 5.7或characterEncodingutf8mb4更通用并且建库建表时显式指定字符集。前面给的建表 SQL 里已经写了utf8mb4。如果你是从 navicat 或 cmd 客户端手动建的表注意检查SHOW CREATE TABLE car的输出确认CHARSET不是你建完表后忘了指定的默认值。5.3 ResultSet 游标越界next()判断是保命符现象登录时明明有这条记录但代码走到rs.getString时报java.sql.SQLException: Before start of result set。原因ResultSet的游标初始位置在第一行之前必须调用一次next()才会移动到第一行。很多新手模仿别人代码时漏了这层或者写了if (rs.next())判断下一行是否存在却在判断后又拿了一个不存在的列。解决写一个统一习惯——取第一行用if遍历多行用while。如果确定只有一行数据if (rs.next())就够了如果有多行用while (rs.next())。在 JDBC 里ResultSet是个游标对象而不是集合这种理解会帮你避免一半以上的报错。写 mapper 或 DAO 层时建议封装一个BeanListHandler工具方法把rs.next()的循环放在一处业务代码只拿ListCar以后排查问题会舒服很多。5.4 MySQL 8.0 时区报错导致时间差 8 小时现象停车场记录里入场时间是 14:00界面上显示 06:00或者偶尔抛The server time zone value Öйú±ê׼ʱ¼ä is unrecognized。原因MySQL 8.0 默认时区是SYSTEM而操作系统时区名跟 JDBC 驱动里的java.util.TimeZone映射不全驱动就会报错或错配偏移。这是 MySQL 安装配置教程里几乎不会讲到但第一次做 java web 项目或桌面项目时最容易踩的。解决建完 MySQL 后执行SET GLOBAL time_zone 08:00;并把连接 URL 里的serverTimezoneAsia/Shanghai保留。这样 MySQL 服务端和 JDBC 驱动两侧都锁定东八区时间字段读写就稳定了。顺带一提DATETIME类型不带时区语义存的就是字面值跟TIMESTAMP不同。这个项目统一用DATETIME即可避免在不同机器上部署时被时区差异坑到。5.5 DELETE 语句误删全部记录WHERE条件没带上现象想在界面上删掉一条入场记录结果表格全空了。原因DELETE FROM parking_record少了WHERE id ?。更隐蔽的版本是UPDATE parking_record SET status 0少了条件。这类错误在 mysql 项目实战里属于低级但高发的因为桌面应用调试时常常手滑。解决DAO 方法里把WHERE条件作为参数强制传入如果参数为空直接抛异常不给 SQL 执行的机会。另外给parking_record加一个“作废”字段而不是物理删除——这个系统的业务逻辑是财务流水要留痕物理删记录会把报表对账搞乱。真正的删除应该是UPDATE parking_record SET status 2 WHERE id ?截图中看不出来但答辩评委一定会问“删除记录后报表还对得上吗”。6. 进阶验证与打磨从能跑到能答辩还差这三件事做完了 CRUD接下来要让它活起来。第一件事是写一个计费测试类把跨小时、跨天、月租车免费这三种情况跑一遍断言calculateFee的返回值。测试代码可以写在main方法里不需要引 JUnit但测试用例的覆盖度直接决定了你答辩时能不能顶住追问。第二件事是给统计报表加一个“今日收入”聚合查询用SUM(total_fee)和GROUP BY DATE(entry_time)按天汇总——这张报表是最容易让评委眼前一亮的因为这暗示你考虑过运营场景而不是只在写作业。第三件事是导出一份 README写清楚 MySQL 版本、JDK 版本、连接池参数、默认账号密码以及如何用命令行直接启动系统javac -encoding UTF-8 -cp lib/*:. -d out src/parking/*.java src/parking/**/*.java java -cp lib/*:out parking.Main这行命令能跑通说明你的 classpath 配置没问题。如果系统要部署到别的机器记得把 MySQL 的bind-address注释掉否则局域网内其他客户端连不上数据库——不过跨机器用 MySQL 客户端你得先把 root 或应用账号的 host 权限设为%具体操作可以参考 mysql 安装配置教程里的用户管理一节。说实话我在课设阶段最懊悔的事就是没在项目一开始就建好“分层 事务 测试”这三个习惯。停车场管理系统的每一步——从车辆入场到出场计费——都天然带着事务边界和时间边界你把它当成迷你业务系统写一遍比看十篇 java 基础教程更管用。希望这篇笔记能帮你少走几段弯路把项目真正做成能落地、能演示、能讲清楚的作品。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →