Java Swing图书管理系统开发与实战
简介:Java Swing图书管理系统是一款基于Java GUI框架Swing与SQL数据库构建的桌面应用,涵盖登录、图书添加、查看及数据库交互等功能。系统采用JDBC连接数据库,实现图书信息的增删改查操作,并通过Swing组件构建用户界面。该项目适合Java初学者掌握GUI编程与数据库连接的实际开发流程,提升Java桌面应用开发能力。
1. Java Swing图形界面开发基础
1.1 Java Swing概述
Java Swing是Java提供的一个用于开发图形用户界面(GUI)的类库,属于Java Foundation Classes(JFC)的一部分。与AWT相比,Swing组件是纯Java实现的,具有更强的跨平台性和丰富的控件库。Swing支持事件驱动编程,使开发者能够构建交互性强、响应及时的桌面应用程序。
在图书管理系统中,Swing负责构建用户操作界面,如登录窗口、图书信息展示、添加与编辑窗口等,是系统与用户交互的核心。掌握Swing的基本组件和布局管理,是实现系统前端功能的前提。
1.2 Swing组件基本使用
Swing提供了丰富的图形界面组件,常见的有:
JFrame:顶级容器,表示主窗口JPanel:中间容器,用于组织其他组件JButton:按钮控件JTextField:文本输入框JLabel:显示静态文本或图像JComboBox、JCheckBox:下拉框与复选框
下面是一个简单的Swing程序示例:
import javax.swing.*;
public class SimpleSwingApp {
public static void main(String[] args) {
// 创建主窗口
JFrame frame = new JFrame("图书管理系统 - 登录");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
// 创建面板并添加组件
JPanel panel = new JPanel();
JLabel label = new JLabel("用户名:");
JTextField textField = new JTextField(15);
JButton button = new JButton("登录");
panel.add(label);
panel.add(textField);
panel.add(button);
// 添加面板到窗口
frame.add(panel);
frame.setVisible(true);
}
}
代码说明:
JFrame是窗口容器,设置标题、大小、关闭行为后通过setVisible(true)显示。JPanel用于组织控件,便于布局管理。JLabel和JTextField构成输入提示与输入框。JButton表示可点击的按钮,后续可绑定事件监听。
1.3 事件监听机制
Swing采用事件监听机制处理用户操作,如点击按钮、选择菜单项等。开发者需为组件注册监听器,当事件发生时,JVM会调用对应的回调方法。
以下示例演示如何为按钮添加点击事件:
button.addActionListener(e -> {
String username = textField.getText();
JOptionPane.showMessageDialog(frame, "欢迎," + username + "!");
});
说明:
addActionListener为按钮注册点击事件监听器。- 使用 Lambda 表达式简化事件处理逻辑。
JOptionPane.showMessageDialog用于弹出提示框,增强用户交互体验。
1.4 布局管理器简介
Swing使用布局管理器(Layout Manager)自动排列组件,避免手动设置坐标与大小。常见的布局包括:
| 布局类型 | 描述 |
|---|---|
FlowLayout |
按照从左到右顺序排列组件,默认对齐方式 |
BorderLayout |
将容器划分为5个区域(东、南、西、北、中) |
GridLayout |
按照网格方式排列组件 |
GridBagLayout |
更加灵活的网格布局,支持组件跨行跨列 |
推荐在实际开发中根据界面需求选择合适的布局方式,避免使用 setBounds() 手动定位,以提高界面的可维护性和跨平台兼容性。
1.5 小结
本章介绍了Java Swing的基础知识,包括核心组件的使用、事件监听机制和布局管理器的选用。通过这些内容,读者已经能够构建一个简单的图形界面,并实现基本的交互功能。这为后续开发图书管理系统的登录界面和主功能界面奠定了坚实基础。下一章将深入讲解如何使用JDBC连接数据库,并设计图书管理系统的数据库结构。
2. JDBC数据库连接与SQL数据库设计
在构建图书管理系统的过程中,数据库的设计与连接是整个系统的核心环节。本章将围绕JDBC(Java Database Connectivity)技术展开,深入讲解如何使用Java连接数据库,并设计出结构合理、易于维护的数据库表结构。通过本章的学习,读者将掌握数据库连接池的配置、数据库建模的原则、SQL脚本的编写方法,以及如何使用DAO模式封装数据库操作和处理异常,从而为后续系统的开发打下坚实基础。
2.1 JDBC基础与数据库连接
Java Database Connectivity(JDBC)是Java中用于与关系型数据库进行交互的标准API。通过JDBC,Java程序可以连接到数据库,执行SQL语句,并对查询结果进行处理。本节将详细介绍JDBC的基础知识、驱动引入方式,以及如何实现数据库连接池。
2.1.1 JDBC驱动的引入与数据库连接方式
JDBC的核心是 java.sql 包,它定义了数据库连接、执行SQL语句、处理结果集等接口。要使用JDBC连接数据库,首先需要引入对应的JDBC驱动。不同数据库厂商提供了各自的JDBC驱动包,例如MySQL的 mysql-connector-java 、PostgreSQL的 postgresql 等。
示例:引入MySQL JDBC驱动
在Maven项目中,可以在 pom.xml 文件中添加如下依赖:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
该依赖引入后,项目即可使用MySQL的JDBC驱动。
连接数据库的基本方式
Java中使用JDBC连接数据库的基本步骤如下:
- 加载数据库驱动类。
- 建立数据库连接。
- 创建SQL语句对象。
- 执行SQL语句并处理结果。
- 关闭资源。
示例代码:JDBC连接MySQL数据库
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class JdbcConnectionExample {
public static void main(String[] args) {
String url = "jdbc:mysql://localhost:3306/library_db?useSSL=false&serverTimezone=UTC";
String username = "root";
String password = "your_password";
try {
// 1. 加载驱动类(JDBC 4.0之后可省略)
Class.forName("com.mysql.cj.jdbc.Driver");
// 2. 获取连接
Connection connection = DriverManager.getConnection(url, username, password);
System.out.println("数据库连接成功!");
// 3. 使用connection进行后续数据库操作(略)
// 4. 关闭连接
connection.close();
} catch (ClassNotFoundException e) {
System.err.println("找不到数据库驱动类");
e.printStackTrace();
} catch (SQLException e) {
System.err.println("数据库连接失败");
e.printStackTrace();
}
}
}
代码逻辑分析:
-
Class.forName("com.mysql.cj.jdbc.Driver"):显式加载MySQL的JDBC驱动类,确保驱动被注册。JDBC 4.0以上版本支持自动加载,可省略此行。 -
DriverManager.getConnection(url, username, password):建立数据库连接,返回Connection对象。 -
connection.close():关闭数据库连接,释放资源。 - URL格式说明 :
jdbc:mysql://:指定使用MySQL数据库。localhost:3306:数据库服务器地址和端口。library_db:目标数据库名称。- 参数
useSSL=false和serverTimezone=UTC用于解决SSL连接和时区问题。
JDBC连接方式小结
| 步骤 | 操作 | 说明 |
|---|---|---|
| 1 | 加载驱动 | 可选,JDBC 4.0以上自动加载 |
| 2 | 获取连接 | 使用 DriverManager 类 |
| 3 | 执行SQL | 使用 Statement 或 PreparedStatement |
| 4 | 处理结果 | 使用 ResultSet 获取查询结果 |
| 5 | 关闭资源 | 避免资源泄露 |
2.1.2 使用Connection接口实现数据库连接池
频繁地打开和关闭数据库连接会导致性能下降。为提高系统效率,通常使用 数据库连接池 来管理连接。连接池在应用启动时创建多个连接,供多个线程重复使用,从而避免重复创建连接的开销。
常见连接池技术
- HikariCP :性能优秀,配置简单,推荐使用。
- Apache DBCP :较早的连接池实现。
- C3P0 :功能丰富但配置较复杂。
- Druid :阿里巴巴开源,具备监控功能。
示例:使用HikariCP配置连接池
首先在 pom.xml 中添加HikariCP依赖:
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
然后编写配置类:
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
public class HikariCPExample {
private static DataSource dataSource;
static {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/library_db?useSSL=false&serverTimezone=UTC");
config.setUsername("root");
config.setPassword("your_password");
config.setMaximumPoolSize(10); // 设置最大连接数
config.setIdleTimeout(30000); // 空闲连接超时时间
config.setConnectionTestQuery("SELECT 1"); // 测试连接有效性
dataSource = new HikariDataSource(config);
}
public static DataSource getDataSource() {
return dataSource;
}
public static void main(String[] args) {
try (Connection conn = dataSource.getConnection()) {
System.out.println("从连接池获取连接成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
代码逻辑分析:
-
HikariConfig:配置连接池的基本参数。 -
setJdbcUrl、setUsername、setPassword:设置数据库连接信息。 -
setMaximumPoolSize:设置最大连接数,根据系统负载合理配置。 -
setIdleTimeout:空闲连接超时时间,避免连接长时间不释放。 -
setConnectionTestQuery:连接有效性测试语句,确保获取的连接可用。 -
HikariDataSource:HikariCP的核心类,用于管理连接池。 -
dataSource.getConnection():从连接池中获取连接,使用完毕后自动归还。
连接池配置参数对比表
| 参数 | HikariCP | DBCP | Druid |
|---|---|---|---|
| 最大连接数 | setMaximumPoolSize |
setMaxTotal |
setInitialSize |
| 最小空闲连接 | setMinimumIdle |
setMinIdle |
setMinIdle |
| 空闲超时 | setIdleTimeout |
setMinEvictableIdleTimeMillis |
setMinEvictableIdleTimeMillis |
| 连接测试SQL | setConnectionTestQuery |
setValidationQuery |
setValidationQuery |
| 自动提交 | setAutoCommit |
setAutoCommit |
setAutoCommit |
连接池使用流程图(Mermaid格式)
graph TD
A[应用请求数据库连接] --> B{连接池是否空闲?}
B -- 是 --> C[创建新连接]
B -- 否 --> D[从池中获取可用连接]
C --> E[加入连接池]
D --> F[执行SQL操作]
F --> G[释放连接回池]
通过连接池的使用,系统可以显著提升数据库访问效率,降低连接创建和销毁的开销,是构建高性能Java应用的关键手段之一。
2.2 图书管理系统数据库设计
数据库设计是系统开发的基础,良好的数据库结构可以提高系统的可维护性、可扩展性和性能。本节将介绍数据库设计的基本原则,并以图书管理系统为例,详细讲解图书信息表、用户表和权限表的设计方法。
2.2.1 数据库表结构设计原则
在进行数据库设计时,应遵循以下基本原则:
- 规范化(Normalization) :通过消除冗余数据,减少更新异常。
- 一致性(Consistency) :确保数据逻辑合理,避免矛盾。
- 完整性(Integrity) :使用主键、外键等约束保证数据正确性。
- 可扩展性(Scalability) :便于后续扩展新功能。
- 命名规范(Naming Convention) :统一命名规则,提高可读性。
数据库设计流程图(Mermaid格式)
graph TD
A[需求分析] --> B[实体识别]
B --> C[关系建模]
C --> D[字段定义]
D --> E[主键与外键约束]
E --> F[创建表结构]
2.2.2 图书信息表、用户表与权限表的设计
图书信息表 books
| 字段名 | 类型 | 描述 |
|---|---|---|
book_id |
INT | 图书ID(主键) |
title |
VARCHAR(255) | 图书标题 |
author |
VARCHAR(100) | 作者 |
isbn |
VARCHAR(13) | ISBN编号(唯一) |
publisher |
VARCHAR(100) | 出版社 |
publish_date |
DATE | 出版日期 |
category |
VARCHAR(50) | 图书分类 |
status |
ENUM(‘available’, ‘borrowed’) | 当前状态 |
CREATE TABLE books (
book_id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
author VARCHAR(100),
isbn VARCHAR(13) UNIQUE,
publisher VARCHAR(100),
publish_date DATE,
category VARCHAR(50),
status ENUM('available', 'borrowed') DEFAULT 'available'
);
用户表 users
| 字段名 | 类型 | 描述 |
|---|---|---|
user_id |
INT | 用户ID(主键) |
username |
VARCHAR(50) | 登录用户名(唯一) |
password_hash |
VARCHAR(255) | 加密后的密码 |
role_id |
INT | 角色ID(外键) |
created_at |
DATETIME | 创建时间 |
CREATE TABLE users (
user_id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role_id INT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (role_id) REFERENCES roles(role_id)
);
权限表 roles
| 字段名 | 类型 | 描述 |
|---|---|---|
role_id |
INT | 角色ID(主键) |
role_name |
VARCHAR(50) | 角色名称(如admin、user) |
CREATE TABLE roles (
role_id INT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(50) UNIQUE NOT NULL
);
表结构关系图(Mermaid格式)
erDiagram
books ||--o{ borrow_records : "借阅记录"
users ||--o{ borrow_records : "用户借阅"
users }|--|| roles : "角色关联"
通过以上设计,图书管理系统具备了基础的表结构模型,能够支撑后续功能开发,如借阅、归还、权限控制等。
本章详细讲解了JDBC数据库连接的实现方法与数据库设计原则,并通过实际示例展示了连接池配置与图书管理系统表结构的设计。下一节将继续深入SQL脚本的编写与数据导入操作,帮助读者掌握完整的数据库操作技能。
3. 图书管理系统的登录界面与权限验证
登录界面与权限验证是图书管理系统的第一道安全屏障,也是用户交互的起点。本章将深入探讨如何利用 Java Swing 构建美观、易用的登录界面,并通过 JDBC 连接数据库实现用户身份验证与权限控制。我们将从 UI 设计、用户验证逻辑、权限控制策略,以及安全性处理四个方面展开详细分析,确保读者能够掌握完整的登录模块开发技能。
3.1 登录界面的UI设计与实现
3.1.1 使用Swing组件构建登录界面
Swing 是 Java 提供的一套图形用户界面库,支持丰富的组件和事件处理机制。在图书管理系统的登录界面中,我们主要使用以下几个 Swing 组件:
JFrame:作为主窗口容器。JLabel:用于显示“用户名”、“密码”等提示文本。JTextField:用于输入用户名。JPasswordField:用于输入密码,具有掩码功能。JButton:用于“登录”和“取消”按钮。
以下是一个简单的登录界面代码示例:
import javax.swing.*;
import java.awt.*;
public class LoginFrame extends JFrame {
private JTextField usernameField;
private JPasswordField passwordField;
public LoginFrame() {
setTitle("图书管理系统 - 登录");
setSize(400, 300);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null); // 居中显示
// 创建面板并设置布局
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(3, 2));
// 添加用户名输入框
panel.add(new JLabel("用户名:"));
usernameField = new JTextField();
panel.add(usernameField);
// 添加密码输入框
panel.add(new JLabel("密码:"));
passwordField = new JPasswordField();
panel.add(passwordField);
// 添加登录按钮
JButton loginButton = new JButton("登录");
JButton cancelButton = new JButton("取消");
// 添加按钮面板
JPanel buttonPanel = new JPanel();
buttonPanel.add(loginButton);
buttonPanel.add(cancelButton);
// 添加面板到窗口
add(panel, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
setVisible(true);
}
public static void main(String[] args) {
new LoginFrame();
}
}
代码逻辑分析:
-
JFrame设置 :设置窗口标题、大小、关闭操作和位置。 - 布局设计 :使用
GridLayout实现 3 行 2 列的布局结构,左侧为标签,右侧为输入框。 - 输入组件 :分别使用
JTextField和JPasswordField接收用户名和密码。 - 按钮与事件绑定 :虽然此处未实现具体事件逻辑,但已经预留了登录与取消按钮。
参数说明:
| 组件 | 功能 |
|---|---|
JFrame |
窗口容器,用于承载整个界面 |
JLabel |
显示静态文本信息 |
JTextField |
输入用户名 |
JPasswordField |
输入密码,内容不可见 |
JButton |
登录和取消操作按钮 |
3.1.2 界面布局优化与美化
在基础界面构建完成后,我们需要进一步优化界面布局与视觉效果。可以通过以下方式提升用户体验:
- 使用
GridBagLayout实现更灵活的布局 - 添加图标和背景图片
- 设置按钮样式与颜色主题
- 添加窗口图标
以下是优化后的代码片段,展示如何使用 GridBagLayout 实现居中布局与背景图片:
import javax.swing.*;
import java.awt.*;
public class EnhancedLoginFrame extends JFrame {
private JTextField usernameField;
private JPasswordField passwordField;
public EnhancedLoginFrame() {
setTitle("图书管理系统 - 登录");
setSize(500, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
// 设置背景图片
JLabel background = new JLabel(new ImageIcon("background.jpg"));
getLayeredPane().add(background, Integer.valueOf(Integer.MIN_VALUE));
((JPanel)getContentPane()).setOpaque(false);
// 主面板
JPanel panel = new JPanel();
panel.setLayout(new GridBagLayout());
panel.setOpaque(false);
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(10, 10, 10, 10);
gbc.anchor = GridBagConstraints.WEST;
// 用户名
gbc.gridx = 0;
gbc.gridy = 0;
panel.add(new JLabel("用户名:"), gbc);
gbc.gridx = 1;
gbc.gridy = 0;
usernameField = new JTextField(20);
panel.add(usernameField, gbc);
// 密码
gbc.gridx = 0;
gbc.gridy = 1;
panel.add(new JLabel("密码:"), gbc);
gbc.gridx = 1;
gbc.gridy = 1;
passwordField = new JPasswordField(20);
panel.add(passwordField, gbc);
// 按钮
JButton loginButton = new JButton("登录");
JButton cancelButton = new JButton("取消");
JPanel buttonPanel = new JPanel();
buttonPanel.setOpaque(false);
buttonPanel.add(loginButton);
buttonPanel.add(cancelButton);
gbc.gridx = 0;
gbc.gridy = 2;
gbc.gridwidth = 2;
panel.add(buttonPanel, gbc);
add(panel);
setVisible(true);
}
public static void main(String[] args) {
new EnhancedLoginFrame();
}
}
优化说明:
-
GridBagLayout:比GridLayout更加灵活,可以实现复杂的布局控制。 - 背景图片 :通过
JLabel加载图片并设置到LayeredPane中,使得背景不影响组件显示。 - 按钮面板 :将按钮单独放入一个面板中,便于集中管理和样式设置。
- 透明背景 :通过设置
setOpaque(false),实现背景透明效果。
优化后界面布局流程图(mermaid):
graph TD
A[EnhancedLoginFrame] --> B[设置窗口属性]
B --> C[添加背景图片到LayeredPane]
C --> D[创建主面板GridBagLayout]
D --> E[添加用户名输入行]
E --> F[添加密码输入行]
F --> G[添加按钮面板]
G --> H[显示窗口]
3.2 用户身份验证逻辑实现
3.2.1 用户输入数据的获取与校验
在用户输入用户名和密码之后,需要对输入数据进行基本校验,防止空值或非法字符。例如:
- 用户名不能为空
- 密码长度必须大于等于6位
- 防止SQL注入攻击(后续章节详述)
以下是简单的数据校验代码:
private boolean validateInput() {
String username = usernameField.getText();
String password = new String(passwordField.getPassword());
if (username.isEmpty()) {
JOptionPane.showMessageDialog(this, "用户名不能为空!", "错误", JOptionPane.ERROR_MESSAGE);
return false;
}
if (password.length() < 6) {
JOptionPane.showMessageDialog(this, "密码长度不能小于6位!", "错误", JOptionPane.ERROR_MESSAGE);
return false;
}
return true;
}
参数说明:
| 字段 | 类型 | 描述 |
|---|---|---|
| username | String | 用户名 |
| password | char[] | 密码数组 |
getText() |
方法 | 获取用户名输入内容 |
getPassword() |
方法 | 获取密码内容(char[]) |
3.2.2 数据库验证与登录状态管理
用户输入通过基本校验后,需要连接数据库进行身份验证。我们可以使用 JDBC 查询数据库中是否存在对应的用户名与密码组合。
import java.sql.*;
public class LoginDAO {
private Connection connection;
public LoginDAO(Connection conn) {
this.connection = conn;
}
public boolean authenticate(String username, String password) {
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, username);
stmt.setString(2, password);
ResultSet rs = stmt.executeQuery();
return rs.next();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
}
SQL 表结构示例(users 表):
| 字段名 | 类型 | 描述 |
|---|---|---|
| id | INT | 主键 |
| username | VARCHAR(50) | 用户名 |
| password | VARCHAR(255) | 密码(建议加密存储) |
| role | VARCHAR(20) | 用户角色(如 admin, user) |
数据库验证流程图(mermaid):
graph TD
A[用户点击登录按钮] --> B[获取用户名与密码]
B --> C[输入校验]
C -- 校验通过 --> D[调用DAO验证数据库]
D --> E[执行SQL查询]
E --> F{查询结果是否匹配?}
F -- 是 --> G[登录成功]
F -- 否 --> H[提示用户名或密码错误]
3.3 用户权限控制机制
3.3.1 权限分类与角色定义
图书管理系统通常包含多种用户角色,如管理员、普通用户等,不同角色拥有不同的权限:
| 角色 | 权限描述 |
|---|---|
| admin | 可添加、编辑、删除图书信息,管理用户 |
| user | 仅可查看图书信息与借阅记录 |
在数据库中,我们可以通过 role 字段来区分用户角色:
ALTER TABLE users ADD COLUMN role VARCHAR(20) DEFAULT 'user';
3.3.2 不同权限用户的界面控制策略
根据用户角色,我们可以动态加载不同的界面。例如:
String role = getUserRole(username);
if ("admin".equals(role)) {
new AdminMainFrame();
} else {
new UserMainFrame();
}
权限控制流程图(mermaid):
graph TD
A[登录成功] --> B[获取用户角色]
B --> C{角色是管理员?}
C -- 是 --> D[跳转到管理员界面]
C -- 否 --> E[跳转到普通用户界面]
示例:根据角色切换界面代码
public void openMainFrame(String role) {
if ("admin".equals(role)) {
dispose(); // 关闭当前登录窗口
new AdminMainFrame().setVisible(true);
} else {
dispose();
new UserMainFrame().setVisible(true);
}
}
3.4 安全性处理与加密存储
3.4.1 用户密码加密存储方法
直接将明文密码存储在数据库中是不安全的。我们应使用哈希算法(如 SHA-256)进行加密:
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class PasswordUtil {
public static String hashPassword(String password) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] hash = md.digest(password.getBytes());
StringBuilder sb = new StringBuilder();
for (byte b : hash) {
sb.append(String.format("%02x", b));
}
return sb.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("密码加密失败", e);
}
}
}
示例:注册时使用加密存储
String hashedPassword = PasswordUtil.hashPassword("123456");
String sql = "INSERT INTO users (username, password, role) VALUES (?, ?, ?)";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, "admin");
stmt.setString(2, hashedPassword);
stmt.setString(3, "admin");
stmt.executeUpdate();
}
3.4.2 防止SQL注入等安全措施
SQL 注入是一种常见的攻击方式,通过预编译语句 PreparedStatement 可以有效防止此类攻击。
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, username);
stmt.setString(2, hashedPassword);
ResultSet rs = stmt.executeQuery();
return rs.next();
}
安全性处理流程图(mermaid):
graph TD
A[用户注册或登录] --> B[密码加密处理]
B --> C[使用PreparedStatement执行SQL]
C --> D[防止SQL注入]
D --> E[安全存储或验证]
本章从登录界面构建、用户验证、权限控制到安全性处理,全面介绍了图书管理系统中登录模块的实现细节。下一章节将深入探讨图书信息的 CRUD 功能实现,进一步完善系统核心功能。
4. 图书信息的CRUD功能实现
图书信息的增删改查(CRUD)是图书管理系统中最核心的功能模块之一。通过本章的学习,开发者将掌握如何基于Java Swing与JDBC实现图书信息的完整管理流程。本章内容将从图书信息添加、查看、编辑、删除到搜索功能进行逐层深入,帮助开发者构建一个功能完备、界面友好、逻辑清晰的图书信息管理模块。
4.1 图书信息添加功能设计
图书信息的添加功能是图书管理系统中第一个需要实现的数据操作功能。该功能不仅涉及界面设计,还包括数据验证、数据库插入等关键操作。
4.1.1 添加界面的布局与控件设置
在Java Swing中,使用 JFrame 作为主窗口容器, JPanel 作为子面板布局管理。图书信息添加界面通常包括以下组件:
JLabel:用于显示字段名称(如书名、作者、ISBN等)。JTextField:用于输入图书信息。JButton:提交按钮,用于触发添加操作。JComboBox:选择框,如图书分类或状态。
import javax.swing.*;
import java.awt.*;
public class BookAddFrame extends JFrame {
private JTextField titleField, authorField, isbnField, publisherField, publishYearField;
private JComboBox<String> categoryBox;
private JButton submitButton;
public BookAddFrame() {
setTitle("添加图书信息");
setSize(500, 400);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLayout(new GridLayout(7, 2));
add(new JLabel("书名:"));
titleField = new JTextField();
add(titleField);
add(new JLabel("作者:"));
authorField = new JTextField();
add(authorField);
add(new JLabel("ISBN:"));
isbnField = new JTextField();
add(isbnField);
add(new JLabel("出版社:"));
publisherField = new JTextField();
add(publisherField);
add(new JLabel("出版年份:"));
publishYearField = new JTextField();
add(publishYearField);
String[] categories = {"文学", "科技", "教育", "历史", "其他"};
categoryBox = new JComboBox<>(categories);
add(new JLabel("分类:"));
add(categoryBox);
submitButton = new JButton("提交");
add(new JLabel());
add(submitButton);
setVisible(true);
}
public static void main(String[] args) {
new BookAddFrame();
}
}
代码逻辑分析:
- 使用
JFrame创建窗口界面,GridLayout用于实现表格状布局。 - 每个字段都由一个
JLabel和一个JTextField组成,布局清晰。 - 使用
JComboBox实现分类选择,增强用户交互体验。 - 提交按钮用于触发后续的数据库插入操作。
4.1.2 数据验证与数据库插入操作
在图书信息提交前,需要对用户输入的数据进行验证,包括非空判断、ISBN格式校验、年份有效性等。
import java.sql.Connection;
import java.sql.PreparedStatement;
public class BookDAO {
public boolean addBook(String title, String author, String isbn, String publisher, int publishYear, String category) {
String sql = "INSERT INTO books (title, author, isbn, publisher, publish_year, category) VALUES (?, ?, ?, ?, ?, ?)";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, title);
pstmt.setString(2, author);
pstmt.setString(3, isbn);
pstmt.setString(4, publisher);
pstmt.setInt(5, publishYear);
pstmt.setString(6, category);
return pstmt.executeUpdate() > 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
代码逻辑分析:
- 使用预编译语句
PreparedStatement防止SQL注入。 DBUtil.getConnection()封装数据库连接逻辑。- 插入成功返回
true,否则返回false并打印异常堆栈信息。 - 数据验证逻辑应放在前端与后端双重处理,避免无效数据进入数据库。
4.2 图书信息查看与表格展示
图书信息的展示是用户操作的核心视图,通过 JTable 组件可以实现数据的表格化展示。
4.2.1 使用JTable组件绑定数据库数据
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.sql.*;
public class BookViewPanel extends JPanel {
private JTable table;
private DefaultTableModel model;
public BookViewPanel() {
setLayout(new BorderLayout());
String[] columns = {"书名", "作者", "ISBN", "出版社", "出版年份", "分类"};
model = new DefaultTableModel(columns, 0);
table = new JTable(model);
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
loadBooks();
}
private void loadBooks() {
String sql = "SELECT * FROM books";
try (Connection conn = DBUtil.getConnection();
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(sql)) {
while (rs.next()) {
Object[] row = {
rs.getString("title"),
rs.getString("author"),
rs.getString("isbn"),
rs.getString("publisher"),
rs.getInt("publish_year"),
rs.getString("category")
};
model.addRow(row);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JFrame frame = new JFrame("图书信息查看");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(800, 600);
frame.add(new BookViewPanel());
frame.setVisible(true);
}
}
代码逻辑分析:
- 使用
DefaultTableModel构建表格模型,支持动态添加行。 - 查询数据库并逐条读取记录,填充到表格中。
- 使用
JScrollPane包裹表格,实现滚动查看功能。 - 采用
ResultSet逐行读取数据,并转换为Object[]添加到表格模型中。
4.2.2 数据的动态刷新与分页显示
为了提高性能,尤其是数据量较大时,需实现分页显示。下面展示一个简单的分页机制:
private int currentPage = 1;
private int pageSize = 10;
private void loadBooks(int page) {
int offset = (page - 1) * pageSize;
String sql = "SELECT * FROM books LIMIT ? OFFSET ?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, pageSize);
pstmt.setInt(2, offset);
ResultSet rs = pstmt.executeQuery();
model.setRowCount(0); // 清空表格
while (rs.next()) {
Object[] row = {
rs.getString("title"),
rs.getString("author"),
rs.getString("isbn"),
rs.getString("publisher"),
rs.getInt("publish_year"),
rs.getString("category")
};
model.addRow(row);
}
} catch (Exception e) {
e.printStackTrace();
}
}
参数说明:
LIMIT ?:限制每页显示的记录数。OFFSET ?:偏移量,表示从第几条记录开始读取。- 分页功能提升系统响应速度,避免一次性加载大量数据。
4.3 图书信息的编辑与更新
图书信息的编辑功能涉及界面构建、数据回显、以及数据库更新操作。
4.3.1 编辑界面的构建与数据回显
public class BookEditFrame extends JFrame {
private JTextField titleField, authorField, isbnField, publisherField, publishYearField;
private JComboBox<String> categoryBox;
private JButton updateButton;
private int bookId;
public BookEditFrame(int id, String title, String author, String isbn, String publisher, int publishYear, String category) {
bookId = id;
setTitle("编辑图书信息");
setSize(500, 400);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
setLayout(new GridLayout(7, 2));
// 各字段初始化
titleField = new JTextField(title);
authorField = new JTextField(author);
isbnField = new JTextField(isbn);
publisherField = new JTextField(publisher);
publishYearField = new JTextField(String.valueOf(publishYear));
String[] categories = {"文学", "科技", "教育", "历史", "其他"};
categoryBox = new JComboBox<>(categories);
categoryBox.setSelectedItem(category);
// 添加组件
add(new JLabel("书名:")); add(titleField);
add(new JLabel("作者:")); add(authorField);
add(new JLabel("ISBN:")); add(isbnField);
add(new JLabel("出版社:")); add(publisherField);
add(new JLabel("出版年份:")); add(publishYearField);
add(new JLabel("分类:")); add(categoryBox);
add(new JLabel()); add(updateButton = new JButton("更新"));
setVisible(true);
}
}
代码说明:
- 构造函数中传入图书原始信息,实现数据回显。
- 使用
JComboBox.setSelectedItem()设置默认分类。 - 更新按钮绑定数据库更新操作。
4.3.2 更新操作的事务处理
public boolean updateBook(int id, String title, String author, String isbn, String publisher, int publishYear, String category) {
String sql = "UPDATE books SET title=?, author=?, isbn=?, publisher=?, publish_year=?, category=? WHERE id=?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setString(1, title);
pstmt.setString(2, author);
pstmt.setString(3, isbn);
pstmt.setString(4, publisher);
pstmt.setInt(5, publishYear);
pstmt.setString(6, category);
pstmt.setInt(7, id);
return pstmt.executeUpdate() > 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
逻辑说明:
- 使用
UPDATE语句更新指定ID的图书信息。 - 所有字段均支持更新。
- 事务控制可通过
conn.setAutoCommit(false)手动提交,确保一致性。
4.4 图书信息的删除与数据一致性
删除操作需谨慎处理,确保数据完整性。
4.4.1 删除操作的确认与实现
public boolean deleteBook(int id) {
String sql = "DELETE FROM books WHERE id=?";
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
pstmt.setInt(1, id);
return pstmt.executeUpdate() > 0;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
逻辑说明:
- 使用预编译语句防止SQL注入。
- 删除操作需通过用户确认,防止误操作。
4.4.2 数据完整性与外键约束处理
在数据库设计时,若图书信息与其他表存在关联(如借阅记录),则应设置外键约束。
ALTER TABLE borrow_records
ADD CONSTRAINT fk_book_id
FOREIGN KEY (book_id) REFERENCES books(id)
ON DELETE CASCADE;
说明:
ON DELETE CASCADE:当图书被删除时,自动删除关联的借阅记录。- 保证数据库一致性,防止孤儿记录。
4.5 图书搜索功能实现
图书搜索功能提升用户查找效率,通常支持多条件组合查询。
4.5.1 多条件组合查询的设计
public void searchBooks(String title, String author, String category) {
StringBuilder sql = new StringBuilder("SELECT * FROM books WHERE 1=1");
if (title != null && !title.isEmpty()) {
sql.append(" AND title LIKE ?");
}
if (author != null && !author.isEmpty()) {
sql.append(" AND author LIKE ?");
}
if (category != null && !category.isEmpty()) {
sql.append(" AND category = ?");
}
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql.toString())) {
int paramIndex = 1;
if (title != null && !title.isEmpty()) {
pstmt.setString(paramIndex++, "%" + title + "%");
}
if (author != null && !author.isEmpty()) {
pstmt.setString(paramIndex++, "%" + author + "%");
}
if (category != null && !category.isEmpty()) {
pstmt.setString(paramIndex++, category);
}
ResultSet rs = pstmt.executeQuery();
model.setRowCount(0);
while (rs.next()) {
Object[] row = {
rs.getString("title"),
rs.getString("author"),
rs.getString("isbn"),
rs.getString("publisher"),
rs.getInt("publish_year"),
rs.getString("category")
};
model.addRow(row);
}
} catch (Exception e) {
e.printStackTrace();
}
}
参数说明:
- 动态拼接SQL语句,避免硬编码。
- 使用
LIKE实现模糊查询,提升用户体验。 - 支持多条件组合查询,增强搜索灵活性。
4.5.2 查询结果的高亮与展示优化
为了增强用户搜索体验,可对匹配字段进行高亮显示。例如,在表格中使用自定义的 TableCellRenderer 实现高亮效果。
class HighlightCellRenderer extends DefaultTableCellRenderer {
private String keyword;
public HighlightCellRenderer(String keyword) {
this.keyword = keyword;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (value != null && value.toString().contains(keyword)) {
c.setBackground(Color.YELLOW);
} else {
c.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
}
return c;
}
}
使用方式:
table.getColumnModel().getColumn(0).setCellRenderer(new HighlightCellRenderer("Java"));
说明:
- 自定义渲染器实现字段高亮。
- 提升用户识别匹配内容的效率。
本章通过图书信息的增删改查完整流程,构建了图书管理系统中最核心的数据管理模块。下一章将深入讲解Java桌面应用的结构设计与部署方式,帮助开发者将整个系统封装为可执行的独立应用程序。
5. Java桌面应用的结构设计与部署
在完成图书管理系统的功能开发之后,合理的结构设计和规范的部署流程是确保项目可维护性、可扩展性和可交付性的关键。本章将围绕Java桌面应用的模块化设计、打包发布、部署配置及后期维护策略展开深入探讨,帮助开发者构建一个结构清晰、部署便捷、易于维护的企业级Java桌面应用。
5.1 项目结构的模块化设计
良好的项目结构是软件开发中不可或缺的一环。通过模块化设计,可以提高代码的可读性、可维护性和团队协作效率。
5.1.1 MVC架构在Swing项目中的应用
MVC(Model-View-Controller)架构是一种广泛应用于GUI开发的设计模式,能够有效解耦界面展示、数据处理和业务逻辑。
- Model(模型) :负责数据存储与操作,例如图书信息的数据库访问类。
- View(视图) :负责用户界面的展示,如Swing中的JFrame、JPanel等组件。
- Controller(控制器) :负责处理用户输入,协调Model与View之间的交互。
示例代码:图书信息编辑界面的MVC结构
// Model
public class Book {
private int id;
private String title;
private String author;
// Getter and Setter
}
// DAO
public class BookDAO {
public Book getBookById(int id) {
// 从数据库获取图书信息
return new Book();
}
}
// View
public class BookEditView extends JFrame {
private JTextField titleField;
private JTextField authorField;
public BookEditView() {
// 初始化界面组件
}
public void setBook(Book book) {
titleField.setText(book.getTitle());
authorField.setText(book.getAuthor());
}
public Book getBook() {
Book book = new Book();
book.setTitle(titleField.getText());
book.setAuthor(authorField.getText());
return book;
}
}
// Controller
public class BookEditController {
private BookEditView view;
private BookDAO bookDAO;
public BookEditController(BookEditView view) {
this.view = view;
this.bookDAO = new BookDAO();
view.addSaveButtonAction(this::saveBook);
}
private void saveBook(ActionEvent e) {
Book book = view.getBook();
// 调用DAO进行更新
}
}
5.1.2 各模块之间的通信与协调
模块之间通过接口或事件监听机制进行通信。例如,Controller通过ActionListener响应View的事件,并调用Model进行数据处理。
- 接口回调 :用于模块间数据传递。
- 事件驱动 :Swing事件机制实现View与Controller的交互。
- 观察者模式 :适用于数据变更后自动刷新UI的场景。
5.2 应用程序的打包与发布
完成开发后,应用程序需要被打包成可执行文件,以便于部署和使用。
5.2.1 使用JAR包打包项目
Java Archive(JAR)文件是一种标准的打包格式,可以将多个类文件、资源文件和元数据打包在一起。
使用Maven打包示例:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.1</version>
<configuration>
<archive>
<manifest>
<mainClass>com.example.Main</mainClass> <!-- 指定主类 -->
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
执行命令:
mvn clean package
生成的JAR文件位于 target/ 目录下。
5.2.2 可执行文件的生成与配置
为了方便非技术人员使用,可以将JAR文件封装为可执行文件(如 .exe 或 .dmg )。
使用Launch4j生成Windows可执行文件:
- 下载并配置 Launch4j
- 创建配置文件
launch4j.xml:
<launch4jConfig>
<dontWrapJar>false</dontWrapJar>
<headerType>gui</headerType>
<jar>target/library_system.jar</jar>
<outfile>dist/LibrarySystem.exe</outfile>
<errTitle></errTitle>
<cmdLine></cmdLine>
<chdir>.</chdir>
<priority>normal</priority>
<downloadUrl>http://java.com/download</downloadUrl>
<supportUrl></supportUrl>
<stayAlive>false</stayAlive>
<restartOnCrash>false</restartOnCrash>
<icon>icon.ico</icon>
</launch4jConfig>
- 执行命令:
launch4j launch4j.xml
生成 LibrarySystem.exe 可执行文件。
5.3 系统部署与运行环境配置
部署是将应用程序交付给用户使用的过程,涉及Java环境配置和数据库服务的安装。
5.3.1 Java运行环境的安装与版本要求
图书管理系统需要Java运行时环境(JRE)或Java开发工具包(JDK)的支持。
推荐配置:
- Java版本:JDK 8 或更高版本(建议使用JDK 17)
- 安装路径建议统一,如
C:\Program Files\Java\jdk-17
验证安装:
java -version
输出应包含:
openjdk version "17.0.7" 2023-04-18
5.3.2 数据库服务的配置与启动
图书管理系统依赖MySQL或PostgreSQL等数据库服务。
MySQL配置步骤:
- 安装MySQL Server(建议使用MySQL 8.0)
- 创建数据库和用户:
CREATE DATABASE library;
CREATE USER 'libadmin'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON library.* TO 'libadmin'@'localhost';
FLUSH PRIVILEGES;
- 导入SQL脚本:
mysql -u root -p library < library.sql
- 配置JDBC连接字符串:
jdbc.url=jdbc:mysql://localhost:3306/library?useSSL=false&serverTimezone=UTC
jdbc.username=libadmin
jdbc.password=password
5.4 系统维护与升级策略
部署完成后,系统进入维护阶段,需建立日志记录、错误追踪和版本更新机制。
5.4.1 日志记录与错误追踪
日志记录是维护的重要工具,Java中常用日志框架包括Log4j、SLF4J和Java Util Logging。
Log4j2配置示例:
<Loggers>
<Root level="INFO">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
</Loggers>
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<File name="File" fileName="logs/app.log">
<PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
</File>
</Appenders>
日志使用示例:
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class BookService {
private static final Logger logger = LogManager.getLogger(BookService.class);
public void addBook(Book book) {
try {
// 添加图书逻辑
} catch (Exception e) {
logger.error("添加图书失败:", e);
}
}
}
5.4.2 版本更新与用户反馈处理
版本管理应采用语义化版本号(如 v1.2.3 ),并记录更新日志。
更新流程:
- 版本号更新(如从
v1.0.0升级到v1.1.0) - 打包新版本JAR文件
- 发布更新说明文档
- 提供用户反馈收集渠道(如邮件、反馈表单)
反馈处理流程图:
graph TD
A[用户反馈] --> B(问题分类)
B --> C{是否为Bug?}
C -->|是| D[提交Issue]
C -->|否| E[功能建议]
D --> F[开发修复]
E --> G[需求评审]
F --> H[版本更新]
G --> H
简介:Java Swing图书管理系统是一款基于Java GUI框架Swing与SQL数据库构建的桌面应用,涵盖登录、图书添加、查看及数据库交互等功能。系统采用JDBC连接数据库,实现图书信息的增删改查操作,并通过Swing组件构建用户界面。该项目适合Java初学者掌握GUI编程与数据库连接的实际开发流程,提升Java桌面应用开发能力。
更多推荐


所有评论(0)