杰瑞科技汇

Java Swing图书管理如何实现核心功能?

  1. 系统功能设计
  2. 项目结构
  3. 核心代码实现 (包含详细注释)
  4. 运行与扩展

系统功能设计

一个基础的图书管理系统应该包含以下核心功能:

Java Swing图书管理如何实现核心功能?-图1
(图片来源网络,侵删)
  • 图书管理 (增删改查)
    • 添加图书: 输入图书信息(如:ISBN、书名、作者、出版社、库存数量)并保存。
    • 删除图书: 根据图书ID或书名查找并删除指定图书。
    • 修改图书: 查找图书并修改其信息(如:修改库存)。
    • 查询图书:
      • 按ID精确查询。
      • 按书名或作者模糊查询。
      • 显示所有图书列表。
  • 数据持久化

    程序关闭后,图书数据不能丢失,我们将使用简单的文件存储(如 CSV 或 JSON 格式)来实现。

  • 图形用户界面

    使用 Java Swing 设计直观、易用的界面。


项目结构

为了代码的清晰和可维护性,我们采用 MVC(Model-View-Controller)的简化思想来组织代码。

BookManagementSystem/
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   ├── model/
│   │   │   │   └── Book.java          // 图书实体类 (Model)
│   │   │   ├── controller/
│   │   │   │   └── BookManager.java   // 图书业务逻辑控制器
│   │   │   ├── ui/
│   │   │   │   ├── MainFrame.java     // 主窗口 (View)
│   │   │   │   ├── AddBookDialog.java // 添加图书对话框 (View)
│   │   │   │   └── BookTablePanel.java // 图书列表表格面板 (View)
│   │   │   └── Main.java              // 程序入口
│   │   └── resources/
│   │       └── books.csv              // 数据存储文件
│   └── test/
│       └── ...
└── pom.xml                            // Maven 项目文件 (可选,但推荐)

核心代码实现

1 Model (图书实体类)

src/main/java/model/Book.java 这是图书数据的基本结构。

package model;
import java.io.Serializable;
// 实现Serializable接口,以便对象可以写入文件
public class Book implements Serializable {
    private String id;         // 图书ID (ISBN)
    private String title;      // 书名
    private String author;     // 作者
    private String publisher;  // 出版社
    private int quantity;      // 库存数量
    public Book(String id, String title, String author, String publisher, int quantity) {
        this.id = id;
        this.title = title;
        this.author = author;
        this.publisher = publisher;
        this.quantity = quantity;
    }
    // Getters and Setters
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getPublisher() {
        return publisher;
    }
    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }
    public int getQuantity() {
        return quantity;
    }
    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
    @Override
    public String toString() {
        return "Book{" +
                "id='" + id + '\'' +
                ", title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", publisher='" + publisher + '\'' +
                ", quantity=" + quantity +
                '}';
    }
}

2 Controller (图书管理器)

src/main/java/controller/BookManager.java 这是核心业务逻辑,负责图书的增删改查以及数据文件的读写。

package controller;
import model.Book;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class BookManager {
    private List<Book> books;
    private static final String FILE_PATH = "resources/books.csv";
    public BookManager() {
        this.books = new ArrayList<>();
        loadBooks();
    }
    // 从文件加载图书数据
    private void loadBooks() {
        File file = new File(FILE_PATH);
        if (!file.exists()) {
            return; // 文件不存在,不执行任何操作
        }
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                String[] parts = line.split(",");
                if (parts.length == 5) {
                    books.add(new Book(parts[0], parts[1], parts[2], parts[3], Integer.parseInt(parts[4])));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 保存图书数据到文件
    public void saveBooks() {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH))) {
            for (Book book : books) {
                writer.write(book.getId() + "," + book.getTitle() + "," + book.getAuthor() + "," + book.getPublisher() + "," + book.getQuantity());
                writer.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    // 添加图书
    public boolean addBook(Book book) {
        if (findBookById(book.getId()) != null) {
            return false; // 图书ID已存在
        }
        books.add(book);
        saveBooks(); // 添加后立即保存
        return true;
    }
    // 根据 ID 删除图书
    public boolean deleteBook(String id) {
        Book book = findBookById(id);
        if (book != null) {
            books.remove(book);
            saveBooks(); // 删除后立即保存
            return true;
        }
        return false;
    }
    // 根据 ID 查找图书
    public Book findBookById(String id) {
        return books.stream().filter(b -> b.getId().equals(id)).findFirst().orElse(null);
    }
    // 根据 书名 或 作者 模糊查询
    public List<Book> searchBooks(String keyword) {
        if (keyword == null || keyword.trim().isEmpty()) {
            return new ArrayList<>(books); // 返回所有图书
        }
        String lowerKeyword = keyword.toLowerCase();
        return books.stream()
                .filter(b -> b.getTitle().toLowerCase().contains(lowerKeyword) || b.getAuthor().toLowerCase().contains(lowerKeyword))
                .collect(Collectors.toList());
    }
    // 获取所有图书
    public List<Book> getAllBooks() {
        return new ArrayList<>(books);
    }
}

3 View (用户界面)

3.1 主窗口

src/main/java/ui/MainFrame.java 这是应用程序的主窗口,集成了菜单栏和图书列表。

package ui;
import controller.BookManager;
import model.Book;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
public class MainFrame extends JFrame {
    private BookManager bookManager;
    private BookTablePanel bookTablePanel;
    private JMenuBar menuBar;
    public MainFrame() {
        bookManager = new BookManager();
        setTitle("图书管理系统");
        setSize(800, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null); // 居中显示
        initMenuBar();
        initUI();
    }
    private void initMenuBar() {
        menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("文件");
        JMenuItem exitItem = new JMenuItem("退出");
        exitItem.addActionListener(e -> System.exit(0));
        fileMenu.add(exitItem);
        JMenu editMenu = new JMenu("编辑");
        JMenuItem addItem = new JMenuItem("添加图书");
        addItem.addActionListener(e -> showAddBookDialog());
        JMenuItem deleteItem = new JMenuItem("删除选中图书");
        deleteItem.addActionListener(e -> deleteSelectedBook());
        editMenu.add(addItem);
        editMenu.add(deleteItem);
        JMenu searchMenu = new JMenu("查询");
        JMenuItem searchAllItem = new JMenuItem("显示所有图书");
        searchAllItem.addActionListener(e -> bookTablePanel.refreshBooks(bookManager.getAllBooks()));
        JMenuItem searchItem = new JMenuItem("搜索图书");
        searchItem.addActionListener(e -> showSearchDialog());
        searchMenu.add(searchAllItem);
        searchMenu.add(searchItem);
        menuBar.add(fileMenu);
        menuBar.add(editMenu);
        menuBar.add(searchMenu);
        setJMenuBar(menuBar);
    }
    private void initUI() {
        bookTablePanel = new BookTablePanel();
        bookTablePanel.refreshBooks(bookManager.getAllBooks());
        add(bookTablePanel, BorderLayout.CENTER);
    }
    private void showAddBookDialog() {
        AddBookDialog dialog = new AddBookDialog(this, "添加图书");
        dialog.setVisible(true);
        if (dialog.isConfirmed()) {
            Book newBook = dialog.getBook();
            if (bookManager.addBook(newBook)) {
                bookTablePanel.refreshBooks(bookManager.getAllBooks());
                JOptionPane.showMessageDialog(this, "添加成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
            } else {
                JOptionPane.showMessageDialog(this, "图书ID已存在!", "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    private void deleteSelectedBook() {
        String selectedId = bookTablePanel.getSelectedBookId();
        if (selectedId == null) {
            JOptionPane.showMessageDialog(this, "请先选择要删除的图书!", "提示", JOptionPane.WARNING_MESSAGE);
            return;
        }
        int option = JOptionPane.showConfirmDialog(this, "确定要删除ID为 " + selectedId + " 的图书吗?", "确认删除", JOptionPane.YES_NO_OPTION);
        if (option == JOptionPane.YES_OPTION) {
            if (bookManager.deleteBook(selectedId)) {
                bookTablePanel.refreshBooks(bookManager.getAllBooks());
                JOptionPane.showMessageDialog(this, "删除成功!", "成功", JOptionPane.INFORMATION_MESSAGE);
            } else {
                JOptionPane.showMessageDialog(this, "删除失败!", "错误", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    private void showSearchDialog() {
        String keyword = JOptionPane.showInputDialog(this, "请输入书名或作者关键词:", "搜索图书", JOptionPane.PLAIN_MESSAGE);
        if (keyword != null) {
            List<Book> searchResults = bookManager.searchBooks(keyword);
            bookTablePanel.refreshBooks(searchResults);
        }
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            try {
                UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
            } catch (Exception e) {
                e.printStackTrace();
            }
            new MainFrame().setVisible(true);
        });
    }
}

3.2 图书列表表格面板

src/main/java/ui/BookTablePanel.java 这是一个可重用的面板,用于以表格形式展示图书列表。

package ui;
import model.Book;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.util.List;
public class BookTablePanel extends JPanel {
    private JTable table;
    private DefaultTableModel tableModel;
    public BookTablePanel() {
        setLayout(new BorderLayout());
        initTable();
    }
    private void initTable() {
        // 定义表格列
        String[] columnNames = {"ID", "书名", "作者", "出版社", "库存"};
        tableModel = new DefaultTableModel(columnNames, 0) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false; // 所有单元格不可编辑
            }
        };
        table = new JTable(tableModel);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // 单行选择
        JScrollPane scrollPane = new JScrollPane(table);
        add(scrollPane, BorderLayout.CENTER);
    }
    // 刷新表格数据
    public void refreshBooks(List<Book> books) {
        tableModel.setRowCount(0); // 清空现有数据
        for (Book book : books) {
            Object[] rowData = {
                    book.getId(),
                    book.getTitle(),
                    book.getAuthor(),
                    book.getPublisher(),
                    book.getQuantity()
            };
            tableModel.addRow(rowData);
        }
    }
    // 获取当前选中的图书ID
    public String getSelectedBookId() {
        int selectedRow = table.getSelectedRow();
        if (selectedRow != -1) {
            return tableModel.getValueAt(selectedRow, 0).toString();
        }
        return null;
    }
}

3.3 添加图书对话框

src/main/java/ui/AddBookDialog.java 一个模态对话框,用于输入新图书的信息。

package ui;
import model.Book;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AddBookDialog extends JDialog {
    private JTextField idField, titleField, authorField, publisherField, quantityField;
    private Book newBook;
    private boolean confirmed = false;
    public AddBookDialog(Frame owner, String title) {
        super(owner, title, true); // true 表示模态对话框
        initUI();
    }
    private void initUI() {
        JPanel panel = new JPanel(new GridLayout(5, 2, 5, 5));
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        panel.add(new JLabel("图书ID (ISBN):"));
        idField = new JTextField();
        panel.add(idField);
        panel.add(new JLabel("书名:"));
        titleField = new JTextField();
        panel.add(titleField);
        panel.add(new JLabel("作者:"));
        authorField = new JTextField();
        panel.add(authorField);
        panel.add(new JLabel("出版社:"));
        publisherField = new JTextField();
        panel.add(publisherField);
        panel.add(new JLabel("库存数量:"));
        quantityField = new JTextField();
        panel.add(quantityField);
        JButton confirmButton = new JButton("确定");
        JButton cancelButton = new JButton("取消");
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(confirmButton);
        buttonPanel.add(cancelButton);
        confirmButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (validateInput()) {
                    newBook = new Book(
                            idField.getText(),
                            titleField.getText(),
                            authorField.getText(),
                            publisherField.getText(),
                            Integer.parseInt(quantityField.getText())
                    );
                    confirmed = true;
                    dispose();
                }
            }
        });
        cancelButton.addActionListener(e -> dispose());
        add(panel, BorderLayout.CENTER);
        add(buttonPanel, BorderLayout.SOUTH);
        pack();
        setLocationRelativeTo(getOwner());
    }
    private boolean validateInput() {
        if (idField.getText().trim().isEmpty() || titleField.getText().trim().isEmpty() || quantityField.getText().trim().isEmpty()) {
            JOptionPane.showMessageDialog(this, "ID、书名和库存不能为空!", "输入错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }
        try {
            int quantity = Integer.parseInt(quantityField.getText());
            if (quantity < 0) {
                JOptionPane.showMessageDialog(this, "库存数量不能为负数!", "输入错误", JOptionPane.ERROR_MESSAGE);
                return false;
            }
        } catch (NumberFormatException e) {
            JOptionPane.showMessageDialog(this, "库存数量必须是整数!", "输入错误", JOptionPane.ERROR_MESSAGE);
            return false;
        }
        return true;
    }
    public boolean isConfirmed() {
        return confirmed;
    }
    public Book getBook() {
        return newBook;
    }
}

4 程序入口

src/main/java/Main.java

package ui;
public class Main {
    public static void main(String[] args) {
        MainFrame.main(args); // 直接调用MainFrame的main方法,因为它包含了主逻辑
    }
}

运行与扩展

如何运行

  1. 环境准备: 确保你已安装 JDK 8 或更高版本。

  2. 项目结构: 按照上面的目录结构创建文件和包。

  3. 编译运行:

    • 如果你使用 IDE (如 IntelliJ IDEA 或 Eclipse),直接创建一个 Java 项目,将代码复制到对应包中,然后运行 Main.java

    • 如果使用命令行:

      # 确保在 src 目录的父目录下
      # 编译所有 java 文件
      javac -d . src/main/java/**/*.java
      # 运行主类
      java -cp . ui.Main
  4. 首次运行: 程序会自动在 src/main/resources/ 目录下创建 books.csv 文件来存储数据。

可能的扩展方向

这个基础版本已经非常完整,你可以在此基础上进行扩展:

  1. 用户管理: 添加管理员和普通用户角色,普通用户只能查询,管理员可以进行增删改。
  2. 借阅功能: 添加“借阅”和“归还”按钮,当借阅时,减少图书库存,并记录借阅人、借阅时间等信息,这需要一个新的 BorrowRecord 类。
  3. 更友好的UI:
    • 使用 JXDatePicker 来选择日期(用于借阅记录)。
    • 使用图标美化按钮和菜单。
    • 实现分页显示,当图书数量很多时,一页一页地展示。
  4. 更强大的数据存储:
    • 将 CSV 文件替换为 JSONXML,它们在结构化数据上更灵活。
    • 进阶:集成 数据库 (如 MySQL, SQLite),使用 JDBC 连接数据库,将 BookManager 中的文件操作替换为 SQL 操作,这是最专业、最健壮的方案。
  5. 高级搜索: 实现多条件组合查询(同时按作者和出版社搜索)。
  6. 数据统计: 添加一个功能,可以统计各类图书的数量、最受欢迎的图书等,并用图表展示,可以使用 JFreeChart 等库。
分享:
扫描分享到社交APP
上一篇
下一篇