图书管理系统(JDBC、MySQL)

   

目录

一、建立连接

1. 思路

2. 代码

二、 管理员上架功能

1. 思路

2. 代码

三、读者注册功能

1. 思路

2. 代码

四、读者借书功能

1. 思路

2. 代码

五、读者还书功能

1. 思路

2. 代码

六、读者查看借阅历史功能

1. 思路

2. 代码 

(1)Record 类

(2)实现功能代码


    该图书系统实现的五个功能:管理员上架功能、读者注册功能、读者借书功能、读者还书功能、读者查阅借阅资料功能。

一、建立连接

1. 思路

  为了写代码的方便,新建了一个 uti l包下的 DBUtil 类来实现连接的建立。要使用代码时,直接调用DBUtil下的connection() 方法即可。而其他功能写在新建的 lib 包下。

2. 代码

package util;

import com.mysql.cj.jdbc.MysqlDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

/**
 * Created with IntelliJ IDEA.
 * Description:  用来创建连接对象 Connection
 * User: WangWZ
 * Date: 2022-12-08
 * Time: 19:00
 */
public class DBUtil {
    private static final DataSource dataSource;
    static {
        MysqlDataSource mysqlDataSource = new MysqlDataSource();
        mysqlDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/java45_1206?characterEncoding=utf8&&useSSL=false&&serverTimezone=Asia/Shanghai");
        mysqlDataSource.setUser("root");
        mysqlDataSource.setPassword("12345");

        dataSource = mysqlDataSource;
    }

    public static Connection connection() throws SQLException {
        return dataSource.getConnection();
    }
}

二、 管理员上架功能

1. 思路

(1) 首先要读取要上架的图书信息:书名、要上架多少本书;

(2) 执行 SQL 语句:
      上架书籍:要先知道书架里有没有这本书 。select bid from books where name = ... ;

  • 若原来没有这本书,select 查找结果为一条记录。然后 intert 添加这本书  insert into books (name,count,total) values ...
  • 若有这本书,select 查找结果为 0 条结果。然后 update 更新这本书的数据  update books set current = current +..., total = total + ... where bid =...;

     总结得出要执行三条SQL语句:connection 连接只需要一个,准备执行的对象 ps 要三个。

2. 代码

public class 管理员图书上架功能 {
    public static void main(String[] args) throws SQLException {
        //首先要读取要上架的图书信息:书名、要上架多少本书
        Scanner scanner = new Scanner(System.in);
        System.out.println("管理员图书上架功能:");

        System.out.print("请输入要上架的图书书名:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String name = scanner.nextLine();

        System.out.print("请输入本次上架的图书数量:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        int count = Integer.parseInt(scanner.nextLine());

        //执行 SQL 语句
        try (Connection c = DBUtil.connection()) {
            //连接已经创建好
            //(1)判断书架上有没有这本书
            Integer bid;
            String sql = "select bid from books where name = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1,name);   // 对该 sql 语句中的 ? 进行参数绑定
                System.out.println("DEBUG: 执行 sql:" + ps);
                try (ResultSet rs = ps.executeQuery()) {
                    //这里进行是否有这本书的判断
                    if (rs.next() == false) {
                        bid = null;
                    } else {
                        bid = rs.getInt("bid");
                    }

                }
            }
            //根据 bid 分情况执行 SQL 语句
            if (bid == null) {
                //没有这本书,添加
                sql = "insert into books (name,current,total) values (?,?,?)"; 
                try (PreparedStatement ps = c.prepareStatement(sql)) {
                    ps.setString(1,name);
                    ps.setInt(2,count);
                    ps.setInt(3,count);

                    System.out.println("DEBUG: 执行 sql:" + ps);
                    //因为这里执行的是没有结果集的 insert 操作,所以使用 ps.executeUpdate()
                    ps.executeUpdate();
                }
            } else {
                //有这本书,更新
                sql = "update books set current = count + ?,total = total + ? where bid = ?";
                try (PreparedStatement ps = c.prepareStatement(sql)) {
                    ps.setInt(1,count);
                    ps.setInt(2,count);
                    ps.setInt(3,bid);

                    System.out.println("DEBUG: 执行 sql:" + ps);
                    //因为这里执行的是没有结果集的 update 操作,所以使用 ps.executeUpdate()
                    ps.executeUpdate();
                }
            }
        }

        //关闭连接之后,提示用户上架成功
        System.out.println("书籍上架成功");

    }

}

三、读者注册功能

1. 思路

   (1) 先读取用户要注册需要的信息:用户名、密码。

   (2) 执行 SQL 语句:
             读者注册:要先判断该用户是否存在,即用户名是否存在。

  • 若存在该用户:注册失败,提示用户该用户名已存在。
  • 若不存在该用户:进行插入操作  insert into users (username, password) values (?, ?);

    (3)因为在 users 表中,username 是唯一键,所以当已经存在该用户名时再进行插入会报错,我们可以通过处理异常来提醒用户注册失败。

2. 代码

public class 读者注册功能 {
    public static void main(String[] args) throws SQLException {
        //先读取用户要注册需要的信息:用户名、密码
        Scanner scanner = new Scanner(System.in);
        System.out.println("读者注册功能:");

        System.out.print("请输入要注册的用户名:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String username = scanner.nextLine();

        System.out.print("请输入要注册的密码:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String password = scanner.nextLine();

        //执行 SQL 语句
        try (Connection c = DBUtil.connection()) {
            String sql = "insert into users (username,password) values (?,?)";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1,username);
                ps.setString(2,password);
                System.out.println("DEBUG: 执行 sql:" + ps);
                ps.executeUpdate();
            }
        } catch (SQLIntegrityConstraintViolationException exc) {
            //说明 username 的唯一约束被破坏了
            System.out.println("注册失败,该用户名已存在");
            return;
        }

        System.out.println("注册成功");

    }
}

四、读者借书功能

1. 思路

  (1) 先提示用户输入借书功能需要的信息:①先登录:用户名、密码。 ②借书信息:书名

  (2) 执行 SQL 语句:要完成一个完整的读者借书功能需要考虑三部分:①登录验证;②书名判断;③进行借书。

     ① 登录验证:用户输完用户名和密码后判断 users 表中有无该用户以及密码是否正确,用户名和密码均正确才显示登录成功,并且获取 uid 值,反之则显示登录失败。select uid from users where username = ? and password = ?;  (用 uid 是因为在 records 表中要用)

     ② 书名判断:用户输完书名后,判断 books 表中是否有该书,以及 current 是否不为 0。

  • 有书的情况下,再调用 rs.getInt() 方法获取出 该条记录的current 的值,若等于 0 提示用户库存不够无法借书,反之获取 bid 值并进行下一步借书操作
  • 没书的情况下,提示用户没有该书。select bid,current from books where name = ?;       (用 bid 是因为在 records 表中要用)

      ③ 进行借书:代码执行到这里说明可以正常借书。要完成借书操作:在 records 表中插入借书记录;更新 books 表中的 current 数据。
      insert into records (uid, bid, borrowed_at) values (?, ?, ?);
      update books set current = current - 1 where bid = ?;

   (3)因为借书需要获取当前的时间,所以写了一个方法nowTime() 来进行当前时间的获取。

2. 代码

public class 读者借书功能 {
    public static void main(String[] args) throws SQLException {
        //先提示用户输入借书功能需要的信息:①先登录:用户名、密码。 ②借书信息:书名

        //执行 SQL 语句
        Scanner scanner = new Scanner(System.in);
        System.out.println("读者借书功能:");
        System.out.print("请输入用户名:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String username = scanner.nextLine();

        System.out.print("请输入密码:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String password = scanner.nextLine();
        int uid;
        int bid;
        //登录验证
        try (Connection c = DBUtil.connection()) {
            String sql = "select uid from users where username = ? and password = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1,username);
                ps.setString(2,password);
                System.out.println("DEBUG: 执行 SQL :" + ps);
                try (ResultSet rs = ps.executeQuery()) {
                    if (rs.next() == false) {
                        System.out.println("登录失败");
                        return;
                    } else {
                        System.out.println("登陆成功");
                        uid = rs.getInt("uid");
                        // uid = rs.getInt(1); 也可以,表示获取 select 字段的第一个
                    }
                }
            }
        }
        //书名判断
        System.out.print("请输入要借的书:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String name = scanner.nextLine();
        try (Connection c = DBUtil.connection()) {
            String sql = "select bid, current from books where name = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1,name);
                try (ResultSet rs = ps.executeQuery()) {
                    if (rs.next() == false) {
                        System.out.println("没有该书");
                        return;
                    } else {
                        int current = rs.getInt("current");
                        if (current <= 0) {
                            System.out.println("该书已被全部借书");
                            return;
                        } else {
                            bid = rs.getInt("bid");
                        }
                    }
                }
            }
        }
        //进行借书
        try (Connection c = DBUtil.connection()) {
            String sql = "insert into records (uid, bid, borrowed_at) values (?, ? ,?)";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,uid);
                ps.setInt(2,bid);
                ps.setString(3,nowTime());  //要传入借书的时间,这里使用方法传入时间字符串
                System.out.println("DEBUG: 执行 SQL:" + ps);
                ps.executeUpdate();
            }
            sql = "update books set current = current - 1 where bid = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,bid);
                System.out.println("DEBUG: 执行 SQL :" + ps);
                ps.executeUpdate();
            }
        }
        System.out.println("借书成功");
    }

    private static String nowTime() {
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return now.format(formatter);
        // yyyy 代表 4 个长度的年,如 2022
        // MM  代表 2 个长度的月,如 02
        // dd  代表 2 个长度的日,如 06
        // HH  代表 24 小时,如 20
        // mm :37
        // ss :秒
    }
}

五、读者还书功能

1. 思路

   (1)先提示用户输入借书功能需要的信息:①先登录:用户名、密码。 ②还书信息:书名。

   (2)执行 SQL:要完成一个完整的读者还书功能需要考虑四部分:①登录验证;②是否有该书判断;③是否借过该书判断;④进行还书。
        ①  登录验证:用户输完用户名和密码后判断 users 表中有无该用户以及密码是否正确,用户名和密码均正确才显示登录成功,并且获取 uid 值,反之则显示登录失败。select uid from users where username = ? and password = ?;  (用 uid 是因为在 records 表中要用)
        ② 是否有该书判断:用户输完书名后,在 books 表中查找是否有该本书。(为了获取 bid,因为 records 表中记录的是 bid 而不是 name)

  • 没有该书,提示用户没有该书。
  • 有该书,获取 bid 的值,进行下一步操作。 select bid from books where name = ?;

       ③ 是否借过该书判断:判断 books 中有该本书后,判断 records 表中是否有该书的借书记录。

  •  有借书记录书的情况下,再调用 rs.getInt() 方法获取出该条记录的 id 的值。(为了进行还书的操作,即要修改哪条记录)
  •  没借书记录的情况下,提示用户没有借过该书。select id from records where uid = ? and bid = ? and returned_at is null;

      ④ 进行还书:代码执行到这里说明可以正常还书。要完成还书操作:在 records 表中更新借书记录(填入还书时间);更新 books 表中的 current 数据。
      update records set returned_at = ? where id = ?;
      update books set current = current + 1 where bid = ?;

   (3)这里还是用到 nowTime() 方法。

2. 代码

public class 读者还书功能 {
    public static void main(String[] args) throws SQLException {
        //先提示用户输入借书功能需要的信息:①先登录:用户名、密码。 ②还书信息:书名
        //执行 SQL
        Scanner scanner = new Scanner(System.in);
        System.out.println("读者还书功能:");
        System.out.print("请输入用户名:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String username = scanner.nextLine();

        System.out.print("请输入密码:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String password = scanner.nextLine();
        int uid;
        int bid;
        int id;
        //登录验证
        try (Connection c = DBUtil.connection()) {
            String sql ="select uid from users where username = ? and password = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1,username);
                ps.setString(2,password);
                System.out.println("DEBUG: 执行 SQL :" + ps);
                try (ResultSet rs = ps.executeQuery()) {
                    if (rs.next() == false) {
                        System.out.println("登录失败,没有该用户");
                        return;
                    } else {
                        System.out.println("登陆成功");
                        uid = rs.getInt("uid");
                    }
                }
            }
        }
        //是否有该书判断
        System.out.print("请输入要还的书书名:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String name = scanner.nextLine();
        try (Connection c = DBUtil.connection()) {
            String sql = "select bid from books where name = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1,name);
                System.out.println("DEBUG: 执行 SQL:" + ps);
                try (ResultSet rs = ps.executeQuery()) {
                    if (rs.next() == false) {
                        System.out.println("没有该书");
                        return;
                    } else {
                        bid = rs.getInt("bid");
                    }
                }
            }
        }
        //是否借过该书判断
        try (Connection c = DBUtil.connection()) {
            String sql = "select id from records where bid = ? and uid = ? and returned_at is null";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,bid);
                ps.setInt(2,uid);
                System.out.println("DEBUG: 执行 SQL: " + ps);
                try (ResultSet rs = ps.executeQuery()) {
                    if (rs.next() == false) {
                        System.out.println("没有相关借书记录");
                        return;
                    } else {
                        id = rs.getInt("id");
                    }
                }
            }
        }
        //进行还书
        try (Connection c = DBUtil.connection()) {
            String sql = "update records set returned_at = ? where id = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1,nowTime());
                ps.setInt(2,id);
                System.out.println("DEBUG: 执行 SQL: " + ps);
                ps.executeUpdate();
            }
            sql = "update books set current = current + 1 where bid = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,bid);
                System.out.println("DEBUG: 执行 SQL: " + ps);
                ps.executeUpdate();
            }
        }
        System.out.println("还书成功");
    }
    private static String nowTime() {
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return now.format(formatter);
    }
}

六、读者查看借阅历史功能

1. 思路

   (1)先提示用户输入查看借阅历史需要的信息:用户名、密码。

   (2)大致思路:

  • 因为一名用户可能会借阅好多本书,所以我们查询时可以按时间倒序或正序的方式查找;
  • 查找后因为需要显示,所以可以定义一个类( Record ),里面存放要显示的信息,同时通过重写 toString 方法来进行显示;
  •  一名用户可能会有很多条借阅记录,每条记录都是一个 Record 对象,所以要显示所有记录,选择用链表进行存储每条记录;

   (3)期望显示的内容:
       按照借阅时间的倒叙排序(最新借的在最上面)
       2022-12-06 20:43:18 借了 《红楼梦》
       2022-12-06 20:39:22 借了 《西游记》
      下面部分展示的曾经结果并且已经还了的书,也按照借阅时间的倒叙
       2022-12-06 20:43:18 借了 《红楼梦》,于 2022-12-06 21:43:28 归还
       2022-12-06 20:39:22 借了 《西游记》,于 2022-12-06 21:43:28 归还 

   (4)执行 SQL :要完成一个完整的读者查看借阅历史功能需要考虑三部分:①登录验证;②查询该用户的借阅记录;③将查询出来的 bid 都转换为书名 name。
        ① 登录验证:用户输完用户名和密码后判断 users 表中有无该用户以及密码是否正确,用户名和密码均正确才显示登录成功,并且获取 uid 值,反之则显示登录失败。select uid from users where username = ? and password = ?;  (用 uid 是因为在 records 表中要用)
        ② 查询该用户的借阅记录

  • 若没有借阅记录,提示用户没有借阅记录。
  • 若有借阅记录,则进行下一步操作。select bid, borrowed_at, returned_at from records where uid = ? order by borrowed_at desc;

       ③ 将查询出来的 bid 都转换成书名 name:

  • 先用 HashSet 存储 bid 列表(因为要求不重复,不要求顺序,所以选择使用 Set 接口下的 HashSet);
  • 因为要根据 bid 对照出 name,涉及到映射,所以使用 Map 类定义一个对象存储 映射关系。
  • 最后通过遍历存储借阅记录的链表,将每条记录里对应的 bid 的 name 根据 映射关系 找出并填入。

2. 代码 

(1)Record 类

public class Record {
    public int bid;
    public String bookName;
    public String borrowedAt;
    public String returnedAt;

    public Record(int bid, String borrowedAt, String returnedAt) {
        this.bid = bid;
        this.borrowedAt = borrowedAt;
        this.returnedAt = returnedAt;
    }

    @Override
    public String toString() {
        if (returnedAt == null) {
            return borrowedAt + " 借了《" + bookName + "》";
        }
        return borrowedAt + " 借了《" + bookName + "》于" + returnedAt + "归还";
    }
}

(2)实现功能代码

public class 读者查看借阅历史功能 {
    public static void main(String[] args) throws SQLException {
        //先提示用户输入查看借阅历史需要的信息:用户名、密码。
        Scanner scanner = new Scanner(System.in);
        System.out.println("读者查看借阅历史功能:");
        System.out.print("请输入用户名:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String username = scanner.nextLine();
        System.out.print("请输入密码:");
        if (!scanner.hasNextLine()) {
            System.out.println("退出");
            return;
        }
        String password = scanner.nextLine();
        int uid;
        //登录验证
        try (Connection c = DBUtil.connection()) {
            String sql = "select uid from users where username = ? and password = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setString(1,username);
                ps.setString(2,password);
                System.out.println("DEBUG: 执行 SQL:" + ps);
                try (ResultSet rs = ps.executeQuery()) {
                    if (!rs.next()) {
                        System.out.println("登录失败");
                        return;
                    } else {
                        System.out.println("登陆成功");
                        uid = rs.getInt("uid");
                    }
                }
            }
        }
        //查询该用户的借阅记录 -> 存储
        List<Record> recordList = new ArrayList<>();
        try (Connection c = DBUtil.connection()) {
            String sql = "select bid, borrowed_at, returned_at from records where uid = ?";
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                ps.setInt(1,uid);
                System.out.println("DEBUG: 执行 SQL: " + ps);
                try (ResultSet rs = ps.executeQuery()) {
                    while (rs.next()) {
                        int bid = rs.getInt("bid");
                        String borrowedAt = rs.getString("borrowed_at");
                        String returnedAt = rs.getString("returned_at");
                        Record record = new Record(bid,borrowedAt,returnedAt);
                        recordList.add(record);
                    }
                }
            }
        }
        //若链表为空,说明没有借阅记录,直接提示用户即可
        if (recordList.isEmpty()) {
            System.out.println("无借阅记录");
            return;
        }
        //将查询出来的 bid 都转换成书名 name
        Set<String> bidSet = new HashSet<>();
        for (Record r : recordList) {
            int bid = r.bid;
            //将 bid 转为 String 类型是为了用 String.join()方法,最后用在 sql 语句中 selece....in(×, ×,×);
            String bidStr = String.valueOf(bid);
            bidSet.add(bidStr);
        }
        Map<Integer,String> bidToBookNameMap = new HashMap<>();
        //String.join("x", list):将列表中的数据以 x 的间隔格式显示
        String in = String.join(", ",bidSet);
        try (Connection c = DBUtil.connection()) {
            //这里只能使用字符串拼接
            String sql = String.format("select bid, name from books where bid in (%s)", in);
            try (PreparedStatement ps = c.prepareStatement(sql)) {
                System.out.println("DEBUG: 执行 SQL: " + ps);
                try (ResultSet rs = ps.executeQuery()) {
                    //将映射关系放入 bidToBookNameMap
                    while (rs.next()) {
                        int bid = rs.getInt("bid");
                        String name = rs.getString("name");
                        bidToBookNameMap.put(bid,name);
                    }
                }
            }
        }
        //通过 bidToBookNameMap 可以将 recordList 中的 bookName 进行填写了
        for (Record record : recordList) {
            int bid = record.bid;
            String bookName = bidToBookNameMap.get(bid);
            record.bookName = bookName;
        }
        //打印 recordList
        for (Record record : recordList) {
            if (record.returnedAt == null) {
                System.out.println(record);
            }
        }
        for (Record record : recordList) {
            if (record.returnedAt != null) {
                System.out.println(record);
            }
        }
    }
}

  • 9
    点赞
  • 108
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值