首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 書店系統畢業設計:用戶模組 Swing UI 完整實作 (第三部分)

     編輯:Java 相關知識

UI 層架構設計

採用 **JPanel 卡片切換** 模式:主視窗 bookStoreApp 持有 JFrame,透過 setContentPane(new XxxPanel(frame)) 實現面板無縫切換。每個面板持有主視窗引用以便回調切換。

一、列表面板 (listPanel) — 核心入口

package cn.hncu.bookStore.user.ui;

import java.util.List;
import javax.swing.*;
import cn.hncu.bookStore.user.business.factory.UserEBIFactory;
import cn.hncu.bookStore.user.vo.UserModel;

public class listPanel extends JPanel {
    private static final long serialVersionUID = 1L;
    private JFrame mainFrame;
    private JList jList; // 顯示 UserModel.toString()
    private JButton btnToAdd, btnToDelete, btnToUpdate, btnToQuery;

    // 建構子:載入所有用戶
    public listPanel(JFrame mainFrame) {
        this.mainFrame = mainFrame;
        initComponents();
        loadAllUsers();
    }

    // 重載建構子:顯示查詢結果
    public listPanel(JFrame mainFrame, List list) {
        this.mainFrame = mainFrame;
        initComponents();
        jList.setListData(list.toArray());
    }

    private void loadAllUsers() {
        List list = UserEBIFactory.getUserEBI().getAll();
        jList.setListData(list.toArray());
    }

    // 元件初始化 (NetBeans GUI Builder 產生代碼精簡版)
    private void initComponents() {
        setLayout(null);
        setBackground(new Color(0, 153, 51));
        setMinimumSize(new Dimension(800, 600));

        JLabel lblTitle = new JLabel("用戶管理");
        lblTitle.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 36));
        lblTitle.setForeground(new Color(204, 0, 204));
        lblTitle.setBounds(330, 100, 190, 60);
        add(lblTitle);

        jList = new JList<>();
        jList.setFont(new Font("Microsoft YaHei UI", Font.BOLD, 24));
        JScrollPane scrollPane = new JScrollPane(jList);
        scrollPane.setBounds(190, 170, 410, 220);
        add(scrollPane);

        // 按鈕統一樣式
        Font btnFont = new Font("Microsoft YaHei UI", Font.BOLD, 18);
        btnToAdd = createButton("新增用戶", 60, 470, btnFont, e -> switchTo(new AddPanel(mainFrame)));
        btnToDelete = createButton("刪除用戶", 240, 470, btnFont, this::deleteAction);
        btnToUpdate = createButton("修改用戶", 430, 470, btnFont, this::updateAction);
        btnToQuery = createButton("查詢用戶", 600, 470, btnFont, e -> switchTo(new QueryPanel(mainFrame)));
    }

    private JButton createButton(String text, int x, int y, Font font, ActionListener listener) {
        JButton btn = new JButton(text);
        btn.setFont(font);
        btn.setBounds(x, y, 110, 40);
        btn.addActionListener(listener);
        add(btn);
        return btn;
    }

    private void switchTo(JPanel panel) {
        mainFrame.setContentPane(panel);
        mainFrame.validate();
    }

    private void deleteAction(ActionEvent evt) {
        Object selected = jList.getSelectedValue();
        if (selected == null) { showMsg("請選擇要刪除的用戶"); return; }
        String uuid = selected.toString().split(",")[0];
        switchTo(new DeletePanel(mainFrame, uuid));
    }

    private void updateAction(ActionEvent evt) {
        Object selected = jList.getSelectedValue();
        if (selected == null) { showMsg("請選擇要修改的用戶"); return; }
        String uuid = selected.toString().split(",")[0];
        switchTo(new UpdatePanel(mainFrame, uuid));
    }

    private void showMsg(String msg) {
        JOptionPane.showMessageDialog(this, msg);
    }
}

二、新增面板 (AddPanel)

public class AddPanel extends JPanel {
    private JFrame mainFrame;
    private JTextField tfdName, tfdUuid;
    private JPasswordField tfdPwd, tfdPwd2;
    private JComboBox combType;
    private JButton btnAdd, btnCancel;

    public AddPanel(JFrame mainFrame) {
        this.mainFrame = mainFrame;
        initComponents();
        loadTypes();
    }

    private void loadTypes() {
        combType.removeAllItems();
        for (UserTypeEnum e : UserTypeEnum.values()) combType.addItem(e.getName());
    }

    private void initComponents() {
        // ... 佈局代碼省略 (類似 listPanel,含標籤、輸入框、下拉選單、按鈕)
        btnAdd.addActionListener(this::addAction);
        btnCancel.addActionListener(e -> backToList());
    }

    private void addAction(ActionEvent evt) {
        String name = tfdName.getText().trim();
        String uuid = tfdUuid.getText().trim(); // 實務應由系統自動生成,這裡為演示保留手動
        String pwd = new String(tfdPwd.getPassword());
        String pwd2 = new String(tfdPwd2.getPassword());
        
        if (!pwd.equals(pwd2)) { showMsg("密碼不一致"); return; }
        
        UserModel um = new UserModel();
        um.setName(name);
        um.setUuid(uuid);
        um.setPwd(pwd);
        um.setType(UserTypeEnum.getTypeByName(combType.getSelectedItem().toString()));
        
        if (UserEBIFactory.getUserEBI().create(um)) {
            backToList();
        } else {
            showMsg("用戶已存在 (UUID 衝突)");
        }
    }

    private void backToList() {
        mainFrame.setContentPane(new listPanel(mainFrame));
        mainFrame.validate();
    }
}

三、刪除面板 (DeletePanel) — 確認刪除

public class DeletePanel extends JPanel {
    private JFrame mainFrame;
    private String uuid;
    private UserEBI ebi = UserEBIFactory.getUserEBI();
    // 元件:顯示用戶資訊 (唯讀)、確認刪除/取消按鈕

    public DeletePanel(JFrame mainFrame, String uuid) {
        this.mainFrame = mainFrame; this.uuid = uuid;
        initComponents();
        loadUserData();
    }

    private void loadUserData() {
        UserModel um = ebi.getSingle(uuid);
        // 填充各欄位並設為不可編輯
        tfdUuid.setText(uuid); tfdUuid.setEnabled(false);
        tfdName.setText(um.getName()); tfdName.setEnabled(false);
        // ... 密碼、類型同理
    }

    private void deleteAction(ActionEvent evt) {
        if (ebi.delete(uuid)) backToList();
        else showMsg("刪除失敗,用戶可能已不存在");
    }
}

四、修改面板 (UpdatePanel)

public class UpdatePanel extends JPanel {
    private JFrame mainFrame;
    private String uuid;
    private UserEBI ebi = UserEBIFactory.getUserEBI();
    // 元件:可編輯姓名、密碼、類型 (UUID 唯讀)

    public UpdatePanel(JFrame mainFrame, String uuid) {
        this.mainFrame = mainFrame; this.uuid = uuid;
        initComponents();
        loadUserData();
    }

    private void loadUserData() {
        UserModel um = ebi.getSingle(uuid);
        tfdUuid.setText(uuid); tfdUuid.setEnabled(false);
        tfdName.setText(um.getName());
        tfdPwd.setText(um.getPwd()); tfdPwd2.setText(um.getPwd());
        combType.setSelectedIndex(um.getType() - 1); // 枚舉索引對應
    }

    private void updateAction(ActionEvent evt) {
        String name = tfdName.getText().trim();
        String pwd = new String(tfdPwd.getPassword());
        String pwd2 = new String(tfdPwd2.getPassword());
        if (!pwd.equals(pwd2)) { showMsg("密碼不一致"); return; }
        
        UserModel um = new UserModel();
        um.setUuid(uuid);
        um.setName(name);
        um.setPwd(pwd);
        um.setType(UserTypeEnum.getTypeByName(combType.getSelectedItem().toString()));
        
        if (ebi.update(um)) backToList();
        else showMsg("更新失敗");
    }
}

五、查詢面板 (QueryPanel) — 多條件查詢

public class QueryPanel extends JPanel {
    private JFrame mainFrame;
    private JTextField tfdName, tfdUuid;
    private JComboBox combType;
    private JButton btnQuery, btnCancel;

    public QueryPanel(JFrame mainFrame) {
        this.mainFrame = mainFrame;
        initComponents();
        loadTypes();
    }

    private void loadTypes() {
        combType.addItem("請選擇"); // 預設項
        for (UserTypeEnum e : UserTypeEnum.values()) combType.addItem(e.getName());
    }

    private void queryAction(ActionEvent evt) {
        UserQueryModel qm = new UserQueryModel();
        qm.setName(tfdName.getText().trim());
        qm.setUuid(tfdUuid.getText().trim());
        
        if (combType.getSelectedIndex() > 0) { // 非「請選擇」
            qm.setType(UserTypeEnum.getTypeByName(combType.getSelectedItem().toString()));
        }
        
        List list = UserEBIFactory.getUserEBI().getByCondition(qm);
        mainFrame.setContentPane(new listPanel(mainFrame, list));
        mainFrame.validate();
    }
}

六、關鍵 UI 設計模式總結

模式實作方式效益
卡片切換JFrame.setContentPane(new Panel(frame))單視窗多面板、狀態隔離、無需 CardLayout 複雜管理
依賴注入 (手動)面板建構子傳入 mainFrame (JFrame)面板間解耦、易測試、避免單例污染
業務邏輯分離UI 僅調用 UserEBIFactory.getUserEBI()UI 不含業務規則、DAO 細節完全隱藏
模型驅動 UIJList 直接顯示 UserModel.toString()資料與視圖綁定簡單、自動刷新
輸入驗證密碼雙輸入比對、UUID 衝突檢查前端攔截基礎錯誤、減少業務層異常

七、Swing 開發最佳實踐提醒

  1. EDT 規則:所有 UI 操作必須在 Event Dispatch Thread 執行。本範例因按鈕事件本身在 EDT,故安全。若有耗時操作 (檔案 IO、網路),必須用 SwingWorker 背景執行。
  2. 佈局管理器:教學常用 null 佈局 (setBounds) 易上手,但**生產必須用** BorderLayout/GridBagLayout/MigLayout 實現自適應。
  3. 資源釋放:面板切換時舊面板若持有資源 (執行緒、連線),需在 removeNotify() 或自定義 dispose() 清理。
  4. 外觀一致性:統一字體、顏色、間距常數,建立 UIConstants 類別集中管理。

八、完整用戶模組總結 (三部分合併)

user 模組完整結構:
├── vo/                    # UserModel, UserQueryModel (Serializable)
├── common/                # UserTypeEnum (權限枚舉 + 反向查找)
├── dao/
│   ├── dao/               # UserDAO (介面)
│   ├── impl/              # UserDAOFileImpl (序列化檔案實作)
│   └── factory/           # UserDAOFactory
├── business/
│   ├── ebi/               # UserEBI (業務介面)
│   ├── ebo/               # UserEBO (業務實作 + UUID 整合)
│   └── factory/           # UserEBIFactory
└── ui/                    # listPanel, AddPanel, UpdatePanel, DeletePanel, QueryPanel

結語

用戶模組展示了 **Swing 面板卡片切換**、**分層架構 (UI/EBI/DAO/VO)**、**枚舉驅動權限**、**檔案序列化持久化**、**工廠模式解耦** 的完整教學級實作。雖簡化了密碼加密、併發控制、異常處理等生產細節,但架構骨架清晰、擴展性強,是進階學習 Java 桌面/企業級開發的優秀範本。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved