Java课程设计:图书管理系统
项目概述
本项目旨在开发一个功能完善的、基于控制台的图书管理系统,系统使用Java语言进行开发,采用面向对象的思想,通过文件存储数据,实现图书的增、删、改、查等基本功能,并具备用户友好的交互界面,通过本项目的实践,可以巩固和深化对Java基础、面向对象编程、集合框架、I/O流以及异常处理等核心知识点的理解和应用。

功能需求分析
系统主要分为两大模块:图书管理模块 和 用户交互模块。
1 图书管理模块 (核心功能)
-
添加图书
- 输入图书信息:ISBN、书名、作者、出版社、出版年份、库存数量。
- 系统自动生成一个唯一的ID。
- 将新图书信息保存到数据文件中。
- 约束:ISBN不能重复,库存数量不能为负数。
-
删除图书
(图片来源网络,侵删)- 通过图书ID或ISBN进行查找。
- 确认后删除该图书信息。
- 约束:如果图书不存在,给出提示。
-
修改图书信息
- 通过图书ID或ISBN进行查找。
- 允许用户修改除ID外的所有信息(书名、作者、出版社、年份、库存)。
- 修改后更新数据文件。
- 约束:如果图书不存在,给出提示。
-
查询图书
- 按ID查询:精确查询,快速定位。
- 按ISBN查询:精确查询。
- 按书名查询:模糊查询,支持部分匹配。
- 按作者查询:模糊查询。
- 显示所有图书:以列表形式展示所有图书信息。
-
数据持久化
- 系统启动时,从文件(如
books.dat)中加载所有图书信息。 - 每次对图书信息进行增、删、改操作后,自动将数据写回文件,确保数据不丢失。
- 系统启动时,从文件(如
2 用户交互模块

-
主菜单
- 显示系统功能列表,引导用户进行操作。
- 包含:添加、删除、修改、查询、显示所有、退出系统等选项。
-
输入处理
- 对用户的输入进行合法性校验(年份必须是数字,库存不能为负)。
- 对非法输入进行捕获和处理,给出友好提示,避免程序崩溃。
-
界面友好性
- 操作提示清晰。
- 执行结果(成功/失败)有明确的反馈。
技术选型
- 编程语言:Java (推荐使用 JDK 8 或更高版本)
- 开发环境:IntelliJ IDEA / Eclipse
- 核心技术:
- 面向对象:使用
class来定义Book和BookManager。 - 集合框架:使用
ArrayList<Book>来在内存中存储和管理图书对象,因为它动态扩容,便于增删改。 - I/O流:使用
ObjectInputStream和ObjectOutputStream来实现对象的序列化和反序列化,从而将ArrayList对象直接存入和读出文件。 - 异常处理:使用
try-catch块处理可能发生的IOException,ClassNotFoundException等异常。
- 面向对象:使用
系统设计
1 类图设计
+---------------------+
| Book |
+---------------------+
| - id: String |
| - isbn: String | String |
| - author: String |
| - publisher: String |
| - year: int |
| - stock: int |
+---------------------+
| + getId(): String |
| + getIsbn(): String |
| + ... (getters) |
| + setId(String): void |
| + ... (setters) |
| + toString(): String|
+---------------------+
^
|
| uses / contains
|
+---------------------+
| BookManager |
+---------------------+
| - bookList: ArrayList<Book> |
| - dataFile: File |
+---------------------+
| + addBook(Book): void |
| + deleteBook(String): boolean |
| + updateBook(Book): boolean |
| + findBookById(String): Book |
| + findBookByIsbn(String): Book|
| + findBooksByTitle(String): ArrayList<Book>|
| + listAllBooks(): void |
| + saveToFile(): void |
| + loadFromFile(): void |
+---------------------+
^
|
| creates
|
+---------------------+
| MainApp |
+---------------------+
| + main(String[]): void |
+---------------------+
2 核心类设计
-
Book.java(图书实体类)- 属性:
id,isbn,title,author,publisher,year,stock,所有属性设为private,并提供public的getter和setter方法。 - 方法:
- 构造方法:无参构造和全参构造。
toString()方法:用于格式化输出图书信息。
- 属性:
-
BookManager.java(图书管理器类)- 属性:
bookList:ArrayList<Book>,用于在内存中存放所有图书。dataFile:File对象,指向数据存储文件(如books.dat)。
- 方法:
loadFromFile(): 系统启动时调用,从文件加载数据到bookList。saveToFile(): 每次增删改后调用,将bookList保存到文件。addBook(Book book): 添加图书,并检查ID和ISBN唯一性。deleteBook(String idOrIsbn): 删除图书。updateBook(Book book): 更新图书信息。findBookById(String id): 根据ID精确查找。findBookByIsbn(String isbn): 根据ISBN精确查找。findBooksByTitle(String keyword): 根据书名模糊查找。listAllBooks(): 遍历并打印所有图书。
- 属性:
-
MainApp.java(主程序入口类)- 方法:
main(String[] args) - 功能:
- 创建
BookManager实例。 - 调用
bookManager.loadFromFile()加载数据。 - 进入一个
while循环,显示主菜单。 - 根据用户输入,调用
BookManager的相应方法。 - 处理用户输入,并进行异常捕获。
- 用户选择退出时,调用
bookManager.saveToFile()保存数据,并结束程序。
- 创建
- 方法:
核心代码实现
1 Book.java
import java.io.Serializable;
// 实现Serializable接口,以便对象可以被序列化
public class Book implements Serializable {
private String id;
private String isbn;
private String title;
private String author;
private String publisher;
private int year;
private int stock;
// 无参构造
public Book() {}
// 全参构造
public Book(String id, String isbn, String title, String author, String publisher, int year, int stock) {
this.id = id;
this.isbn = isbn;
this.title = title;
this.author = author;
this.publisher = publisher;
this.year = year;
this.stock = stock;
}
// Getters and Setters
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getIsbn() { return isbn; }
public void setIsbn(String isbn) { this.isbn = isbn; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getAuthor() { return author; }
public void setAuthor(String author) { this.author = author; }
public String getPublisher() { return publisher; }
public void setPublisher(String publisher) { this.publisher = publisher; }
public int getYear() { return year; }
public void setYear(int year) { this.year = year; }
public int getStock() { return stock; }
public void setStock(int stock) { this.stock = stock; }
@Override
public String toString() {
return String.format("ID: %s, ISBN: %s, 书名: %s, 作者: %s, 出版社: %s, 年份: %d, 库存: %d",
id, isbn, title, author, publisher, year, stock);
}
}
2 BookManager.java
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
public class BookManager implements Serializable {
private ArrayList<Book> bookList;
private final File dataFile = new File("books.dat");
public BookManager() {
bookList = new ArrayList<>();
loadFromFile();
}
// 从文件加载数据
public void loadFromFile() {
if (dataFile.exists()) {
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(dataFile))) {
bookList = (ArrayList<Book>) ois.readObject();
System.out.println("数据加载成功!");
} catch (IOException | ClassNotFoundException e) {
System.err.println("加载文件时出错: " + e.getMessage());
bookList = new ArrayList<>(); // 如果加载失败,初始化一个空列表
}
} else {
System.out.println("数据文件不存在,将创建新文件。");
}
}
// 保存数据到文件
public void saveToFile() {
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(dataFile))) {
oos.writeObject(bookList);
// System.out.println("数据保存成功!"); // 可以选择不打印,以免干扰用户
} catch (IOException e) {
System.err.println("保存文件时出错: " + e.getMessage());
}
}
// 添加图书
public void addBook(Book book) {
// 检查ID和ISBN是否已存在
if (findBookById(book.getId()) != null || findBookByIsbn(book.getIsbn()) != null) {
System.out.println("添加失败:ID或ISBN已存在!");
return;
}
bookList.add(book);
saveToFile();
System.out.println("图书添加成功!");
}
// 删除图书
public boolean deleteBook(String idOrIsbn) {
Book book = findBookById(idOrIsbn);
if (book == null) {
book = findBookByIsbn(idOrIsbn);
}
if (book != null) {
bookList.remove(book);
saveToFile();
System.out.println("图书删除成功!");
return true;
} else {
System.out.println("未找到ID或ISBN为 " + idOrIsbn + " 的图书!");
return false;
}
}
// 更新图书
public boolean updateBook(Book updatedBook) {
for (int i = 0; i < bookList.size(); i++) {
Book book = bookList.get(i);
if (book.getId().equals(updatedBook.getId())) {
// 检查新ISBN是否与其他图书冲突
if (!book.getIsbn().equals(updatedBook.getIsbn()) && findBookByIsbn(updatedBook.getIsbn()) != null) {
System.out.println("更新失败:新ISBN已存在!");
return false;
}
bookList.set(i, updatedBook);
saveToFile();
System.out.println("图书信息更新成功!");
return true;
}
}
System.out.println("未找到ID为 " + updatedBook.getId() + " 的图书!");
return false;
}
// 查找方法...
public Book findBookById(String id) {
return bookList.stream().filter(book -> book.getId().equals(id)).findFirst().orElse(null);
}
public Book findBookByIsbn(String isbn) {
return bookList.stream().filter(book -> book.getIsbn().equals(isbn)).findFirst().orElse(null);
}
public List<Book> findBooksByTitle(String keyword) {
return bookList.stream().filter(book -> book.getTitle().toLowerCase().contains(keyword.toLowerCase())).collect(Collectors.toList());
}
public void listAllBooks() {
if (bookList.isEmpty()) {
System.out.println("图书馆中没有图书。");
} else {
System.out.println("===== 图书列表 =====");
bookList.forEach(System.out::println);
System.out.println("===================");
}
}
// 生成唯一ID的辅助方法
public String generateId() {
return "B" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
}
}
3 MainApp.java
import java.util.InputMismatchException;
import java.util.List;
import java.util.Scanner;
public class MainApp {
private static final Scanner scanner = new Scanner(System.in);
private static final BookManager bookManager = new BookManager();
public static void main(String[] args) {
while (true) {
showMenu();
int choice = getChoice();
processChoice(choice);
}
}
private static void showMenu() {
System.out.println("\n===== 图书管理系统 =====");
System.out.println("1. 添加图书");
System.out.println("2. 删除图书");
System.out.println("3. 修改图书");
System.out.println("4. 查询图书");
System.out.println("5. 显示所有图书");
System.out.println("0. 退出系统");
System.out.print("请输入您的选择: ");
}
private static int getChoice() {
try {
return scanner.nextInt();
} catch (InputMismatchException e) {
scanner.next(); // 清除错误的输入
System.out.println("输入无效,请输入数字!");
return -1; // 返回一个无效值
}
}
private static void processChoice(int choice) {
scanner.nextLine(); // 消耗掉nextInt()后的换行符
switch (choice) {
case 1:
addBookUI();
break;
case 2:
deleteBookUI();
break;
case 3:
updateBookUI();
break;
case 4:
searchBookUI();
break;
case 5:
bookManager.listAllBooks();
break;
case 0:
System.out.println("感谢使用,系统退出。");
bookManager.saveToFile(); // 确保退出前保存
System.exit(0);
default:
System.out.println("无效的选择,请重新输入!");
}
}
// UI交互方法...
private static void addBookUI() {
System.out.println("--- 添加新图书 ---");
System.out.print("请输入ISBN: ");
String isbn = scanner.nextLine();
System.out.print("请输入书名: ");
String title = scanner.nextLine();
System.out.print("请输入作者: ");
String author = scanner.nextLine();
System.out.print("请输入出版社: ");
String publisher = scanner.nextLine();
System.out.print("请输入出版年份: ");
int year = getIntegerInput();
System.out.print("请输入库存数量: ");
int stock = getIntegerInput();
if (year <= 0 || stock < 0) {
System.out.println("输入错误:年份和库存必须为有效正数!");
return;
}
String id = bookManager.generateId();
Book newBook = new Book(id, isbn, title, author, publisher, year, stock);
bookManager.addBook(newBook);
}
private static void deleteBookUI() {
System.out.println("--- 删除图书 ---");
System.out.print("请输入要删除的图书ID或ISBN: ");
String idOrIsbn = scanner.nextLine();
bookManager.deleteBook(idOrIsbn);
}
private static void updateBookUI() {
System.out.println("--- 修改图书信息 ---");
System.out.print("请输入要修改的图书ID: ");
String id = scanner.nextLine();
Book book = bookManager.findBookById(id);
if (book == null) {
System.out.println("未找到该ID的图书!");
return;
}
System.out.println("找到图书: " + book);
System.out.print("请输入新书名 (留空则不修改): ");
String newTitle = scanner.nextLine();
if (!newTitle.isEmpty()) book.setTitle(newTitle);
System.out.print("请输入新作者 (留空则不修改): ");
String newAuthor = scanner.nextLine();
if (!newAuthor.isEmpty()) book.setAuthor(newAuthor);
// ... 可以继续添加其他字段的修改逻辑
bookManager.updateBook(book);
}
private static void searchBookUI() {
System.out.println("--- 查询图书 ---");
System.out.println("1. 按ID查询");
System.out.println("2. 按ISBN查询");
System.out.println("3. 按书名查询");
System.out.print("请选择查询方式: ");
int searchChoice = getChoice();
scanner.nextLine(); // 消耗换行符
switch (searchChoice) {
case 1:
System.out.print("请输入图书ID: ");
String id = scanner.nextLine();
Book book = bookManager.findBookById(id);
if (book != null) {
System.out.println("查询结果: " + book);
} else {
System.out.println("未找到该ID的图书。");
}
break;
case 2:
System.out.print("请输入图书ISBN: ");
String isbn = scanner.nextLine();
Book bookByIsbn = bookManager.findBookByIsbn(isbn);
if (bookByIsbn != null) {
System.out.println("查询结果: " + bookByIsbn);
} else {
System.out.println("未找到该ISBN的图书。");
}
break;
case 3:
System.out.print("请输入书名关键词: ");
String keyword = scanner.nextLine();
List<Book> books = bookManager.findBooksByTitle(keyword);
if (!books.isEmpty()) {
System.out.println("查询结果:");
books.forEach(System.out::println);
} else {
System.out.println("未找到包含关键词的图书。");
}
break;
default:
System.out.println("无效的选择。");
}
}
private static int getIntegerInput() {
while (true) {
try {
return scanner.nextInt();
} catch (InputMismatchException e) {
scanner.next(); // 清除错误输入
System.out.print("输入无效,请输入一个整数: ");
}
}
}
}
项目扩展与优化 (进阶方向)
如果你想让项目更上一层楼,可以考虑以下扩展:
- 引入数据库:将文件存储替换为MySQL或SQLite数据库,这需要学习JDBC,是更企业级的做法。
- 图形用户界面:使用Java Swing或JavaFX开发GUI版本,提供更直观的用户体验。
- 用户角色管理:增加“管理员”和“普通用户”角色,管理员拥有所有权限,普通用户只有查询和借阅(需要增加借阅记录表)权限。
- 借阅与归还功能:
- 增加一个
User类和一个LoanRecord类。 LoanRecord记录谁、在什么时候、借了哪本书、什么时候归还。- 修改图书的
stock为availableStock,借书时减少,还书时增加。
- 增加一个
- 排序功能:在显示图书列表时,可以按书名、出版年份等字段进行排序。
- 单元测试:使用 JUnit 为
BookManager中的核心方法(如addBook,deleteBook)编写单元测试,确保代码质量。
部署与运行指南
- 环境准备:确保你的电脑上已安装JDK和开发环境(如IDEA)。
- 创建项目:在IDEA中创建一个新的Java项目。
- 创建类:在
src目录下创建Book.java,BookManager.java, 和MainApp.java三个类,并将上述代码分别复制进去。 - 运行:运行
MainApp.java的main方法。 - 操作:根据控制台提示进行操作,第一次运行后,会在项目根目录下自动生成一个
books.dat文件,用于存储数据。
这个方案为你提供了一个非常坚实的基础,你可以直接在此基础上进行编码和调试,完成你的课程设计,祝你项目顺利!
