Java GUI智慧公交管理系统:Swing+MySQL完整课设资源解析
简介:这是一套基于 Java GUI 与 MySQL 8.0 开发的智慧公交管理系统完整项目,面向高校数据库课程设计、Java 桌面应用开发实训及公交信息化初学者。系统围绕车辆信息、员工信息、线路站点、排班方案及登录权限等模块展开,内置管理员、调度员、员工三类角色,分别对应独立数据表,配置环境后运行 Login.java 即可连通数据库使用。资源共 2 个文件,包含项目压缩包与 busmanage.sql 数据库脚本,整体大小 10.72MB,其中 SQL 脚本可直接导入 MySQL Workbench 8.0 CE 建库,项目包则涵盖完整 Java 源码与界面,便于二次开发与功能扩展。已有 1137 人学习下载,适合需要完整可运行范例、数据库表设计参考或 GUI 布局思路的读者。包内目录层次清晰,从登录入口到各管理模块均有对应实现,配合数据表结构可快速理解车辆调度与排班流程,是一份能直接运行并用于课程汇报或项目练手的实用资源。
1. Java GUI 智慧公交管理系统:先说这份资源到底是什么
Java 课程设计里最让人头疼的任务,不是写一个按钮,而是把界面、数据库和业务逻辑拼成一个能跑的系统。这份 Java GUI 智慧公交管理系统(简称 IB)正好补上这一步:Swing 做界面,MySQL 8.0 存数据,车辆信息、员工信息、线路站点、排班方案和修改密码都做成了可操作的模块,管理员、调度员、员工三种角色分开登录,各自进不同的功能边界。它的场景很明确——Java GUI 课设、数据库大作业、或者你想看一个完整 Swing 项目怎么组织代码。新手可以照它梳理 GUI 事件和 JDBC 的对应关系;想交作业的同学可以直接替换界面文案、调整查询条件。我按 win10 + IDEA 2021.3.3 + JDK 1.8.0_201 跑通了一整遍,下面内容全部按这个路径讲。
2. 表结构与权限设计:七张表和三张角色登录表怎么串起一辆车
打开这份资源,我最先看的不是 Main 包,而是 busmanage.sql。很多同学拿到 Java GUI 项目,上来就启动 Login.java,结果要么账号密码不对,要么点完按钮没反应。原因很简单:界面和数据库没对齐。所以第二章先把表结构理清楚,后面跑代码的时候才知道每个框里填的到底是什么。
2.1 数据库清单:从员工、车辆到线路站点
数据库名称是 busmanage,建在 MySQL 8.0 下,用 MySQL Workbench 8.0 CE 管理。我打开 SQL 文件扫了一圈,核心是七张业务表:员工表、登录表、排班表、站点表、线路表、车辆表、线路-站点表。它们之间的关系并不复杂,先列一张表看清楚职责:
| 数据表 | 作用 | 典型字段方向 |
|---|---|---|
| 员工表 | 存司机、调度员等人员资料,排班时按员工编号关联 | 员工编号、姓名、所属线路或岗位 |
| 登录表 | 存用户名和密码,按角色区分来源 | 账号、密码、角色标识 |
| 排班表 | 记录某天某个班次谁开哪辆车跑哪条线 | 排班编号、员工、车辆、线路、日期、班次 |
| 站点表 | 维护所有站点的基础信息 | 站点编号、站点名称、站序 |
| 线路表 | 维护线路基础数据,如起点终点、票价 | 线路编号、线路名称、起点站、终点站 |
| 车辆表 | 维护车辆档案和运营状态 | 车牌号、车辆类型、载客量、状态 |
| 线路-站点表 | 连接线路和站点,决定一条线路经过哪些站 | 线路编号、站点编号、站点顺序 |
这里最容易被忽略的是“登录表”不是一张通用表:管理员、调度员、员工三类账号在库里是分开存放的,运行说明里也明确写着“三个不同的数据库表格分别存放他们的用户名与密码”。也就是说,登录逻辑不能只SELECT * FROM user,而是要按角色去查对应来源。理解这一点,你后面改登录功能时才不会把三种人的权限搅在一起。
2.2 三种角色的登录与权限边界
管理员是最高权限,车辆、员工、线路、站点、排班全部能看能改;调度员主要处理排班方案和线路站点;员工登录后更多是查看自己的排班和修改个人密码。这个边界不是写死在代码里的唯一一套逻辑,但你拿到资源后看到的界面权限基本是按这个思路切的。
我一般会先在 Login.java 里看它的角色判断分支,常见做法是switch (role)或者if (role == 1)这种方式。给你一个通用的登录判断骨架,后续改成三张角色表也容易:
// roleType: 1-管理员 2-调度员 3-员工 String sql; switch (roleType) { case 1: sql = "SELECT * FROM login_admin WHERE username = ? AND password = ?"; break; case 2: sql = "SELECT * FROM login_dispatch WHERE username = ? AND password = ?"; break; case 3: sql = "SELECT * FROM login_employee WHERE username = ? AND password = ?"; break; default: throw new IllegalArgumentException("无效角色"); }注意上述表名是通用示意,你拿到实际 SQL 文件后,以里面的真实表名为准。逻辑说明很简单:先根据角色选查询目标,再使用PreparedStatement绑定参数,避免直接把用户输入拼进 SQL 字符串。参数说明里最关键的是roleType,它来自登录界面下拉框或单选按钮,程序需要先判断它是否为合法值,再决定查哪张表。
2.3 表之间的数据联动:线路-站点表为什么会存在
线路和站点是典型的多对多关系:一条线路经过多个站点,一个站点可能有多条线路经过。如果直接在线路表里加一个“途经站点”字符串字段,查询和修改都会变得非常痛苦,比如要统计某个站点有哪些线路时,只能用LIKE去匹配字符串,性能差、精度也差。所以这份资源里专门拆了一张“线路-站点表”,解决多对多关联。
这张表的核心价值是“站序”。同一趟线路,站点的先后顺序决定了票价和行车方向,所以中间表里一定有一个类似sort_order或station_no的字段。查询某条线路的完整站点列表时,SQL 基本是:
SELECT s.station_id, s.station_name, rs.sort_order FROM route_station rs JOIN station s ON rs.station_id = s.station_id WHERE rs.route_id = ? ORDER BY rs.sort_order;这里route_station就是线路-站点表,变量?是线路编号。JOIN station是为了拿到站点名称,ORDER BY rs.sort_order保证站点按线路行进顺序展示。为什么不能直接SELECT * FROM route_station WHERE route_id=??因为这张中间表通常只存 ID 和顺序,界面要显示的是站点名称,不 JOIN 就拿到的是让人看不懂的编号。这个查询模式在员工查询线路时非常高频,理解它在后面改排班界面时会省很多时间。
3. 环境复现:从 MySQL 8.0 建库到 IDEA 跑起 Login.java 的完整路径
“百分百可运行”这句话成立的前提是环境对得上。这份资源标明的运行环境是:win10 专业版 x64、MySQL 8.0、MySQL Workbench 8.0 CE、IDEA 2021.3.3、JDK 1.8.0_201、mysql-connector-java-8.0.29.jar。如果你的本机版本差太多,第一步跑不起来很正常,问题不在代码,而在环境组合。
3.1 软件版本与兼容性选型
先把版本对齐这件事说透。JDK 1.8 是 Java Swing 项目最舒服的版本,IDEA 2021.3.3 对 JDK 8 的支持非常成熟,不会出现新版本 IDEA 默认把语言级别调到 17 导致的语法或编译问题。MySQL 8.0 的默认认证插件是caching_sha2_password,这意味着 JDBC 驱动版本必须够新,所以资源里明确要求mysql-connector-java-8.0.29.jar。
| 组件 | 版本 | 注意事项 |
|---|---|---|
| 操作系统 | win10 专业版 x64 | win11 也能跑,但路径最好全英文 |
| MySQL | 8.0 | 默认字符集建议建库时指定 utf8mb4 |
| MySQL Workbench | 8.0 CE | 用于导入 busmanage.sql 和改数据 |
| IDEA | 2021.3.3 | 用社区版或专业版都行,核心是 Project SDK 要对 |
| JDK | 1.8.0_201 | 不要用 JDK 17 跑这个项目,连接参数会变敏感 |
| JDBC 驱动 | mysql-connector-java-8.0.29.jar | 版本低于 8.0 会在 MySQL 8 上连不上 |
项目不是 Maven 工程,没有pom.xml,依赖是通过 IDEA 手动添加 jar 包完成的。所以你要做的第一件事不是改代码,而是把驱动 jar 放到一个不会乱动的位置,比如项目根目录下的libs文件夹。我习惯建libs目录后把驱动放进去,这样后续拷贝项目不会丢依赖。
3.2 MySQL 端:创建 busmanage 库并导入 SQL
我喜欢先建库再导数据,避免 Workbench 打开 SQL 文件后因为库不存在而报错。先启动 MySQL 服务,然后打开命令行或 Workbench 的 SQL 执行窗口:
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS busmanage DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" mysql -u root -p busmanage < busmanage.sql第一条命令创建busmanage数据库,并指定utf8mb4字符集,这是解决中文乱码的第一步。第二条命令把整个 SQL 文件导入到busmanage库中。参数说明:-u root是你的账号,-p表示需要密码,< busmanage.sql指当前命令行所在目录下的 SQL 文件。如果导入时报“表已存在”,在执行前加一句DROP DATABASE IF EXISTS busmanage;再重建。
导入完成后,我建议在 Workbench 里刷新一下左侧的 SCHEMAS,确认七张表都出来了。顺手做一件事:打开任意一张表,看一下建表语句里的存储引擎是不是InnoDB。InnoDB 才能保证外键关联和事务一致性,如果发现是 MyISAM,后面做排班插入时容易出怪问题。
3.3 IDEA 端:JDK、驱动 jar 和运行入口
用 IDEA 打开项目后,先检查 Project Structure。搜索框搜Structure,打开后找到 Project,把 SDK 改成 1.8,Language Level 也改成 8。这一步如果漏掉,即使本机装了 JDK 8,IDEA 也可能用模块里的低版本语言级别编译,出现 lambda 或 try-with-resources 报错。
接着把驱动 jar 加入项目。右键点击mysql-connector-java-8.0.29.jar,选择 Add as Library,范围选 Module。这一步很关键,不加 jar 包的话,Class.forName("com.mysql.cj.jdbc.Driver")会直接抛ClassNotFoundException。我见过很多同学把 jar 下载了但没 add,白折腾半小时。
最后运行入口在Main包里的Login.java。右键运行之前,先看一下连接字符串里的 URL 参数,常见的写法是这样:
private static final String URL = "jdbc:mysql://localhost:3306/busmanage" + "?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8" + "&allowPublicKeyRetrieval=true"; private static final String USER = "root"; private static final String PASSWORD = "123456";这段代码的逻辑是告诉 JDBC 驱动:数据库在本地 3306 端口,库名busmanage,不需要 SSL,时区用上海时间,编码用 utf8,并允许获取公钥。参数说明里最容易漏的是allowPublicKeyRetrieval=true,不写这个 MySQL 8.0 会报Public Key Retrieval is not allowed。PASSWORD一定要改成你自己本机的 MySQL 密码,不要用资源里原来的占位值。改完 URL 和密码后运行 Login.java,能看到登录窗口就说明环境基本通了。
4. 核心功能模块:车辆、线路、排班的增删改查与联动
系统里的功能模块看着多,其实都是同一套套路:界面控件触发事件,事件里拼 SQL,SQL 返回结果集,结果集填到 JTable 或文本框。这一章我挑三个最典型的模块讲,作为你自己改功能的参考模板。
4.1 车辆信息管理:从车辆列表到新增一辆车
车辆信息管理一般有查询、新增、修改、删除四个操作。我拿到这个模块后,第一个想看的不是界面上有几个按钮,而是查询方法里有没有用PreparedStatement。如果还停留在字符串拼接 SQL 的水平,建议改成下面这种写法:
public List<Vehicle> listVehicles(String keyword) { List<Vehicle> result = new ArrayList<>(); String sql = "SELECT vehicle_id, plate_no, type, status " + "FROM vehicle WHERE plate_no LIKE ?"; try (Connection conn = DBUtil.getConnection(); PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, "%" + keyword + "%"); try (ResultSet rs = ps.executeQuery()) { while (rs.next()) { Vehicle v = new Vehicle(); v.setId(rs.getInt("vehicle_id")); v.setPlateNo(rs.getString("plate_no")); v.setType(rs.getString("type")); v.setStatus(rs.getString("status")); result.add(v); } } } catch (SQLException e) { e.printStackTrace(); } return result; }逻辑说明:DBUtil.getConnection()通常是一个工具类里的方法,负责加载驱动并返回连接。PreparedStatement先用?占位,再通过ps.setString绑定关键词,这样车牌号里的单引号不会破坏 SQL 结构。参数说明:keyword是查询框输入的内容,即使为空也不能直接拼进 SQL,否则用户输入' OR 1=1就会把所有车辆查出来。新增车辆时同理,用INSERT INTO vehicle(plate_no, type, status) VALUES(?,?,?),车辆状态建议用下拉框限制为“运营/停运/维修”,而不是让用户自己填,避免脏数据。
拿到List<Vehicle>之后,界面层再把它转成 JTable 的DefaultTableModel,滚动面板一刷新,列表就出来了。这里有一个经常踩的小坑:JTable 的列名要跟 SQL 查询出来的字段顺序一致,不然界面表头显示的是空的 column 名。
4.2 线路与站点联动:查一条线路经过哪些站点
线路和站点之间靠线路-站点表联动,这在第二章讲过。真正做界面时,下拉框选线路,下方表格显示这条线路经过的所有站点:
SELECT rs.sort_order, s.station_name FROM route_station rs JOIN station s ON rs.station_id = s.station_id WHERE rs.route_id = ? ORDER BY rs.sort_order;这个 SQL 放在一个名为findStationsByRouteId(int routeId)的方法里执行,返回结果集后填到表格。注意ORDER BY rs.sort_order必须放在查询里,不要在 Java 里手动排序。数据库排序更稳定,而且当站点数量多时,SQL 一条语句搞定,Java 代码能少写十几行。
4.3 排班方案管理:一个排班记录关联四个维度
排班表是整个系统里关联字段最多的表,一条记录要同时指向员工、车辆、线路和日期班次。新增排班的 SQL 大致是:
INSERT INTO schedule (ref_emp, ref_vehicle, ref_route, work_date, shift) VALUES (?, ?, ?, ?, ?);这里ref_emp、ref_vehicle、ref_route分别是员工表、车辆表、线路表的外键。逻辑说明:如果直接让用户手输员工编号,很常见的结果是输了一个不存在的 ID,插入时外键报错,用户一头雾水。更好的做法是在排班界面的下拉框里,先查询可选员工、车辆、线路,用户只能从下拉框选择,界面层再拿选中的 ID 作为?的值填充。
排班冲突是另一个值得注意的点。同一辆车同一天不能排两个班次,同一员工同一天也不能排两个班。这个校验写在 GUI 的按钮点击事件里,而不是数据库里。常见做法是先查一次:
SELECT COUNT(*) FROM schedule WHERE ref_vehicle = ? AND work_date = ? AND shift = ?;如果COUNT(*)大于 0,直接弹窗提示“该车辆在此班次已排班”,不再执行插入。把校验放到插入前,比数据库抛异常再捕获要友好得多。这块逻辑也是我给这类课设项目加得最多的安全校验。
5. 避坑实战:运行、乱码、时区和驱动五处翻车点
这一章是血泪经验。你以为代码没问题,结果一运行就翻车;你以为翻车是 Java 写错了,结果查了半天是 MySQL 8.0 的驱动参数问题。下面五条都是这个项目里最容易复现的坑。
5.1 第一个坑:MySQL 8.0 连不上,报 Public Key Retrieval is not allowed
现象:点击登录按钮后,控制台抛出java.sql.SQLNonTransientConnectionException: Public Key Retrieval is not allowed。
原因:MySQL 8.0 默认使用caching_sha2_password认证,首次连接时客户端需要获取服务端公钥,而 JDBC 驱动默认不允许自动获取。
解决:连接 URL 上追加两个参数,allowPublicKeyRetrieval=true&useSSL=false。前者允许驱动自动拿公钥,后者告诉驱动不要走 SSL,减少握手失败的可能。这个坑出现概率极高,尤其是从 MySQL 5.7 项目迁移过来的代码,基本必踩。
5.2 第二个坑:表字段中文全部变成问号
现象:登录后,界面上员工姓名、站点名称全部显示为??,但命令行查询正常。
原因:数据库连接串里没带characterEncoding=utf8,或者建库时字符集不是 utf8mb4。JDBC 连接和 MySQL 服务端字符集不一致,中文写入后读取就乱码。
解决:连接串加characterEncoding=utf8,同时在建库 SQL 里指定DEFAULT CHARACTER SET utf8mb4。注意 utf8 和 utf8mb4 的区别:MySQL 的 utf8 最多支持三个字节,一些生僻字和特殊符号存不进去,直接指定 utf8mb4 更省心。如果在 Workbench 里导入 SQL 前没建库,可以改一下 SQL 文件第一行的建库语句,把字符集补上再导入。
5.3 第三个坑:serverTimezone 时区报错
现象:启动 Login.java 时报The server time zone value 'Öйú±ê׼ʱ¼ä' is unrecognized,或者提示服务器时区不存在。
原因:MySQL 8.0 和 JDBC 驱动对时区判断变严格,驱动读不到服务器默认时区就会报错。控制台那串乱码是“中国标准时间”被错误编码后的显示,属于时区问题而不是真乱码。
解决:URL 上显式加serverTimezone=Asia/Shanghai。如果加了仍然报错,再检查 MySQL 系统变量time_zone,可以执行SET GLOBAL time_zone = '+08:00';让服务端时区变成东八区。两处都统一后,这个问题基本消失。
5.4 第四个坑:IDEA 编译报 Java heap space
现象:运行时报java.lang.OutOfMemoryError: Java heap space,而且不是业务代码里创建大数组,是编译阶段就崩。
原因:IDEA 构建进程Gradle或Maven的堆内存太小,项目同时引用了多个库时,编译会撑爆内存。也有人直接在idea64.exe.vmoptions里把-Xmx调到 8000m,结果问题更大,因为 IDEA 自身堆和编译进程堆不是一回事。
解决:对于这种小项目,先确认是不是只由编译引起。在 IDEA 的Help -> Change Memory Settings里把内存从默认值调到 1024m 到 2048m 就够用了,不要盲目改到 8000m。如果改完还报,执行File -> Invalidate Caches / Restart清掉索引缓存。这门课设项目正常情况下占用内存极小,报堆溢出大概率是构建缓存或 IDEA 自身内存设置太保守。
5.5 第五个坑:多个 JDK 版本导致运行环境混乱
现象:命令行java -version显示的是 JDK 17,IDEA 里语言级别却是 1.8,编译时出现invalid source release: 17或Warning: Support for Java 8之类的提示。
原因:本机装了多个 JDK,环境变量JAVA_HOME指向了最新版本,IDEA 默认没有按项目设置去强制使用 JDK 1.8。
解决:先确认资源要求的版本,然后在 IDEAProject Structure -> Project -> SDK里明确选择 1.8,在Settings -> Build Tools -> Maven里把 JRE 也设为 1.8(如果是 Maven 项目)。我碰到这种情况会先写一个检查清单:java -version、echo %JAVA_HOME%、IDEA Project SDK 三项完全一致后,再运行 Login.java。环境变量和 IDEA 配置不一致是这类老项目跑不起来的头号元凶。
6. 进阶验证:从登录入口验证权限、打印 SQL 和扩展建议
跑通只是第一步,这个系统真正值得看的是登录入口和排班联动。我在验证一份新拿到的课设资源时,习惯按三个点检查:登录是否真的按角色分流、SQL 是否参数化、列表刷新是否正确。
6.1 登录入口的三个验证点
第一个验证点,用管理员、调度员、员工各自的账号登录,看进入的主界面菜单是否不同。如果三个账号进去界面都一样,说明登录表角色判断没生效。第二个验证点,故意输错密码,看程序是否给出提示并且不跳转。很多半成品在这里直接卡死,要么没有任何提示,要么弹一个空白的异常框。第三个验证点,在登录方法里临时加一行System.out.println(ps.toString()),打印参数绑定后的完整 SQL,确认每个?都已经被账号和密码填充,而不是直接拼字符串。
6.2 把列表导出成 CSV 的小技巧
这个项目是桌面应用,最实用的扩展是“导出排班表”。把 JTable 的每一行循环写进 CSV 文件,几行代码就能实现:
try (FileWriter fw = new FileWriter("schedule_export.csv", StandardCharsets.UTF_8); BufferedWriter bw = new BufferedWriter(fw)) { for (String column : columns) { bw.write(column + ","); } bw.newLine(); for (Object[] row : rows) { for (Object cell : row) { bw.write(cell + ","); } bw.newLine(); } }注意用StandardCharsets.UTF_8写出,否则 Excel 打开 CSV 时中文会乱码。导出前最好加一个JFileChooser让用户选保存位置,而不是直接写到项目根目录。
从那以后,我每次拿到一份新的 Java 课程设计资源,都会强制先走一遍“建库、看连接串、跑登录入口”的链路:数据库连不上不看代码,账号表对不上不看界面。这份智慧公交系统的结构不复杂,但把这条链路走通之后,你再回头去看 Swing 的事件监听、JDBC 的参数绑定、关系表的 JOIN 查询,都会觉得它们是连成一体的,而不是几段孤立的代码。希望帮到你。
本文还有配套的精品资源,点击获取