Java实现图书借阅管理系统(IO流存储数据,附源码)

     阅读:28

目录

前言

一、项目概述

1.项目功能结构图

2.项目功能说明

3.项目其他说明

二、开发过程中需要注意的问题

1.开发顺序及思路

2.IO流读写

3.数据共享

4.业务逻辑问题

三、源码链接


前言

        长期以来,人们使用传统的人工方式管理图书馆的日常业务,其操作流程比较烦琐。在借书时,读者首先将要借的书和借阅证交给工作人员,然后工作人员将每本书的信息卡片和读者的借阅证放在一个小格栏里,最后在借阅证和每本书贴的借阅条上填写借阅信息。在还书时,读者首先将要还的书交给工作人员,工作人员根据图书信息找到相应的书卡和借阅证,并填好相应的还书信息。太过于繁琐了!所以,我们需求设计一个图书管理系统来方便学生的借书和图书馆管理书籍。


        在正式开始介绍这个项目之前,我想发表一下我做这个项目的一些感想。说实话,这个项目对我而言,是我学java以来第一次做的最大最难的项目。虽然图书管理这个项目是一个常见的java小白练习项目,但当我自己真正的一句一句代码的编写时才知道什么叫欲哭无泪!o(╥﹏╥)o

        其实现在做完之后感觉也没有那么难了,成就感爆棚!O(∩_∩)O哈哈~  好了,我们言归正传,给大家分享下这个项目一些需要注意的地方。

一、项目概述

1.项目功能结构图

2.项目功能说明

(1)读者信息管理:包括读者信息添加和读者信息查询与修改功能。用户登录成功之后,可以浏览所有读者的信息,也可以检索特定读者的信息;同时,可以对读者信息进行维护,包括增加、删除及修改。具体信息包括读者类型(读者的类型决定着他可以借到书的最大数量和最大归还天数)、读者姓名、出生日期、性别、电话、所在院系、注册日期等。(相关数据可通过I/O流文件中读写

(2)图书信息管理:包括图书信息添加和图书信息查询与修改功能。用户登录成功之后,可以浏览所有图书信息和检索特定图书的信息;也可以对图书信息进行维护。包括添加图书、删除图书以及修改图书信息。具体信息包括:图书ISBN、图书名称、作者、出版社、出版日期、库存数量、单价、图书类别等。(相关数据可通过I/O流文件中读写

(3)图书借阅管理:包括图书借阅和图书归还功能。图书借阅功能,先输入读者的编号,然后输入要借阅的图书的信息,记录系统当前时间即借阅时间;图书归还功能,输入读者的编号,选择其名下已借阅的图书,判断当前日期即归还日期与借阅日期的差值是否超过了规定的期限,计算罚金,从而进行图书的归还操作。具体信息包括:借阅日期、归还日期、罚金。由于要计算罚金,故需要知道该读者的读者类型,根据类型判断其可借图书天数、可借图书数量等。(相关数据可通过I/O流文件中读写

(4)基础信息维护:包括图书类别设置、读者类别设置及罚金设置。图书类别设置,可以对图书的类别进行增加、删除、修改和查询;读者类别设置可以对读者的类别进行增加、删除、修改和查询;罚金设置,可以指定超期一天的罚金标准。(相关数据可通过I/O流文件中读写

(5)用户管理:包括修改密码、用户添加和删除。修改密码,是指当前用户修改自己的密码;用户添加和删除,是对新增和去除系统用户时对用户信息的维护。(相关数据可通过I/O流从文件中读写)

3.项目其他说明

  • 注意命名(类名,包名,方法名,注释等),请严格遵循Java命名规则完成项目。
  • 每一个业务逻辑操作需要加上日志打印功能(用I/o流实现,比如什么时候进行了增删改等操作,需要有记录,或者发现异常了也需要将信息同步在日志文件里)
  • 每个功能模块,如果有异常抛出,需要自定义异常来进行处理。

        由于时间关系,日志打印功能我没有每个业务逻辑操作都加上,只在用户登录和退出系统时加了日志,这个功能非常简单,有多余时间或者追求完美的小伙伴可以把每个业务逻辑都加上。


二、开发过程中需要注意的问题

1.开发顺序及思路

        首先第一个问题就是开发顺序。我们拿到一个项目不能盲目地就开始写代码,一定要仔细研究需求文档,理清各功能模块之间的关系。这次的图书管理系统,我建议的开发顺序是登录及用户管理 —> 基础信息维护 —> 读者信息管理 —> 图书信息管理 —> 图书借阅管理。我采用这个开发顺序的依据是各个模块之间的依赖程度

        登录及用户管理模块与其他模块之间都没有什么关系,它是依赖程度最小的模块,所以我最先开发这个模块。其次是基础信息维护,因为添加读者和图书是要先有类别的,基础信息维护就是对读者和图书类别进行维护的模块,所以它的顺序要先于读者和图书信息管理。然后就是读者和图书了,最后是借阅,因为借阅肯定要先有读者和图书才能借阅嘛。

2.IO流读写

2.1 创建文件读写工具类

        这个图书管理系统的相关数据需要持久化存储到文件中,所以需要进行大量的IO流读写操作,那么为了减少代码量,提高效率,所以我们需要创建一个专门进行文件读写操作的工具类,开发过程中要读写数据时直接调用这个工具类里的方法就可以了。文件读写工具类的代码如下:

○ 文件读写工具类代码

package com.library.util;

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

public class FileOperation {
    //对象序列化方法
    public static <T> void objSerial(List<T> list, File f) {
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(f))) {
            oos.writeObject(list);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //对象反序列化方法
    public static <T> List<T> objDeserial(File f) {
        List<T> list = new ArrayList<>();
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(f))) {
            list = (List<T>) ois.readObject();
        } catch (EOFException e) {
            return list;
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return list;
    }

    //Properties集合输出流
    public static void propOutput(Properties prop, File f) {
        try (FileOutputStream fos = new FileOutputStream(f)) {
            prop.store(fos, "----fine----");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //Properties集合输入流
    public static Properties propInput(File f) {
        Properties prop = new Properties();
        try (FileInputStream fis = new FileInputStream(f)) {
            prop.load(fis);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return prop;
    }

    //输出日志记录
    public static void printLog(String log) {
        try (BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\专业学习\\Java学习\\" +
                "librarymanagement\\src\\com\\library\\info\\log.txt", true))) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
            bw.write(sdf.format(new Date()) + "  " + log);
            bw.newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

        对象序列化是使用最多的,基本上用户、类别、读者、图书、借阅信息等主要数据都是用它进行读写操作。properties结合IO流我是专门用来读写罚金的;最后那个字符缓冲流是用来输出日志记录的。

2.2 数据读写注意事项

        读数据时采用静态代码块的方式读取到集合中。为什么要用静态代码块呢?因为如果不用静态代码块的话,你每次new一个对象它就会读取一次,这样读取效率低下不说,更重要的是可能会造成数据出错。静态代码块只会在类加载时读取,也就是说它只会读取一次,不会出现多次读取从而造成数据错误。我基本上主要功能模块都是采用的这种方式。

private static final File BOOK_INFO = new File("D:\\专业学习\\Java学习\\librarymanagement\\src\\" +
            "com\\library\\info\\bookInfo.txt");
    private static List<Book> books;  //所有图书信息

    //静态代码块创建图书信息文件并读取信息
    static {
        try {
            BOOK_INFO.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        books = FileOperation.objDeserial(BOOK_INFO);
    }

3.数据共享

        这是非常重要的一个问题,在前面我说过各个模块之间都有不同程度的依赖,他们之间的一些数据可能是共通的,所以我们要尤其注意数据共享的这个问题。特别是在做一些增删改查操作时,你不能这边这个模块修改了,而另一个依赖它的模块的数据却纹丝不动吧?

        我举个例子,比如读者借阅了一本图书,那么该图书的库存数量应该减1,减1的操作是在图书借阅管理模块里实现的,但是你在图书管理模块查询时库存数量却没有变,这个就是没有实现数据共享。

避免这个问题的方法有两种:

  1. 进行对象传递时采用直传递。中间不要new任何的对象,将对象作为方法的参数传递过去。如果嫌麻烦,还可以直接使用static(static尽量少用)。
  2. 分别修改两个模块。(不建议这样做,这样显得很low,而且在正式项目开发中也不会允许这样写的,因为这种方法实质上是没有实现数据共享的)。

        我采用的是第一种方法直传递。另外要注意数据共享更改后要记得把所有相关模块的数据保存到文件里。

4.业务逻辑问题

        关于业务逻辑上的问题我只讲大家容易忽略的两点。

        ① 用户管理模块中的用户删除功能要注意不能把当前登录的用户删除了,也就是说不能自己删除自己。我解决这个问题的方法是在用户逻辑类UserService中添加一个当前登录用户的变量,删除时与这个变量进行比较判断。相当于我用了一个缓存的思想。

        ② 注意不能将处于借阅状态中的读者和图书删除掉。读者借阅图书后还没有归还,你不可能就把这个读者和图书删除了吧?这个是很多小伙伴容易忽略的一点。针对这个问题我采取的方法是分别在读者类(Reader)和图书类(Book)中增加一个借阅计数器,当处于借阅状态中的读者或图书数量等于0时就可以删除,非零就不能删除。


三、源码链接

        因为代码比较多,所以我把源码放百度网盘上,有需要的小伙伴自取哦,如果对代码有任何疑问可以私聊博主。源码都是博主历经千辛万苦写出来的,所以源码禁止商用,仅供学习交流使用!!!

链接:https://pan.baidu.com/s/185fjiXz-_iG0ClqTcIFMGA 
提取码:y8ax

ps:博主创作不易,小伙伴们,动动你们的小手指,给博主点个赞吧,谢谢!