Merge pull request '图书管理系统' (#1) from chr into main

main
mc2zuomsq 2 weeks ago
commit 0bb163056f

@ -1,2 +1,3 @@
# LMS
图书管理系统

@ -0,0 +1,29 @@
### IntelliJ IDEA ###
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

@ -0,0 +1,3 @@
# 默认忽略的文件
/shelf/
/workspace.xml

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="liberica-11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/SoftwareTest1.iml" filepath="$PROJECT_DIR$/SoftwareTest1.iml" />
</modules>
</component>
</project>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>

@ -0,0 +1,3 @@
{
"CurrentProjectSetting": null
}

@ -0,0 +1,8 @@
{
"ExpandedNodes": [
"",
"\\src"
],
"SelectedNode": "\\SoftwareTest1.iml",
"PreviewInSolutionExplorer": false
}

Binary file not shown.

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

@ -0,0 +1,32 @@
id|title|author|publisher|publicationYear|category|available|borrowDate|dueDate
B202508301601754|大侦探赵港|赵港|504出版社|2025|侦探推理|true||
B202508301603090|王瑜的幸福生活|王瑜|504出版社|2025|玄幻|true||
B202508301604039|我和我上下左右铺的兄弟|程昊冉|504出版社|2025|文艺小说|false|2025-08-31|2025-09-14
B202508301604767|504探秘|王华建|504出版社|2025|纪实|true||
B202508301606894|人性的弱点|戴尔卡内基|中信出版社|2017|社会学名著|true||
B202508301607206|水浒传|施耐庵|岳麓书社|2017|文学名著|true||
B202508301607816|三国演义|罗贯中|岳麓书社|2017|文学名著|true||
B202508301608580|红楼梦|曹雪芹|岳麓书社|2017|文学名著|true||
B202508301609333|西游记|吴承恩|岳麓书社|2017|文学名著|true||
B202508301611036|和乌鸦做邻居|沈石溪|浙江少年儿童出版社|2017|小说|true||
B202508301611430|象母怨|沈石溪|浙江少年儿童出版社|2012|小说|true||
B202508301612567|鸟奴|沈石溪|浙江少年儿童出版社|2010|小说|true||
B202508301613732|红瓦黑瓦-|曹文轩|江苏少年儿童出版社|2013|小说|true||
B202508301613410|青铜葵花|曹文轩|江苏少年儿童出版社|2013|小说|true||
B202508301614911|山羊不吃天堂草|曹文轩|江苏少年儿童出版社|2015|小说|true||
B202508301614130|伊索寓言|伊索|北方妇女儿童出版社|2009|世界名著|true||
B202508301616073|绿野仙踪|鲍姆|吉林出版集团|2010|世界名著|true||
B202508301616578|简爱|夏洛蒂勃朗特|吉林出版集团|2010|世界名著|true||
B202508301617919|在人间|高尔基|吉林出版集团|2010|世界名著|true||
B202508301618131|了不起的盖茨比|菲茨杰拉德|北方文艺出版社|2015|世界名著|true||
B202508301618894|Java程序设计|耿祥义|清华大学出版社|2022|教科书|true||
B202508301619332|格列佛游记|乔纳森斯威夫特|中译出版社|2018|世界名著|true||
B202508301620575|麦田里的守望者|JD塞林格|译林出版社|2015|世界名著|true||
B202508301622821|格林童话全集|格林兄弟|译林出版社|2015|哲理童话|true||
B202508301623632|小王子|圣埃克苏佩里|译林出版社|2014|哲理童话|true||
B202508301624883|苏菲的世界|乔斯坦贾德|作家出版社|2010|世界名著|true||
B202508301625212|三体|刘慈欣|重庆出版社|2017|科幻小说|true||
B202508301625496|三体2|刘慈欣|重庆出版社|2017|科幻小说|true||
B202508301626099|红岩|罗广斌、杨益言|中国青年出版社|2015|文学名著|true||
B202508301627605|人生|路遥|北京十月文艺出版社|2012|文艺小说|true||
B202508301628269|平凡的世界|路遥|北京十月文艺出版社|2016|文艺小说|true||

@ -0,0 +1,3 @@
id|userId|bookId|borrowDate|dueDate|returnDate
R202508301552773|U202508301102521|B202508301551475|2025-08-30|2025-09-13|2025-08-30
R202508311438050|U202508311436068|B202508301604039|2025-08-31|2025-09-14|null

@ -0,0 +1,74 @@
//图书实体类
public class Book {
private String id; // 图书ID
private String title; // 标题
private String author; // 作者
private String publisher; // 出版社
private int publicationYear; // 出版年份
private String category; // 类别
private boolean isAvailable; // 是否可借阅
private String borrowDate; // 借阅日期(临时存储,用于显示)
private String dueDate; // 应还日期(临时存储,用于显示)
//构造方法
public Book(String id, String title, String author, String publisher,
int publicationYear, String category, boolean isAvailable) {
this.id = id;
this.title = title;
this.author = author;
this.publisher = publisher;
this.publicationYear = publicationYear;
this.category = category;
this.isAvailable = isAvailable;
this.borrowDate = "";
this.dueDate = "";
}
public String getId() {
return id;
}
public String getTitle() {
return title;
}
public String getAuthor() {
return author;
}
public String getPublisher() {
return publisher;
}
public int getPublicationYear() {
return publicationYear;
}
public String getCategory() {
return category;
}
public boolean isAvailable() {
return isAvailable;
}
public void setAvailable(boolean available) {
isAvailable = available;
}
public String getBorrowDate() {
return borrowDate;
}
public void setBorrowDate(String borrowDate) {
this.borrowDate = borrowDate;
}
public String getDueDate() {
return dueDate;
}
public void setDueDate(String dueDate) {
this.dueDate = dueDate;
}
}

@ -0,0 +1,48 @@
//借阅记录类
public class BorrowRecord {
private String id; // 记录唯一ID
private String userId; // 借阅用户ID
private String bookId; // 所借图书ID
private String borrowDate; // 借阅日期
private String dueDate; // 应还日期
private String returnDate; // 实际归还日期null表示未归还
//构造方法
public BorrowRecord(String id, String userId, String bookId,
String borrowDate, String dueDate, String returnDate) {
this.id = id;
this.userId = userId;
this.bookId = bookId;
this.borrowDate = borrowDate;
this.dueDate = dueDate;
this.returnDate = returnDate;
}
public String getId() {
return id;
}
public String getUserId() {
return userId;
}
public String getBookId() {
return bookId;
}
public String getBorrowDate() {
return borrowDate;
}
public String getDueDate() {
return dueDate;
}
public String getReturnDate() {
return returnDate;
}
public void setReturnDate(String returnDate) {
this.returnDate = returnDate;
}
}

@ -0,0 +1,446 @@
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
//图书馆类,管理用户、图书和借阅记录(负责数据的加载、保存和业务逻辑处理)
public class Library {
private List<User> users; // 存储所有用户
private List<Book> books; // 存储所有图书
private List<BorrowRecord> borrowRecords; // 存储所有借阅记录
// 数据文件路径
private static final String USERS_FILE = "users.txt";
private static final String BOOKS_FILE = "books.txt";
private static final String BORROW_RECORDS_FILE = "borrow_records.txt";
//初始化数据集合并加载文件数据
public Library() {
users = new ArrayList<>();
books = new ArrayList<>();
borrowRecords = new ArrayList<>();
// 加载已保存的数据,如果文件不存在则初始化默认数据
loadAllData();
}
//ID生成
private String generateId(String prefix) {
// 1. 获取当前日期时间格式化为年月日时分例如202310251530
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
String dateTime = sdf.format(new Date());
// 2. 生成0-999之间的随机数确保同一分钟内不会生成重复ID
int random = new Random().nextInt(1000);
// 3. 拼接前缀、日期时间和随机数随机数补3位不足补0
return String.format("%s%s%03d", prefix, dateTime, random);
}
// 用户登录
public User login(String username, String password) {
for (User user : users) {
if (user.getUsername().equals(username) && user.getPassword().equals(password)) {
return user;
}
}
return null;
}
//用户注册
public boolean registerUser(String username, String password, String email, String phone) {
// 检查用户名是否已存在
for (User user : users) {
if (user.getUsername().equals(username)) {
return false;
}
}
// 生成用户IDUUser + 年月日时分 + 随机数)
String userId = generateId("U");
User newUser = new User(userId, username, password, email, phone, false);
users.add(newUser);
// 保存用户数据到文件
saveUsersData();
return true;
}
//添加书籍
public void addBook(String title, String author, String publisher,
int publicationYear, String category) {
// 生成书籍IDBBook + 年月日时分 + 随机数)
String bookId = generateId("B");
Book newBook = new Book(bookId, title, author, publisher, publicationYear, category, true);
newBook.setBorrowDate("");
newBook.setDueDate("");
books.add(newBook);
// 保存书籍数据到文件
saveBooksData();
}
//借阅图书
public boolean borrowBook(String userId, String bookId) {
// 查找图书
Book book = findBookById(bookId);
if (book == null || !book.isAvailable()) {
return false; // 图书不存在或已被借出
}
// 生成借阅记录IDR Record+ 年月日时分 + 随机数)
String recordId = generateId("R");
// 计算借阅日期当前日期和应还日期14天后
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String borrowDate = sdf.format(new Date());
// 计算14天后的日期作为应还日期
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_MONTH, 14);
String dueDate = sdf.format(calendar.getTime());
// 创建借阅记录
BorrowRecord record = new BorrowRecord(recordId, userId, bookId, borrowDate, dueDate, null);
borrowRecords.add(record);
// 更新图书状态
book.setAvailable(false);
book.setBorrowDate(borrowDate);
book.setDueDate(dueDate);
// 保存所有相关数据
saveBooksData();
saveBorrowRecordsData();
return true;
}
//归还图书
public boolean returnBook(String bookId) {
// 查找图书
Book book = findBookById(bookId);
if (book == null || book.isAvailable()) {
return false; // 图书不存在或未被借出
}
// 查找对应的借阅记录并更新归还日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String returnDate = sdf.format(new Date());
for (BorrowRecord record : borrowRecords) {
if (record.getBookId().equals(bookId) && record.getReturnDate() == null) {
record.setReturnDate(returnDate);
break;
}
}
// 更新图书状态
book.setAvailable(true);
book.setBorrowDate("");
book.setDueDate("");
// 保存所有相关数据
saveBooksData();
saveBorrowRecordsData();
return true;
}
//搜索图书
public List<Book> searchBooks(String keyword) {
List<Book> results = new ArrayList<>();
String lowerKeyword = keyword.toLowerCase();
for (Book book : books) {
if (book.getTitle().toLowerCase().contains(lowerKeyword) ||
book.getAuthor().toLowerCase().contains(lowerKeyword) ||
book.getCategory().toLowerCase().contains(lowerKeyword)) {
results.add(book);
}
}
return results;
}
//检查逾期图书
public List<Book> checkOverdueBooks(String userId) {
List<Book> overdueBooks = new ArrayList<>();
Date today = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
for (BorrowRecord record : borrowRecords) {
// 查找未归还且属于该用户的借阅记录
if (record.getUserId().equals(userId) && record.getReturnDate() == null) {
Date dueDate = sdf.parse(record.getDueDate());
// 检查是否逾期
if (dueDate.before(today)) {
Book book = findBookById(record.getBookId());
if (book != null) {
overdueBooks.add(book);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return overdueBooks;
}
//查找图书
private Book findBookById(String bookId) {
for (Book book : books) {
if (book.getId().equals(bookId)) {
return book;
}
}
return null;
}
//获取用户借阅的图书列表
public List<Book> getUserBorrowedBooks(String userId) {
List<Book> borrowedBooks = new ArrayList<>();
for (BorrowRecord record : borrowRecords) {
if (record.getUserId().equals(userId) && record.getReturnDate() == null) {
Book book = findBookById(record.getBookId());
if (book != null) {
borrowedBooks.add(book);
}
}
}
return borrowedBooks;
}
//加载所有数据(用户、图书、借阅记录)
private void loadAllData() {
loadUsersData();
loadBooksData();
loadBorrowRecordsData();
//创建一个默认管理员
if (!hasAdminUser()) {
String adminId = generateId("U");
users.add(new User(adminId, "admin", "admin123", "admin.com", "123456789", true));
saveUsersData();
}
}
private boolean hasAdminUser() {
for (User user : users) {
if (user.isAdmin()) {
return true;
}
}
return false;
}
//加载用户数据
private void loadUsersData() {
File file = new File(USERS_FILE);
if (!file.exists()) {
return; // 文件不存在则不加载
}
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
// 跳过表头行
br.readLine();
while ((line = br.readLine()) != null) {
// 按分隔符分割字段格式id|username|password|email|phone|isAdmin
String[] parts = line.split("\\|");
if (parts.length == 6) {
User user = new User(
parts[0], // id
parts[1], // username
parts[2], // password
parts[3], // email
parts[4], // phone
Boolean.parseBoolean(parts[5]) // isAdmin
);
users.add(user);
}
}
} catch (IOException e) {
System.err.println("加载用户数据失败: " + e.getMessage());
}
}
//加载图书数据
private void loadBooksData() {
File file = new File(BOOKS_FILE);
if (!file.exists()) return;
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
br.readLine(); // 跳过表头
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.isEmpty()) continue;
// 关键使用split("\\|", -1)保留空字段(避免忽略末尾的空值)
String[] parts = line.split("\\|", -1);
// 验证字段数量必须为9个包括空字段
if (parts.length != 9) {
System.err.println("跳过无效行(字段数不对):" + line);
continue;
}
try {
// 解析核心字段前7个
Book book = new Book(
parts[0],
parts[1].replace("||", "|"), // 还原特殊字符
parts[2].replace("||", "|"),
parts[3].replace("||", "|"),
Integer.parseInt(parts[4].trim()), // 处理可能的空格
parts[5],
Boolean.parseBoolean(parts[6].trim())
);
// 处理空借阅日期(允许为空字符串)
book.setBorrowDate(parts[7]);
book.setDueDate(parts[8]);
books.add(book); // 添加到内存集合
} catch (NumberFormatException e) {
System.err.println("年份解析失败(行:" + line + "" + e.getMessage());
} catch (Exception e) {
System.err.println("解析图书失败(行:" + line + "" + e.getMessage());
}
}
} catch (IOException e) {
System.err.println("加载图书失败:" + e.getMessage());
}
}
//加载借阅记录数据
private void loadBorrowRecordsData() {
File file = new File(BORROW_RECORDS_FILE);
if (!file.exists()) {
return; // 文件不存在则不加载
}
try (BufferedReader br = new BufferedReader(new FileReader(file))) {
String line;
// 跳过表头行
br.readLine();
while ((line = br.readLine()) != null) {
// 按分隔符分割字段格式id|userId|bookId|borrowDate|dueDate|returnDate
String[] parts = line.split("\\|");
if (parts.length == 6) {
BorrowRecord record = new BorrowRecord(
parts[0], // id
parts[1], // userId
parts[2], // bookId
parts[3], // borrowDate
parts[4], // dueDate
parts[5].equals("null") ? null : parts[5] // returnDate
);
borrowRecords.add(record);
}
}
} catch (IOException e) {
System.err.println("加载借阅记录失败: " + e.getMessage());
}
}
//保存用户数据到文件
public void saveUsersData() {
try (FileWriter fw = new FileWriter(USERS_FILE)) {
// 写入表头
fw.write("id|username|password|email|phone|isAdmin\n");
// 写入用户数据
for (User user : users) {
String line = String.format("%s|%s|%s|%s|%s|%s\n",
user.getId(),
user.getUsername(),
user.getPassword(),
user.getEmail(),
user.getPhone(),
user.isAdmin()
);
fw.write(line);
}
} catch (IOException e) {
System.err.println("保存用户数据失败: " + e.getMessage());
}
}
//保存图书数据到文件
public void saveBooksData() {
File file = new File(BOOKS_FILE);
try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
bw.write("id|title|author|publisher|publicationYear|category|available|borrowDate|dueDate\n");
for (Book book : books) {
// 处理空字段:确保空值被保存为""而非null
String borrowDate = book.getBorrowDate() == null ? "" : book.getBorrowDate();
String dueDate = book.getDueDate() == null ? "" : book.getDueDate();
// 拼接字段时保留空字符串位置(关键:即使为空也保留|之间的位置)
String line = String.format(
"%s|%s|%s|%s|%d|%s|%s|%s|%s\n",
book.getId(),
book.getTitle().replace("|", "||"),
book.getAuthor().replace("|", "||"),
book.getPublisher().replace("|", "||"),
book.getPublicationYear(),
book.getCategory(),
book.isAvailable(),
borrowDate, // 允许空字符串
dueDate // 允许空字符串
);
bw.write(line);
}
bw.flush();
} catch (IOException e) {
System.err.println("保存图书失败:" + e.getMessage());
}
}
//保存借阅记录到文件使用FileWriter字符流
public void saveBorrowRecordsData() {
try (FileWriter fw = new FileWriter(BORROW_RECORDS_FILE)) {
// 写入表头
fw.write("id|userId|bookId|borrowDate|dueDate|returnDate\n");
// 写入借阅记录
for (BorrowRecord record : borrowRecords) {
String returnDate = record.getReturnDate() == null ? "null" : record.getReturnDate();
String line = String.format("%s|%s|%s|%s|%s|%s\n",
record.getId(),
record.getUserId(),
record.getBookId(),
record.getBorrowDate(),
record.getDueDate(),
returnDate
);
fw.write(line);
}
} catch (IOException e) {
System.err.println("保存借阅记录失败: " + e.getMessage());
}
}
//保存所有数据
public void saveAllData() {
saveUsersData();
saveBooksData();
saveBorrowRecordsData();
}
// getter方法
public List<User> getAllUsers() {
return new ArrayList<>(users);
}
public List<Book> getAllBooks() {
return new ArrayList<>(books);
}
}

@ -0,0 +1,706 @@
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.*;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Date;
//系统主界面
public class LibrarySystemGUI extends JFrame {
// 核心业务逻辑对象,处理图书、用户和借阅相关操作
private Library library;
// 当前登录用户
private User currentUser;
// 主面板使用CardLayout实现面板切换登录/注册/用户/管理员界面)
private JPanel mainPanel;
// 登录面板及组件
private JPanel loginPanel;
private JTextField usernameField; // 用户名输入框
private JPasswordField passwordField; // 密码输入框
// 注册面板及组件
private JPanel registerPanel;
private JTextField regUsernameField; // 注册用户名输入框
private JPasswordField regPasswordField;// 注册密码输入框
private JTextField regEmailField; // 注册邮箱输入框
private JTextField regPhoneField; // 注册电话输入框
// 用户主面板及组件
private JPanel userPanel;
private JTextField searchField; // 图书搜索框
private JTable booksTable; // 图书列表表格
private DefaultTableModel booksTableModel; // 图书表格数据模型
private JTable borrowedBooksTable; // 已借图书表格
private DefaultTableModel borrowedBooksTableModel; // 已借图书表格数据模型
// 管理员面板及组件
private JPanel adminPanel;
private JTable allBooksTable; // 所有图书表格(管理员用)
private DefaultTableModel allBooksTableModel; // 所有图书表格数据模型
private JTable usersTable; // 用户列表表格(管理员用)
private DefaultTableModel usersTableModel; // 用户表格数据模型
// 添加图书的输入框
private JTextField addBookTitleField;
private JTextField addBookAuthorField;
private JTextField addBookPublisherField;
private JTextField addBookYearField;
private JTextField addBookCategoryField;
//初始化界面并加载数据
public LibrarySystemGUI() {
super("在线图书管理系统"); // 设置窗口标题
setSize(900, 600); // 设置窗口大小
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口时退出程序
setLocationRelativeTo(null); // 窗口居中显示
// 初始化图书馆业务对象(会自动加载文件中的数据)
library = new Library();
// 初始化所有界面组件
initComponents();
// 默认显示登录面板
showLoginPanel();
// 窗口关闭时保存所有数据到文件
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
library.saveAllData();
}
});
}
//初始化所有界面组件
private void initComponents() {
mainPanel = new JPanel(new CardLayout());
// 初始化各功能面板
initLoginPanel();
initRegisterPanel();
initUserPanel();
initAdminPanel();
// 将所有面板添加到主面板(用于切换显示)
mainPanel.add(loginPanel, "login");
mainPanel.add(registerPanel, "register");
mainPanel.add(userPanel, "user");
mainPanel.add(adminPanel, "admin");
// 将主面板添加到窗口
add(mainPanel);
}
//登陆面板
private void initLoginPanel() {
loginPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5); // 组件间距
gbc.anchor = GridBagConstraints.WEST; // 组件左对齐
// 标题
JLabel titleLabel = new JLabel("在线图书管理系统");
titleLabel.setFont(new Font("宋体", Font.BOLD, 24));
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 2; // 跨两列
gbc.anchor = GridBagConstraints.CENTER; // 居中对齐
loginPanel.add(titleLabel, gbc);
// 重置约束
gbc.anchor = GridBagConstraints.WEST;
gbc.gridwidth = 1;
gbc.gridy++;
// 用户名输入区
JLabel usernameLabel = new JLabel("用户名:");
loginPanel.add(usernameLabel, gbc);
gbc.gridx = 1;
usernameField = new JTextField(20);
loginPanel.add(usernameField, gbc);
// 密码输入区
gbc.gridx = 0;
gbc.gridy++;
JLabel passwordLabel = new JLabel("密码:");
loginPanel.add(passwordLabel, gbc);
gbc.gridx = 1;
passwordField = new JPasswordField(20);
loginPanel.add(passwordField, gbc);
// 按钮区
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.CENTER;
JPanel buttonPanel = new JPanel();
JButton loginButton = new JButton("登录");
loginButton.addActionListener(e -> handleLogin()); // 绑定登录事件
buttonPanel.add(loginButton);
JButton registerButton = new JButton("注册");
registerButton.addActionListener(e -> showRegisterPanel()); // 绑定注册面板显示事件
buttonPanel.add(registerButton);
loginPanel.add(buttonPanel, gbc);
}
//注册面板
private void initRegisterPanel() {
registerPanel = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5, 5, 5, 5);
gbc.anchor = GridBagConstraints.WEST;
// 标题
JLabel titleLabel = new JLabel("用户注册");
titleLabel.setFont(new Font("宋体", Font.BOLD, 18));
gbc.gridx = 0;
gbc.gridy = 0;
gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.CENTER;
registerPanel.add(titleLabel, gbc);
// 重置约束
gbc.anchor = GridBagConstraints.WEST;
gbc.gridwidth = 1;
gbc.gridy++;
// 用户名输入
JLabel usernameLabel = new JLabel("用户名:");
registerPanel.add(usernameLabel, gbc);
gbc.gridx = 1;
regUsernameField = new JTextField(20);
registerPanel.add(regUsernameField, gbc);
// 密码输入
gbc.gridx = 0;
gbc.gridy++;
JLabel passwordLabel = new JLabel("密码:");
registerPanel.add(passwordLabel, gbc);
gbc.gridx = 1;
regPasswordField = new JPasswordField(20);
registerPanel.add(regPasswordField, gbc);
// 邮箱输入
gbc.gridx = 0;
gbc.gridy++;
JLabel emailLabel = new JLabel("邮箱:");
registerPanel.add(emailLabel, gbc);
gbc.gridx = 1;
regEmailField = new JTextField(20);
registerPanel.add(regEmailField, gbc);
// 电话输入
gbc.gridx = 0;
gbc.gridy++;
JLabel phoneLabel = new JLabel("电话:");
registerPanel.add(phoneLabel, gbc);
gbc.gridx = 1;
regPhoneField = new JTextField(20);
registerPanel.add(regPhoneField, gbc);
// 按钮区
gbc.gridx = 0;
gbc.gridy++;
gbc.gridwidth = 2;
gbc.anchor = GridBagConstraints.CENTER;
JPanel buttonPanel = new JPanel();
JButton registerButton = new JButton("注册");
registerButton.addActionListener(e -> handleRegister()); // 绑定注册事件
buttonPanel.add(registerButton);
JButton backButton = new JButton("返回");
backButton.addActionListener(e -> showLoginPanel()); // 绑定返回登录事件
buttonPanel.add(backButton);
registerPanel.add(buttonPanel, gbc);
}
//初始化普通用户面板
private void initUserPanel() {
userPanel = new JPanel(new BorderLayout());
// 顶部面板 - 标题和搜索区
JPanel topPanel = new JPanel(new BorderLayout());
JLabel titleLabel = new JLabel("图书管理系统 - 用户界面", SwingConstants.CENTER);
titleLabel.setFont(new Font("宋体", Font.BOLD, 18));
topPanel.add(titleLabel, BorderLayout.NORTH);
// 搜索面板
JPanel searchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
searchField = new JTextField(30);
JButton searchButton = new JButton("搜索图书");
searchButton.addActionListener(e -> searchBooks()); // 绑定搜索事件
JButton refreshButton = new JButton("显示所有图书");
refreshButton.addActionListener(e -> refreshBooksTable()); // 绑定刷新事件
JButton logoutButton = new JButton("退出登录");
logoutButton.addActionListener(e -> logout()); // 绑定退出事件
searchPanel.add(new JLabel("搜索: "));
searchPanel.add(searchField);
searchPanel.add(searchButton);
searchPanel.add(refreshButton);
searchPanel.add(logoutButton);
topPanel.add(searchPanel, BorderLayout.SOUTH);
userPanel.add(topPanel, BorderLayout.NORTH);
// 中间分割面板(上下分栏)
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
// 图书列表区域
JPanel booksPanel = new JPanel(new BorderLayout());
booksPanel.setBorder(BorderFactory.createTitledBorder("图书列表"));
// 图书表格列名
String[] booksColumnNames = {"ID", "标题", "作者", "出版社", "年份", "类别", "状态"};
booksTableModel = new DefaultTableModel(booksColumnNames, 0) {
// 表格不可编辑
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
booksTable = new JTable(booksTableModel);
booksTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // 单选模式
JScrollPane booksScrollPane = new JScrollPane(booksTable); // 滚动面板
booksPanel.add(booksScrollPane, BorderLayout.CENTER);
// 借阅按钮
JButton borrowButton = new JButton("借阅选中图书");
borrowButton.addActionListener(e -> borrowSelectedBook()); // 绑定借阅事件
booksPanel.add(borrowButton, BorderLayout.SOUTH);
// 已借图书区域
JPanel borrowedPanel = new JPanel(new BorderLayout());
borrowedPanel.setBorder(BorderFactory.createTitledBorder("我的借阅"));
// 已借图书表格列名
String[] borrowedColumnNames = {"ID", "标题", "作者", "借阅日期", "应还日期", "状态"};
borrowedBooksTableModel = new DefaultTableModel(borrowedColumnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
borrowedBooksTable = new JTable(borrowedBooksTableModel);
borrowedBooksTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
JScrollPane borrowedScrollPane = new JScrollPane(borrowedBooksTable);
borrowedPanel.add(borrowedScrollPane, BorderLayout.CENTER);
// 归还按钮
JButton returnButton = new JButton("归还选中图书");
returnButton.addActionListener(e -> returnSelectedBook()); // 绑定归还事件
borrowedPanel.add(returnButton, BorderLayout.SOUTH);
// 设置分割面板内容
splitPane.setTopComponent(booksPanel);
splitPane.setBottomComponent(borrowedPanel);
splitPane.setDividerLocation(250); // 分割位置
userPanel.add(splitPane, BorderLayout.CENTER);
}
//管理员面板
private void initAdminPanel() {
adminPanel = new JPanel(new BorderLayout());
// 顶部面板
JPanel topPanel = new JPanel(new BorderLayout());
JLabel titleLabel = new JLabel("图书管理系统 - 管理员界面", SwingConstants.CENTER);
titleLabel.setFont(new Font("宋体", Font.BOLD, 18));
topPanel.add(titleLabel, BorderLayout.NORTH);
// 退出按钮
JButton logoutButton = new JButton("退出登录");
logoutButton.addActionListener(e -> logout());
JPanel logoutPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
logoutPanel.add(logoutButton);
topPanel.add(logoutPanel, BorderLayout.SOUTH);
adminPanel.add(topPanel, BorderLayout.NORTH);
// 中间分割面板(左右分栏)
JSplitPane mainSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
// 左侧 - 书籍管理
JPanel booksManagementPanel = new JPanel(new BorderLayout());
booksManagementPanel.setBorder(BorderFactory.createTitledBorder("书籍管理"));
// 图书表格
String[] booksColumnNames = {"ID", "标题", "作者", "出版社", "年份", "类别", "状态"};
allBooksTableModel = new DefaultTableModel(booksColumnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
allBooksTable = new JTable(allBooksTableModel);
JScrollPane booksScrollPane = new JScrollPane(allBooksTable);
booksManagementPanel.add(booksScrollPane, BorderLayout.CENTER);
// 添加书籍面板
JPanel addBookPanel = new JPanel(new GridLayout(2, 6, 5, 5));
addBookPanel.setBorder(BorderFactory.createTitledBorder("添加新书籍"));
addBookPanel.add(new JLabel("标题:"));
addBookTitleField = new JTextField();
addBookPanel.add(addBookTitleField);
addBookPanel.add(new JLabel("作者:"));
addBookAuthorField = new JTextField();
addBookPanel.add(addBookAuthorField);
addBookPanel.add(new JLabel("出版社:"));
addBookPublisherField = new JTextField();
addBookPanel.add(addBookPublisherField);
addBookPanel.add(new JLabel("年份:"));
addBookYearField = new JTextField();
addBookPanel.add(addBookYearField);
addBookPanel.add(new JLabel("类别:"));
addBookCategoryField = new JTextField();
addBookPanel.add(addBookCategoryField);
JButton addBookButton = new JButton("添加书籍");
addBookButton.addActionListener(e -> addNewBook()); // 绑定添加书籍事件
addBookPanel.add(addBookButton);
booksManagementPanel.add(addBookPanel, BorderLayout.SOUTH);
// 右侧 - 用户管理
JPanel usersManagementPanel = new JPanel(new BorderLayout());
usersManagementPanel.setBorder(BorderFactory.createTitledBorder("用户管理"));
// 用户表格
String[] usersColumnNames = {"ID", "用户名", "邮箱", "电话", "角色"};
usersTableModel = new DefaultTableModel(usersColumnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
usersTable = new JTable(usersTableModel);
JScrollPane usersScrollPane = new JScrollPane(usersTable);
usersManagementPanel.add(usersScrollPane, BorderLayout.CENTER);
// 设置分割面板内容
mainSplitPane.setLeftComponent(booksManagementPanel);
mainSplitPane.setRightComponent(usersManagementPanel);
mainSplitPane.setDividerLocation(450);
adminPanel.add(mainSplitPane, BorderLayout.CENTER);
}
//处理用户登录
private void handleLogin() {
String username = usernameField.getText().trim();
String password = new String(passwordField.getPassword()).trim();
// 验证输入不为空
if (username.isEmpty() || password.isEmpty()) {
JOptionPane.showMessageDialog(this, "请输入用户名和密码", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
// 调用图书馆业务逻辑进行登录验证
currentUser = library.login(username, password);
if (currentUser == null) {
JOptionPane.showMessageDialog(this, "用户名或密码错误", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 检查是否有逾期书籍并提醒
List<Book> overdueBooks = library.checkOverdueBooks(currentUser.getId());
if (!overdueBooks.isEmpty()) {
StringBuilder sb = new StringBuilder();
sb.append("您有").append(overdueBooks.size()).append("本图书已逾期:\n");
for (Book book : overdueBooks) {
sb.append("- ").append(book.getTitle()).append("\n");
}
sb.append("请尽快归还!");
JOptionPane.showMessageDialog(this, sb.toString(), "逾期提醒", JOptionPane.WARNING_MESSAGE);
}
// 根据用户角色显示对应界面
if (currentUser.isAdmin()) {
refreshAdminPanelData();
showAdminPanel();
} else {
refreshUserPanelData();
showUserPanel();
}
}
//用户注册
private void handleRegister() {
String username = regUsernameField.getText().trim();
String password = new String(regPasswordField.getPassword()).trim();
String email = regEmailField.getText().trim();
String phone = regPhoneField.getText().trim();
// 验证输入完整性
if (username.isEmpty() || password.isEmpty() || email.isEmpty() || phone.isEmpty()) {
JOptionPane.showMessageDialog(this, "请填写所有字段", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
// 调用业务逻辑注册用户
boolean success = library.registerUser(username, password, email, phone);
if (success) {
JOptionPane.showMessageDialog(this, "注册成功,请登录", "成功", JOptionPane.INFORMATION_MESSAGE);
showLoginPanel();
// 清空注册表单
regUsernameField.setText("");
regPasswordField.setText("");
regEmailField.setText("");
regPhoneField.setText("");
} else {
JOptionPane.showMessageDialog(this, "用户名已存在", "错误", JOptionPane.ERROR_MESSAGE);
}
}
//搜索图书(按标题、作者或类别)
private void searchBooks() {
String keyword = searchField.getText().trim();
if (keyword.isEmpty()) {
refreshBooksTable(); // 空关键词时显示所有图书
return;
}
// 调用业务逻辑搜索图书
List<Book> results = library.searchBooks(keyword);
updateBooksTable(results);
}
//刷新列表
private void refreshBooksTable() {
List<Book> allBooks = library.getAllBooks();
updateBooksTable(allBooks);
}
//更新图书表格数据
private void updateBooksTable(List<Book> books) {
booksTableModel.setRowCount(0); // 清空表格
for (Book book : books) {
// 构造表格行数据
Object[] row = {
book.getId(),
book.getTitle(),
book.getAuthor(),
book.getPublisher(),
book.getPublicationYear(),
book.getCategory(),
book.isAvailable() ? "可借阅" : "已借出"
};
booksTableModel.addRow(row);
}
}
//更新借阅图书数据
private void updateBorrowedBooksTable() {
borrowedBooksTableModel.setRowCount(0); // 清空表格
List<Book> borrowedBooks = library.getUserBorrowedBooks(currentUser.getId());
try {
Date today = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
for (Book book : borrowedBooks) {
String status = "正常";
// 检查是否逾期
if (!book.getDueDate().isEmpty()) {
Date dueDate = sdf.parse(book.getDueDate());
if (dueDate.before(today)) {
status = "已逾期";
}
}
// 构造表格行数据
Object[] row = {
book.getId(),
book.getTitle(),
book.getAuthor(),
book.getBorrowDate(),
book.getDueDate(),
status
};
borrowedBooksTableModel.addRow(row);
}
} catch (Exception e) {
e.printStackTrace();
}
}
//借阅选中的图书
private void borrowSelectedBook() {
int selectedRow = booksTable.getSelectedRow();
if (selectedRow == -1) {
JOptionPane.showMessageDialog(this, "请先选择一本图书", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
// 获取选中图书的ID
String bookId = (String) booksTableModel.getValueAt(selectedRow, 0);
// 调用业务逻辑借阅图书
boolean success = library.borrowBook(currentUser.getId(), bookId);
if (success) {
JOptionPane.showMessageDialog(this, "借阅成功", "成功", JOptionPane.INFORMATION_MESSAGE);
refreshUserPanelData(); // 刷新界面数据
} else {
JOptionPane.showMessageDialog(this, "借阅失败,该书可能已被借出", "错误", JOptionPane.ERROR_MESSAGE);
}
}
//归还选中的图书
private void returnSelectedBook() {
int selectedRow = borrowedBooksTable.getSelectedRow();
if (selectedRow == -1) {
JOptionPane.showMessageDialog(this, "请先选择一本要归还的图书", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
// 获取选中图书的ID
String bookId = (String) borrowedBooksTableModel.getValueAt(selectedRow, 0);
// 调用业务逻辑归还图书
boolean success = library.returnBook(bookId);
if (success) {
JOptionPane.showMessageDialog(this, "归还成功", "成功", JOptionPane.INFORMATION_MESSAGE);
refreshUserPanelData(); // 刷新界面数据
} else {
JOptionPane.showMessageDialog(this, "归还失败", "错误", JOptionPane.ERROR_MESSAGE);
}
}
//添加新书籍
private void addNewBook() {
String title = addBookTitleField.getText().trim();
String author = addBookAuthorField.getText().trim();
String publisher = addBookPublisherField.getText().trim();
String yearStr = addBookYearField.getText().trim();
String category = addBookCategoryField.getText().trim();
// 验证输入完整性
if (title.isEmpty() || author.isEmpty() || publisher.isEmpty() || yearStr.isEmpty() || category.isEmpty()) {
JOptionPane.showMessageDialog(this, "请填写所有字段", "提示", JOptionPane.WARNING_MESSAGE);
return;
}
// 验证年份格式
int year;
try {
year = Integer.parseInt(yearStr);
} catch (NumberFormatException e) {
JOptionPane.showMessageDialog(this, "请输入有效的年份", "错误", JOptionPane.ERROR_MESSAGE);
return;
}
// 调用业务逻辑添加图书
library.addBook(title, author, publisher, year, category);
JOptionPane.showMessageDialog(this, "书籍添加成功", "成功", JOptionPane.INFORMATION_MESSAGE);
// 清空表单并刷新表格
addBookTitleField.setText("");
addBookAuthorField.setText("");
addBookPublisherField.setText("");
addBookYearField.setText("");
addBookCategoryField.setText("");
refreshAdminPanelData();
}
//刷新用户面板数据
private void refreshUserPanelData() {
refreshBooksTable();
updateBorrowedBooksTable();
}
//刷新管理员面板数据
private void refreshAdminPanelData() {
// 更新书籍表格
allBooksTableModel.setRowCount(0);
List<Book> allBooks = library.getAllBooks();
for (Book book : allBooks) {
Object[] row = {
book.getId(),
book.getTitle(),
book.getAuthor(),
book.getPublisher(),
book.getPublicationYear(),
book.getCategory(),
book.isAvailable() ? "可借阅" : "已借出"
};
allBooksTableModel.addRow(row);
}
// 更新用户表格
usersTableModel.setRowCount(0);
List<User> allUsers = library.getAllUsers();
for (User user : allUsers) {
Object[] row = {
user.getId(),
user.getUsername(),
user.getEmail(),
user.getPhone(),
user.isAdmin() ? "管理员" : "普通用户"
};
usersTableModel.addRow(row);
}
}
//退出登录
private void logout() {
currentUser = null;
// 清空登录表单
usernameField.setText("");
passwordField.setText("");
showLoginPanel();
}
//面板切换方法
private void showLoginPanel() {
CardLayout cl = (CardLayout) mainPanel.getLayout();
cl.show(mainPanel, "login");
}
private void showRegisterPanel() {
CardLayout cl = (CardLayout) mainPanel.getLayout();
cl.show(mainPanel, "register");
}
private void showUserPanel() {
CardLayout cl = (CardLayout) mainPanel.getLayout();
cl.show(mainPanel, "user");
}
private void showAdminPanel() {
CardLayout cl = (CardLayout) mainPanel.getLayout();
cl.show(mainPanel, "admin");
}
//主方法
public static void main(String[] args) {
// 在事件调度线程中启动GUI确保线程安全
SwingUtilities.invokeLater(() -> {
new LibrarySystemGUI().setVisible(true);
});
}
}

@ -0,0 +1,44 @@
// 用户类
public class User {
private String id; // 用户唯一ID
private String username; // 用户名
private String password; // 密码
private String email; // 邮箱
private String phone; // 电话
private boolean isAdmin; // 是否为管理员
//构造方法
public User(String id, String username, String password, String email, String phone, boolean isAdmin) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
this.phone = phone;
this.isAdmin = isAdmin;
}
// getter和setter方法
public String getId() {
return id;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getEmail() {
return email;
}
public String getPhone() {
return phone;
}
public boolean isAdmin() {
return isAdmin;
}
}

@ -0,0 +1,6 @@
id|username|password|email|phone|isAdmin
U202508301101784|admin|admin123|admin.com|123456789|true
U202508301102521|whj|whj123|whj.com|1234578|false
U202508301202625|wy|wy123|wy.com|12345|false
U202508301520384|zg|zg123|zg.com|123678|false
U202508311436068|chr|chr123|chr.com|1234567|false
Loading…
Cancel
Save