目录
一、项目演示
1、 数据库数据演
2、管理员
新增书籍数据库变换
3、用户
1、登录注册
2、借阅与归还数据库变换
借阅:
归还
二、项目分析
图书管理系统里主要涉及以下几个对象:书、书架类、各种增删改查操作类、用户类、以及操作数据库的类
文件部署:
不同包里放不同的操作与类
Book包里是与书有关的类
MySQL包里是与数据库操作有关的类
operation包里主要是与增删改查有关的类
User包里主要是用户与管理⚪类
Main用于组织各个类
三、环境
1、idea
2、MySQL5.7
官网可以下载
3、数据库驱动包
在之前的文章里有讲到,数据库驱动包的安装与使用
使用JavaSE与SQL相关知识
四、数据库表设计
1、管理员表
Admin表,主要字段有id,用户名与密码
2、普通用户表
user表主要字段与管理员表相同
3、图书表
book 表 字段主要有书名、作责、价格、类型以及状态(是否被借出)
4、借阅记录表
record 表 主要字段有借阅人姓名与书籍名
5、结构
五、各个类
1、书
首先书类里有与上面数据库字段相同的成员变量,使用private修饰并提供了公开的接口
public class Book {
private String name; //书名
private String author; //作者
private int price; //价格
private String type; //类型
private boolean isBorrowed;//是否借出
//构造方法
public Book(String name, String author, int price, String type) {
this.name = name;
this.author = author;
this.price = price;
this.type = type;
}
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 int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public boolean isBorrowed() {
return isBorrowed;
}
public void setBorrowed(boolean borrowed) {
this.isBorrowed = borrowed;
}
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", type='" + type + '\'' +
((isBorrowed == true)?",已经借出":",未借出")+
'}';
}
}
2、书架类
主要是用于存放书籍,主要的字段是一个Book类的数组,目前是数组后续可以换为链表,与一个用于记录书架上书数量的整形变量,都是提供了公开的接口,另外在构造函数里加入了JDBC操作用于初始化书架,JDBC操作可以看之前的文章
public class BookList {
//后使用链表
private Book[] books = new Book[100];
private int usedSize; //记录数组里有几本书
public BookList() throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("数据库密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "select * from book";
PreparedStatement statement = connection.prepareStatement(sql);
//4.发生请求
ResultSet resultSet = statement.executeQuery();
while(resultSet.next()){
String name = resultSet.getString("name");
String author = resultSet.getString("author");
int price = resultSet.getInt("price");
String type = resultSet.getString("type");
String state = resultSet.getString("state");
books[usedSize] = new Book(name,author,price,type);
//初始化书籍
if(state.equals("未借出")){
boolean b = false;
books[usedSize].setBorrowed(b);
}else{
books[usedSize].setBorrowed(true);
}
usedSize++;
}
//5.释放资源
resultSet.close();
statement.close();
connection.close();
}
/**
* @param pos 此时pos一定是合法的
* @return 书*/
public Book getBook(int pos){
return books[pos];
}
/**
*
* @param pos pos一定是合法的
* @param book 是要放的书
*/
public void setBooks(int pos,Book book){
books[pos] = book;
}
/**
* 实时获取书的数量
* @return 书的数量
*/
public int getUsedSize(){
return usedSize;
}
/**
* 实时修改当前书的数量
* @param usedSize
*/
public void setUsedSize(int usedSize){
this.usedSize=usedSize;
}
}
3、operation包
以下类都是操作类,可以先创建类不去写具体实现,等Main组织好结构后再去写具体实现
1、接口
每个类都是对应得增删改查得操作,于是我们写一个操作接口,然后让具体的操作类去实现他
,将每个功能封装成对象
public interface IOperation {
void work(BookList bookList);
}
每个增删改查类,都去implements他,然后对应得增删改查重写work操作
2、查找图书类
比如查找类,实现接口后重写查找操作
每个类对应的业务操作实现简单,主要是每个操作类都去实现操作接口然后将操作封装为对象
这些类在后续都会进行组织
3、显示图书类
4、删除图书类
在删除时,先通过书名循环查找,找到后进行删除,具体删除操作就是让这个书的位置的后一本书去代替,后一本依次往前填,在这个操作后使用图书数据库类对数据库里的数据进行删除,这个类在后面会讲到
public class DelOperation implements IOperation{
@Override
public void work(BookList bookList) throws SQLException {
System.out.println("请输入你要删除的书名");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
int size = -1;
for (int i = 0; i < bookList.getUsedSize(); i++) {
if(bookList.getBook(i).getName().equals(name)){
size = i;
JDBCBook jdbcBook = new JDBCBook();
jdbcBook.delMySQL(bookList.getBook(i));
break;
}
}
if(size != -1){
for (int i = size; i < bookList.getUsedSize()-1; i++) {
bookList.setBooks(i,bookList.getBook(i+1));
}
bookList.setBooks(bookList.getUsedSize()-1,null);
bookList.setUsedSize(bookList.getUsedSize()-1);
}else{
System.out.println("没有这本书");
}
}
}
5、添加图书类
这个类先输入后添加到数组,然后利用图书数据库操作类加入数据库
6、借阅图书类
先查找书,然后判断是否借出,如果没借出就通过输入自己的用户名与密码进行借阅,归还时通过用户密码来判断该书是否由该用户借阅,借阅成功后,在数据库记录表里通过数据库操作类写入记录表
public class BorrowOperation implements IOperation{
/**
* 借书时
* 查找书名-》找到-》输入用户名-》输入密码-》判断密码是否正确-》写入借阅表-》借阅成功
* */
@Override
public void work(BookList bookList) throws SQLException {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入书名");
String book = scanner.nextLine();
for (int i = 0; i < bookList.getUsedSize(); i++) {
if (bookList.getBook(i).getName().equals(book)) {
if(bookList.getBook(i).isBorrowed()){
System.out.println("已被别人借出");
return;
}
//找到-》输入密码与姓名
System.out.println("请输入您的用户名");
String name = scanner.nextLine();
System.out.println("请输入密码");
String password = scanner.nextLine();
//判断密码是否正确
JDBCUser jdbcUser = new JDBCUser();
if(password.equals(jdbcUser.findMySql(name))){
bookList.getBook(i).setBorrowed(true);
System.out.println("借阅成功");
//改变图书状态
JDBCBook jdbcBook = new JDBCBook();
jdbcBook.updateMySQL(bookList.getBook(i));
//添加借阅记录
JDBCRecord jdbcRecord = new JDBCRecord();
jdbcRecord.addRecord(name,book);
}else{
System.out.println("借阅失败");
}
return;
}
}
}
}
7、归还图书类
先找到该书,然后判断是不是此时登录的用户借阅然后进行归还操作
public class ReturnOperation implements IOperation{ /** * 还书时 * 查找书名-》找到书-》判断是不是登录用户借阅-》从数据库里查找-》从数据库删除这条借阅记录 * 如何判断借书者是还书者 * 输入用户密码-》判断信息 * */ @Override public void work(BookList bookList) throws SQLException { Scanner scanner = new Scanner(System.in); System.out.println("请输入书名"); String b = scanner.nextLine(); for (int i = 0; i < bookList.getUsedSize(); i++) { Book book = bookList.getBook(i); //找到书籍 if(book.getName().equals(b)&&bookList.getBook(i).isBorrowed()){ //输入密码判断是否是借书者 System.out.println("请输入密码"); String password = scanner.nextLine(); JDBCRecord jdbcRecord = new JDBCRecord(); if(password.equals(jdbcRecord.findMySql(b))){ book.setBorrowed(false); System.out.println("归还成功"); //改变状态 JDBCBook jdbcBook = new JDBCBook(); jdbcBook.updateMySQL(bookList.getBook(i)); //删除借阅记录 jdbcRecord.delMySql(b); return; }else{ System.out.println("归还失败"); return; } } } System.out.println("未找到"); } }
8、退出类
利用System.exit(0)退出系统
public class ExitOperation implements IOperation{
@Override
public void work(BookList bookList) {
System.out.println("退出系统");
System.exit(0);
}
}
4、用户包
无论时普通用户还是管理员都有对应得用户名与密码,及操作菜单,菜单没有具体实现,于是把他抽象成一个抽象类,然后让普通用户与管理员继承他,然后再去根据对应得操作重写菜单方法
1、父类
2、普通用户
普通用户继承父类后,通过提供构造方法帮组父类构造之外,还要重写父类里抽象方法menu
public int menu(){
System.out.println("hello "+this.name+" 欢迎来到图书馆!");
System.out.println("1.查找图书!");
System.out.println("2.借阅图书!");
System.out.println("3.归还图书!");
System.out.println("0.退出系统!");
System.out.println("请输入你的选择");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
3、管理员类
与普通用户一样,通过构造方法帮助父类构造之后,重写父类里得抽象方法menu
public int menu(){
System.out.println("hello "+this.name+" 欢迎来到图书馆!");
System.out.println("1.查找图书!");
System.out.println("2.新增图书!");
System.out.println("3.删除图书!");
System.out.println("4.显示图书!");
System.out.println("0.退出系统!");
System.out.println("请输入你的选择");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
5、MySQL包
主要有根据不同数据库所需的需求所写的操作四个数据库的四个类,基本语法都是JDBC
1、Admin数据库JDBC
在该项目里该数据库使用主要以登录时验证密码为主,所以主要以查找为主,使用JDBC,写一个查找密码的方法并封装成对象
public class JDBCAdmin {
/**
* 该类涉及管理员表只有查找管理员密码
* 所以只写查找密码
*/
public String findMySql(String name) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("g密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "select * from Admin where name=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,name);
//4.发生请求
ResultSet resultSet = statement.executeQuery();
while(resultSet.next()){
String n = resultSet.getString("name");
if(n.equals(name)){
String password = resultSet.getString("password");
resultSet.close();
statement.close();
connection.close();
return password;
}
}
return null;
}
}
2、user数据库JDBC
该表主要用于用户登录时查找密码,以及用户注册时新增数据,所以只有增查两个操作
public class JDBCUser {
/**
* user
* 设计用户表
* 1》登录:即查找密码
* 2》注册:即添加用信息
* 3》借阅
* 4》归还:在归还时判断借出该书的是否时登录的用户*/
//1》登录
public String findMySql(String name) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "select * from user where name=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,name);
//4.发送请求
ResultSet resultSet = statement.executeQuery();
while(resultSet.next()){
String n = resultSet.getString("name");
if(n.equals(name)){
String password = resultSet.getString("password");
resultSet.close();
statement.close();
connection.close();
return password;
}
}
return null;
}
//2》注册
public int addMySQL(NormalUser normalUser) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "insert into user(name,password) values(?,?)";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,normalUser.getName());
statement.setString(2, normalUser.getPassword());
//4.发生请求
int n = statement.executeUpdate();
//5.释放资源
statement.close();
connection.close();
return n;
}
}
3、book数据库JDBC
book数据库主要用于存放书,他涉及用户查找书,借阅书时修改借阅状态以及管理员删除书,还有在构造书架类时将数据库里的书数据加载到书架书数组上,所以涉及1》删除书籍2》查找书籍
3》修改书籍4》初始化书架
其中初始化书架的JDBC操作直接放在了书架类的构造函数里,当实例化书架对象时就会自动初始化书
public class JDBCBook {
/**
* book
* 1》涉及了添加书
* 2》修改书名状态
* 3》删除书*/
/**
* @param book 要借出与归还的书
* @return 返回
*/
public int updateMySQL(Book book) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("数据库密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "update book set state=? where name=?";
PreparedStatement statement = connection.prepareStatement(sql);
if(book.isBorrowed()){
statement.setString(1,"已经借出");
}else{
statement.setString(1,"未借出");
}
statement.setString(2,book.getName());
//4.发生请求
int n = statement.executeUpdate();
//5.释放资源
statement.close();
connection.close();
return n;
}
/**
* @param book 书
* @return 返回值判断是否删除成功
*/
public int delMySQL(Book book) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "delete from book where name=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,book.getName());
//4.发生请求
int n = statement.executeUpdate();
//5.释放资源
statement.close();
connection.close();
return n;
}
/**
* @param book 是一本书
* @return 通过返回值判断是否写入数据库
*/
public int addMySQL(Book book) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "insert into book values(?,?,?,?,?)";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,book.getName());
statement.setString(2,book.getAuthor());
statement.setInt(3,book.getPrice());
statement.setString(4,book.getType());
if(book.isBorrowed()){
statement.setString(5,"已经借出");
}else{
statement.setString(5,"未借出");
}
//4.发生请求
int n = statement.executeUpdate();
//5.释放资源
statement.close();
connection.close();
return n;
}
}
4、record数据库JDBC
record数据库主要用与记录当前书籍的借阅记录,与用户归还书籍时删除借阅记录,以及归还时通过密码判断借阅该书的是否是正在登录的用户
public class JDBCRecord {
/**
* record
* 该数据库涉及
* 1》借阅书籍时添加信息:借阅人姓名,书籍名
* 2》归还书籍时判断还书者与借书者是否统一:联合查询密码
* 3》删除借阅记录
* */
/**
* @param book 书名
* @param name 用户名
* */
public void addRecord(String name,String book) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("g密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "insert into record values(?,?)";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,name);
statement.setString(2,book);
//4.发生请求
statement.executeUpdate();
//5.释放资源
statement.close();
connection.close();
}
//判断密码
/**
* @param book 还书的名字*/
public String findMySql(String book) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("y密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "select * from user,record where user.name=record.name and record.book=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,book);
//4.发送请求
ResultSet resultSet = statement.executeQuery();
while(resultSet.next()){
String n = resultSet.getString("book");
if(n.equals(book)){
String password = resultSet.getString("password");
resultSet.close();
statement.close();
connection.close();
return password;
}
}
return null;
}
//删除记录
public void delMySql(String book) throws SQLException {
//1.创建数据源
DataSource dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL("jdbc:mysql://127.0.0.1:3306/Library?characterEncoding=utf8&useSSL=false");
((MysqlDataSource)dataSource).setUser("root");
((MysqlDataSource)dataSource).setPassword("y密码");
//2.建立连接
Connection connection = dataSource.getConnection();
//3.构造请求
String sql = "delete from record where book=?";
PreparedStatement statement = connection.prepareStatement(sql);
statement.setString(1,book);
//4.发生请求
int n = statement.executeUpdate();
//5.释放资源
statement.close();
connection.close();
}
}
六、组织各个类
通过Main来对各个类进行组织,首先通过实例化一个书架对象来初始化书籍
public static void main(String[] args) throws SQLException {
BookList bookList = new BookList(); //准备图书
}
然后开始登录操作,提供一个登录函数,此时如果是管理员就在登录成功后返回一个实例化的管理员对象,如果是普通用户登录成功或者注册成功都返回一个实例化的普通成员对象,这两个类都继承了user类所以返回值使用user,在main函数里也使用user对象来接收
public static User login() {
}
public static void main(String[] args) throws SQLException {
BookList bookList = new BookList(); //准备图书
//登录
User user = login();
}
普通用户-》选择登录或注册-》进行对应操作
此时登录时先输入用户名-》选择身份-》
管理员-》直接进行登录操作-》登录成功
public static User Init(String name,String choice) throws SQLException {
NormalUser normalUser = new NormalUser(name);
JDBCUser jdbcUser = new JDBCUser();
Scanner scanner = new Scanner(System.in);
System.out.println("请输入密码:");
if(choice.equals("1")){
String password = scanner.nextLine();
normalUser.setPassword(password);
if(normalUser.getPassword().equals(jdbcUser.findMySql(name))){
return normalUser;
}else{
System.out.println("密码错误,退出系统");
System.exit(0);
return null;
}
}else{
String password = scanner.nextLine();
normalUser.setPassword(password);
/**
* 此处数据库操作写入用户表
* */
jdbcUser.addMySQL(normalUser);
return normalUser;
}
}
public static User login() throws SQLException {
System.out.println("请输入你的姓名");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
System.out.println("请输入你的身份:1.管理员 2.普通用户");
String choice = scanner.nextLine();
if(choice.equals("1")){
/**
* 从管理员用户表里通过名字找密码
* 找到后对比
*/
System.out.println("请输入密码");
AdminUser adminUser = new AdminUser(name);
String password = scanner.nextLine();
adminUser.setPassword(password);
JDBCAdmin jdbcAdmin = new JDBCAdmin();
if(adminUser.getPassword().equals(jdbcAdmin.findMySql(name))){
return adminUser;
}else{
System.out.println("密码错误,退出系统");
System.exit(0);
return null;
}
}else{
/**
* 用户登录与注册
* 登录涉及查询数据表
* 注册设计添加数据
*/
System.out.println("请选择》:1.登录 2.注册");
String ch = scanner.nextLine();
Init(name,ch);
return new NormalUser(name);
}
}
此时登录成功后返回一个user对象,然后通过父类的引用调用重写的方法menu发生多态,普通用户打印出普通用户的菜单,管理⚪打印出管理员的菜单,然后通过选择操作判断进行哪个操作,此时在父类user里写一个操作接口数组与调用操作接口数组的方法,然后在普通成员与管理员的子类构造方法里根据不同的操作去初始化这个数组,初始化时相当于发送了向上转型,然后在操作接口数组的函数里,通过用户返回的选择,调用接口数组里的不同操作对象里重写的work方法实现多态
public abstract class User {
protected String name;
protected String password;
protected IOperation[] iOperations;
public User(String name) {
this.name = name;
}
public void setPassword(String password){
this.password = password;
}
public String getPassword(){
return this.password;
}
public String getName() {
return name;
}
public abstract int menu();
public void doOperation(int choice, BookList bookList) throws SQLException {
this.iOperations[choice].work(bookList);
}
}
在子类里
public class AdminUser extends User{
public AdminUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),
new FindOperation(),
new AddOperation(),
new DelOperation(),
new DisplayOperation()
};
}
public int menu(){
System.out.println("hello "+this.name+" 欢迎来到图书馆!");
System.out.println("1.查找图书!");
System.out.println("2.新增图书!");
System.out.println("3.删除图书!");
System.out.println("4.显示图书!");
System.out.println("0.退出系统!");
System.out.println("请输入你的选择");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
public class NormalUser extends User{
public NormalUser(String name) {
super(name);
this.iOperations = new IOperation[]{
new ExitOperation(),
new FindOperation(),
new BorrowOperation(),
new ReturnOperation()
};
}
public int menu(){
System.out.println("hello "+this.name+" 欢迎来到图书馆!");
System.out.println("1.查找图书!");
System.out.println("2.借阅图书!");
System.out.println("3.归还图书!");
System.out.println("0.退出系统!");
System.out.println("请输入你的选择");
Scanner scanner = new Scanner(System.in);
int choice = scanner.nextInt();
return choice;
}
}
在mian函数里
public static void main(String[] args) throws SQLException {
BookList bookList = new BookList(); //准备图书
//登录
User user = login();
while(true){
int choice = user.menu(); //向上转型 父类的引用引用了子类的对象,多态
//user父类里用户操作接口数组的方法
user.doOperation(choice,bookList);
}
}