使用JDBC+javafx写一个简单功能齐全的图书管理系统

Posted 冷兮雪

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用JDBC+javafx写一个简单功能齐全的图书管理系统相关的知识,希望对你有一定的参考价值。

目录

1、JDBC的使用

 2、对应包和Java文件的层级关系及对应的含义

3、数据库

4、相关代码

1)、bookmanager包

Ⅰ、main函数

Ⅱ、utils包

Ⅲ、bean包 

Ⅳ、controller包 

 2)resources(为资源文件包,可以看链接文章了解)

Ⅰ、book包

Ⅱ、 login包

5、效果展示(对应功能实现在相应代码中)

1)、登录功能

 2)、注册功能

 3)、后台主页面

 4)、编辑页和添加页

 5)、修改密码页

 6)、注销页

在文章结尾有图书管理系统的效果展示

1、JDBC的使用

后面会用到大量jdbc语句来实现数据库的增删改查,可以先简单看看下面这篇文章。

jdbc的简单使用与封装

 2、对应包和Java文件的层级关系及对应的含义

 上面DBUtils为jdbc的封装,详情可以看jdbc的简单使用与封装,还有dp.properties文件也在这篇文章中收到,我后面就不再过多概述。

3、数据库

admin:

book:

 category:

4、相关代码

1)、bookmanager包

Ⅰ、main函数

BookManagerApplication

package com.hk.sky.bookmanager;

import com.hk.sky.bookmanager.bean.Admin;
import com.hk.sky.bookmanager.controller.LoginController;
import com.hk.sky.bookmanager.dao.AdminDao;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;


public class BookManagerApplication extends Application 
    AdminDao adminDao=new AdminDao();
    //获取上一次用户登录的信息
    Admin admin=adminDao.getLast();
    @Override
    public void start(Stage stage) throws IOException 
        //登录页面的资源文件为login/login.fxml
        FXMLLoader fxmlLoader = new FXMLLoader(BookManagerApplication.class.getResource("login/login.fxml"));
        //设置登录窗口的长和宽
        Scene scene = new Scene(fxmlLoader.load(), 290, 240);
        stage.setTitle("管理员登录");
        stage.setScene(scene);
        LoginController loginController=fxmlLoader.getController();
        //如果admin不是为null,则说明上一次有用户登录,则直接在登录页面显示账号和密码
        if (admin!=null)
            loginController.set(admin.getAccount(),admin.getPassword());
        stage.show();
    
    //启动
    public static void main(String[] args) 
        launch();
    

Ⅱ、utils包

DBUtils

package com.hk.sky.bookmanager.utils;
import java.io.IOException;
import java.sql.*;
import java.util.Properties;

/**
 * 封装数据连接,关闭的工具类
 */
public class DBUtils 

    private static String url;
    private static String username;
    private static String password;

    // 读取配置文件
    static 
        Properties prop = new Properties();

        try 
            // DBUtils.class.getClassLoader().getResourceAsStream()方法可以从类路径中读取资源文件
            prop.load(DBUtils.class.getClassLoader().getResourceAsStream("db.properties"));

            // 通过key获取value
            url = prop.getProperty("jdbc.url");
            username = prop.getProperty("jdbc.username");
            password = prop.getProperty("jdbc.password");
         catch (IOException e) 
            throw new RuntimeException(e);
        
    


    // 将创建连接的方法封装成静态方法,方便调用
    // 如何将url、username、password放到配置文件当中,然后读取出来
    public static Connection getConnection() 
        // 创建连接的时候,有会异常:SQLException,不建议抛出,建立捕获
        Connection conn = null;
        try 
            conn = DriverManager.getConnection(
                    url,
                    username,
                    password
            );
         catch (SQLException e) 
            e.printStackTrace();
        

        return conn;
    
    
    // 将关闭连接的方法封装成静态方法,方便调用
    public static void close(ResultSet rs, PreparedStatement pStmt, Connection conn) 
        if (rs != null) 
            try 
                rs.close();
             catch (SQLException e) 
                e.printStackTrace();
            
        
        if (pStmt != null) 
            try 
                pStmt.close();
             catch (SQLException e) 
                e.printStackTrace();
            
        
        if (conn != null) 
            try 
                conn.close();
             catch (SQLException e) 
                e.printStackTrace();
            
        
    

Ⅲ、bean包 

Admin

package com.hk.sky.bookmanager.bean;

public class Admin 
    //账号
    private String account;
    //密码
    private String password;
    //上一次登录
    private int last;

    public String getAccount() 
        return account;
    

    public String getPassword() 
        return password;
    

    public void setAccount(String account) 
        this.account = account;
    

    public void setPassword(String password) 
        this.password = password;
    

    public int getLast() 
        return last;
    

    public void setLast(int last) 
        this.last = last;
    

    @Override
    public String toString() 
        return "Admin" +
                "account='" + account + '\\'' +
                ", password='" + password + '\\'' +
                ", last=" + last +
                '';
    

book

package com.hk.sky.bookmanager.bean;

public class Book 
    private int id;
    private String bookName;
    private String author;
    private int price;
    private int stock;
    private String publisher;
    private String detail;
    private int typeId;

    public void setDetail(String detail) 
        this.detail = detail;
    
    public String getDetail() 
        return detail;
    

    public int getId() 
        return id;
    

    public String getBookName() 
        return bookName;
    

    public String getAuthor() 
        return author;
    

    public int getPrice() 
        return price;
    

    public int getStock() 
        return stock;
    

    public String getPublisher() 
        return publisher;
    

    public void setId(int id) 
        this.id = id;
    

    public void setBookName(String bookName) 
        this.bookName = bookName;
    

    public void setAuthor(String author) 
        this.author = author;
    

    public void setPrice(int price) 
        this.price = price;
    

    public void setStock(int stock) 
        this.stock = stock;
    

    public void setPublisher(String publisher) 
        this.publisher = publisher;
    

    public void setTypeId(int typeId) 
        this.typeId = typeId;
    

    public int getTypeId() 
        return typeId;
    
    public Book()
    public Book(String name, String author, String publisher, int price, String detail, int stock, int typeId) 
        this.bookName = name;
        this.author = author;
        this.publisher = publisher;
        this.price = price;
        this.detail = detail;
        this.stock = stock;
        this.typeId = typeId;
    

Category

package com.hk.sky.bookmanager.bean;

public class Category 
    private int id;
    private String typeName;

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

    public String getTypeName() 
        return typeName;
    

    public void setTypeName(String typeName) 
        this.typeName = typeName;
    

    @Override
    public String toString() 
        return typeName;
    

Ⅳ、controller包 

AddController

package com.hk.sky.bookmanager.controller;

import com.hk.sky.bookmanager.bean.Book;
import com.hk.sky.bookmanager.bean.Category;
import com.hk.sky.bookmanager.dao.BookDao;
import com.hk.sky.bookmanager.dao.CategoryDao;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.stage.Stage;

import java.net.URL;
import java.sql.SQLException;
import java.util.*;


public class AddController implements Initializable 
    @FXML
    public Button add;
    @FXML
    public Button edit;

    @FXML
    private ComboBox<Category> categoryComboBox;

    private ObservableList<Category> observableList = FXCollections.observableArrayList();

    private CategoryDao categoryDao = new CategoryDao();

    private BookDao bookDao = new BookDao();

    @FXML
    private TextField bookName;
    @FXML
    private TextField bookAuthor;
    @FXML
    private TextField bookPublisher;
    @FXML
    private TextField bookPrice;
    @FXML
    private TextField detail;
    @FXML
    private TextField bookStock;
    public Book book;

    public void setBook(Book book) 
        this.book = book;
    
    //B用来判断是添加书籍还是编辑书籍
    public boolean B;
    public void setB(boolean i)
        this.B=i;
    
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) 
        Platform.runLater(() -> 
            // 页面第一次加载的时候,就显示下拉列表
            observableList.clear();
            List<Category> categories = categoryDao.getAllCategories();
            observableList.addAll(categories);
            categoryComboBox.setItems(observableList);
            //添加书籍  修改书籍
            if (B)
                add.setVisible(true);
                add.setText("添加");
                edit.setVisible(false);
                edit.setText("");
                categoryComboBox.setValue(categories.get(0));
            else 
                bookName.setText(book.getBookName());
                bookAuthor.setText(book.getAuthor());
                bookPublisher.setText(book.getPublisher());
                bookPrice.setText(String.valueOf(book.getPrice()));
                detail.setText(book.getDetail());
                bookStock.setText(String.valueOf(book.getStock()));
                categoryComboBox.setValue(categories.get(book.getTypeId()));
                edit.setVisible(true);
                edit.setText("修改");
                add.setDisable(false);
                add.setText("");
            
        );
    
    //给添加按钮设置点击事件
    public void addBook() throws SQLException 
        // 用户点击添加按钮时,获取所有的数据,并插入到数据库当中
        String name = bookName.getText();
        String author = bookAuthor.getText();
        String publisher = bookPublisher.getText();
        String detail1 = detail.getText();

        // 将格式进行转换
        // 表单验证,判断用户是否输入内容
        if (name.equals("") || author.equals("") || publisher.equals("") || detail1.equals("") ||
                bookPrice.getText().equals("") || bookStock.getText().equals("")) 

            Alert error = new Alert(Alert.AlertType.ERROR, "输入错误");
            Button err = new Button();
            error.setTitle("您的书籍信息输入错误!");
            error.setHeaderText("请正确填写所要添加书籍的信息!");
            err.setOnAction((ActionEvent e) -> 
                error.showAndWait();
            );
            Optional<ButtonType> result = error.showAndWait();
         else if (!bookPrice.getText().matches("[1-9]+[0-9]*")||!bookStock.getText().matches("[1-9]+[0-9]*"))
            Alert error = new Alert(Alert.AlertType.ERROR, "输入错误");
            Button err = new Button();
            error.setTitle("您的书籍信息输入错误!");
            error.setHeaderText("库存和价格必须为整数!");
            err.setOnAction((ActionEvent e) -> 
                error.showAndWait();
            );
            Optional<ButtonType> result = error.showAndWait();
        else
            // 思路:将上面获取到的数据封装成book,然后插入到数据库当中
            // 但是仔细思考,我们会碰到一个难点:如何获取ComboBox的选项?也就是说如何知道用户选的是哪一个类型的书籍?
            Category selectedCategory = categoryComboBox.getValue();
            int price = Integer.parseInt(bookPrice.getText());
            int stock = Integer.parseInt(bookStock.getText());

            // 将所有的数据封装成书籍
            Book book = new Book(name, author, publisher, price, detail1, stock, selectedCategory.getId());
            // 调用BookDao中的方法将数据插入到数据库当中
            Alert information = new Alert(Alert.AlertType.INFORMATION, "恭喜您书籍添加成功");
            Button err = new Button();
            information.setTitle("添加成功!");
            information.setHeaderText("林氏图书馆又收录了一本新书,感谢!");
            err.setOnAction((ActionEvent e) -> 
                information.showAndWait();
            );
            Optional<ButtonType> result = information.showAndWait();

            // 插入成功之后,首先当前属性应该关闭
            if (bookDao.insertBook(book))
                ((Stage) bookName.getScene().getWindow()).close();
            
        
    
    //给编辑按钮设置点击事件
    public void editBook(ActionEvent actionEvent) throws SQLException
        // 用户点击添加按钮时 ,获取所有的数据,并插入到数据库当中
        String name = bookName.getText();
        String author = bookAuthor.getText();
        String publisher = bookPublisher.getText();
        String detail1 = detail.getText();

        // 将格式进行转换
        // 表单验证,判断用户是否输入内容
        if (name.equals("")||author.equals("")||publisher.equals("")||detail1.equals("")||
                bookPrice.getText().equals("")||bookStock.getText().equals(""))

            Alert error=new Alert(Alert.AlertType.ERROR,"输入错误");
            Button err=new Button();
            error.setTitle("您的书籍信息输入错误!");
            error.setHeaderText("请正确填写所要修改书籍的信息!");
            err.setOnAction((ActionEvent e)->
                error.showAndWait();
            );
            Optional<ButtonType> result = error.showAndWait();
        else if (!bookPrice.getText().matches("[1-9]+[0-9]*")||!bookStock.getText().matches("[1-9]+[0-9]*"))
            Alert error = new Alert(Alert.AlertType.ERROR, "输入错误");
            Button err = new Button();
            error.setTitle("您的书籍信息输入错误!");
            error.setHeaderText("库存和价格必须为整数!");
            err.setOnAction((ActionEvent e) -> 
                error.showAndWait();
            );
            Optional<ButtonType> result = error.showAndWait();
        else 
            int price = Integer.parseInt(bookPrice.getText());
            int stock = Integer.parseInt(bookStock.getText());

            // 思路:将上面获取到的数据封装成book,然后插入到数据库当中
            // 但是仔细思考,我们会碰到一个难点:如何获取ComboBox的选项?也就是说如何知道用户选的是哪一个类型的书籍?
            Category selectedCategory = categoryComboBox.getValue();

            // 将所有的数据封装成书籍
            Book book1 = new Book(name, author, publisher, price, detail1, stock, selectedCategory.getId());
            book1.setId(book.getId());
            // 调用BookDao中的方法将数据插入到数据库当中
            Alert information=new Alert(Alert.AlertType.INFORMATION,"恭喜您书籍信息修改成功");
            Button err=new Button();
            information.setTitle("修改成功!");
            information.setHeaderText("谢谢您为林氏图书馆添砖加瓦,感谢!");
            err.setOnAction((ActionEvent e)->
                information.showAndWait();
            );
            Optional<ButtonType> result = information.showAndWait();
            boolean success = bookDao.updateBook(book1);
            // 插入成功之后,首先当前属性应该关闭
            if (success) 
                ((Stage)bookName.getScene().getWindow()).close();
            
        
    

 EnrollController

package com.hk.sky.bookmanager.controller;

import com.hk.sky.bookmanager.bean.Admin;
import com.hk.sky.bookmanager.dao.AdminDao;
import com.hk.sky.bookmanager.utils.DBUtils;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Objects;
import java.util.Optional;

public class EnrollController 
    @FXML
    public TextField username1;
    @FXML
    public PasswordField password1;
    @FXML
    public Text errorMsg;//提示错误信息
    @FXML
    private Button alert;
    @FXML
    private Button enroll;
    @FXML
    public Text title;
    AdminDao adminDao=new AdminDao();

    //给注册按钮设置点击事件
    public void enrollBtn() 
        String account=username1.getText();
        String pw=password1.getText();

        if (Objects.equals(account, ""))
            errorMsg.setText("请填写用户名");
        else if (Objects.equals(pw, ""))
            errorMsg.setText("请填写密码");
        else 
            boolean b=adminDao.enroll(account,pw);
            if(!b)
                errorMsg.setText("用户名已使用,请更改用户名!");
            else 
                Alert information=new Alert(Alert.AlertType.INFORMATION,"恭喜"+account+"用户注册成功");
                Button err=new Button();
                information.setTitle("注册成功!");
                information.setHeaderText("林氏图书馆欢迎您的到来!");
                err.setOnAction((ActionEvent e)->
                    information.showAndWait();
                );
                Optional<ButtonType> result = information.showAndWait();
                // 关闭当前Stage,问题:如何获取当前的stage?
                Stage currentWindow = (Stage)username1.getScene().getWindow();
                currentWindow.close();
            

        
    

    //区分是注册还是修改密码,修改密码的话账号无法更改,输入框为不可选择,注册按钮消失,修改按钮显示
    public void qf(boolean b)
        if (b)
            enroll.setVisible(false);
            alert.setVisible(true);

            username1.setDisable(true);
        
    
    //s用来保存原密码,修改密码无法更改为原密码
    public String s;
    public void setS(String ss)
        s=ss;
    
    //给修改密码设置点击事件
    public void alertBtn() throws SQLException 
        if (password1.getText().equals(""))
            errorMsg.setText("密码不能为空");
        else if(password1.getText().equals(s))
            errorMsg.setText("不能与最近使用密码相同");
        else 
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "你是否真的要修改该密码?");
            alert.setTitle("修改密码");
            alert.setHeaderText("确认修改?");
            Optional<ButtonType> result = alert.showAndWait();
            if (result.isPresent())
                adminDao.alertPassword(username1.getText(),password1.getText());
                Alert information = new Alert(Alert.AlertType.INFORMATION, "恭喜您修改密码成功!");
                Button err = new Button();
                information.setTitle("修改密码");
                information.setHeaderText("修改密码成功!");
                err.setOnAction((ActionEvent e) -> 
                    information.showAndWait();
                );
                Optional<ButtonType> rs = information.showAndWait();
            
        
    

 HouTaiController

package com.hk.sky.bookmanager.controller;

import com.hk.sky.bookmanager.BookManagerApplication;
import com.hk.sky.bookmanager.bean.Admin;
import com.hk.sky.bookmanager.bean.Book;
import com.hk.sky.bookmanager.dao.AdminDao;
import com.hk.sky.bookmanager.dao.BookDao;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import java.io.IOException;
import java.net.URL;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.ResourceBundle;

public class HouTaiController implements Initializable 
    /*搜索框*/
    public TextField search;
    /*下拉框*/
    public ComboBox categorySelect;

    // 不能直接从这里查询用户信息,因为在当前这个类当中,我不知道是谁登录了
    // 通过上一个类传递到当前类当中,我们需要在当前类中定义要传递的数据,然后通过set方法设置该属性的值
    private Admin admin;
    public String bookName;
    public String bookAuthor;
    public String Publish;
    //表示查询到的行
    public int sumPage;
    //n表示页数
    public int n;
    public void setAdmin(Admin admin) 
        this.admin = admin;
    
    public void setSumPage(int i)
        this.sumPage=i;
        double j=i/9.0;
        n=(int) Math.ceil(j);
    
    public void setBookName(String s)
        bookName=s;
    
    @FXML
    private Text welcomeMsg;
    @FXML
    private Text searchCount;
    @FXML
    private Text searchPage;
    @FXML//返回按钮
    private Button fh;
    //给表添加数据
    @FXML
    private TableView<Book> bookTable;
    // 准备表格中的数据
    private ObservableList<Book> data = FXCollections.observableArrayList();
    // 准备dao类,它负责到数据库中查询
    private BookDao bookDao = new BookDao();
    private AdminDao adminDao=new AdminDao();
    //添加按钮操作
    // 编辑按钮
    private TableColumn<Book, Integer> editColumn = new TableColumn<>("编辑");

    // 删除按钮
    private TableColumn<Book, Integer> delColumn = new TableColumn<>("删除");

    // 详情按钮
    private TableColumn<Book, Integer> detailColumn = new TableColumn<>("详情");


    // 上一个页面中将admin传递过来,我们需要在当前窗口中来获取传递过来的数据,然后将值设置给页面中的元素显示
    // 将当前类实现Initializable接口,然后在initialize(初始化)方法中获取设置的值,然后设置给页面中的元素
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) 
        // 通过UI线程获取值,并设置值
        Platform.runLater(() -> 
            welcomeMsg.setText("欢迎" + admin.getAccount() + "管理员登录!");
            searchCount.setText("共"+sumPage+"条记录");
            categorySelect.getItems().addAll(
                    "书名",
                    "出版社",
                    "作者"
            );
            categorySelect.setValue("书名");
            // 查询数据库,设置ObservableList,并添加至tableView当中
            List<Book> books = bookDao.set(search.getText(),0);
            data.addAll(books);
            bookTable.setItems(data);

            //1、添加编辑按钮
            editColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getId()));
            editColumn.setCellFactory(param -> new TableCell<>()
                final Button editBtn = new Button("编辑");
                @Override
                protected void updateItem(Integer item, boolean empty) 
                    super.updateItem(item, empty);
                    if (item == null) 
                        setGraphic(null);
                        return;
                    
                    setGraphic(editBtn);
                    // 添加点击事件
                    editBtn.setOnMouseClicked(event ->
                        try 
                            Stage newStage = new Stage();
                            FXMLLoader fxmlLoader = new FXMLLoader(BookManagerApplication.class.getResource("book/add.fxml"));
                            Scene scene = new Scene(fxmlLoader.load(), 280, 400);
                            newStage.setTitle("编辑书籍");
                            newStage.setScene(scene);
                            AddController addController=fxmlLoader.getController();
                            addController.setB(false);
                            addController.setBook(bookDao.getbookById(item));
                            newStage.show();
                            // 我们需要监听添加页面关闭后,刷新tableview
                            // CloseRequest()只有在用户点击右上角的叉时才会触发
                            newStage.setOnHiding(evt->
                                refreshTableView(i);
                            );
                         catch (IOException e) 
                            throw new RuntimeException(e);
                        

                    );
                
            );
            //将列添加至表中
            bookTable.getColumns().add(editColumn);

            //2、添加删除按钮
            delColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getId()));
            delColumn.setCellFactory(param -> new TableCell<>()
                // 创建删除按钮
                final Button editBtn = new Button("删除");

                @Override
                protected void updateItem(Integer item, boolean empty) 
                    super.updateItem(item, empty);
                    if (item == null) 
                        setGraphic(null);
                        return;
                    
                    setGraphic(editBtn);

                    // 添加点击事件
                    editBtn.setOnMouseClicked(event -> 
                        // 添加一个对话框,判断用户是否需要真的删除
                        Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "你是否需要真的删除这本吗?");
                        alert.setTitle("警告");
                        alert.setHeaderText("确认删除?");
                        Optional<ButtonType> result = alert.showAndWait();

                        if (result.isPresent() && result.get() == ButtonType.OK) 
                            // 实现删除功能
                            bookDao.deleteBookById(item);
                            // 刷新页面
                            refreshTableView(i);
                        
                    );

                
            );
            //将列添加至表中
            bookTable.getColumns().add(delColumn);

            // 3、添加详情按钮
            detailColumn.setCellValueFactory(param -> new ReadOnlyObjectWrapper<>(param.getValue().getId()));
            detailColumn.setCellFactory(param -> new TableCell<>()
                // 创建详情按钮
                final Button editBtn = new Button("详情");
                @Override
                protected void updateItem (Integer item,boolean empty)
                    super.updateItem(item, empty);
                    if (item == null) 
                        setGraphic(null);
                        return;
                    
                    setGraphic(editBtn);

                    // 添加点击事件
                    editBtn.setOnMouseClicked(event -> 
                        try 
                            Stage newStage = new Stage();
                            FXMLLoader fxmlLoader = new FXMLLoader(BookManagerApplication.class.getResource("book/show.fxml"));
                            Scene scene = new Scene(fxmlLoader.load(), 280, 270);
                            newStage.setTitle("书籍详情");
                            newStage.setScene(scene);

                            // 将当前书籍id传递到下一个页面当中
                            ShowController showController = fxmlLoader.getController();
                            showController.setBook(bookDao.getbookById(item));

                            // 显示要打开的Stage,stage.show()
                            newStage.show();
                         catch (IOException e) 
                            throw new RuntimeException(e);
                        
                    );
                    //将列添加至表中
                
            );
            bookTable.getColumns().add(detailColumn);
        );
    

    public void refreshTableView(int i)
        // 在往集合中添加数据之前,先清空集合
        data.clear();

        List<Book> books = null;
        // 查询数据库,设置ObservableList,并添加至tableView当中
        if(categorySelect.getValue().equals("作者")&&bookAuthor!=null) 
            setSumPage(bookDao.likeSumCountByAuthor(search.getText()));
            if (i==n)
                i--;
            books= bookDao.setByAuthor(bookAuthor, i);
            searchCount.setText("共"+bookDao.likeSumCountByAuthor(search.getText())+"条记录");
        else if (categorySelect.getValue().equals("出版社")&&Publish!=null)
            setSumPage(bookDao.likeSumCountByPublish(search.getText()));
            if (i==n)
                i--;
            books= bookDao.setByPublish(Publish, i);
            searchCount.setText("共"+bookDao.likeSumCountByPublish(search.getText())+"条记录");
        else 
            setSumPage(bookDao.likeSumCount(search.getText()));
            if (i==n)
                i--;
            books= bookDao.set(bookName, i);
            searchCount.setText("共"+bookDao.likeSumCount(search.getText())+"条记录");

        

        data.addAll(books);
        bookTable.setItems(data);

        int z=i+1;
        searchPage.setText("第"+z+"页");
    

    int i=0;
    //首页按钮
    public void start()
        if (i!=0)
            data.clear();
            List<Book> books=null;
            // 查询数据库,设置ObservableList,并添加至tableView当中
            if (categorySelect.getValue().equals("出版社")&&Publish!=null)
                books=bookDao.setByPublish(Publish,0);
            else if (categorySelect.getValue().equals("作者")&&bookAuthor!=null)
                books=bookDao.setByAuthor(bookAuthor,0);
            else 
                books= bookDao.set(bookName,0);
            

            data.addAll(books);
            bookTable.setItems(data);
            i=0;
            searchPage.setText("第"+1+"页");
        
    
    //尾页按钮
    public void end()
        if (i!=n-1)
            data.clear();
            List<Book> books=null;
            // 查询数据库,设置ObservableList,并添加至tableView当中
            // 查询数据库,设置ObservableList,并添加至tableView当中
            if (categorySelect.getValue().equals("出版社")&&Publish!=null)
                books=bookDao.setByPublish(Publish,n-1);
            else if (categorySelect.getValue().equals("作者")&&bookAuthor!=null)
                books=bookDao.setByAuthor(bookAuthor,n-1);
            else 
                books= bookDao.set(bookName,n-1);
            

            data.addAll(books);
            bookTable.setItems(data);
            i=n-1;
            searchPage.setText("第"+n+"页");
        
    
    //上一页按钮
    public void up()
        if (i>0&&i<=n-1)
            data.clear();
            // 查询数据库,设置ObservableList,并添加至tableView当中
            List<Book> books=null;
            // 查询数据库,设置ObservableList,并添加至tableView当中
            if (categorySelect.getValue().equals("出版社")&&Publish!=null)
                books=bookDao.setByPublish(Publish,--i);
            else if (categorySelect.getValue().equals("作者")&&bookAuthor!=null)
                books=bookDao.setByAuthor(bookAuthor,--i);
            else 
                books= bookDao.set(bookName,--i);
            
            data.addAll(books);
            bookTable.setItems(data);
            int z=i+1;
            searchPage.setText("第"+z+"页");
        
    
    //下一页按钮
    public void next()
        if (i<n-1&&i>=0)
            data.clear();
            // 查询数据库,设置ObservableList,并添加至tableView当中
            List<Book> books=null;
            // 查询数据库,设置ObservableList,并添加至tableView当中
            if (categorySelect.getValue().equals("出版社")&&Publish!=null)
                books=bookDao.setByPublish(Publish,++i);
            else if (categorySelect.getValue().equals("作者")&&bookAuthor!=null)
                books=bookDao.setByAuthor(bookAuthor,++i);
            else 
                books= bookDao.set(bookName,++i);
            
            data.addAll(books);
            bookTable.setItems(data);
            int z=i+1;
            searchPage.setText("第"+z+"页");
        
    
    //搜索按钮
    public void searchBtn() throws IOException 
       if (categorySelect.getValue().equals("书名"))
        if (!Objects.equals(search.getText(), ""))
            if (bookDao.likeSumCount(search.getText())==0)
                Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "抱歉,为查找到有关该图书!");
                alert.setTitle("查找错误");
                alert.setHeaderText("请重新填写所要查找书籍的名称!");
                Optional<ButtonType> result = alert.showAndWait();
            else 
                fh.setVisible(true);
                bookName=search.getText();
                // 在往集合中添加数据之前,先清空集合
                data.clear();
                // 查询数据库,设置ObservableList,并添加至tableView当中
                List<Book> books = bookDao.set(bookName,0);
                data.addAll(books);
                bookTable.setItems(data);
                setSumPage(bookDao.likeSumCount(bookName));
                searchCount.setText("共"+bookDao.likeSumCount(search.getText())+"条记录");
                i=0;
                searchPage.setText("第"+1+"页");
            
        else 
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "错误,搜索框中未输入查询数据!");
            alert.setTitle("输入错误");
            alert.setHeaderText("请填写所要查找书籍的名称,书籍名不能为空!");
            Optional<ButtonType> result = alert.showAndWait();
        
       else if (categorySelect.getValue().equals("作者"))
           if (!Objects.equals(search.getText(), ""))
               if (bookDao.likeSumCountByAuthor(search.getText())==0)
                   Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "抱歉,未查找到有关该图书!");
                   alert.setTitle("查找错误");
                   alert.setHeaderText("请重新填写所要查找书籍的作者!");
                   Optional<ButtonType> result = alert.showAndWait();
               else 
                   fh.setVisible(true);
                   bookAuthor=search.getText();
                   // 在往集合中添加数据之前,先清空集合
                   data.clear();
                   // 查询数据库,设置ObservableList,并添加至tableView当中
                   List<Book> books = bookDao.setByAuthor(bookAuthor,0);
                   data.addAll(books);
                   bookTable.setItems(data);
                   setSumPage(bookDao.likeSumCountByAuthor(bookAuthor));
                   searchCount.setText("共"+bookDao.likeSumCountByAuthor(bookAuthor)+"条记录");
                   i=0;
                   searchPage.setText("第"+1+"页");
               
           else 
               Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "错误,搜索框中未输入查询数据!");
               alert.setTitle("输入错误");
               alert.setHeaderText("请填写所要查找书籍的作者,作者名不能为空!");
               Optional<ButtonType> result = alert.showAndWait();
           
       else 
           if (!Objects.equals(search.getText(), ""))
               if (bookDao.likeSumCountByPublish(search.getText())==0)
                   Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "抱歉,未查找到有关该图书!");
                   alert.setTitle("查找错误");
                   alert.setHeaderText("请重新填写所要查找书籍的出版社!");
                   Optional<ButtonType> result = alert.showAndWait();
               else 
                   fh.setVisible(true);
                   Publish=search.getText();
                   // 在往集合中添加数据之前,先清空集合
                   data.clear();
                   // 查询数据库,设置ObservableList,并添加至tableView当中
                   List<Book> books = bookDao.setByPublish(Publish,0);
                   data.addAll(books);
                   bookTable.setItems(data);
                   setSumPage(bookDao.likeSumCountByPublish(Publish));
                   searchCount.setText("共"+bookDao.likeSumCountByPublish(Publish)+"条记录");
                   i=0;
                   searchPage.setText("第"+1+"页");
               
           else 
               Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "错误,搜索框中未输入查询数据!");
               alert.setTitle("输入错误");
               alert.setHeaderText("请填写所要查找书籍的出版社,出版社名不能为空!");
               Optional<ButtonType> result = alert.showAndWait();
           
       
    
    //删除按钮
    public void deleteBtn() 
        Book book1=null;
        String bookName=search.getText();
        book1=bookDao.getBookByBookName(bookName);
        if (book1!=null)
            // 添加一个对话框,判断用户是否需要真的删除
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "你是否需要真的删除这本书吗?");
            alert.setTitle("警告");
            alert.setHeaderText("确认删除?");
            Optional<ButtonType> result = alert.showAndWait();

            if (result.isPresent() && result.get() == ButtonType.OK) 
                // 实现删除功能
                bookDao.deleteBookByBookName(bookName);
                // 刷新页面
                refreshTableView(i);
            
        else 
            // 添加一个对话框,告诉用户没有这本书
            Alert error=new Alert(Alert.AlertType.ERROR,"删除错误,该图书馆未收录此书!");
            Button err=new Button();
            error.setTitle("删除错误!");
            error.setHeaderText("请重新填写要删除的书籍!");
            err.setOnAction((ActionEvent e)->
                error.showAndWait();
            );
            Optional<ButtonType> result = error.showAndWait();
        
    
    //添加按钮
    public void addBtn()  
        try 
            Stage newStage = new Stage();
            FXMLLoader fxmlLoader = new FXMLLoader(BookManagerApplication.class.getResource("book/add.fxml"));
            Scene scene = new Scene(fxmlLoader.load(), 280, 400);
            newStage.setTitle("添加书籍");
            newStage.setScene(scene);
            AddController addController=fxmlLoader.getController();
            addController.setB(true);

            newStage.show();
            // 我们需要监听添加页面关闭后,刷新tableview
            // CloseRequest()只有在用户点击右上角的叉时才会触发
            newStage.setOnHiding(event -> 
                refreshTableView(i);
            );
         catch (IOException e) 
            throw new RuntimeException(e);
        

    
    //返回按钮
    public void back(ActionEvent actionEvent) 
        categorySelect.setValue("书名");
        search.setText("");
        bookName=search.getText();
        // 在往集合中添加数据之前,先清空集合
        data.clear();
        // 查询数据库,设置ObservableList,并添加至tableView当中
        List<Book> books = bookDao.set(bookName,0);
        data.addAll(books);
        bookTable.setItems(data);
        setSumPage(bookDao.likeSumCount(bookName));
        searchCount.setText("共"+bookDao.likeSumCount(search.getText())+"条记录");
        i=0;
        searchPage.setText("第"+1+"页");
        fh.setVisible(false);
    
    //注销按钮
    public void zx(ActionEvent actionEvent) throws IOException 
        Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "你是否真的要注销该账号?");
        alert.setTitle("警告");
        alert.setHeaderText("确认注销?");
        Optional<ButtonType> result = alert.showAndWait();
        if (result.isPresent() && result.get() == ButtonType.OK) 
            adminDao.delete(admin.getAccount());
            //提醒用户该账号已注销,请重新登录
            Alert information = new Alert(Alert.AlertType.INFORMATION, "该账号已注销!");
            Button err = new Button();
            information.setTitle("登录失败!");
            information.setHeaderText("该账号已注销,请重新登录");
            err.setOnAction((ActionEvent e) -> 
                information.showAndWait();
            );
            Optional<ButtonType> result1 = information.showAndWait();

            //关闭 后台 页面
            Stage currentWindow = (Stage)search.getScene().getWindow();
            currentWindow.close();

            //重新显示登录页面
            Stage stage = new Stage();
            FXMLLoader fxmlLoader = new FXMLLoader(BookManagerApplication.class.getResource("login/login.fxml"));
            Scene scene = new Scene(fxmlLoader.load(), 290, 240);
            stage.setTitle("用户登录");
            stage.setScene(scene);

            stage.show();
        
    
    //修改密码
    public void xgmm(ActionEvent actionEvent) throws IOException 
        Stage stage = new Stage();
        FXMLLoader fxmlLoader = new FXMLLoader(BookManagerApplication.class.getResource("login/enroll.fxml"));
        Scene scene = new Scene(fxmlLoader.load(), 290, 251);
        stage.setTitle("修改密码");
        stage.setScene(scene);
        EnrollController enrollController=fxmlLoader.getController();
        enrollController.username1.setText(admin.getAccount());
        enrollController.password1.setText(admin.getPassword());
        String s=admin.getPassword();
        enrollController.title.setText("修改密码");
        enrollController.setS(admin.getPassword());

        enrollController.qf(true);
        stage.show();
        //添加监听事件,检查密码是否更换
        stage.setOnHiding(evt -> 
            try 
                if (adminDao.checkPassword(admin.getAccount(),s))
                    Alert information = new Alert(Alert.AlertType.INFORMATION, "该账号已注销!");
                    Button err = new Button();
                    information.setTitle("登录失败!");
                    information.setHeaderText("该账号已注销,请重新登录");
                    err.setOnAction((ActionEvent e) -> 
                        information.showAndWait();
                    );
                    Optional<ButtonType> result1 = information.showAndWait();

                    //关闭 后台 页面
                    Stage currentWindow = (Stage)search.getScene().getWindow();
                    currentWindow.close();

                    //重新显示登录页面
                    Stage stage1 = new Stage();
                    FXMLLoader fxmlLoader1 = new FXMLLoader(BookManagerApplication.class.getResource("login/login.fxml"));
                    Scene scene1 = new Scene(fxmlLoader1.load(), 290, 240);
                    stage1.setTitle("用户登录");
                    stage1.setScene(scene1);
                    LoginController loginController=fxmlLoader1.getController();
                    loginController.username.setText(admin.getAccount());
                    stage1.show();
                    adminDao.reset();
                
             catch (IOException e) 
                throw new RuntimeException(e);
            
        );

    

LoginController

package com.hk.sky.bookmanager.controller;

import com.hk.sky.bookmanager.BookManagerApplication;
import com.hk.sky.bookmanager.bean.Admin;
import com.hk.sky.bookmanager.dao.AdminDao;
import com.hk.sky.bookmanager.dao.BookDao;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import javafx.scene.text.Text;
import javafx.stage.Stage;

import java.io.IOException;

public class LoginController 

    @FXML
    public TextField username;

    @FXML
    private PasswordField password;

    @FXML
    private Text errorMsg;
    //设置上一次登录账号的账号密码
    public void set(String un,String pw)
        if (un!=null&&pw!=null)
            username.setText(un);
            password.setText(pw);
        
    

    @FXML
    //登录按钮 检查是否有该账号以及账号密码的正确性
    public void checkLogin() throws IOException 
        // 获取输入框中的内容
        String uname = username.getText();
        String pwd = password.getText();

        // 判断用户名与密码
        AdminDao adminDao = new AdminDao();
        Admin admin = adminDao.checkLogin(uname, pwd);
        if (admin == null) 
            errorMsg.setText("用户名或者密码错误");
         else 
            // 跳转到后面页面
            // 创建要打开的Stage,问题:stage如何创建?
            Stage newStage = new Stage();
            FXMLLoader fxmlLoader = new FXMLLoader(BookManagerApplication.class.getResource("book/houtai.fxml"));
            Scene scene = new Scene(fxmlLoader.load(), 700, 430);
            newStage.setTitle("后台页面");
            newStage.setScene(scene);

            // 关闭当前Stage,问题:如何获取当前的stage?
            Stage currentWindow = (Stage) username.getScene().getWindow();
            currentWindow.close();
            //消除上次用户登录的信息
            adminDao.reset();
            //保存这次用户登录的信息
            adminDao.setLast(username.getText());

            // 将当前用户的信息传递到下一个页面当中
            HouTaiController houTaiController = fxmlLoader.getController();
            BookDao bookdao=new BookDao();
            houTaiController.setSumPage(bookdao.sumPage());
            houTaiController.setAdmin(admin);
            houTaiController.setBookName("");

            // 显示要打开的Stage,stage.show()
            newStage.show();
        
    
    //注册按钮
    public void enrollLogin() throws IOException
        Stage stage = new Stage();
        FXMLLoader fxmlLoader = new FXMLLoader(BookManagerApplication.class.getResource("login/enroll.fxml"));
        Scene scene = new Scene(fxmlLoader.load(), 290, 251);
        stage.setTitle("用户注册");
        stage.setScene(scene);
        stage.show();
    

 ShowController

package com.hk.sky.bookmanager.controller;

import com.hk.sky.bookmanager.bean.Book;
import com.hk.sky.bookmanager.dao.BookDao;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.text.Text;

import java.net.URL;
import java.util.ResourceBundle;

public class ShowController implements Initializable 
    @FXML
    public Text bookId;
    Book book=null;
    public void setBook(Book book1)
        this.book=book1;
    
    private BookDao bookDao = new BookDao();

    @FXML
    private Text bookName;
    @FXML
    private Text bookAuthor;
    @FXML
    private Text bookPublish;
    @FXML
    private Text bookPrice;
    @FXML
    private Text bookStock;
    @FXML
    private Text bookDetail;

    //书籍详情页面显示
    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) 
        Platform.runLater(() -> 
            bookId.setText(String.valueOf(book.getId()));
            bookName.setText(book.getBookName());
            bookAuthor.setText(book.getAuthor());
            bookPublish.setText(book.getPublisher());
            bookPrice.setText(String.valueOf(book.getPrice()));
            bookStock.setText(String.valueOf(book.getStock()));
            bookDetail.setText(book.getDetail());
        );
    

module-info

module com.example.bookmange 
    requires javafx.controls;
    requires javafx.fxml;
    requires javafx.web;

    requires org.controlsfx.controls;
    requires validatorfx;
    requires org.kordamp.ikonli.javafx;
    requires org.kordamp.bootstrapfx.core;
    requires eu.hansolo.tilesfx;
    requires java.sql;

    opens com.hk.sky.bookmanager to javafx.fxml;
    exports com.hk.sky.bookmanager;
    exports com.hk.sky.bookmanager.controller;
    opens com.hk.sky.bookmanager.controller to javafx.fxml;
    opens com.hk.sky.bookmanager.bean to javafx.base;

 2)resources(为资源文件包,可以看链接文章了解)

Ⅰ、book包

add.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<?import javafx.geometry.Insets?>
<?import javafx.scene.text.Text?>
<?import java.net.URL?>
<GridPane xmlns="http://javafx.com/javafx"
          xmlns:fx="http://javafx.com/fxml"
          fx:controller="com.hk.sky.bookmanager.controller.AddController"
          prefHeight="400.0" prefWidth="600.0" hgap="20" vgap="20">

    <padding>
        <Insets left="20" top="30"/>
    </padding>

    <Text text="类型:" GridPane.rowIndex="0" GridPane.columnIndex="0"/>
    <ComboBox  GridPane.halignment="CENTER" GridPane.rowIndex="0" GridPane.columnIndex="1" fx:id="categoryComboBox">
    </ComboBox>

    <Text text="书名:" GridPane.rowIndex="1" GridPane.columnIndex="0"/>
    <TextField fx:id="bookName" GridPane.rowIndex="1" GridPane.columnIndex="1"/>

    <Text text="作者:" GridPane.rowIndex="2" GridPane.columnIndex="0"/>
    <TextField fx:id="bookAuthor" GridPane.rowIndex="2" GridPane.columnIndex="1"/>

    <Text text="出版社:" GridPane.rowIndex="3" GridPane.columnIndex="0"/>
    <TextField fx:id="bookPublisher" GridPane.rowIndex="3" GridPane.columnIndex="1"/>

    <Text text="价格:" GridPane.rowIndex="4" GridPane.columnIndex="0"/>
    <TextField fx:id="bookPrice" GridPane.rowIndex="4" GridPane.columnIndex="1"/>

    <Text text="内容简介:" GridPane.rowIndex="5" GridPane.columnIndex="0"/>
    <TextField fx:id="detail" GridPane.rowIndex="5" GridPane.columnIndex="1"/>

    <Text text="库存:" GridPane.rowIndex="6" GridPane.columnIndex="0"/>
    <TextField fx:id="bookStock" GridPane.rowIndex="6" GridPane.columnIndex="1"/>

    <Button fx:id="add" text="添加" onAction="#addBook" GridPane.rowIndex="7" GridPane.columnIndex="0" GridPane.columnSpan="2"
            GridPane.halignment="CENTER" styleClass="aBtn" visible="true" > </Button>

    <Button fx:id="edit" onAction="#editBook" GridPane.rowIndex="7" GridPane.columnIndex="0" GridPane.columnSpan="2"
            GridPane.halignment="CENTER" styleClass="eBtn" visible="false"> </Button>
    <stylesheets>
        <URL value="@add.css"/>
    </stylesheets>

</GridPane>

 houtai.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<?import javafx.scene.text.Text?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<?import java.net.URL?>
<AnchorPane xmlns="http://javafx.com/javafx"
            xmlns:fx="http://javafx.com/fxml"
            fx:controller="com.hk.sky.bookmanager.controller.HouTaiController"
            prefHeight="550.0" prefWidth="580.0" styleClass="ht">


    <Button fx:id="fh" text="返回" visible="false" onAction="#back"/>

    <Text id="wm" fx:id="welcomeMsg" AnchorPane.leftAnchor="290" AnchorPane.topAnchor="10"/>

    <Button  text="修改密码"  onActio

基于JavaSE + JDBC的图书管理系统

前言

这个数据库管理系统是纯后端的,基于JavaSE和JDBC,第三方jar包用了druid的数据库连接池,本来想用DButils做CRUD,后来想想自己对增删改查的流程还不够熟练所以就自己写了DAO。
在写之前本来觉得挺简单一个事,谁知道越写越复杂,越写发现自己技术的欠缺。所以这个图书管理系统,还存在许多问题,贴出来大家共同学习进步,也真心希望有大佬能提出一些宝贵的建议,在此提前感谢!

设计思路

此处内容属于补充内容,是我在写完整个管理系统后,对于整个项目逻辑的梳理,在实际的代码实现上,可能并没有达到这个设计思路所要求的标准,主要原因在于自己经验和技术的欠缺。
这个设计思路只是一个笼统的概述,不涉及到细节层面,并且这只是我个人的一些设计思路。作为一个Java入门学习者,写出来的目的不是为了授业,而只是为了总结与交流。
本来想写一个针对于细节的总结博客,但是时间实在有限,Java学习之路前途漫漫,还有很多未知的技术等着学习,所以不能止步于眼下的风景,而迷失了学习的目标。相信随着未来学习的深入,对于项目的设计会有更加清晰的认知。

整个项目的设计思路,我总结了3个方面,分别为:数据处理方面(后端),用户交互方面(前端),接口对接方面(前后端交互)。
数据处理方面

  1. 分析管理系统所需要的信息,然后捋清楚信息之间的关系,并以此创建数据表。
  2. 分析系统所针对的用户群体,以及用户群体间的关系,并以此创建数据表。
  3. 分析针对于不同用户所需要提供的功能。
  4. 将所有功能进行整合,把每一个功能对应到所要操作的数据表中,并统计出每一张表所要提供的CRUD操作、操作需求的参数、以及操作所返回的结果。(CRUD操作的设计要尽可能通用)。
  5. 根据数据表创建相应的实体类。
  6. 根据所需提供的操作,编写针对于不同表的CRUD方法以及sql语句,并提供接口。

用户交互方面

  1. 分析系统所需要的页面,以及每一个页面所需要提供的功能。
  2. 一般需要提供登录和注册页面,登录页面需要校验用户输入的用户名和密码,将用户名和密码信息传递至后端数据库中查找此条纪录,找到根据用户的身份登录到不同的页面,找不到则提示错误。(对于用户名和密码校验,后端也应该提供接口用于查询)
  3. 根据用户的身份跳转到相应的页面,该页面中提供了针对于该用户群体所需要的操作。
  4. 对于用户选择的不同操作。创建不同的接口与后端对应的接口进行交互。
  • 如果是添加操作,应该校验所用户输入的信息,对于一些特殊字段,应该先将信息传递至数据库中进行查询校验,并返回结果来决定后续操作是否可以正常进行。当操作完毕后,提示用户操作的结果。
  • 如果是删除操作,将用户输入的信息传递至数据库中进行delete操作,如果纪录存在,则会删除成功并返回操作所影响的纪录数。如果纪录不存在,则不会删除数据库任何纪录,并返回0。根据返回值来提示用户操作的结果。
  • 如果是修改操作,需要用户输入一个关键字段信息(一般为主键),并在数据库中查询是否存在。
    1)不存在则返回null,并提示重新输入。
    2)存在则返回承载了该条纪录的对象。并提示用户输入修改信息。(对此操作应该提供给用户一个不修改字段的权力,即如果用户不想修改该字段信息,那么可以提示输入回车表示默认不修改)。
    3)当用户输入完毕后,将用户输入的信息重新封装在返回的对象中,并传递至数据库执行update操作。
  • 如果是查询操作,针对于不同用户的查询权限,提供相应的功能,并创建不同的接口对接到后端对应的查询接口。对于查询的需求很多,可能涉及到单表查询,多表联查,条件查询,查询关键字段等等,对于不同的查询所需求的参数不同,并且返回的结果也不相同,对于这些查询需求,后端都应该提供相应的接口支持。这一块个人感觉是最难的地方,以自己目前的经验和技术很难设计出通用的查询接口。因此在具体实现时,出现了大量冗余的代码。

接口对接方面

  1. 针对于不同的功能需要提供不同的接口进行对接,完成前后端的交互。
  2. 前端需要将用户输入的信息通过接口传递至数据库中。
  3. 后端需要根据用户的请求对数据进行相应的CRUD操作。

接口对接相关的知识自己还没有学习过,所以在写的时候属于盲人抹黑的状态,需要什么接口就临时写一个,导致了代码在非常冗余,没用很好的运用到自己学习的面向对象特性。

数据库的搭建

刚开始准备写的时候,只想建3张表,一张user表,一张admin表和一张book表,但是后面开始写的时候发现3张表貌似不够用,所以最终我定义了5张表。分别为:

tb_booktype 图书类型表

表结构如下:

该表存放了图书的类型,作为下面的图书信息表的父表。

  1. tid 类型编号,主键自增
  2. type 图书类型,唯一键。

tb_bookinfo 图书信息表

表结构如下:

该表用于存放图书详细信息,包括:

  1. bid 图书编号,主键自增,主要用于查询。
  2. name 图书名称。
  3. author 作者
  4. publish 出版社
    nameauthorpublish 三个字段我做了联合唯一约束,目的防止插入相同的书籍纪录。
  5. price 价格
  6. num 图书数量
  7. tid 图书类型编号,作为外键关联到tb_booktype

tb_borrowinfo 图书借阅信息表

表结构如下:

该表用于保存图书借阅的信息,该表关联了tb_bookinfo表,以及下面介绍的tb_user表。

  1. bor_id 图书借阅编号,主键自增。
  2. book_id 图书编号,作为外键关联 tb_bookinfo表。
  3. user_id 用户编号,作为外键管理tb_user 表。
  4. bordate 借阅日期。
  5. retdate 应归还日期。在Java中默认为1个月之后。
  6. comment 备注。

tb_status 用户身份表

表结构如下:

该表用于纪录管理系统中用户的身份信息。在这个管理系统中,我没有分别定义管理员表和用户表而是用这个status表来区分不同的用户身份。

  1. sid 身份编号,主键自增,设置1为管理员,2为客户。
  2. status 用户身份,唯一键,该管理系统中只设置了2个身份。

tb_user 用户信息表

表结构如下:

该表用于存放用户的个人信息,sid作为外键与tb_status连接,其它字段不太重要,不在此介绍。

功能

在这个管理系统中,用户分为管理员和客户,根据用户的身份不同给予了不同的功能。

管理员的功能

客户的功能

功能演示视频

视频地址:https://www.bilibili.com/video/BV18h411n75U/
CSDN我没有资格上传。。。

项目结构

对于MVC设计模式只是听过,但具体每一个模块是做什么的不太了解,所以就照葫芦画瓢仿造了一个。
在该管理系统中,我分成了5个package存放不同功能的类和接口。

dao模块

dao模块中是关于数据库增删改查的操作。

baseDAO

baseDAO中定义的是通用的增删改查操作,其它针对于一张表的xxxxDAOImpl类都继承了该类。

package com.goodgoodstudy.dao;

import com.goodgoodstudy.Util.JDBCUtils;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// 定义为抽象类表示该类不能被实例化
public abstract class BaseDAO<T> {

    // BaseDAO的子类(XxxDAOImpl)在创建对象时,会调用父类(即BaseDAO)的构造器,并加载父类的结构,代码块就会给Clazz初始化
    private Class<T> clazz;

    {
        //  获取参数化类型实例,  this既代表了实例化的子类
        ParameterizedType paramType = (ParameterizedType) this.getClass().getGenericSuperclass();

        //  调用getActualTypeArguments() 【获取泛型类型】
        Type[] types = paramType.getActualTypeArguments();

        //  只有一个泛型参数,因此types[0]就是子具体要操作的那个类。
        clazz = (Class<T>) types[0];
    }

    /**
     * 通用的增删改操作
     *
     * @param conn  数据库连接
     * @param sql   sql语句
     * @param param 填充占位符的参数
     * @return
     */
    public int update(Connection conn, String sql, Object... param) throws SQLException {
        // 获取数据库操作对象
        PreparedStatement ps = null;
        int updateCount = 0;
        try {
            ps = conn.prepareStatement(sql);
            // 填充占位符
            for (int i = 0; i < param.length; i++) {
                ps.setObject(i + 1, param[i]); // 与数据库相关的索引都是从1开始
            }
            // 执行操作
            updateCount = ps.executeUpdate(); // 接收操作所影响的纪录数量
        } catch (SQLException e) {
            throw new SQLException(e);
        } finally {
            JDBCUtils.closeResource(null, ps, null); // 关闭资源,考虑事务,因此不在方法内关闭外部获取的数据库连接
        }
        return updateCount;
    }


    /**
     * 通用的查询操作(获取一条纪录)
     *
     * @param conn
     * @param sql
     * @param param
     * @return
     */
    public T getInstance(Connection conn, String sql, Object... param) {
        PreparedStatement ps = null;
        ResultSet rs = null;
        T t = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < param.length; i++) {
                ps.setObject(i + 1, param[i]);
            }
            // 执行查询操作, 并获取结果集
            rs = ps.executeQuery();

            // 获取结果集元数据
            ResultSetMetaData md = rs.getMetaData();
            // 通过元数据获取查询纪录的列数
            int colCount = md.getColumnCount();
            // 判断结果集下一条是否有数据,
            if (rs.next()) {
                t = clazz.getDeclaredConstructor().newInstance(); // 利用clazz动态创建相应的对象,用了接收结果集的数据
                for (int i = 0; i < colCount; i++) {
                    Object colVal = rs.getObject(i + 1); // 获取每一列的数据
                    String colLabel = md.getColumnLabel(i + 1); // 获取每一列的别名
                    Field field = clazz.getDeclaredField(colLabel); // 通过别名创建对应属性的Field对象
                    field.setAccessible(true); // 访问私有属性,需要设置为true
                    field.set(t, colVal);  // 给t对象的field属性赋值为colVal
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            JDBCUtils.closeResource(null, ps, rs);
        }
        return t; // 返回承载了纪录的对象
    }

    /**
     * 通用的查询操作(获取多条纪录)
     *
     * @param conn
     * @param sql
     * @param param
     * @return
     */
    public List<T> getForList(Connection conn, String sql, Object... param) {
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<T> list = new ArrayList<>();
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < param.length; i++) {
                ps.setObject(i + 1, param[i]);
            }
            rs = ps.executeQuery();
            ResultSetMetaData md = rs.getMetaData();

            int colCount = md.getColumnCount();
            // 获取多条纪录,将if 改为 while
            while (rs.next()) {
                T t = clazz.getDeclaredConstructor().newInstance();
                for (int i = 0; i < colCount; i++) {
                    Object colVal = rs.getObject(i + 1);
                    String colLabel = md.getColumnLabel(i + 1);
                    Field field = clazz.getDeclaredField(colLabel);
                    field.setAccessible(true);
                    field.set(t, colVal);
                }
                list.add(t); // 将接收纪录的对象添加近list中
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            JDBCUtils.closeResource(null, ps, rs);
        }
        return list; // 返回list
    }


    /**
     * 用于多表联查返回一条记录
     *
     * @param conn
     * @param sql
     * @param param
     * @return
     */
    public Map<String, Object> getInstanceMap(Connection conn, String sql, Object... param) {
        PreparedStatement ps = null;
        ResultSet rs = null;
        Map<String, Object> row = null;
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < param.length; i++) {
                ps.setObject(i + 1, param[i]);
            }
            rs = ps.executeQuery();
            ResultSetMetaData md = rs.getMetaData();
            int colCount = md.getColumnCount();
            if (rs.next()) {
                // 创建Map接收查询到的一行纪录
                row = new HashMap<>();
                for (int i = 0; i < colCount; i++) {
                    row.put(md.getColumnLabel(i + 1), rs.getObject(i + 1));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            JDBCUtils.closeResource(null, ps, rs);
        }
        return row; // 返回row
    }


    /**
     * 用于多表联查返回多条纪录,将查询的每条纪录以键值对的形式封装在Map中,再存入List集合中并返回
     *
     * @param conn
     * @param sql
     * @param param
     * @return
     */
    public List<Map<String, Object>> getForMapList(Connection conn, String sql, Object... param) {
        PreparedStatement ps = null;
        ResultSet rs = null;
        List<Map<String, Object>> list = new ArrayList<>();
        try {
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < param.length; i++) {
                ps.setObject(i + 1, param[i]);
            }
            rs = ps.executeQuery();
            ResultSetMetaData md = rs.getMetaData();
            int colCount = md.getColumnCount();
            while (rs.next()) {

                // 创建Map接收每一行的纪录
                Map<String, Object> row = new HashMap<>();
                for (int i = 0; i < colCount; i++) {
                    row.put(md.getColumnLabel(i + 1), rs.getObject(i + 1));
                }
                list.add(row); // 将map添加进list
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭资源
            JDBCUtils.closeResource(null, ps, rs);
        }
        return list; // 返回list
    }


    /**
     * 用于查询特殊值的通用方法,返回一个特殊值
     * 例如:查询总数,最大值等
     *
     * @param conn
     * @param sql
     * @param params
     * @return
     */
    public Object getValue(Connection conn, String sql, Object... params) {
        PreparedStatement ps = null;
        Object value = null;
        ResultSet rs = null;
        try {
            ps = conn.prepareStatement(sql);
            value = null;
            for (int i = 0; i < params.length; i++) {
                ps.setObject(i + 1, params[i]);
            }
            rs = ps.executeQuery();
            if (rs.next()) {
                value = rs.getObject(1);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            JDBCUtils.closeResource(null, ps, rs);
        }
        return value;
    }
}

BookInfoDAO 与 BookInfoDAOImpl

  1. BookInfoDAO 接口
    BookInfoDAO 作为接口规定了针对于tb_bookinfo表的CRUD操作。
package com.goodgoodstudy.dao;

import com.goodgoodstudy.entity.BookInfo;

import java.sql.图书管理系统( JSP + JDBC + Servlet )实现-01: 流程分析和数据库建表阶段

JDBC-图书管理系统

Servlet+JDBC设计实现图书系统管理功能实现

基于JavaSE + JDBC的图书管理系统

图书管理系统( ( JSP + JDBC + Servlet ) )实现-05: 实现登录功能

图书管理系统( ( JSP + JDBC + Servlet ) )实现-06: 查询所有书籍功能

(c)2006-2024 SYSTEM All Rights Reserved IT常识