目录
前言
今天给大家介绍的是一项Java综合项目——图书管理系统。本项目是一个完整的综合项目,其中结合文件IO流,实现了操作当中所有信息动态永久存储的效果,并且具有一定的实用性。那接下来就请跟紧博主的脚步,一起来领略本项目的魅力吧~

历经一周的时间博主夜以继日的完成了该项目,几千行的代码其中并不缺乏让我抓狂的地方,但最终还是被拿下,不得不说还是有一丢丢的成就感,相信平时在写项目代码的你们也会有同样的感觉,或许这就是编程的魅力所在。
项目需求
本项目的设计需求较为广阔,总体来说可以算是没有具体的需求,然而具体的操作以及实现效果全凭自己根据实际情况进行分析判断,然后再进行设计,以此实现基本的功能操作即可。
项目功能结构图:

项目设计
博主在刚开始接触到本项目的时候最看重的就是功能结构图,这才是核心所在,每个模块的功能需求一览无遗。根据先易后难的这个原则,首先设计的是主界面、用户管理模块。
主界面
设计思路:该部分的代码简单,根据简单的判断和流程设计即可实现。
主界面代码结构图:

界面效果:

用户管理
设计思路:定义全局变量文件路径和用户id,通过Properties集合实现与文件信息的交互,用户id作为键,用户名和密码作为值保存到集合然后存储到文件,用户名和密码通过","隔开,方便单独获取值,用split()方法分割字符串。(其他模块数据与文件交互的地方都是这样实现,只是键和值的设计不同)总体来说该部分设计还是比较简单,注意一下实现流程和操作判断就可以了。
注意:存储到文件中的记录信息是无序的,为了让查询的时候有序排列,就要将从文件中读取信息的Properties集合中的数据赋值给TreeMap集合,然后再进行显示输出就是有序的排列。(其他模块的数据读取也是如此)

用户属性:用户ID、用户名、密码。
用户管理代码结构图:

登录部分的代码:
public String userLogin() throws IOException {
System.out.println("~请您先进行登录~");
//判断存放用户信息的文件是否存在,不存在就创建
if (!file.exists()) {
file.createNewFile();
}
//调用工具类中的方法,将文件内容读到集合
Properties prop = TSUtility.fileReadProperties(file);
//集合无信息先进行注册
if (prop.size() == 0) {
System.out.println("当前无用户信息,请您先进行注册!");
//调用注册的方法,并给定一个参数,用于日志打印的记录信息
userRegister("此时无账号,第一个用户");
System.out.println("请您登录...");
}
//注册成功之后再把文件内容读到集合(更新读取文件数据)
prop = TSUtility.fileReadProperties(file);
//调用方法,判断用户名
String userName = isUserName();
//判断密码
System.out.print("密码:");
String userPw = sc.next();
int n = -1; //设置一个状态值,用于判断密码是否正确
while (true) {
Set<String> strings = prop.stringPropertyNames();
for (String key : strings) {
//判断密码是否正确
if (userPw.equals(prop.getProperty(key).split(",")[1])) {
n++;
break;
}
}
if (n == -1) {
System.out.print("密码错误!重新输入:");
String newUserPw = sc.next();
userPw = newUserPw; //输入的值赋值给userPw用于循环判断
} else {
System.out.println("登录成功! 欢迎您:" + userName);
//调用工具类,将用户的操作信息保存到文件(日志)
TSUtility.writeToFile(userName+"登录系统");
return userName;
}
}
}
然后再分析接下来的几个模块,还是根据先易后难的原则,博主选择设计的顺序是读者信息管理、图书信息管理、基本信息维护。
读者信息管理
设计思路:读者id作为键,其他属性作为值保存到集合然后存储到文件。该部分的设计也就是一些增删改查,但要注意的是各个限制条件一定要思考的全面(比如修改读者信息时,首先进行判断是否存在读者信息,其次判断用户输入的id是否合理,然后再看该读者是否借书还未归还),以及判断顺序(也就是以上三种判断的顺序,很显然首先应该判断的就是是否存在读者信息,然而如果首先判断用户输入的id就不太合理)
读者属性:读者ID、姓名、性别、电话、出生日期、所在院系、注册日期、类别、可借阅数量、可借阅天数。
读者管理代码结构图:

修改读者部分的代码:
public void updateReader(String userName) throws IOException, CustomizeException {
//使用工具类,文件内容读到集合
Properties prop = TSUtility.fileReadProperties(file);
//判断集合中是否有数据
if (prop.size() == 0) {
//自定义异常
throw new CustomizeException("当前无任何读者信息!");
} else {
showAllReaderInfo(prop);
System.out.println("注意:借阅图书还未归还的读者不能被修改!");
System.out.print("请输入要修改的读者ID(-1退出修改):");
String s = sc.next();
if (s.equals("-1")){
System.out.println("已退出修改!");
}else {
String readerId = TSUtility.isId(prop, s);
//调用方法,判断读者是否借书还未归还
Properties readerTypeProp = TSUtility.fileReadProperties(file1);
boolean b = isReaderNoReturn(prop, readerId, readerTypeProp);
if (b) {
throw new CustomizeException("该读者有借阅的图书未归还,不能修改!");
} else {
//实现不修改就按回车返回之前的值
System.out.print("姓名(" + prop.getProperty(readerId).split(",")[0] + "):");
String readerName = TSUtility.readString(4,prop.getProperty(readerId).split(",")[0]);
System.out.print("姓别(" + prop.getProperty(readerId).split(",")[1] + "):");
String ss = TSUtility.readString(1,prop.getProperty(readerId).split(",")[1]);
char readerSex = TSUtility.isSex(ss);
System.out.print("电话(6-11位)(" + prop.getProperty(readerId).split(",")[2] + "):");
String s1 = TSUtility.readString(11,prop.getProperty(readerId).split(",")[2]);
String readerTell = TSUtility.isTell(s1);
System.out.println("出生日期(" + prop.getProperty(readerId).split(",")[3] + "):");
Date readerBirthDay = TSUtility.newInputDay(prop.getProperty(readerId).split(",")[3]);
System.out.print("所在院系(" + prop.getProperty(readerId).split(",")[4] + "):");
String readerCollege = TSUtility.readString(12,prop.getProperty(readerId).split(",")[4]);
//修改集合并保存到文件
prop.setProperty(readerId, readerName + "," + readerSex + "," + readerTell + "," + readerBirthDay + ","
+ readerCollege + "," + prop.getProperty(readerId).split(",")[5] + ",null,0,0");
FileWriter fw = new FileWriter(file);
prop.store(fw, "------ReaderInfo------");
fw.close();
//调用工具类,将用户的操作信息保存到文件(日志)
TSUtility.writeToFile(userName+"修改了一位读者信息");
System.out.println("修改读者成功!");
}
}
}
}
图书信息管理
设计思路:图书id作为键,其他属性作为值保存到集合然后存储到文件。(该部分的设计与读者信息大同小异)
图书属性:图书ID、名称、作者、出版社、出版日期、实际数量、总量、单价、类别、状态。
图书管理代码结构图:

删除图书部分的代码:
public void deleteBook(String userName) throws IOException,CustomizeException {
//文件内容读到集合
Properties prop = TSUtility.fileReadProperties(file);
//判断集合中是否有数据
if (prop.size() == 0) {
throw new CustomizeException("当前无任何图书信息!");
} else {
//调用方法,显示所有图书信息
showAllBookInfo(prop);
System.out.println("注意:已被借阅的图书不能被删除!");
System.out.print("请输入要删除的图书ID:");
String s = sc.next();
//调用工具类中的方法,获取正确的图书id
String bookId = TSUtility.isId(prop, s);
if (prop.getProperty(bookId).split(",")[8].equals("已被借阅")) {
throw new CustomizeException("该图书已被借阅,不能删除!");
} else {
System.out.println("确定删除?(Y/N)");
char c = TSUtility.readConfirmSelection();
if (c == 'Y') {
//调用工具类中的方法,删除选择的图书
Properties newprop = TSUtility.deletePropertiesElement(bookId, prop);
//集合中的内容写到文件
FileWriter fw = new FileWriter(file);
newprop.store(fw, "------BookInfo------");
fw.close();
TSUtility.writeToFile(userName+"删除了一本图书");
System.out.println("删除图书成功!");
} else {
System.out.println("已取消删除!");
}
}
}
}
基本信息维护
设计思路:该部分包括图书类别设置、读者类别设置、罚金设置。其中图书类别设置是以图书类别id作为键,类别名作为值保存到集合然后存储到文件,读者类别设置是以读者类别id作为键,其他属性作为值保存到集合然后存储到文件。罚金初始化为零,由用户进行设置不同类别的罚金。
图书类别属性:图书类别ID、类别名。
读者类别属性:读者类别ID、类别名、可借阅数量、可借阅天数、罚金。
读者类别代码结构图:

读者分类部分的代码:
public static void addReaderToReaderType(String userName) throws IOException, CustomizeException {
//文件内容读到集合
Properties prop = TSUtility.fileReadProperties(file);
if (prop.size() == 0) {
throw new CustomizeException("暂无读者类别信息!");
} else {
//读者信息读到一个新集合
Properties propReader = TSUtility.fileReadProperties(file1);
//显示所有读者信息
rs.showAllReaderInfo(propReader);
if (propReader.size() == 0) {
throw new CustomizeException("暂无读者信息!");
} else {
Set<String> strings = propReader.stringPropertyNames();
int n = -1; //状态值,用于判断是否还有未分类的读者
//判断是否还有未分类的读者
for (String key : strings) {
if (propReader.getProperty(key).split(",")[6].equals("null")) {
n++;
break;
}
}
if (n == -1) {
System.out.println("读者已全部被分类,无法添加读者类别!");
} else {
String readerTypeName = isReaderTypeName();
String readerTypeId = returnReaderTypeId(readerTypeName);
System.out.print("请输入想要添加到此类别的读者ID:");
String readerId = sc.next();
int n1 = -1; //定义一个状态值,用于判断读者id是否存在
while (true) {
//判断输入的读者ID是否存在
for (String key : strings) {
if (key.equals(readerId)) {
n1++;
break;
}
}
if (n1 == -1) {
System.out.print("输入错误!重新输入:");
String newReaderTypeId = sc.next();
readerId = newReaderTypeId; //重新输入的值赋值给原来的参与判断
} else {
if (!propReader.getProperty(readerId).split(",")[6].equals("null")) {
System.out.println("该读者已被分类!");
} else {
//修改集合并保存到文件
propReader.setProperty(readerId, propReader.getProperty(readerId).split(",")[0] + ","
+ propReader.getProperty(readerId).split(",")[1] + ","
+ propReader.getProperty(readerId).split(",")[2] + ","
+ propReader.getProperty(readerId).split(",")[3] + ","
+ propReader.getProperty(readerId).split(",")[4] + ","
+ propReader.getProperty(readerId).split(",")[5] + "," + readerTypeName + ","
+ prop.getProperty(readerTypeId).split(",")[1] + ","
+ prop.getProperty(readerTypeId).split(",")[2]);
FileWriter fw = new FileWriter(file1);
propReader.store(fw, "------ReaderInfo------");
fw.close();
TSUtility.writeToFile(userName+"给一个读者分了类");
System.out.println("读者分类成功!");
}
break;
}
}
}
}
TSUtility.readReturn();
}
}
同学们请注意,重点来了,本项目最主要的功能就是实现图书的借阅与归还。其中涉及到读者和图书的属性变化,还有各个限制条件,思考清楚了再进行代码的编写十分必要!!!

前几个模块写起来还算是得心应手,最后这个主要的功能设计时就要格外的注意属性值的变化和操作的条件判断。
图书借阅管理
设计思路:读者id和姓名作为键,其他属性作为值保存到集合然后存储到文件。
借阅图书时首先要进行多重判断(是否存在图书、是否存在读者、是否有已经分类的读者、该读者是否已经借阅过该图书、该图书的实际数量是否为零...),然后再将读者可借阅数量减一,图书的实际数量减一,然后把借阅记录保存到文件并保存到借阅归还的日志文件。
归还图书时首先也要进行判断,是否存在借阅图书的信息,根据归还日期和最迟归还日期判断该读者是否逾期归还:如果未逾期,将读者的可借阅数量加一、图书的实际数量加一;如果预期归还,将要根据预期的天数和该类别的罚金进行计算,交罚金后才可视为归还成功,归还成功后删除借阅文件中的此条记录信息,然后再将信息保存到借阅归还的日志文件。
图书借阅属性:读者ID、姓名、图书ID、名称、借阅日期、最迟归还日期、归还日期、状态、罚金。
图书借阅代码结构图:

图书借阅部分的代码:
public void bookLend(String userName) throws IOException, CustomizeException {
if (!borrowFile.exists()) {
borrowFile.createNewFile();
}
if (!borrowLogFile.exists()) {
borrowLogFile.createNewFile();
}
//读者文件内容读到集合
Properties readerProp = TSUtility.fileReadProperties(readerFile);
if (readerProp.size() == 0) {
throw new CustomizeException("当前无读者信息!");
} else {
//图书文件内容读到集合
Properties bookProp = TSUtility.fileReadProperties(bookFile);
if (bookProp.size() == 0) {
throw new CustomizeException("当前无图书信息!");
} else {
int n = -1; //定义一个状态值
//判断是否有已分类的读者
Set<String> strings = readerProp.stringPropertyNames();
for (String key : strings) {
if (!readerProp.getProperty(key).split(",")[6].equals("null")) {
n++;
break;
}
}
if (n == -1) {
throw new CustomizeException("当前不存在已分类的读者,分类后才可以借阅!");
} else {
rs.showAllReaderInfo(readerProp);
System.out.print("请输入已分类的读者ID:");
String s = sc.next();
String readerId = rs.isTypeReaderId(readerProp, s);
//创建集合保存数据到文件,借阅信息
Properties borrowProp = TSUtility.fileReadProperties(borrowFile);
//获取集合的键:读者ID+姓名
String key = readerId + "," + readerProp.getProperty(readerId).split(",")[0];
//判断是否有相同的读者信息,相同则改变一下键的值,不然存不进去
Set<String> strings1 = borrowProp.stringPropertyNames();
for (String key1 : strings1){
if (key1.equals(key)){
key = readerId + "," + readerProp.getProperty(readerId).split(",")[0]+" ";
break;
}
}
if (Integer.parseInt(readerProp.getProperty(readerId).split(",")[7]) == 0) {
System.out.println("读者可借阅的图书数量已达到上限!");
} else {
bs.showAllBookInfo(bookProp);
System.out.print("请输入想要借阅的图书ID:");
String s1 = sc.next();
String bookId = TSUtility.isId(bookProp, s1);
int n1 = -1;
//判断借阅文件中的读者是否已经借阅过该图书,不能重复借阅
for (String ss : strings1){
if (key.trim().equals(ss) && ss.split(",")[0].equals(bookId)){
n1++;
}
}
if (n1 != -1){
System.out.println("读者已经借阅过该图书,不能重复借阅!");
}else {
//判断输入的图书ID实际数量是否为零
if (Integer.parseInt(bookProp.getProperty(bookId).split(",")[4]) == 0) {
System.out.println("图书实际数量为零,不能进行借阅!");
} else {
System.out.println("您借阅的图书是:");
System.out.println("名称:"+bookProp.getProperty(bookId).split(",")[0]+" 作者:"+
bookProp.getProperty(bookId).split(",")[1]+" 出版社:"+
bookProp.getProperty(bookId).split(",")[2]+" 出版日期:"+
bookProp.getProperty(bookId).split(",")[3]);
System.out.println("确定借阅?(Y/N)");
char c = TSUtility.readConfirmSelection();
if (c == 'Y') {
//获取图书的实际数量并减一
String bookNumber = String.valueOf(Integer.parseInt(bookProp.getProperty(bookId).split(",")[4]) - 1);
//修改被借阅的图书实际数量和状态值
bookProp.setProperty(bookId, bookProp.getProperty(bookId).split(",")[0] + ","
+ bookProp.getProperty(bookId).split(",")[1] + ","
+ bookProp.getProperty(bookId).split(",")[2] + ","
+ bookProp.getProperty(bookId).split(",")[3] + ","
+ bookNumber + "," + bookProp.getProperty(bookId).split(",")[5] + ","
+ bookProp.getProperty(bookId).split(",")[6] + ","
+ bookProp.getProperty(bookId).split(",")[7] + ",已被借阅");
//集合内容保存到文件
FileWriter fw = new FileWriter(bookFile);
bookProp.store(fw, "------BookInfo------");
fw.close();
//获取读者借书数量减一
String borrowBooksNumber = String.valueOf(Integer.parseInt(readerProp.getProperty(readerId).split(",")[7]) - 1);
//获取读者可借阅天数
int borrowingDays = Integer.parseInt(readerProp.getProperty(readerId).split(",")[8]);
readerProp.setProperty(readerId, readerProp.getProperty(readerId).split(",")[0] + ","
+ readerProp.getProperty(readerId).split(",")[1] + ","
+ readerProp.getProperty(readerId).split(",")[2] + ","
+ readerProp.getProperty(readerId).split(",")[3] + ","
+ readerProp.getProperty(readerId).split(",")[4] + ","
+ readerProp.getProperty(readerId).split(",")[5] + ","
+ readerProp.getProperty(readerId).split(",")[6] + ","
+ borrowBooksNumber + "," + borrowingDays);
//集合内容保存到文件
FileWriter fw1 = new FileWriter(readerFile);
readerProp.store(fw1, "------ReaderInfo------");
fw1.close();
//设置日期格式
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
String borrowDate = df.format(new java.util.Date());
//获取最迟归还图书的日期
String returnDate = returnDate(borrowingDays);
//借阅信息保存到文件
borrowProp.setProperty(key, bookId + "," + bookProp.getProperty(bookId).split(",")[0]
+ "," + borrowDate + "," + returnDate + ",null,未归还,0");
FileWriter fw2 = new FileWriter(borrowFile);
borrowProp.store(fw2, "------BookBorrowInfo------");
fw2.close();
//记录借阅日志保存到文件
Properties logProp = TSUtility.fileReadProperties(borrowLogFile);
//借阅信息添加到此集合
logProp.setProperty(key, bookId + "," + bookProp.getProperty(bookId).split(",")[0]
+ "," + borrowDate + "," + returnDate + ",null,未归还,0");
FileWriter fw3 = new FileWriter(borrowLogFile);
logProp.store(fw3, "------BookBorrowLog------");
fw3.close();
TSUtility.writeToFile(userName+"处理了一项图书借阅");
System.out.println("借阅图书成功!");
} else {
System.out.println("已取消借阅!");
}
}
}
}
}
}
}
}
本项目创建的包、类、文件:

总结
可以发现博主在多处地方使用了工具类(其中的方法有: 将文件内容读到集合、按指定格式输入有效的日期、集合类型的转换与赋值、删除文件中指定的某条记录...)不得不承认的是工具类是真的很不错,那种用重复的代码而且多个地方都会使用到的功能就可以写成一个方法,然后再放到工具类里面,这样用起来你会收获到意想不到的快乐。

到这里本项目就已经介绍完了,感兴趣的小伙伴可以在博主的主页获取完整代码。
本文详细介绍了一个Java项目,图书管理系统,涉及文件IO流操作,实现用户管理、读者信息管理、图书信息管理,重点在于图书借阅管理的复杂逻辑和持久数据存储。
5331

被折叠的 条评论
为什么被折叠?



