news 2026/7/13 12:07:42

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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 JDK)
  • MySQL 5.7+(注意配置字符集为utf8mb4)
  • Navicat或DBeaver(可视化操作数据库)
# 检查Java环境(应显示1.8+) java -version # 启动MySQL服务(Linux/Mac) sudo service mysql start

2.2 创建Maven项目

在IDEA中新建Maven项目,添加以下依赖到pom.xml:

<dependencies> <!-- MySQL驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.28</version> </dependency> <!-- 单元测试 --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> </dependencies>

2.3 数据库设计

创建名为address_book的数据库,然后执行以下SQL:

CREATE 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 List<Contact> searchContacts(int userId, String keyword) { List<Contact> 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?useSSL=false"; 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 List<Contact> getContactsByPage(int userId, int page, int pageSize) { List<Contact> 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) { List<Contact> 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?useUnicode=true&characterEncoding=UTF-8

6.2 界面卡顿

耗时操作(如数据库查询)应该在SwingWorker中执行:

new SwingWorker<List<Contact>, Void>() { @Override protected List<Contact> doInBackground() throws Exception { return ContactService.getAllContacts(userId); } @Override protected void done() { try { updateTable(get()); } catch (Exception e) { e.printStackTrace(); } } }.execute();

6.3 数据库连接池

生产环境建议使用HikariCP等连接池:

<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> </dependency>
public 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(); } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/13 12:07:28

STM32F030RC与MCP3551高精度ADC系统设计与优化

1. MCP3551与STM32F030RC硬件搭档解析 MCP3551作为Microchip推出的22位Δ-Σ ADC芯片&#xff0c;在工业测量领域有着广泛应用。其核心优势在于极低的噪声性能&#xff08;典型值2.5μVrms&#xff09;和高达2LSB的积分非线性度。与STM32F030RC这款Cortex-M0内核MCU搭配&#x…

作者头像 李华
网站建设 2026/7/13 12:06:57

Camera Tuning 实战:从实验室到场景的成像优化指南

1. Camera Tuning的核心逻辑&#xff1a;从实验室到真实场景的闭环Camera Tuning的本质是建立客观数据与主观体验的桥梁。实验室里用imatest跑分的参数再漂亮&#xff0c;如果用户拍出的照片发朋友圈不好看&#xff0c;这个调校就是失败的。我见过太多工程师沉迷于DXO评分&…

作者头像 李华
网站建设 2026/7/13 12:05:59

ComfyUI+Krea2人设图生成:从工作流搭建到提示词工程实战

在AI绘画领域&#xff0c;人设图生成一直是创作者们关注的重点。最近在测试Krea2模型时&#xff0c;发现其在人物角色设计方面表现出色&#xff0c;但网上关于具体工作流配置和提示词规则的详细教程相对零散。本文将分享一套完整的ComfyUIKrea2人设图生成方案&#xff0c;包含工…

作者头像 李华
网站建设 2026/7/13 12:05:44

多分类混淆矩阵实战:从TP/TN/FP/FN计算到性能指标解析

1. 三分类混淆矩阵实战入门第一次接触多分类混淆矩阵时&#xff0c;我也被那些TP、FP、TN、FN绕得头晕。直到在图像识别项目中踩了几个坑&#xff0c;才真正搞明白它们的计算逻辑。让我们从一个真实的三分类案例开始&#xff0c;假设我们训练了一个识别猫、狗、兔子的模型&…

作者头像 李华
网站建设 2026/7/13 12:04:14

Python/Java/C++ 3语言对比:函数参数传递机制与5个易错点分析

Python/Java/C 三语言函数参数传递机制深度对比与实战避坑指南 当我们在不同编程语言间切换时&#xff0c;函数参数传递机制往往是最容易产生认知混淆的领域之一。Python开发者初学Java时可能会困惑为何列表参数的行为与预期不符&#xff0c;C程序员转向Python时又会对"一…

作者头像 李华