Java 实战:从零开发图书管理系统
在学习 JavaSE 的过程中,通过实战项目来巩固知识是非常有效的方式。
图书管理系统是一个经典的小型项目,它涵盖了 Java 面向对象编程、异常处理等多个核心知识点。通过开发这个系统,我们能将零散的知识整合起来,深入理解 Java 程序的设计与开发流程。
基于 JavaSE 开发的图书管理系统实战项目。涵盖用户管理(管理员/普通用户)、书籍 CRUD、借阅归还逻辑及权限控制。采用面向对象设计,应用单例模式、代理模式及工厂模式。实现文件持久化存储,支持图书搜索、统计、库存管理及过期清理功能。通过该项目巩固了封装、继承、多态等核心知识点及异常处理流程。

在学习 JavaSE 的过程中,通过实战项目来巩固知识是非常有效的方式。
图书管理系统是一个经典的小型项目,它涵盖了 Java 面向对象编程、异常处理等多个核心知识点。通过开发这个系统,我们能将零散的知识整合起来,深入理解 Java 程序的设计与开发流程。
通过思维导图可以更好的理解整个图书系统。
在图书系统中,先设计四大模块:用户,书籍,工具,常量值。
在图书管理系统中,用户分为 管理员和普通用户(不止一个哦),但他们都有这些属性:姓名,ID,角色。
public abstract class User {
private String name;
private int userID;
private String role; // 用户角色
public User(String name, int userID, String role) {
this.name = name;
this.userID = userID;
this.role = role;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getUserID() { return userID; }
public void setUserID(int userID) { this.userID = userID; }
public String getRole() { return role; }
public void setRole(String role) { this.role = role; }
/**
* @return 返回具体选择了什么操作
* 1 2 3 4 ...
*/
public abstract int display();
@Override
public String toString() {
return "User{" + "name='" + name + '\'' + ", userID=" + userID + ", role='" + role + "'}";
}
}
public class AdminUser extends User {
public Scanner scanner;
public Library library;
public AdminUser(String name, int userID) {
super(name, userID, "管理员");
scanner = ScannerSingleton.getScannerSingleton();
library = Library.getLibrary();
}
@Override
public int display() {
System.out.println(" 管理员 " + this.getName() + " 的操作菜单:");
System.out.println("1. 查找图书 ");
System.out.println("2. 打印所有的图书 ");
System.out.println("3. 退出系统 ");
System.out.println("4. 上架图书 ");
System.out.println("5. 修改图书 ");
System.out.println("6. 下架图书 ");
System.out.println("7. 统计借阅次数 ");
System.out.println("8. 查看最后欢迎的前 K 本书 ");
System.out.println("9. 查看库存状态 ");
System.out.println("10. 检查超过一年未下架的图书 ");
System.out.println(" 请选择你的操作: ");
return scanner.nextInt();
}
// 其他操作方法具体实现...
}
public class NormalUser extends User {
public Scanner scanner;
public Library library;
// 存储图书借阅信息
private PairOfUidAndBookId[] pairOfUidAndBookIds;
// 当前图书借阅量
private int borrowedCount;
private final AnalyzingBorrowedBook analyzingBorrowedBook = new AnalyzingBorrowedBook();
public NormalUser(String name, int userID) {
super(name, userID, "普通用户");
loadBorrowedBook();
scanner = ScannerSingleton.getScannerSingleton();
library = Library.getLibrary();
}
private void loadBorrowedBook() {
PairOfUidAndBookId[] allBorrowedBook;
// 加载文件借阅信息
try {
allBorrowedBook = analyzingBorrowedBook.loadObject(Constant.BORROWED_BOOK_MAX_NUM);
// 默认已借阅图书数组大小为 BORROW_BOOK_MAX_NUM
pairOfUidAndBookIds = new PairOfUidAndBookId[Constant.BORROW_BOOK_MAX_NUM];
// 没有读取到已借阅图书
if (allBorrowedBook == null) {
borrowedCount = 0;
} else {
// 实际数组长度
int allBorrowedBookLen = allBorrowedBook.length;
// 读取超出范围
if (allBorrowedBookLen > pairOfUidAndBookIds.length) {
// 重新分配内存
pairOfUidAndBookIds = new PairOfUidAndBookId[allBorrowedBookLen];
}
// 拷贝到已借阅图书数组中
for (int i = 0; i < allBorrowedBookLen; i++) {
pairOfUidAndBookIds[i] = allBorrowedBook[i];
// 更新数据
borrowedCount = allBorrowedBookLen;
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void storeBorrowBook() {
try {
analyzingBorrowedBook.storyObject(pairOfUidAndBookIds, Constant.BORROWED_BOOK_MAX_NUM);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public int display() {
System.out.println(" 用户 " + this.getName() + " 的操作菜单:");
System.out.println("1. 查找图书 ");
System.out.println("2. 打印所有的图书 ");
System.out.println("3. 退出系统 ");
System.out.println("4. 借阅图书 ");
System.out.println("5. 归还图书 ");
System.out.println("6. 查看当前个人借阅情况 ");
System.out.println(" 请选择你的操作: ");
return scanner.nextInt();
}
// 其他操作方法具体实现...
}
public class ProxyUser {
private User realUser;
private Library library;
public ProxyUser(User user) {
this.realUser = user;
library = Library.getLibrary();
}
public int display() {
return this.realUser.display();
}
public int getRealUser() {
return this.realUser.display();
}
// 管理员相关方法
// 普通用户相关方法
}
Book:存放书籍各种属性。
public class Book implements Comparable<Book> {
// 书 id
private int bookId;
// 书名
private String title;
// 作者
private String author;
// 类别
private String category;
// 出版年份
private int publishYearl;
// 借阅状态
private boolean isBorrowed;
// 借阅次数
private int borrowCount;
// 上架时间
private LocalDate shelfDate;
// 构造方法,初始化图书对象,id,借阅状态,次数不用传参
public Book(String title, String author, String category, int publishYearl, LocalDate shelfDate) {
this.title = title;
this.author = author;
this.category = category;
this.publishYearl = publishYearl;
this.shelfDate = shelfDate;
}
public int getBookId() { return bookId; }
public void setBookId(int bookId) { this.bookId = bookId; }
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 getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public int getPublishYearl() { return publishYearl; }
public void setPublishYearl(int publishYearl) { this.publishYearl = publishYearl; }
public boolean isBorrowed() { return isBorrowed; }
public void setBorrowed(boolean borrowed) { isBorrowed = borrowed; }
public int getBorrowCount() { return borrowCount; }
public void setBorrowCount(int borrowCount) { this.borrowCount = borrowCount; }
public LocalDate getShelfDate() { return shelfDate; }
public void setShelfDate(LocalDate shelfDate) { this.shelfDate = shelfDate; }
// 对借阅次数 每次自增 1 自减 1
public void incrementBorrowCount() { this.borrowCount++; }
public void decreaseBorrowCount() { this.borrowCount--; }
@Override
public String toString() {
return "Book{" + "bookId=" + bookId + ", title='" + title + "'" + ", author='" + author + "'" + ", category='" + category + "'" + ", publishYearl=" + publishYearl + ", isBorrowed=" + isBorrowed + ", borrowCount=" + borrowCount + ", shelfDate=" + shelfDate + '}';
}
// 将书籍信息拼接成 JSON 格式的字符串
public String toJSON() {
StringBuilder json = new StringBuilder();
json.append(bookId).append(",");
json.append(title).append(",");
json.append(author).append(",");
json.append(category).append(",");
json.append(borrowCount).append(",");
json.append(isBorrowed).append(",");
json.append(borrowCount).append(",");
json.append(shelfDate != null ? shelfDate.format(DateTimeFormatter.ISO_LOCAL_DATE) : "null");
return json.toString();
}
// 对后期对象的比较做准备
@Override
public int compareTo(Book o) {
return o.getBorrowCount() - this.getBorrowCount();
}
}
初始化数组容量,可以放在常量值包中。
public class Library {
// 存储的书籍
public Book[] books;
// 记录当前有效书籍
public int bookCount;
private static Library library;
public Scanner scanner = new Scanner(System.in);
private AnalyzingBook analyzingBook = new AnalyzingBook();
private Library() {
// 调用该构造方法时,要加载文件当中的数据到 books 数组当中
loadAllBook();
}
public static Library getLibrary() {
if (library == null) {
library = new Library();
}
return library;
}
// 写成独立的方法,方便后面实时更新
private void loadAllBook() {
// 读取文件书籍到 allBook 数组中
try {
Book[] allBook = analyzingBook.loadObject(Constant.ALL_BOOK_FILE_NAME);
// 给当前书架默认分配大小为 5
books = new Book[Constant.CAPACIYY];
if (allBook == null) {
bookCount = 0;
} else {
int allBookLen = allBook.length;
// 5
if (allBookLen > books.length) {
books = new Book[allBookLen];
}
for (int i = 0; i < allBookLen; i++) {
books[i] = allBook[i];
}
// 有效书籍 bookCount = allBookLen;
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// 存储图书到文件中
private void storeBook() {
try {
analyzingBook.storeObject(books, Constant.ALL_BOOK_FILE_NAME);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
实现文件内容的读取每本书籍之间使用'\n'进行分割把对应书籍组装成书籍对象。
先将书籍数组对象中每个书籍对象进行字符串的序列号,也就是 Book 类中的 toJSON 方法。
public class AnalyzingBook {
public void storeObject(Book[] books, String filename) throws IOException {
// 有效书籍
int booksUseLen = 0;
for (int i = 0; i < books.length; i++) {
if (books[i] != null) {
booksUseLen++;
}
}
// 使每个属性使用逗号拼接
StringBuilder jsonArray = new StringBuilder();
for (int i = 0; i < booksUseLen; i++) {
if (books[i] != null) {
jsonArray.append(books[i].toJSON());
if (i != booksUseLen - 1) {
jsonArray.append("\n");
}
}
}
// 把内存中存储的数据写到磁盘上
FileUtils.writeFile(jsonArray.toString(), filename);
}
// 从文件读取数据
public Book[] loadObject(String filename) throws IOException {
// 从磁盘的文件中读取数据
String content = FileUtils.readFile(filename);
if (content == null || content.isEmpty()) {
System.out.println("图书馆为空");
return null;
}
// 用\n作为分隔符进行字符串分隔
String[] bookJsonStrings = content.split("\n");
// 把对应的字符串'组装'成书籍对象
Book[] bookList = new Book[bookJsonStrings.length];
for (int i = 0; i < bookJsonStrings.length; i++) {
Book book = parseBookJson(bookJsonStrings[i]);
bookList[i] = book;
}
return bookList;
}
// '0,java,baby...'
private Book parseBookJson(String json) {
String[] pairs = json.split(",");
int bookId = Integer.parseInt(pairs[0]);
String title = pairs[1];
String author = pairs[2];
String category = pairs[3];
int publishYear = Integer.parseInt(pairs[4]);
boolean isBorrowed = Boolean.parseBoolean(pairs[5]);
int borrowCount = Integer.parseInt(pairs[6]);
LocalDate shelfDate = LocalDate.parse(pairs[7]);
if (title != null && author != null && category != null && shelfDate != null) {
Book book = new Book(title, author, category, publishYear, shelfDate);
book.setBorrowed(isBorrowed);
book.setBorrowCount(borrowCount);
book.setBookId(bookId);
return book;
}
return null;
}
// 测试
public static void main(String[] args) {
Book[] books = new Book[4];
books[0] = new Book("java", "baby", "编程", 1994, LocalDate.of(2023, 9, 24));
books[1] = new Book("mysql", "lisi", "编程", 1999, LocalDate.of(2024, 2, 10));
books[2] = new Book("php", "baby", "编程", 2020, LocalDate.of(2023, 9, 23));
books[3] = new Book("西游记", "吴承恩", "小说", 2024, LocalDate.of(2023, 9, 23));
AnalyzingBook analyzingBook = new AnalyzingBook();
try {
analyzingBook.storeObject(books, "Constant.ALL_BOOK_FILE_NAME");
// 将数据读到 ret 数组里面
Book[] ret = analyzingBook.loadObject("Constant.ALL_BOOK_FILE_NAME");
for (int i = 0; i < ret.length; i++) {
System.out.println(ret[i]);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
判断代理对象是否具有权限调用对应用户的方法进行操作查找图书,显示图书,退出系统这三个功能两种用户都具备,写在 Library 中,不需要区分。
public class ProxyUser {
private User realUser;
private Library library;
public ProxyUser(User user) {
this.realUser = user;
library = Library.getLibrary();
}
public int display() {
return this.realUser.display();
}
public int getRealUser() {
return this.realUser.display();
}
// 管理员相关方法
// 用户相关方法
}
这三个功能两种用户都具备,写在 Library 中,不需要区分。 使用常量代替 case 的判断条件,并定义在 Constant 中。
public void handleOperation(int choice) {
if (this.realUser instanceof AdminUser) {
switch (choice) {
case Constant.SEARCH_BOOK: library.searchBook(); break;
case Constant.DISPLAY_BOOK: library.displayBook(); break;
case Constant.EXIT: library.exit(); break;
case Constant.ADD_BOOK: addBook(); break;
case Constant.UPDATE_BOOK: updateBook(); break;
case Constant.REMOVE_BOOK: removeBook(); break;
case Constant.BORROWED_BOOK_COUNT: borrowCount(); break;
case Constant.GENERATE_BOOK: generateBook(); break;
case Constant.CHECK_INVENTORY_STATUS: checkInventoryStatus(); break;
case Constant.CHECK_AND_REMOVE_OLD_BOOK: checkAndRemoveOldBooks(); break;
default: System.out.println("无效的操作。 ");
}
} else if (realUser instanceof NormalUser) {
// 普通用户操作
switch (choice) {
case Constant.SEARCH_BOOK: library.searchBook(); break;
case Constant.DISPLAY_BOOK: library.displayBook(); break;
case Constant.EXIT: library.exit(); break;
case Constant.BORROWED_BOOK: borrowBook(); break;
case Constant.RETURN_BOOK: returnBook(); break;
case Constant.VIEW_BORROW_HISTORY_BOOK: viewBorrowHistory(); break;
default: System.out.println("无效的操作。 ");
}
}
}
private void checkRealUserWhetherAdminUser(String msg) {
if (!(this.realUser instanceof AdminUser)) {
throw new PermissionException(msg);
}
}
// 上架图书
public void addBook() {
System.out.println("代理类 addBook 方法执行了");
try {
checkRealUserWhetherAdminUser("普通用户没有权限添加书籍");
} catch (PermissionException e) {
e.printStackTrace();
}
((AdminUser)(this.realUser)).addBook();
}
// 上架图书
public void addBook() {
System.out.println("Admin 类 addBook 方法执行了");
scanner.nextLine(); // 防止有其他字符影响输入
System.out.println("请输入书名: ");
String title = scanner.nextLine(); // 输入书名
System.out.println("请输入作者: ");
String author = scanner.nextLine(); // 输入作者
System.out.println("请输入类别: ");
String category = scanner.nextLine(); // 输入图书类别
System.out.println("请输入出版年份: ");
int year = scanner.nextInt(); // 输入出版年份
LocalDate shelfDate = LocalDate.now();
Book book = new Book(title, author, category, year, shelfDate);
library.addBook(book);
}
public void addBook(Book book) {
System.out.println("Library 类 addBook 执行了");
if (bookCount >= books.length) {
System.out.println("图书馆已满,无法上架图书");
return;
}
books[bookCount] = book;
Book bookLast = books[bookCount - 1];
book.setBookId(bookLast.getBookId() - 1);
storeBook();
System.out.println("图书上架成功,名称为:" + book.getTitle());
}
// 图书修改支持修改书名作者类别
public void updateBook() {
try {
checkRealUserWhetherAdminUser("普通用户没有权限更新书籍");
} catch (PermissionException e) {
e.printStackTrace();
}
((AdminUser)(this.realUser)).updateBook();
}
// 图书修改支持修改书名作者类别
public void updateBook() {
// 展示所有书籍
library.displayBook();
System.out.println("请输入你要修改的 id:");
int bookId = scanner.nextInt();
scanner.nextLine();
Book book = library.searchById(bookId);
if (book == null) {
System.out.println("没有你要找的这本 ID 的书:" + bookId);
return;
}
System.out.println("当前书名:" + book.getTitle());
System.out.println("请输入新的书名:");
String newTitle = scanner.nextLine(); // 输入新的书名
System.out.println("当前作者:" + book.getAuthor());
System.out.println("请输入新的作者: ");
String newAuthor = scanner.nextLine(); // 输入新的作者
System.out.println("当前类别:" + book.getCategory());
System.out.println("请输入新的类别: ");
String newCategory = scanner.nextLine(); // 输入新的类别
book.setTitle(newTitle);
book.setAuthor(newAuthor);
book.setCategory(newCategory);
library.updateBook(book);
}
// 通过 bookId 找到对应书籍,没=没有就返回 null
public Book searchById(int bookId) {
loadAllBook(); // 最新的图书
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
if (book.getBookId() == bookId) {
return book;
}
}
return null;
}
public void updateBook(Book book) {
int bookId = book.getBookId();
int index = searchByIdReturnIndex(book.getBookId());
books[index] = book;
if (index == -1) {
System.out.println("没有你要更新的图书,此时 Id 为:" + bookId);
return;
}
books[index] = book;
storeBook(); // 更新数据
System.out.println("书籍已被更新,文件已被写入,更新之后书籍为:");
System.out.println(books[index]);
}
private int searchByIdReturnIndex(int bookId) {
loadAllBook();
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
if (book.getBookId() == bookId) {
return i;
}
}
return -1;
}
// 删除书籍
public void removeBook() {
try {
checkRealUserWhetherAdminUser("普通用户没有权限删除书籍");
} catch (PermissionException e) {
e.printStackTrace();
}
((AdminUser)(this.realUser)).removeBook();
}
// 删除书籍
public void removeBook() {
library.displayBook();
System.out.println("请输入");
int bookId = scanner.nextInt();
scanner.nextLine();
Book removeBook = library.searchById(bookId);
if (removeBook == null) {
System.out.println("没有你要删除的图书");
return;
}
library.removeBook(bookId);
System.out.println("图书:" + removeBook.getTitle() + "已经被删除! ");
}
public void removeBook(int bookId) {
// 实现移除逻辑
int index = searchByIdReturnIndex(bookId);
if (index != -1) {
// 移动后续元素
for (int i = index; i < bookCount - 1; i++) {
books[i] = books[i + 1];
}
books[bookCount - 1] = null;
bookCount--;
storeBook();
}
}
// 统计每本书的借阅次数
public void borrowCount() {
try {
checkRealUserWhetherAdminUser("普通用户没有权限查看图书借阅次数");
} catch (PermissionException e) {
e.printStackTrace();
}
((AdminUser)(this.realUser)).borrowCount();
}
// 统计每本书的借阅次数
public void borrowCount() {
library.borrowCount();
}
public void borrowCount() {
loadAllBook();
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
System.out.println("书名:" + book.getTitle() + "借阅次数:" + book.getBorrowCount());
}
}
// 查询最受欢迎的前 n 本书
public void generateBook() {
try {
checkRealUserWhetherAdminUser("普通用户没有权限查询最受欢迎的前 n 本书");
} catch (PermissionException e) {
e.printStackTrace();
}
((AdminUser)(this.realUser)).generateBook();
}
// 查询最受欢迎的前 k 本书
public void generateBook() {
System.out.println("请输入你要查看的最受欢迎的前 K 本书 , 注意 k 值不能超过:" + library.bookCount);
int k = scanner.nextInt();
if (k <= 0 || k > library.bookCount) {
System.out.println("没有最受欢迎的前" + k + "本书");
return;
}
library.generateBook(k);
}
public void generateBook(int k) {
loadAllBook();
// 把所有书籍放在临时数组,进行排序
Book[] tmp = new Book[bookCount];
for (int i = 0; i < bookCount; i++) {
tmp[i] = books[i];
}
// 开始排序
Arrays.sort(tmp);
// 把前 k 本书拷贝到新数组
Book[] generateBooks = new Book[k];
for (int i = 0; i < k; i++) {
generateBooks[i] = tmp[i];
}
// 打印新数组
System.out.println("最受欢迎书籍:");
for (int i = 0; i < generateBooks.length; i++) {
Book book = generateBooks[i];
System.out.println("ID: " + book.getBookId() + "书名:" + book.getTitle() + "作者:" + book.getAuthor() + "借阅次数:" + book.getBorrowCount());
}
}
// 查看库存状态
public void checkInventoryStatus() {
try {
checkRealUserWhetherAdminUser("普通用户没有权限查看库存状态");
} catch (PermissionException e) {
e.printStackTrace();
}
((AdminUser)(this.realUser)).checkInventoryStatus();
}
// 查看库存状态
public void checkInventoryStatus() {
library.checkInventoryStatus();
}
public void checkInventoryStatus() {
loadAllBook();
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
String status = "未借出";
if (book.isBorrowed()) {
status = "已借出";
}
System.out.println("书名:" + book.getTitle() + "目前状态:" + status);
}
}
// 并移除上架超过一年的图书
public void checkAndRemoveOldBooks() {
try {
checkRealUserWhetherAdminUser("普通用户没有权限移除上架超过一年的图书");
} catch (PermissionException e) {
e.printStackTrace();
}
((AdminUser)(this.realUser)).checkAndRemoveOldBooks();
}
// 并移除上架超过一年的图书
public void checkAndRemoveOldBooks() {
library.checkAndRemoveOldBooks();
}
public void checkAndRemoveOldBooks() {
// 移除上架超过一年的图书
loadAllBook();
// 获取当前时间戳
long currentTimestamp = System.currentTimeMillis();
// 将当前时间戳转换为 LocalDate
LocalDate currentDate = Instant.ofEpochMilli(currentTimestamp).atZone(ZoneId.systemDefault()).toLocalDate();
boolean flg = false;
for (int i = 0; i < bookCount; i++) {
Book book = books[i];
// 获取当前书籍的上架时间
LocalDate specifiedDate = book.getShelfDate();
// 计算两个日期之间的差值(以年为单位)
long yearsBetween = ChronoUnit.YEARS.between(specifiedDate, currentDate);
if (yearsBetween >= 1) {
System.out.print("图书" + book.getTitle() + "已经上架超过一年,是否移除?(y/n): ");
scanner.nextLine();
String response = scanner.nextLine();
if (response.equalsIgnoreCase("y")) {
// 确认删除调用 remove 方法进行删除
removeBook(book.getBookId());
i--; // 因为后面的书已经向前移动,所以要重新检查当前索引位置
}
flg = true;
}
}
if (!flg) {
System.out.println("没有上架超过一年的图书! ");
}
storeBook();
}
private void checkRealUserWhetherNormalUser(String msg) {
if (!(realUser instanceof NormalUser)) {
throw new PermissionException(msg);
}
}
// 借阅图书
public void borrowBook() {
System.out.println("代理类 borrowBook 方法执行了");
checkRealUserWhetherNormalUser("管理员不能借阅图书,请换做普通用户来借阅");
((NormalUser)(this.realUser)).borrowBook();
}
// 借阅图书
public void borrowBook() {
scanner.nextLine();
System.out.println("请输入你要借阅的图书 id:");
int bookId = scanner.nextInt();
scanner.nextLine();
// 如果书架没有书 不能借阅
if (library.bookCount == 0) {
System.out.println("书架没有书籍暂时不能借阅");
return;
}
// 加载已借阅的图书信息
loadBorrowedBook();
// 判断要借阅的书 是否存在
Book book = library.searchById(bookId);
if (book == null) {
System.out.println("没有该 id 相关书籍:" + bookId);
return;
}
// 开始准备借阅图书
for (int i = 0; i < borrowedCount; i++) {
PairOfUidAndBookId pairOfUidAndBookIds1 = pairOfUidAndBookIds[i];
if (pairOfUidAndBookIds1.getBookId() == book.getBookId()) {
// getUserID 当前用户 ID
if (pairOfUidAndBookIds1.getUserID() == getUserID()) {
System.out.println("这本书自己已经借阅过");
return;
} else {
System.out.println("这本书别人已经借阅过");
return;
}
}
}
library.borrowBook(bookId); // 修正拼写错误
// 写入借阅书籍的 txt
PairOfUidAndBookId pairOfUidAndBookId = new PairOfUidAndBookId(getUserID(), book.getBookId());
pairOfUidAndBookIds[borrowedCount % 4] = pairOfUidAndBookId;
borrowedCount++;
storeBorrowBook();
System.out.println("借阅书籍成功");
}
public void borrowBook(int bookId) {
loadAllBook();
Book book = searchById(bookId);
book.setBorrowed(true);
book.incrementBorrowCount();
storeBook();
}
// 归还图书
public void returnBook() {
System.out.println("代理类 returnBook 方法执行了");
checkRealUserWhetherNormalUser("管理员不能归还图书,请换做普通用户来归还");
((NormalUser)(this.realUser)).returnBook();
}
// 归还图书
public void returnBook() {
loadBorrowedBook();
if (borrowedCount == 0) {
System.out.println("目前没有用户借阅过书籍");
return;
}
scanner.nextLine();
System.out.println("请输入你要归还的书籍 ID:");
int bookId = scanner.nextInt();
scanner.nextLine();
// 判断要借阅的书 是否已经被自己借阅过了
Book book = library.searchById(bookId);
if (book == null) {
System.out.println("没有该 Id 相关的书籍:" + bookId);
return;
}
for (int i = 0; i < borrowedCount; i++) {
// 判断书的 ID 是否相同
if (pairOfUidAndBookIds[i].getBookId() == book.getBookId()) {
// 判断用户 ID
if (getUserID() == pairOfUidAndBookIds[i].getUserId()) {
library.returnBook(bookId);
System.out.println("图书 '" + book.getTitle() + "'已成功归还");
// 用最后一本书替换归还掉的书
pairOfUidAndBookIds[i] = pairOfUidAndBookIds[borrowedCount - 1];
// 清空最后一个
pairOfUidAndBookIds[borrowedCount - 1] = null;
borrowedCount--;
storeBorrowBook();
} else {
System.out.println("该图书不是你借阅的,无法归还:" + book.getTitle());
}
return;
}
}
}
public void returnBook(int bookId) {
loadAllBook();
Book book = searchById(bookId);
book.setBorrowed(false);
book.decreaseBorrowCount();
storeBook();
}
// 查看当前个人借阅情况
public void viewBorrowHistory() {
System.out.println("代理类 viewBorrowHistory 方法执行了");
checkRealUserWhetherNormalUser("管理员不能查看图书,请换做普通用户来查看");
((NormalUser)(this.realUser)).viewBorrowHistory();
}
// 查看当前个人借阅情况
public void viewBorrowHistory() {
loadBorrowedBook();
System.out.println("借阅情况如下:");
if (borrowedCount == 0) {
System.out.println("目前没有借阅记录");
} else {
boolean flg = false;
for (int i = 0; i < borrowedCount; i++) {
// 用户 id 相同时,查看书籍 id
if (pairOfUidAndBookIds[i].getUserID() == getUserID()) {
flg = true;
Book book = library.searchById(pairOfUidAndBookIds[i].getBookId());
System.out.println(book);
}
}
if (!flg) {
System.out.println("你没有借阅过书籍");
}
}
}
运用的工厂,代理模式,可以参考相关设计模式详解。
public class LibrarySystem {
public static void main(String[] args) {
// 工厂模式
IUserFactory adminUserFactory = new AdminUserFactory();
User adminUser = adminUserFactory.createUser("王先生", 1);
IUserFactory normalUserFactory = new NormalUserFactory();
User normal1 = normalUserFactory.createUser("小白", 2);
User normal2 = normalUserFactory.createUser("小飞", 3);
// 代理模式
ProxyUser proxyUserAdmin = new ProxyUser(adminUser);
ProxyUser proxyUserNormal1 = new ProxyUser(normal1);
ProxyUser proxyUserNormal2 = new ProxyUser(normal2);
LibrarySystem librarySystem = new LibrarySystem();
ProxyUser currentUser = librarySystem.selectProxyRole(proxyUserAdmin, proxyUserNormal1, proxyUserNormal2);
while (true) {
int choice = currentUser.display();
// 选择 choice 就执行这个用户的某个操作
currentUser.handleOperation(choice);
}
}
public ProxyUser selectProxyRole(ProxyUser proxyUserAdmin, ProxyUser proxyUsernormal1, ProxyUser proxyUsernormal2) {
System.out.println("选择角色进行登录:");
System.out.println("1. 管理员\n2. 普通用户 (小白)\n3. 普通用户 (小飞)\n4. 退出系统 ");
ProxyUser currentUser = null;
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
switch (choice) {
case 1: currentUser = proxyUserAdmin; break;
case 2: currentUser = proxyUsernormal1; break;
case 3: currentUser = proxyUsernormal2; break;
case 4: System.exit(0); System.out.println("退出系统了"); break;
default: break;
}
return currentUser;
}
}
【总结】
通过图书管理系统的开发,我对 JavaSE 的核心知识点有了更深入的理解:熟练运用面向对象思想(封装、继承、多态)进行类设计。理解单例模式、代理模式等设计模式在实际项目中的应用。提升了调试能力,能快速定位并解决空指针、数组越界等常见异常。这个项目不仅巩固了 JavaSE 知识,也让我体会到软件开发的完整流程,从需求分析、模块设计到编码实现、调试优化,每一步都需要严谨的思考与实践。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online