Java课程设计实战:从零构建Swing通讯录管理系统(附完整源码)

📅 2026/7/13 12:07:51
Java课程设计实战:从零构建Swing通讯录管理系统(附完整源码)
1. 项目概述与核心功能通讯录管理系统是Java课程设计中非常经典的实战项目它涵盖了GUI开发、数据库操作、模块化设计等核心知识点。这个项目特别适合刚学完Java基础语法的同学练手能帮你把零散的知识点串联起来。我当年做第一个Java课设时也选择了类似项目实测对理解面向对象编程特别有帮助。这个系统主要实现三大核心模块用户管理处理注册和登录逻辑确保只有授权用户能访问通讯录联系人管理实现联系人的增删改查CRUD操作数据持久化通过JDBC将数据存储到MySQL数据库技术选型方面我们使用Swing做图形界面比AWT更现代MySQL作为数据库免费且轻量JDBC进行数据库连接。这些技术栈在企业级应用开发中也很常见学会后对后续学习JavaEE或Spring框架都有帮助。2. 开发环境搭建2.1 基础工具准备推荐使用IntelliJ IDEA社区版免费作为开发工具比Eclipse对新手更友好。我实测在配置环境时能少踩很多坑。还需要安装JDK 1.8建议用Oracle JDKMySQL 5.7注意配置字符集为utf8mb4Navicat或DBeaver可视化操作数据库# 检查Java环境应显示1.8 java -version # 启动MySQL服务Linux/Mac sudo service mysql start2.2 创建Maven项目在IDEA中新建Maven项目添加以下依赖到pom.xmldependencies !-- MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId version8.0.28/version /dependency !-- 单元测试 -- dependency groupIdjunit/groupId artifactIdjunit/artifactId version4.13.2/version scopetest/scope /dependency /dependencies2.3 数据库设计创建名为address_book的数据库然后执行以下SQLCREATE TABLE users ( id INT PRIMARY KEY AUTO_INCREMENT, username VARCHAR(50) UNIQUE NOT NULL, password VARCHAR(100) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE contacts ( id INT PRIMARY KEY AUTO_INCREMENT, user_id INT NOT NULL, name VARCHAR(50) NOT NULL, phone VARCHAR(20), email VARCHAR(50), company VARCHAR(100), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (user_id) REFERENCES users(id) );提示建议给phone和email字段添加索引能显著提升搜索性能。我在实际项目中发现当联系人超过5000条时无索引的模糊查询会变得很慢。3. 登录注册模块实现3.1 登录界面设计使用Swing的JFrame和JPanel构建登录窗口。关键点在于使用GridBagLayout进行组件布局比绝对定位更灵活为密码框使用JPasswordField添加焦点监听实现回车键登录public class LoginFrame extends JFrame { private JTextField usernameField; private JPasswordField passwordField; public LoginFrame() { setTitle(通讯录管理系统 - 登录); setSize(400, 300); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel new JPanel(new GridBagLayout()); GridBagConstraints gbc new GridBagConstraints(); gbc.insets new Insets(5, 5, 5, 5); // 用户名标签和输入框 gbc.gridx 0; gbc.gridy 0; panel.add(new JLabel(用户名:), gbc); gbc.gridx 1; gbc.gridy 0; gbc.fill GridBagConstraints.HORIZONTAL; usernameField new JTextField(15); panel.add(usernameField, gbc); // 密码标签和输入框 gbc.gridx 0; gbc.gridy 1; panel.add(new JLabel(密码:), gbc); gbc.gridx 1; gbc.gridy 1; passwordField new JPasswordField(15); passwordField.addActionListener(e - attemptLogin()); // 回车触发登录 panel.add(passwordField, gbc); // 登录按钮 gbc.gridx 0; gbc.gridy 2; gbc.gridwidth 2; JButton loginButton new JButton(登录); loginButton.addActionListener(e - attemptLogin()); panel.add(loginButton, gbc); add(panel); setLocationRelativeTo(null); // 窗口居中 } private void attemptLogin() { // 登录逻辑实现 } }3.2 用户认证逻辑创建UserService处理数据库操作注意要使用PreparedStatement防止SQL注入public class UserService { public static boolean login(String username, String password) { String sql SELECT password FROM users WHERE username ?; try (Connection conn DBUtil.getConnection(); PreparedStatement stmt conn.prepareStatement(sql)) { stmt.setString(1, username); ResultSet rs stmt.executeQuery(); if (rs.next()) { String storedPassword rs.getString(password); return storedPassword.equals(hashPassword(password)); } } catch (SQLException e) { e.printStackTrace(); } return false; } private static String hashPassword(String plain) { // 实际项目应该用BCrypt等安全哈希算法 return plain; // 示例简化处理 } }3.3 注册功能实现注册时需要检查用户名是否已存在并确认两次密码一致public static boolean register(String username, String password, String confirmPassword) { if (!password.equals(confirmPassword)) { return false; } String checkSql SELECT id FROM users WHERE username ?; String insertSql INSERT INTO users(username, password) VALUES(?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement checkStmt conn.prepareStatement(checkSql); PreparedStatement insertStmt conn.prepareStatement(insertSql)) { // 检查用户名是否存在 checkStmt.setString(1, username); ResultSet rs checkStmt.executeQuery(); if (rs.next()) { return false; // 用户名已存在 } // 插入新用户 insertStmt.setString(1, username); insertStmt.setString(2, hashPassword(password)); return insertStmt.executeUpdate() 0; } catch (SQLException e) { e.printStackTrace(); return false; } }4. 通讯录核心功能开发4.1 主界面设计主界面采用经典的BorderLayout北部搜索栏中部JTable展示联系人南部操作按钮public class ContactsFrame extends JFrame { private JTable contactsTable; private DefaultTableModel tableModel; public ContactsFrame(int userId) { setTitle(通讯录管理系统); setSize(800, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 表格模型 tableModel new DefaultTableModel(new Object[]{ID, 姓名, 电话, 邮箱, 公司}, 0); contactsTable new JTable(tableModel); // 搜索面板 JPanel searchPanel new JPanel(); JTextField searchField new JTextField(20); JButton searchButton new JButton(搜索); searchButton.addActionListener(e - searchContacts(searchField.getText())); searchPanel.add(searchField); searchPanel.add(searchButton); // 操作按钮 JPanel buttonPanel new JPanel(); JButton addButton new JButton(添加); JButton editButton new JButton(编辑); JButton deleteButton new JButton(删除); buttonPanel.add(addButton); buttonPanel.add(editButton); buttonPanel.add(deleteButton); // 布局 add(searchPanel, BorderLayout.NORTH); add(new JScrollPane(contactsTable), BorderLayout.CENTER); add(buttonPanel, BorderLayout.SOUTH); loadContacts(userId); } private void loadContacts(int userId) { // 加载联系人数据 } }4.2 联系人增删改查实现ContactService处理业务逻辑public class ContactService { public static boolean addContact(int userId, String name, String phone, String email, String company) { String sql INSERT INTO contacts(user_id, name, phone, email, company) VALUES(?, ?, ?, ?, ?); try (Connection conn DBUtil.getConnection(); PreparedStatement stmt conn.prepareStatement(sql)) { stmt.setInt(1, userId); stmt.setString(2, name); stmt.setString(3, phone); stmt.setString(4, email); stmt.setString(5, company); return stmt.executeUpdate() 0; } catch (SQLException e) { e.printStackTrace(); return false; } } public static ListContact searchContacts(int userId, String keyword) { ListContact contacts new ArrayList(); String sql SELECT * FROM contacts WHERE user_id ? AND (name LIKE ? OR phone LIKE ?); try (Connection conn DBUtil.getConnection(); PreparedStatement stmt conn.prepareStatement(sql)) { stmt.setInt(1, userId); stmt.setString(2, % keyword %); stmt.setString(3, % keyword %); ResultSet rs stmt.executeQuery(); while (rs.next()) { Contact contact new Contact(); contact.setId(rs.getInt(id)); contact.setName(rs.getString(name)); contact.setPhone(rs.getString(phone)); contact.setEmail(rs.getString(email)); contact.setCompany(rs.getString(company)); contacts.add(contact); } } catch (SQLException e) { e.printStackTrace(); } return contacts; } }4.3 数据库工具类DBUtil封装通用数据库操作public class DBUtil { private static final String URL jdbc:mysql://localhost:3306/address_book?useSSLfalse; private static final String USER root; private static final String PASSWORD 123456; static { try { Class.forName(com.mysql.cj.jdbc.Driver); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static Connection getConnection() throws SQLException { return DriverManager.getConnection(URL, USER, PASSWORD); } public static void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs ! null) rs.close(); if (stmt ! null) stmt.close(); if (conn ! null) conn.close(); } catch (SQLException e) { e.printStackTrace(); } } }5. 项目优化与扩展5.1 输入验证对所有用户输入进行校验public static boolean isValidPhone(String phone) { return phone.matches(^1[3-9]\\d{9}$); // 简单手机号验证 } public static boolean isValidEmail(String email) { return email.matches(^\\w[a-zA-Z_]?\\.[a-zA-Z]{2,3}$); }5.2 数据分页当联系人数量多时实现分页查询public static ListContact getContactsByPage(int userId, int page, int pageSize) { ListContact contacts new ArrayList(); String sql SELECT * FROM contacts WHERE user_id ? LIMIT ? OFFSET ?; try (Connection conn DBUtil.getConnection(); PreparedStatement stmt conn.prepareStatement(sql)) { stmt.setInt(1, userId); stmt.setInt(2, pageSize); stmt.setInt(3, (page - 1) * pageSize); ResultSet rs stmt.executeQuery(); while (rs.next()) { // 组装Contact对象 } } catch (SQLException e) { e.printStackTrace(); } return contacts; }5.3 导出功能添加导出为Excel的功能public static boolean exportToExcel(int userId, String filePath) { ListContact contacts getAllContacts(userId); try (Workbook workbook new XSSFWorkbook()) { Sheet sheet workbook.createSheet(通讯录); // 创建表头 Row headerRow sheet.createRow(0); headerRow.createCell(0).setCellValue(姓名); headerRow.createCell(1).setCellValue(电话); // 其他列... // 填充数据 for (int i 0; i contacts.size(); i) { Row row sheet.createRow(i 1); Contact contact contacts.get(i); row.createCell(0).setCellValue(contact.getName()); row.createCell(1).setCellValue(contact.getPhone()); // 其他字段... } try (FileOutputStream fos new FileOutputStream(filePath)) { workbook.write(fos); return true; } } catch (IOException e) { e.printStackTrace(); return false; } }6. 常见问题解决6.1 中文乱码问题确保数据库连接URL添加字符集参数jdbc:mysql://localhost:3306/address_book?useUnicodetruecharacterEncodingUTF-86.2 界面卡顿耗时操作如数据库查询应该在SwingWorker中执行new SwingWorkerListContact, Void() { Override protected ListContact doInBackground() throws Exception { return ContactService.getAllContacts(userId); } Override protected void done() { try { updateTable(get()); } catch (Exception e) { e.printStackTrace(); } } }.execute();6.3 数据库连接池生产环境建议使用HikariCP等连接池dependency groupIdcom.zaxxer/groupId artifactIdHikariCP/artifactId version5.0.1/version /dependencypublic class DataSource { private static final HikariConfig config new HikariConfig(); private static final HikariDataSource ds; static { config.setJdbcUrl(jdbc:mysql://localhost:3306/address_book); config.setUsername(root); config.setPassword(123456); config.addDataSourceProperty(cachePrepStmts, true); config.addDataSourceProperty(prepStmtCacheSize, 250); ds new HikariDataSource(config); } public static Connection getConnection() throws SQLException { return ds.getConnection(); } }