✨在上个文章中我们介绍了图书管理系统📖,但是功能并不是很齐全,所以在本篇文章中,我又增加了几个功能:
为了方便大家阅读,已经把完整的代码放到下面啦!如果时第一次看到本篇文章的伙伴,可以先点上面链接看详细讲解版本🎊
1.根据用户的喜好,推荐相应类型的书籍
2.检查是否有逾期书籍,并将检查时间与借书时间保存文本文件中
3.当查找书目时,仅输入“西”或“西游”或“游记”就能找到《西游记》(模糊匹配)
1.library包
1.1Book类
package library;
//增加代码
import java.time.LocalDate;
//一本书
public class Book {//现实世界的书
private String name;
private String author;
private String type;
private double price;
private boolean isBorrowed;
// 增加代码
private LocalDate borrowDate; // 借阅日期
private LocalDate dueDate; // 应归还日期
public Book(String name, String author, String type, double price){
this.name=name;
this.author=author;
this.type=type;
this.price=price;
this.isBorrowed=false;
}
//alt+ins自动生成
//get,set方法可以随时更改属性,但是构造方法只能初始化一次
//增加代码
public LocalDate getBorrowDate() {
return borrowDate;
}
public void setBorrowDate(LocalDate borrowDate) {
this.borrowDate = borrowDate;
}
public LocalDate getDueDate() {
return dueDate;
}
public void setDueDate(LocalDate dueDate) {
this.dueDate = dueDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean borrowed) {
isBorrowed = borrowed;
}
@Override
public String toString() {//当执行打印操作时会默认调用
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", type='" + type + '\'' +
", price=" + price +
", isBorrowed=" + (isBorrowed?"已借出":"未借出") +
'}';
}
}
1.2BookList类
package library;
public class BookList {
private Book[] books=new Book[1024];//此数组中每个类型都是Book类类型
//长度不方便灵活调整,预先创造大空间
//把booklist想象为一个书架,书架总共有1024个位置,不能修改大小,所以设置为private
//长度不方便灵活调整,预先创造大空间
private int size =0;//有效元素
public BookList() {
books[0] = new Book("西游记", "吴承恩", "古典小说", 100);//books[0]中存放的是一组实例对象
books[1] = new Book("红楼梦", "曹雪芹", "古典小说", 90);
books[2] = new Book("高等数学", "高斯", "数学", 40);
books[3] = new Book("Java入门", "詹姆斯高斯林", "计算机", 70);
books[4] = new Book("红楼梦", "曹雪芹", "古典小说", 90);
books[5] = new Book("三体", "刘慈欣", "科幻小说", 65);
books[6] = new Book("Python编程", "Eric Matthes", "计算机", 75);
books[7] = new Book("活着", "余华", "文学", 50);
books[8] = new Book("C++ Primer", "Stanley Lippman", "计算机", 120);
books[9] = new Book("百年孤独", "马尔克斯", "文学", 78);
size = 10;
}
public Book getBook(int index) {//得到序号为index的书籍
return books[index];//不会越界,因为此时还没满
}
public void setBook(int index,Book book) {
books[index] = book;
}//将序号index处设置为××书
public int getSize() {
return size;//有效书籍数量
}
public void setSize(int size) {
this.size = size;//设置有效书籍数量
}
}
1.3Main类
package library;
import library.user.NormalUser;
import library.user.User;
import library.user.Admin;
import java.util.Scanner;
public class Main {
private static User login(){
System.out.println("请输入您的姓名:");
Scanner scanner =new Scanner(System.in);
String name = scanner.next();
System.out.println("请输入您的角色(1.普通用户2.管理员)");
int role = scanner.nextInt();
if (role==1){
return new NormalUser(name);
}else if(role==2){
return new Admin(name);
}else{
System.out.println("输入的角色有误");
return null;
}
}
public static void main(String[] args) {
//书记管理
library.BookList booklist=new BookList();
//管理员和普通用户让用户选择
User user = login();
//User user=new NormalUser(name)
//User user=new Admin(name)
//向上转型
while(true){
int choice = user.menu();//多态
user.work(choice,booklist);//将选择的菜单与书籍列表传入,假如是查找,普通用户
}
}
}
2.Operation包
2.1AddOperation类
package library.Operation;
import library.user.User;
import library.Book;
import library.BookList;
import java.util.Scanner;
public class AddOperation implements IOperation {
@Override
public void work(User user,BookList bookList) {
System.out.println("新增图书");
Scanner scanner=new Scanner(System.in);
System.out.println("请输入书名:");
String name = scanner.next();
System.out.println("请输入作者:");
String author =scanner.next();
System.out.println("请输入价格");
double price = scanner.nextDouble();
System.out.println("请输入类别");
String type=scanner.next();
Book book =new Book(name,author,type,price);
int size=bookList.getSize();
bookList.setBook(size,book);//传入book就相当于传入引用的空间
bookList.setSize(size+1);//不能忘了修改size
System.out.println("新增图书完成!");
}
}
2.2BorrowOperation类
package library.Operation;
import library.Book;
import library.BookList;
import library.user.User;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;
public class BorrowOperation implements IOperation {
@Override
public void work(User user,BookList bookList) {
System.out.println("借书");
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要借阅的图书编号:");
int id= scanner.nextInt();
if(id<0||id>=bookList.getSize()){
System.out.println("输入错误");
return;
}
Book book=bookList.getBook(id);//获取第id本书对象
if(book.isBorrowed()){//先判断一下是否被借出
System.out.println("该书已经被借出了");//如果真就被借出了
return;
}
book.setBorrowed(true);
book.setBorrowDate(LocalDate.now());
book.setDueDate(LocalDate.now().plusDays(1)); // 两周后到期
// 记录用户的借阅类型以用于推荐
user.recordBorrowedType(book.getType());
// 新增:将借书记录写入文件
try (BufferedWriter writer = new BufferedWriter(new FileWriter(CheckOverdueOperation.OVERDUE_FILE, true))) {
String timestamp = LocalDate.now().format(DateTimeFormatter.ISO_DATE);
writer.write("=== 借书操作时间: " + timestamp + " ===");
writer.newLine();
writer.write("书名: " + book.getName()
+ ", 借阅日期: " + book.getBorrowDate()
+ ", 应归还日期: " + book.getDueDate());
writer.newLine();
writer.newLine(); // 空行分隔不同记录
} catch (IOException e) {
System.out.println("警告:借书记录保存失败,但借书操作已成功。错误信息: " + e.getMessage());
}
//book.setBorrowed(true);//没借出我就可以借了
System.out.println("借书成功!");
//增加代码
System.out.println("应归还日期:" + book.getDueDate());
}
}
2.3CheckOverdueOperation类
//package library.Operation;
//
//
//
//import library.Book;
//import library.BookList;
//import library.user.User;
//
//import java.time.LocalDate;//增加
//import java.util.Scanner;
//
//public class CheckOverdueOperation implements IOperation {
// @Override
// public void work(User user,BookList bookList) {
// boolean a=false;
// System.out.println("=== 逾期书籍检查 ===");
// for (int i = 0; i < bookList.getSize(); i++) {
// Book book = bookList.getBook(i);//获取每一本书
// if (book.isBorrowed() && LocalDate.now().isAfter(book.getDueDate())) {//
// //isAfter用来检测一个日期是否在另一个日期之后
// a=true;
// System.out.println("逾期书籍:" + book.getName() + " 应归还日期:" + book.getDueDate());
// }
// }
// if(!a){
// System.out.println("当前没有逾期未归还的书籍");
// }
// }
//}
package library.Operation;
import library.Book;
import library.BookList;
import library.user.User;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
public class CheckOverdueOperation implements IOperation {
public static final String OVERDUE_FILE = "overdue_books.txt"; // 保存逾期记录的文件
@Override
public void work(User user, BookList bookList) {
System.out.println("=== 逾期书籍检查 ===");
boolean hasOverdue = false;
try (BufferedWriter writer = new BufferedWriter(new FileWriter(OVERDUE_FILE, true))) { // true 表示追加模式
// 写入检查时间
String timestamp = LocalDate.now().format(DateTimeFormatter.ISO_DATE);
writer.write("=== 检查时间: " + timestamp + " ===");
writer.newLine();
// 遍历书籍
for (int i = 0; i < bookList.getSize(); i++) {
Book book = bookList.getBook(i);
if (book.isBorrowed() && LocalDate.now().isAfter(book.getDueDate())) {
// 控制台输出
System.out.println("逾期书籍:" + book.getName() + " 应归还日期:" + book.getDueDate());
// 写入文件
writer.write("书名: " + book.getName()
+ ", 应归还日期: " + book.getDueDate());
writer.newLine();
hasOverdue = true;
}
}
if (!hasOverdue) {
System.out.println("当前没有逾期未归还的书籍");
writer.write("无逾期书籍");
writer.newLine();
}
writer.newLine(); // 空行分隔不同检查记录
} catch (IOException e) {
System.out.println("保存逾期记录失败: " + e.getMessage());
}
}
}
2.4DelOperation类
package library.Operation;
import library.Book;
import library.BookList;
import java.util.Scanner;
import library.user.User;
public class DelOperation implements IOperation {
@Override
public void work(User user,BookList bookList) {
System.out.println("删除书籍");
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要删除书籍的序号:");
int index=scanner.nextInt();
if(index<0||index>=bookList.getSize()) {
System.out.println("序号超出范围");
return;
}
if(index == bookList.getSize()-1){
bookList.setSize(bookList.getSize()-1);//如果是最后一本书,直接将有效元素设置为size-1即可
}else{//如果删除中间元素,就可以把最后一个元素,复制到待删除元素的位置上,然后size-1即可
Book lastBook = bookList.getBook(bookList.getSize()-1);//先获取到最后一本书
bookList.setBook(index,lastBook);
bookList.setSize(bookList.getSize()-1);
}
System.out.println("删除书籍完成!");
}
}
2.5ExitOperation类
package library.Operation;
import library.BookList;
import library.user.User;
public class ExitOperation implements IOperation {
@Override
public void work(User user,BookList bookList) {
System.out.println("goodbye!");
System.exit(0);//结束程序的方法
}
}
2.6FindOperation类
package library.Operation;
import library.Book;
import library.BookList;
import library.user.User;
import java.util.Scanner;
public class FindOperation implements IOperation {
@Override
public void work(User user, BookList bookList) {
System.out.println("查找操作");
Scanner scanner = new Scanner(System.in);
//新增代码
System.out.println("请输入查找的书名(支持模糊匹配):");
String keyword = scanner.next();
boolean found = false;
for (int i = 0; i < bookList.getSize(); i++) {
Book book = bookList.getBook(i);
// 使用 contains 实现模糊匹配
if (book.getName().contains(keyword)) {
System.out.println(book);
found = true;
}
}
if (!found) {
System.out.println("未找到包含 \"" + keyword + "\" 的书籍");
}
System.out.println("查找完毕");
}
}
2.7 IOperation接口
package library.Operation;
import library.user.User;
import library.BookList;
public interface IOperation {
// 理论上是可行的,但是不加接口的话,无法保证所有的类都提供了work方法,也没法保证work方法的参数都是相同的。
// 而加上后就能强制统一,方便后续的调用,否则如果大家提供的方法各不相同,就会显得很乱。
//也可以使用抽象类,但是我这个接口我只想保存一些方法,并没有什么实例属性要继承的
//并且不能多继承
//而User中的类是抽象性,因为我们需要继承name的属性
void work(User user,BookList bookList);
//在每一个操作中都要
}
2.8 ListOperation类
package library.Operation;
import library.user.User;
import library.Book;
import library.BookList;
public class ListOperation implements IOperation {
@Override
public void work(User user,BookList bookList) {
System.out.println("查看书籍列表");
for(int i=0;i<bookList.getSize();i++){
Book book = bookList.getBook(i);//拿到第i本书
System.out.println("["+i+"]"+book);//进入到BookList类中,调用toString方法
}
}
}
2.9 RecommendOperation类
package library.Operation;
//新建RecommendOperation.java
import library.Book;
import library.BookList;
import library.user.User;
public class RecommendOperation implements IOperation {
@Override
public void work(User user, BookList bookList) {
System.out.println("=== 根据您的喜好推荐 ===");
String favoriteType = user.getFavoriteType();
System.out.println("根据您的阅读历史,我们推荐以下" + favoriteType + "类书籍:");
int count = 0;
for (int i = 0; i < bookList.getSize(); i++) {
Book book = bookList.getBook(i);
if (book.getType().equals(favoriteType) && !book.isBorrowed()) {
System.out.println("《" + book.getName() + "》" + " - " + book.getAuthor());
count++;
if (count >= 3) break; // 最多推荐3本
}
}
if (count == 0) {
System.out.println("暂时没有找到相关推荐,试试其他类型的书籍吧!");
}
}
}
2.10 ReturnOperation类
package library.Operation;
import library.user.User;
import library.Book;
import library.BookList;
import java.util.Scanner;
public class ReturnOperation implements IOperation {
@Override
public void work(User user,BookList bookList) {
System.out.println("还书");
Scanner scanner=new Scanner(System.in);
System.out.println("请输入要归还的图书编号:");
int id= scanner.nextInt();
if(id<0||id>=bookList.getSize()){
System.out.println("输入错误");
return;
}
Book book=bookList.getBook(id);
if(!book.isBorrowed()){//先判断一下是否被借出false
System.out.println("该书没借出,不能归还");//如果没被借出了,就不能换
return;
}
book.setBorrowed(false);
System.out.println("还书成功!");
}
}
3.user包
3.1Admin
package library.user;
import library.Operation.IOperation;
import library.Operation.*;
import java.util.Scanner;
public class Admin extends User{
//private IOperation[] operations;//存放管理员的方法,这是什么类型呢,接口类型
//写到父类即可
public Admin(String name) {
super(name);
operations=new IOperation[]{
new ExitOperation(),//0
new ListOperation(),//1
new FindOperation(),//2
new AddOperation(),//3
new DelOperation(),//4
};
}
@Override
public int menu() {
System.out.println("==============================");
System.out.println("欢迎您,"+name+"!");
System.out.println("1.查看书籍列表");
System.out.println("2.按照名字查找图书");
System.out.println("3.新增图书");
System.out.println("4.删除图书");
System.out.println("0.退出");
System.out.println("===============================");
System.out.println("请输入您的操作:");
Scanner scanner=new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
3.2NormalUser
package library.user;
import library.Operation.IOperation;
import library.Operation.*;
import java.util.Scanner;
public class NormalUser extends User {
//private IOperation[] operations;
public NormalUser(String name) {
super(name);
//对所要的方法进行初始化
operations = new IOperation[]{//普通用户进行的操作
new ExitOperation(),//这是一个数组,此处下标为0
new ListOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation(),
new CheckOverdueOperation(), // 新增逾期检查
new RecommendOperation(), // 新增推荐功能
};
}
@Override
public int menu() {
//打印菜单
System.out.println("==============================");
System.out.println("欢迎你,"+name+"!");
//查看书籍列表
//查找图书
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("0.退出");
System.out.println("===============================");
System.out.println("请输入您的操作:");
Scanner scanner=new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
3.3User
package library.user;
import java.util.HashMap;
import library.BookList;
import library.Operation.IOperation;
import java.util.Map;
public abstract class User {
//不同 的用户不同的操作
protected String name;//各个子类都有的内容,直接放在父类中
//protected子类可以直接获取到,不必再去用getter setter
protected IOperation[] operations;
//当前这个类能进行那些操作,就往这个数组里添加对应的对象
public User(String name){
this.name=name;
}
public abstract int menu();//不知道父类的菜单(父类就没有菜单),我知道的只有管理员和用户的菜单
// 所以使用abstract,子类再进行重写
//为了避免父类被不小心创建出实例,所以要抽象(因为不能出现“父类菜单”)
// 新增代码
protected Map<String, Integer> borrowHistory = new HashMap<>(); // 新增:借阅类型统计
// 新增:记录借阅类型
public void recordBorrowedType(String type) {
borrowHistory.put(type, borrowHistory.getOrDefault(type, 0) + 1);
//使用put方法加入键值对,type存在返回对应的值,否则返回0
//put的作用是向Map集合中添加键值对,或者更新已经存在的键值对{文学,0}
}
// 新增:获取最常借阅的类型
public String getFavoriteType() {
String favorite = "未知";
int maxCount = 0;
for (Map.Entry<String, Integer> entry : borrowHistory.entrySet()) {
//entrySet用于返回一个包含Map中所有键值对的集合
//Map.Entry用来表示一个键值对实体
if (entry.getValue() > maxCount) {
maxCount = entry.getValue();
favorite = entry.getKey();
}
}
return favorite;
}
public void work(int choice, BookList bookList){//3.进入到父类的work方法
if(choice<0||choice>=operations.length){
System.out.println("输入的选项非法");
return;
}
operations[choice].work(this,bookList);//4.调用我选择的方法里面的work方法,就能用此方法对booklist进行操作了
}
}