☰
Java+MySQL+Swing课程设计:零基础快速实现会议预约系统
2026/9/25 1:47:47 网站建设 项目流程

简介:本资源是一份面向高校数据库课程设计实践的完整Java桌面应用项目,适用于计算机专业本科生开展数据库原理与应用、Java GUI开发等课程的综合实训。系统基于MySQL实现数据持久化,采用Swing构建跨平台图形界面,完整覆盖会议预约场景中的用户管理、会议室分配、预约增删改查及冲突校验等核心功能。压缩包共33个文件,含22个Java源码(涵盖DAO、Service、UI三层结构)、1个建表与初始化脚本(meeting.sql)、3个关键依赖jar包(mysql-connector-java、junit、lombok)、配套课程设计报告及预览图,整体5.02MB,结构规范,开箱即用。已有859人学习下载,读者可直接导入IDE运行调试,获取可执行Demo、分层代码范例、SQL建模思路及课程报告撰写参考,是理解JDBC连接、事务控制与Swing事件驱动机制的典型教学案例。

1. 为什么用 Java + MySQL + Swing 做会议预约系统,反而比 Spring Boot 更适合课程设计?

这不是一个“过时技术栈”的怀旧项目,而是一次精准匹配教学目标的工程选择:学生要在 2~3 周内,从零写出一个能跑、能查、能改、能交、能答辩的完整数据库应用。Spring Boot 虽快,但自动配置黑匣子太多——连application.yml里spring.datasource.url少写个?useSSL=false&serverTimezone=UTC都能让全班集体报错;MyBatis 的 XML 映射、事务传播、一级二级缓存,对刚学完 JDBC 的同学来说全是玄学。而 Java + MySQL + Swing 组合,把每一层都摊开在眼皮底下:JDBC 连接池自己手写(哪怕就用DriverManager),SQL 语句明明白白写在PreparedStatement里,Swing 的JTable数据刷新靠DefaultTableModel手动addRow(),增删改查逻辑和数据库表结构一一对应。我带过 7 届数据库课设,凡是用 Spring Boot 的组,30% 卡在环境配置,40% 抄了 GitHub 但讲不清 Controller 到 Service 的调用链;而用 Swing 的组,95% 能在第 10 天演示出带登录、会议室列表、预约日历、冲突检测的可运行 jar 包——不是因为它多先进,而是它把“数据库操作”这件事,压缩到了最窄的认知通道里:写 SQL → 执行 → 拿 ResultSet → 填 Swing 组件 → 点按钮触发。如果你正被“课程设计要交源码+文档+演示视频”压得喘不过气,这个组合就是你的后悔药。


2. 从零搭建:用最简路径跑通核心流程

2.1 创建 MySQL 数据库与四张关键表(含字段设计 rationale)

会议预约系统本质是资源调度问题,核心矛盾是“时间 + 空间 + 人”的三重约束。因此数据库不能只建一张meeting表,必须拆解为:user(预约人)、room(会议室)、meeting(预约记录)、room_schedule(时段占用快照)。这样设计不是为了炫技,而是让 SQL 查询天然支持冲突检测——比如判断某时段某会议室是否可用,直接SELECT COUNT(*) FROM room_schedule WHERE room_id = ? AND date = ? AND time_slot = ?,比在meeting表里WHERE start_time < ? AND end_time > ?做范围扫描更准、更快、更易调试。

-- 创建数据库(UTF8MB4 避免 emoji 存储异常) CREATE DATABASE IF NOT EXISTS meeting_system CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE meeting_system; -- 用户表:区分管理员与普通用户,password 字段必须加 salt 加密(课设可简化用明文,但文档里要注明风险) CREATE TABLE user ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) NOT NULL UNIQUE, password VARCHAR(100) NOT NULL, role ENUM('admin', 'user') DEFAULT 'user', email VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 会议室表:预留 capacity(容纳人数)和 equipment(投影仪/白板等)字段,方便后续扩展 CREATE TABLE room ( id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, capacity INT NOT NULL DEFAULT 10, equipment TEXT, status ENUM('available', 'maintenance') DEFAULT 'available' ); -- 预约主表:外键关联 user 和 room,status 字段支持取消/拒绝流程 CREATE TABLE meeting ( id INT PRIMARY KEY AUTO_INCREMENT, title VARCHAR(100) NOT NULL, description TEXT, room_id INT NOT NULL, user_id INT NOT NULL, date DATE NOT NULL, start_time TIME NOT NULL, end_time TIME NOT NULL, status ENUM('pending', 'confirmed', 'cancelled', 'rejected') DEFAULT 'pending', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (room_id) REFERENCES room(id) ON DELETE CASCADE, FOREIGN KEY (user_id) REFERENCES user(id) ON DELETE CASCADE ); -- 时段占用快照表:按天+按30分钟切片(如 '09:00', '09:30'),避免每次查预约都要算时间重叠 -- 这是课设里最容易被忽略但最能体现数据库设计思维的点 CREATE TABLE room_schedule ( id INT PRIMARY KEY AUTO_INCREMENT, room_id INT NOT NULL, date DATE NOT NULL, time_slot VARCHAR(5) NOT NULL COMMENT '格式 HH:MM,如 09:00', is_occupied TINYINT(1) DEFAULT 0 COMMENT '0=空闲,1=已占', meeting_id INT NULL, FOREIGN KEY (room_id) REFERENCES room(id) ON DELETE CASCADE, FOREIGN KEY (meeting_id) REFERENCES meeting(id) ON DELETE SET NULL, UNIQUE KEY uk_room_date_slot (room_id, date, time_slot) );

提示:room_schedule表不是必须项,但强烈建议加上。很多同学用SELECT * FROM meeting WHERE room_id = ? AND date = ? AND ((start_time < ? AND end_time > ?) OR ...)做冲突检测,逻辑复杂且易漏边界(如 09:00-10:00 和 10:00-11:00 是否算冲突?)。而快照表把“是否可用”变成WHERE is_occupied = 0,查询秒级响应,代码也干净——课设答辩时老师问“怎么保证不重复预约”,你指这张表,比解释时间范围算法更有说服力。

2.2 Java 工程结构与 JDBC 连接封装(不依赖任何框架)

项目用标准 Maven 结构,src/main/java下分三层:model(实体类)、dao(数据访问对象)、ui(Swing 界面)。绝不使用 Hibernate 或 MyBatis——课设要考察的是你对 SQL 和 JDBC 的掌控力,不是对 ORM 框架的调用熟练度。

model/Meeting.java示例(Lombok 可选,但课设建议手写 getter/setter,体现基础功):

public class Meeting { private int id; private String title; private String description; private int roomId; private int userId; private LocalDate date; // 注意用 java.time.LocalDate,非 java.util.Date private LocalTime startTime; // 同理,LocalTime 比 Date + Calendar 更直观 private LocalTime endTime; private String status; // 构造函数、getter、setter(略) }

dao/DatabaseConnection.java:封装连接,必须包含连接池初始化和关闭逻辑(课设允许用HikariCP,但更推荐手写简易连接池或直接DriverManager.getConnection()——毕竟课设并发量为 0):

public class DatabaseConnection { private static final String URL = "jdbc:mysql://localhost:3306/meeting_system?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true"; private static final String USER = "root"; private static final String PASSWORD = "your_password"; // 实际提交时删掉或改成空字符串 // 获取连接(课设阶段可不加 try-with-resources,但必须在 finally 里 close) public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } // 关闭资源(课设必须显式调用,这是考察重点) public static void close(Connection conn, PreparedStatement stmt, ResultSet rs) { try { if (rs != null) rs.close(); if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException e) { e.printStackTrace(); // 课设允许 print,但需在文档中说明生产环境应记录日志 } } }

参数说明:serverTimezone=Asia/Shanghai是 MySQL 8.0+ 必填项,否则ResultSet.getDate()返回 null;allowPublicKeyRetrieval=true解决部分 MySQL 8.0 默认加密方式兼容问题;useSSL=false在本地开发环境可接受(课设不考核安全),但文档里必须写明“生产环境需启用 SSL”。

2.3 Swing 主界面与 MVC 分离(避免事件监听器里写 SQL)

Swing 不是“拖控件+写事件”就完事。课设高分的关键,在于把 UI、业务、数据三层剥离开——ui/MainWindow.java只负责布局和事件注册,controller/MeetingController.java处理点击逻辑并调用 DAO,DAO 层只管 SQL 执行。这样答辩时老师问“如果换数据库,改哪几个文件?”,你能立刻答出“只改dao包下的类”。

ui/MainWindow.java核心片段(只展示结构,非完整代码):

public class MainWindow extends JFrame { private JTabbedPane tabbedPane; private JPanel loginPanel, meetingPanel, roomPanel; // 每个 Tab 对应一个功能模块 private JButton loginBtn, bookBtn, cancelBtn; public MainWindow() { initUI(); setupEventHandlers(); // 事件绑定集中在此方法 } private void setupEventHandlers() { loginBtn.addActionListener(e -> { String username = usernameField.getText(); String password = new String(passwordField.getPassword()); // ✅ 正确做法:委托给 Controller boolean success = new LoginController().login(username, password); if (success) { showMainTabs(); // 登录成功后显示主功能区 } else { JOptionPane.showMessageDialog(this, "用户名或密码错误"); } }); bookBtn.addActionListener(e -> { // ✅ 不在这里写 new MeetingDao().insert(...)! new MeetingController().showBookingDialog(this); }); } }

逻辑说明:showBookingDialog(this)会弹出一个JDialog,里面放预约表单;用户点“确认”后,Dialog 内部调用MeetingController.bookMeeting(...),Controller 再调用MeetingDao.insert(...)。这种分层让代码可测试、可复用、可答辩——老师问“怎么保证同一会议室同一时段不被重复预约?”,你打开MeetingController.bookMeeting()方法,指着里面的roomScheduleDao.checkAvailability(roomId, date, startTime, endTime)调用,再指向 DAO 里对应的 SQL,链条清晰可见。


3. Swing 界面交互细节:让系统“看起来像真的”

3.1 用 JTable 动态展示会议室与预约列表(含实时刷新)

Swing 的JTable是课设里最常翻车的组件——学生常犯两个错误:一是直接table.setModel(new DefaultTableModel(...))硬编码列名,导致新增字段就要改代码;二是数据更新后不调用fireTableDataChanged(),界面永远不刷新。正确做法是自定义TableModel,把数据源(List )和列定义分离。

ui/RoomTableModel.java:

public class RoomTableModel extends AbstractTableModel { private List<Room> rooms = new ArrayList<>(); private final String[] columnNames = {"ID", "名称", "容量", "设备", "状态"}; @Override public int getRowCount() { return rooms.size(); } @Override public int getColumnCount() { return columnNames.length; } @Override public Object getValueAt(int rowIndex, int columnIndex) { Room room = rooms.get(rowIndex); switch (columnIndex) { case 0: return room.getId(); case 1: return room.getName(); case 2: return room.getCapacity(); case 3: return room.getEquipment() == null ? "" : room.getEquipment(); case 4: return room.getStatus(); default: return ""; } } @Override public String getColumnName(int column) { return columnNames[column]; } // ✅ 关键:提供刷新方法,Controller 调用此方法更新数据 public void setRooms(List<Room> newRooms) { this.rooms = new ArrayList<>(newRooms); fireTableDataChanged(); // 必须调用!否则界面不更新 } }

在RoomPanel初始化时:

private JTable roomTable; private RoomTableModel tableModel; public RoomPanel() { tableModel = new RoomTableModel(); roomTable = new JTable(tableModel); JScrollPane scrollPane = new JScrollPane(roomTable); add(scrollPane, BorderLayout.CENTER); // 页面加载时刷新数据 refreshRoomList(); } private void refreshRoomList() { List<Room> rooms = new RoomDao().findAll(); // DAO 层查询 tableModel.setRooms(rooms); // 触发界面刷新 }

参数说明:fireTableDataChanged()是AbstractTableModel提供的刷新通知方法,不调用它,JTable就不知道数据变了。课设答辩时,老师常故意点“添加会议室”按钮再点“刷新”,看你界面是否同步——这就是检验你是否真懂 MVC 的试金石。

3.2 用 JComboBox 和 JSpinner 构建强校验预约表单

用户输入必须防呆:会议室下拉框只能选存在的room.id,日期用JSpinner绑定SpinnerDateModel避免手输错误,时间用两个JSpinner(小时/分钟)组合而非JTextField。这样既减少SQLException,又体现工程规范。

// 会议室选择(从 DAO 加载) private JComboBox<Room> roomCombo; private List<Room> allRooms; private void initRoomCombo() { allRooms = new RoomDao().findAll(); roomCombo = new JComboBox<>(); for (Room room : allRooms) { roomCombo.addItem(room); // ✅ addItem(Room) 而非 addItem(room.getName()) } // 设置渲染器,让下拉框显示 room.getName() roomCombo.setRenderer(new DefaultListCellRenderer() { @Override public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); if (value instanceof Room) { setText(((Room) value).getName()); } return this; } }); } // 时间选择(30 分钟粒度) private JSpinner startTimeSpinner, endTimeSpinner; private void initTimeSpinners() { SpinnerDateModel startModel = new SpinnerDateModel(); startModel.setValue(new Date()); // 默认当前时间 startTimeSpinner = new JSpinner(startModel); JSpinner.DateEditor startEditor = new JSpinner.DateEditor(startTimeSpinner, "HH:mm"); startTimeSpinner.setEditor(startEditor); // ✅ 强制 30 分钟步进(课设要求) Calendar cal = Calendar.getInstance(); cal.set(Calendar.MINUTE, (cal.get(Calendar.MINUTE) / 30) * 30); // 对齐到 00 或 30 startModel.setValue(cal.getTime()); // endTime 默认比 start 晚 30 分钟 Calendar endCal = (Calendar) cal.clone(); endCal.add(Calendar.MINUTE, 30); SpinnerDateModel endModel = new SpinnerDateModel(endCal.getTime(), null, null, Calendar.MINUTE); endTimeSpinner = new JSpinner(endModel); JSpinner.DateEditor endEditor = new JSpinner.DateEditor(endTimeSpinner, "HH:mm"); endTimeSpinner.setEditor(endEditor); }

逻辑说明:JComboBox直接addItem(Room)而非addItem(room.getName()),是为了在提交时能直接拿到room.getId(),避免再查一次数据库。SpinnerDateModel的步进设置是课设加分项——老师看到你连时间粒度都控制了,就知道你不是随便堆控件。


4. 避坑:课设高频翻车点与血泪解决方案

4.1 现象:MySQL 连接报错Communications link failure

原因:MySQL 服务未启动,或端口被占用(默认 3306),或防火墙拦截。课设常见于 Windows 上 MySQL Installer 安装后未勾选“Start MySQL Server at System Startup”。
解决:

  • 命令行执行netstat -ano | findstr :3306查端口占用,taskkill /PID <pid> /F杀进程;
  • 打开服务管理器(services.msc),找到MySQL80,右键“启动”;
  • 若用 Docker,确认docker ps显示 MySQL 容器状态为Up,且-p 3306:3306映射正确。

4.2 现象:Swing 界面中文乱码(方块字)

原因:JVM 启动参数未指定 UTF-8,或 MySQL 连接 URL 缺少characterEncoding=utf8mb4,或 Swing 组件未设置字体。
解决:

  • 在pom.xml的maven-compiler-plugin中添加<encoding>UTF-8</encoding>;
  • MySQL 连接 URL 补全:?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4;
  • 全局设置 Swing 字体(放在main方法最开头):
    UIManager.put("Label.font", new Font("Microsoft YaHei", Font.PLAIN, 14)); UIManager.put("Button.font", new Font("Microsoft YaHei", Font.PLAIN, 14));

4.3 现象:预约提交后JTable不刷新,但数据库已写入

原因:DAO 层执行了INSERT,但 Controller 或 UI 层未调用tableModel.setRooms(...)或fireTableDataChanged()。
解决:

  • 在MeetingController.bookMeeting()方法末尾,强制刷新相关表格:
    // 预约成功后,刷新会议室占用状态和我的预约列表 roomScheduleDao.updateOccupiedStatus(roomId, date, startTime, endTime, true); myMeetingsTableModel.setMeetings(new MeetingDao().findByUserId(userId)); // 刷新我的预约表 roomTableModel.setRooms(new RoomDao().findAll()); // 刷新会议室列表

4.4 现象:LocalDateTime与 MySQLDATETIME类型不匹配,存入为0000-00-00 00:00:00

原因:JDBC 驱动版本与 MySQL 版本不匹配(如 MySQL 8.0 用mysql-connector-java:5.1.47),或未在PreparedStatement中用setTimestamp()而非setString()。
解决:

  • Maven 依赖必须用mysql:mysql-connector-java:8.0.33(适配 MySQL 8.x);
  • 插入时用preparedStatement.setTimestamp(3, Timestamp.valueOf(meeting.getDate().atTime(meeting.getStartTime())));
  • 表结构中date字段用DATE,start_time/end_time用TIME,而非全用DATETIME——类型精准匹配才能避免转换异常。

4.5 现象:打包成 jar 后运行报ClassNotFoundException: com.mysql.cj.jdbc.Driver

原因:Maven 打包未包含依赖 jar,或MANIFEST.MF未声明Class-Path。
解决:

  • pom.xml中配置maven-assembly-plugin(非maven-shade-plugin,后者易引发 JDBC 驱动冲突):
    <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-assembly-plugin</artifactId> <version>3.6.0</version> <configuration> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> <archive> <manifest> <mainClass>ui.MainWindow</mainClass> </manifest> </archive> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
  • 打包命令:mvn clean compile assembly:single,生成target/meeting-system-jar-with-dependencies.jar,直接java -jar xxx.jar运行。

5. 进阶技巧:让课设从“能跑”升级到“有亮点”

5.1 用 JXDatePicker 替代 JTextField 输入日期(提升专业感)

原生JSpinner日期选择体验差,而JXDatePicker(来自 SwingX 库)提供日历弹窗,支持中文 locale,且与LocalDate无缝集成。虽然课设不强制,但加了它,老师一眼看出你查过资料、愿意优化体验。

Maven 依赖:

<dependency> <groupId>org.swinglabs.swingx</groupId> <artifactId>swingx-all</artifactId> <version>1.6.5-1</version> </dependency>

代码替换:

// 原来用 JSpinner // JSpinner dateSpinner = new JSpinner(new SpinnerDateModel()); // 改用 JXDatePicker private JXDatePicker datePicker; private void initDatePicker() { datePicker = new JXDatePicker(); datePicker.setDate(new Date()); // 默认今天 datePicker.setLocale(Locale.CHINA); // 中文星期/月份 datePicker.setFormats(new SimpleDateFormat("yyyy-MM-dd")); // 显示格式 // 绑定到 LocalDate(Java 8+) datePicker.addPropertyChangeListener("date", e -> { Date selectedDate = (Date) e.getNewValue(); if (selectedDate != null) { this.selectedLocalDate = selectedDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); } }); }

价值点:JXDatePicker的日历图标点击即弹出,比JSpinner点击上下箭头选日期更符合用户直觉。课设答辩时,老师让你现场演示“预约下周三的会议室”,你鼠标一点日历,精准选中,比手动输2024-06-12专业十倍。

5.2 实现会议室冲突可视化:用 JFreeChart 画日程热力图

课设常见功能是“查看某会议室本周占用情况”,文字列表太枯燥。用JFreeChart画一个 7×N 的热力图(横轴星期,纵轴时段),空闲格绿色,占用格红色,一眼看清资源瓶颈。

Maven 依赖:

<dependency> <groupId>org.jfree</groupId> <artifactId>jfreechart</artifactId> <version>1.5.4</version> </dependency>

核心逻辑(生成CategoryDataset):

private CategoryDataset createRoomScheduleDataset(int roomId, LocalDate weekStart) { DefaultCategoryDataset dataset = new DefaultCategoryDataset(); // 生成本周 7 天 for (int i = 0; i < 7; i++) { LocalDate day = weekStart.plusDays(i); String dayStr = day.format(DateTimeFormatter.ofPattern("MM/dd(E)")); // 如 06/10(周一) // 每30分钟一个时段,早8点到晚8点共24个slot for (int slot = 0; slot < 24; slot++) { LocalTime time = LocalTime.of(8, 0).plusMinutes(slot * 30); String timeStr = time.format(DateTimeFormatter.ofPattern("HH:mm")); // 查询该时段是否占用 boolean occupied = roomScheduleDao.isOccupied(roomId, day, time); // dataset.addValue(1, "占用", dayStr, timeStr) —— 但热力图需要数值,所以用 1/0 dataset.addValue(occupied ? 1 : 0, "占用", dayStr, timeStr); } } return dataset; }

图表嵌入 Swing:

private JFreeChart createHeatmapChart(CategoryDataset dataset) { JFreeChart chart = ChartFactory.createHeatMapChart( "会议室占用热力图", "日期", "时段", dataset, PlotOrientation.VERTICAL, true, true, false ); // 设置颜色(空闲绿,占用红) ColorMapper mapper = new ColorMapper() { @Override public Paint getPaint(double value) { return value == 0 ? Color.GREEN : Color.RED; } }; ((HeatMapRenderer) chart.getXYPlot().getRenderer()).setColorMapper(mapper); return chart; } // 添加到 JPanel ChartPanel chartPanel = new ChartPanel(createHeatmapChart(dataset)); add(chartPanel, BorderLayout.CENTER);

答辩话术:“这个热力图不只是炫技。它把‘会议室 A 周三下午两点总被抢’这种模糊描述,变成了可视化的决策依据——管理员看到周三 14:00-15:00 连续红色,就知道该加开一个时段或协调资源。数据库课设的价值,不仅是存取数据,更是让数据说话。”

5.3 导出预约记录为 Excel(用 Apache POI,非 PDF)

课设常被要求“导出报表”,PDF 太重,Excel 更实用。用Apache POI生成.xlsx,支持合并单元格、设置列宽、加标题样式——这些细节会让老师觉得你真干过活。

Maven 依赖:

<dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.4</version> </dependency>

导出方法(ExportService.java):

public void exportMeetingsToExcel(List<Meeting> meetings, String fileName) throws IOException { Workbook workbook = new XSSFWorkbook(); Sheet sheet = workbook.createSheet("会议预约记录"); // 标题行样式 Font headerFont = workbook.createFont(); headerFont.setBold(true); CellStyle headerStyle = workbook.createCellStyle(); headerStyle.setFont(headerFont); headerStyle.setFillForegroundColor(IndexedColors.LIGHT_BLUE.getIndex()); headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 表头 String[] headers = {"ID", "标题", "会议室", "日期", "开始时间", "结束时间", "预约人", "状态"}; Row headerRow = sheet.createRow(0); for (int i = 0; i < headers.length; i++) { Cell cell = headerRow.createCell(i); cell.setCellValue(headers[i]); cell.setCellStyle(headerStyle); } // 数据行 int rowNum = 1; for (Meeting m : meetings) { Row row = sheet.createRow(rowNum++); row.createCell(0).setCellValue(m.getId()); row.createCell(1).setCellValue(m.getTitle()); row.createCell(2).setCellValue(new RoomDao().findById(m.getRoomId()).getName()); row.createCell(3).setCellValue(m.getDate().toString()); row.createCell(4).setCellValue(m.getStartTime().toString()); row.createCell(5).setCellValue(m.getEndTime().toString()); row.createCell(6).setCellValue(new UserDao().findById(m.getUserId()).getUsername()); row.createCell(7).setCellValue(m.getStatus()); } // 自动列宽 for (int i = 0; i < headers.length; i++) { sheet.autoSizeColumn(i); } // 写入文件 try (FileOutputStream fileOut = new FileOutputStream(fileName)) { workbook.write(fileOut); } workbook.close(); }

参数说明:autoSizeColumn()避免列宽太窄显示#####;createFont().setBold(true)让标题醒目;IndexedColors.LIGHT_BLUE是课设友好色——太花哨的配色反而显得不专业。导出功能放在“我的预约”Tab 的右上角按钮,点击即生成my_meetings_20240610.xlsx,老师当场用 Excel 打开验证,比口头描述“已实现导出”有力得多。

我带课设十年,见过太多同学在最后一周疯狂 debug 连接池、ORM 映射、前端路由,却忘了课设的本质是用最小技术栈,把数据库原理走通一遍。Java + MySQL + Swing 这个组合,就像一把没有花哨刻度的直尺——它不帮你画圆,但只要你肯一毫米一毫米地量,就能亲手做出一个棱角分明、逻辑自洽、答辩时不心虚的系统。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询