目录
该图书系统实现的五个功能:管理员上架功能、读者注册功能、读者借书功能、读者还书功能、读者查阅借阅资料功能。
一、建立连接
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;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 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 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 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); } } }}
来源地址:https://blog.csdn.net/weixin_60358891/article/details/128245040