java: DDD using oracle 21c

项目结构:

domain:

java 复制代码
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 17:51
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : domain.entities/School.java
 * explain   : 学习  类
 **/
 
package domain.entities;
import java.util.Objects;
 
/**
 *
 */
public class School {
 
    private String schoolId;
    private String schoolName;
    private String schoolTelNo;
 
    public School(String schoolId, String schoolName, String schoolTelNo) {
        this.schoolId = schoolId;
        this.schoolName = schoolName;
        this.schoolTelNo = schoolTelNo;
    }
 
    // Getters and Setters
    public String getSchoolId() { return schoolId; }
    public String getSchoolName() { return schoolName; }
    public String getSchoolTelNo() { return schoolTelNo; }
 
    public void setSchoolName(String schoolName) { this.schoolName = schoolName; }
    public void setSchoolTelNo(String schoolTelNo) { this.schoolTelNo = schoolTelNo; }
 
    // 领域行为
    public void updateContactInfo(String newName, String newTelNo) {
        if (newName != null && !newName.isEmpty()) {
            this.schoolName = newName;
        }
        if (newTelNo != null && !newTelNo.isEmpty()) {
            this.schoolTelNo = newTelNo;
        }
    }
 
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        School school = (School) o;
        return schoolId.equals(school.schoolId);
    }
 
    @Override
    public int hashCode() {
        return Objects.hash(schoolId);
    }
}
 
 
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 18:47
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : domain.entities/QueryParams.java
 * explain   : 学习  类
 **/
 
package domain.entities;
 
/**
 *
 */
public class QueryParams {
    private String searchTerm;  // 搜索关键词
    private int pageNumber;     // 当前页码
    private int pageSize;       // 每页大小
 
    /**
     *
     * @param searchTerm
     * @param pageNumber
     * @param pageSize
     */
    public QueryParams(String searchTerm, int pageNumber, int pageSize) {
        this.searchTerm = searchTerm;
        this.pageNumber = pageNumber;
        this.pageSize = pageSize;
    }
 
    // Getters
    public String getSearchTerm() { return searchTerm; }
    public int getPageNumber() { return pageNumber; }
    public int getPageSize() { return pageSize; }
    public int getOffset() { return (pageNumber - 1) * pageSize; }
}
 
 
 
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 17:53
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : domain/repositories/SchoolRepository.java
 * explain   : 学习  类
 **/
 
package domain.repositories;
 
import domain.entities.School;
import domain.entities.QueryParams;
 
import java.util.List;
 
/**
 *
 */
public interface SchoolRepository {
 
 
    List<School> findAll(int page, int pageSize);
    // 新增支持查询条件的方法
    List<School> findByParams(QueryParams params);
    int countByParams(QueryParams params);
    int countAll();
    School findById(String schoolId);
    void save(School school);
    void delete(String schoolId);
 
}

infrastructure:

java 复制代码
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 18:03
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : SchoolRepositoryImpl.java
 * explain   : 学习  类
 **/
 
package infrastructure.repositories;
 
import domain.entities.School;
import domain.entities.QueryParams;
import domain.repositories.SchoolRepository;
import infrastructure.database.DuOracleHelper;
 
import java.sql.*;
import java.util.ArrayList;
import java.util.List;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
 
 
public class SchoolRepositoryImpl implements SchoolRepository {
 
    @Override
    public List<School> findAll(int page, int pageSize) {
        System.out.println("开始分页查询,页码: " + page + ",每页大小: " + pageSize);
        List<School> schools = new ArrayList<>();
        String sql = "SELECT * FROM School ORDER BY SchoolId " +
                "OFFSET ? ROWS FETCH NEXT ? ROWS ONLY";
 
        try (Connection conn = DuOracleHelper.getConnection()) {
            System.out.println("成功获取数据库连接");
 
            try (PreparedStatement pstmt = conn.prepareStatement(sql)) {
                pstmt.setInt(1, (page - 1) * pageSize);
                pstmt.setInt(2, pageSize);
                System.out.println("执行SQL: " + sql);
                System.out.println("参数1: " + (page - 1) * pageSize);
                System.out.println("参数2: " + pageSize);
 
                try (ResultSet rs = pstmt.executeQuery()) {
                    while (rs.next()) {
                        schools.add(mapToDomain(rs));
                    }
                    System.out.println("查询成功,返回 " + schools.size() + " 条记录");
                }
            }
        } catch (SQLException | IOException e) {
            System.err.println("数据库操作异常: " + e.getMessage());
            e.printStackTrace(); // 打印完整堆栈信息
            throw new RuntimeException("查询学校列表失败", e);
        }
        return schools;
    }
 
    @Override
    public int countAll() {
        String sql = "SELECT COUNT(*) FROM School";
        try (Connection conn = DuOracleHelper.getConnection();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
 
            if (rs.next()) {
                return rs.getInt(1);
            }
        } catch (SQLException | IOException e) {
            throw new RuntimeException("统计学校数量失败", e);
        }
        return 0;
    }
    @Override
    public List<School> findByParams(QueryParams params) {
        List<School> schools = new ArrayList<>();
        StringBuilder sql = new StringBuilder(
                "SELECT * FROM School WHERE 1=1 "
        );
 
        // 构建查询条件
        if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {
            sql.append("AND (SchoolId LIKE ? OR SchoolName LIKE ?) ");
        }
 
        // 添加排序和分页
        sql.append("ORDER BY SchoolId OFFSET ? ROWS FETCH NEXT ? ROWS ONLY");
 
        try (Connection conn = DuOracleHelper.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql.toString())) {
 
            int paramIndex = 1;
            // 设置查询参数
            if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {
                String searchTerm = "%" + params.getSearchTerm() + "%";
                pstmt.setString(paramIndex++, searchTerm);
                pstmt.setString(paramIndex++, searchTerm);
            }
 
            // 设置分页参数
            pstmt.setInt(paramIndex++, params.getOffset());
            pstmt.setInt(paramIndex, params.getPageSize());
 
            try (ResultSet rs = pstmt.executeQuery()) {
                while (rs.next()) {
                    schools.add(mapToDomain(rs));
                }
            }
        } catch (SQLException | IOException e) {
            throw new RuntimeException("按条件查询学校失败", e);
        }
        return schools;
    }
 
    @Override
    public int countByParams(QueryParams params) {
        StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM School WHERE 1=1 ");
 
        // 构建查询条件
        if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {
            sql.append("AND (SchoolId LIKE ? OR SchoolName LIKE ?)");
        }
 
        try (Connection conn = DuOracleHelper.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql.toString())) {
 
            int paramIndex = 1;
            // 设置查询参数
            if (params.getSearchTerm() != null && !params.getSearchTerm().isEmpty()) {
                String searchTerm = "%" + params.getSearchTerm() + "%";
                pstmt.setString(paramIndex++, searchTerm);
                pstmt.setString(paramIndex, searchTerm);
            }
 
            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    return rs.getInt(1);
                }
            }
        } catch (SQLException | IOException e) {
            throw new RuntimeException("统计符合条件的学校数量失败", e);
        }
        return 0;
    }
    // 其他方法实现...
    @Override
    public School findById(String schoolId) {
        String sql = "SELECT * FROM School WHERE SchoolId = ?";
        try (Connection conn = DuOracleHelper.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
 
            pstmt.setString(1, schoolId);
            try (ResultSet rs = pstmt.executeQuery()) {
                if (rs.next()) {
                    return mapToDomain(rs);
                }
            }
        } catch (SQLException | IOException e) {
            throw new RuntimeException("查找学校失败", e);
        }
        return null;
    }
 
    @Override
    public void save(School school) {
        // 检查是插入还是更新
        if (findById(school.getSchoolId()) == null) {
            insertSchool(school);
        } else {
            updateSchool(school);
        }
    }
 
    private void insertSchool(School school) {
        String sql = "INSERT INTO School (SchoolId, SchoolName, SchoolTelNo) VALUES (?, ?, ?)";
        try (Connection conn = DuOracleHelper.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
 
            pstmt.setString(1, school.getSchoolId());
            pstmt.setString(2, school.getSchoolName());
            pstmt.setString(3, school.getSchoolTelNo());
 
            pstmt.executeUpdate();
        } catch (SQLException | IOException e) {
            throw new RuntimeException("添加学校失败", e);
        }
    }
 
    private void updateSchool(School school) {
        String sql = "UPDATE School SET SchoolName = ?, SchoolTelNo = ? WHERE SchoolId = ?";
        try (Connection conn = DuOracleHelper.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
 
            pstmt.setString(1, school.getSchoolName());
            pstmt.setString(2, school.getSchoolTelNo());
            pstmt.setString(3, school.getSchoolId());
 
            pstmt.executeUpdate();
        } catch (SQLException | IOException e) {
            throw new RuntimeException("更新学校失败", e);
        }
    }
 
    @Override
    public void delete(String schoolId) {
        String sql = "DELETE FROM School WHERE SchoolId = ?";
        try (Connection conn = DuOracleHelper.getConnection();
             PreparedStatement pstmt = conn.prepareStatement(sql)) {
 
            pstmt.setString(1, schoolId);
            pstmt.executeUpdate();
        } catch (SQLException | IOException e) {
            throw new RuntimeException("删除学校失败", e);
        }
    }
 
 
    private School mapToDomain(ResultSet rs) throws SQLException {
        return new School(
                rs.getString("SchoolId"),
                rs.getString("SchoolName"),
                rs.getString("SchoolTelNo")
        );
    }
}
 
 
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 18:02
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : SchoolDto.java
 * explain   : 学习  类
 **/
 
package infrastructure.model;
 
/**
 *
 */
public class SchoolDto {
    private String schoolId;
    private String schoolName;
    private String schoolTelNo;
 
    // Getters and Setters
    public String getSchoolId() { return schoolId; }
    public void setSchoolId(String schoolId) { this.schoolId = schoolId; }
    public String getSchoolName() { return schoolName; }
    public void setSchoolName(String schoolName) { this.schoolName = schoolName; }
    public String getSchoolTelNo() { return schoolTelNo; }
    public void setSchoolTelNo(String schoolTelNo) { this.schoolTelNo = schoolTelNo; }
}

application:

java 复制代码
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 18:08
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : application/server/SchoolService.java
 * explain   : 学习  类
 **/
 
package application.server;
 
import domain.entities.QueryParams;
import domain.entities.School;
import domain.repositories.SchoolRepository;
import infrastructure.repositories.SchoolRepositoryImpl;
import java.util.List;
 
 
public class SchoolService {
    private final SchoolRepository repository;
 
    public SchoolService() {
        this.repository = new SchoolRepositoryImpl();
    }
 
    // 分页查询
    public PagedResult<School> getSchoolsByPage(int page, int pageSize) {
        List<School> schools = repository.findAll(page, pageSize);
        int totalCount = repository.countAll();
 
        return new PagedResult<>(
                schools,
                page,
                pageSize,
                (int) Math.ceil((double) totalCount / pageSize),
                totalCount
        );
    }
 
    /**
     * 新增支持搜索的分页查询方法
     * @param searchTerm
     * @param page
     * @param pageSize
     * @return
     */
    public PagedResult<School> getSchoolsByPageAndSearch(String searchTerm, int page, int pageSize) {
        QueryParams params = new QueryParams(searchTerm, page, pageSize);
        List<School> schools = repository.findByParams(params);
        int totalCount = repository.countByParams(params);
 
        return new PagedResult<>(
                schools,
                page,
                pageSize,
                (int) Math.ceil((double) totalCount / pageSize),
                totalCount
        );
    }
 
 
 
    // 其他业务方法...
        public void saveSchool(School school) {
            if (school.getSchoolId() == null || school.getSchoolId().isEmpty()) {
                // 生成新ID的逻辑
                String newId = generateSchoolId();
                school = new School(newId, school.getSchoolName(), school.getSchoolTelNo());
            }
            repository.save(school);
        }
 
        public void updateSchool(School school) {
            repository.save(school); // 假设save方法可以处理更新
        }
 
        public void deleteSchool(String schoolId) {
            repository.delete(schoolId);
        }
 
        public int getTotalSchoolCount() {
            return repository.countAll();
        }
 
        // 生成学校ID的辅助方法
        private String generateSchoolId() {
            // 简单实现,实际应用中可能需要更复杂的ID生成策略
            return "S" + System.currentTimeMillis();
        }
 
    public int getTotalSchoolCount(String searchTerm) {
        QueryParams params = new QueryParams(searchTerm, 1, 10);
        return repository.countByParams(params);
    }
 
    // 分页结果类
    public static class PagedResult<T> {
        private final List<T> items;
        private final int currentPage;
        private final int pageSize;
        private final int totalPages;
        private final int totalItems;
 
        public PagedResult(List<T> items, int currentPage, int pageSize, int totalPages, int totalItems) {
            this.items = items;
            this.currentPage = currentPage;
            this.pageSize = pageSize;
            this.totalPages = totalPages;
            this.totalItems = totalItems;
        }
 
        // Getters
        public List<T> getItems() { return items; }
        public int getCurrentPage() { return currentPage; }
        public int getPageSize() { return pageSize; }
        public int getTotalPages() { return totalPages; }
        public int getTotalItems() { return totalItems; }
        public boolean hasNextPage() { return currentPage < totalPages; }
        public boolean hasPreviousPage() { return currentPage > 1; }
    }
}

presentation:

java 复制代码
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 18:10
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : SchoolController.java
 * explain   : 学习  类
 **/

package presentation.controllers;

import application.server.SchoolService;
import application.server.SchoolService.PagedResult;
import domain.entities.School;
import presentation.views.SchoolView;


public class SchoolController {
    private final SchoolService service;
    private final SchoolView view;

    /**
     *
     * @param view
     */
    public SchoolController(SchoolView view) {
        this.service = new SchoolService();
        this.view = view;
    }

    /**
     *
     * @param searchTerm
     * @param page
     * @param pageSize
     */
    public void loadSchools(String searchTerm, int page, int pageSize) {
        PagedResult<School> result = service.getSchoolsByPageAndSearch(searchTerm, page, pageSize);
        view.displaySchools(result);
    }

    /**
     *
     * @param school
     */
    public void addSchool(School school) {
        service.saveSchool(school);
        // 重新加载数据,保持当前搜索条件和分页
        loadSchools(view.getCurrentSearchTerm(), 1, view.getPageSize());
    }

    /**
     *
     * @param school
     */
    public void updateSchool(School school) {
        service.updateSchool(school);
        // 重新加载当前页
        loadSchools(view.getCurrentSearchTerm(), view.getCurrentPage(), view.getPageSize());
    }

    /**
     *
     * @param schoolId
     */
    public void deleteSchool(String schoolId) {
        // 获取当前分页信息
        String searchTerm = view.getCurrentSearchTerm();
        int currentPage = view.getCurrentPage();
        int pageSize = view.getPageSize();

        // 执行删除
        service.deleteSchool(schoolId);

        // 获取删除后的总记录数
        int totalRecords = service.getTotalSchoolCount(searchTerm);

        // 计算删除后应该显示的页码
        int totalPages = Math.max(1, (int) Math.ceil((double) totalRecords / pageSize));
        int newPage = Math.min(currentPage, totalPages);

        // 加载正确的页
        loadSchools(searchTerm, newPage, pageSize);
    }
    /*
    public void deleteSchool(String schoolId) {
        // 获取当前分页信息
        String searchTerm = view.getCurrentSearchTerm();
        int currentPage = view.getCurrentPage();
        int pageSize = view.getPageSize();

        // 执行删除
        service.deleteSchool(schoolId);

        // 获取删除后的总记录数
        int totalRecords = service.getTotalSchoolCount(searchTerm);

        // 计算删除后应该显示的页码
        int totalPages = Math.max(1, (int) Math.ceil((double) totalRecords / pageSize));
        int newPage = Math.min(currentPage, totalPages);

        // 加载正确的页
        loadSchools(searchTerm, newPage, pageSize);
    }*/

}



/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 18:12
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : SchoolView.java
 * explain   : 学习  类
 **/

package presentation.views;

import application.server.SchoolService.PagedResult;
import domain.entities.School;
import presentation.controllers.SchoolController;
import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;


public class SchoolView extends JFrame {

    private final SchoolController controller;
    private JTable schoolTable;
    private SchoolTableModel tableModel;
    private JButton firstPageBtn, prevPageBtn, nextPageBtn, lastPageBtn;
    private JButton addButton,editButton,deleteButton,refreshButton;
    private JLabel pageInfoLabel;
    private int currentPage = 1;
    private int pageSize = 10;
    private String currentSearchTerm = null;  // 新增:当前搜索关键词
    private JTextField searchField;           // 新增:搜索输入框

    public SchoolView() {
        this.controller = new SchoolController(this);
        initComponents();
        loadInitialData();

        // 添加按钮事件
        addButton.addActionListener(e -> showAddSchoolDialog());
        editButton.addActionListener(e -> showEditSchoolDialog());
        deleteButton.addActionListener(e -> performDeleteSchool());


    }

    private void initComponents() {
        setTitle("学校管理系统");
        setSize(800, 600);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // 创建工具栏和按钮
        JToolBar toolBar = new JToolBar();
        refreshButton = new JButton("刷新");
        addButton = new JButton("添加");
        editButton = new JButton("编辑");
        deleteButton = new JButton("删除");

        toolBar.add(refreshButton);
        toolBar.add(addButton);
        toolBar.add(editButton);
        toolBar.add(deleteButton);


        // 创建搜索面板
        JPanel searchPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        JLabel searchLabel = new JLabel("搜索:");
        searchField = new JTextField(20);
        JButton searchButton = new JButton("搜索");

        searchButton.addActionListener(e -> performSearch());

        searchPanel.add(searchLabel);
        searchPanel.add(searchField);
        searchPanel.add(searchButton);

        // 初始化表格
        tableModel = new SchoolTableModel();
        schoolTable = new JTable(tableModel);
        JScrollPane scrollPane = new JScrollPane(schoolTable);

        // 添加按钮事件
        refreshButton.addActionListener(e -> loadInitialData());
        addButton.addActionListener(e -> showAddSchoolDialog());
        editButton.addActionListener(e -> showEditSchoolDialog());
        deleteButton.addActionListener(e -> performDeleteSchool());

        // 初始化分页控件
        initPaginationControls();

        // 布局
        setLayout(new BorderLayout());
        add(toolBar, BorderLayout.NORTH);
        add(searchPanel, BorderLayout.SOUTH);
        add(scrollPane, BorderLayout.CENTER);
        add(createPaginationPanel(), BorderLayout.SOUTH);
    }

    /**
     * 添加
     */
    private void showAddSchoolDialog() {
        JDialog dialog = new JDialog(this, "添加学校", true);
        dialog.setSize(400, 300);
        dialog.setLocationRelativeTo(this);

        // 创建表单组件
        JLabel idLabel = new JLabel("学校ID:");
        JTextField idField = new JTextField(20);
        JLabel nameLabel = new JLabel("学校名称:");
        JTextField nameField = new JTextField(20);
        JLabel telLabel = new JLabel("联系电话:");
        JTextField telField = new JTextField(20);

        JButton saveButton = new JButton("保存");
        JButton cancelButton = new JButton("取消");

        // 设置布局
        GroupLayout layout = new GroupLayout(dialog.getContentPane());
        dialog.getContentPane().setLayout(layout);
        layout.setAutoCreateGaps(true);
        layout.setAutoCreateContainerGaps(true);

        layout.setHorizontalGroup(
                layout.createParallelGroup(Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                                        .addComponent(idLabel)
                                        .addComponent(nameLabel)
                                        .addComponent(telLabel))
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                                        .addComponent(idField)
                                        .addComponent(nameField)
                                        .addComponent(telField)))
                        .addGroup(Alignment.TRAILING, layout.createSequentialGroup()
                                .addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(cancelButton)
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addComponent(saveButton))
        );

        layout.setVerticalGroup(
                layout.createParallelGroup(Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                                        .addComponent(idLabel)
                                        .addComponent(idField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                                        .addComponent(nameLabel)
                                        .addComponent(nameField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                                        .addComponent(telLabel)
                                        .addComponent(telField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                                .addPreferredGap(ComponentPlacement.RELATED, 40, Short.MAX_VALUE)
                                .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                                        .addComponent(saveButton)
                                        .addComponent(cancelButton)))
        );

        // 添加按钮事件
        saveButton.addActionListener(e -> {
            String id = idField.getText().trim();
            String name = nameField.getText().trim();
            String tel = telField.getText().trim();

            if (id.isEmpty() || name.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "学校ID和学校名称不能为空", "输入错误", JOptionPane.ERROR_MESSAGE);
                return;
            }

            controller.addSchool(new School(id, name, tel));
            dialog.dispose();
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }

    /**
     * 修改
     */
    private void showEditSchoolDialog() {
        int selectedRow = schoolTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "请先选择要修改的学校", "提示", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        // 获取选中的学校数据
        String schoolId = (String) schoolTable.getValueAt(selectedRow, 0);
        String schoolName = (String) schoolTable.getValueAt(selectedRow, 1);
        String schoolTel = (String) schoolTable.getValueAt(selectedRow, 2);

        JDialog dialog = new JDialog(this, "修改学校", true);
        dialog.setSize(400, 300);
        dialog.setLocationRelativeTo(this);

        // 创建表单组件
        JLabel idLabel = new JLabel("学校ID:");
        JTextField idField = new JTextField(schoolId, 20);
        idField.setEditable(false); // ID不可编辑
        JLabel nameLabel = new JLabel("学校名称:");
        JTextField nameField = new JTextField(schoolName, 20);
        JLabel telLabel = new JLabel("联系电话:");
        JTextField telField = new JTextField(schoolTel, 20);

        JButton saveButton = new JButton("保存");
        JButton cancelButton = new JButton("取消");

        // 设置布局(与添加对话框类似)
        GroupLayout layout = new GroupLayout(dialog.getContentPane());
        dialog.getContentPane().setLayout(layout);
        layout.setAutoCreateGaps(true);
        layout.setAutoCreateContainerGaps(true);

        layout.setHorizontalGroup(
                layout.createParallelGroup(Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                                        .addComponent(idLabel)
                                        .addComponent(nameLabel)
                                        .addComponent(telLabel))
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(Alignment.LEADING)
                                        .addComponent(idField)
                                        .addComponent(nameField)
                                        .addComponent(telField)))
                        .addGroup(Alignment.TRAILING, layout.createSequentialGroup()
                                .addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(cancelButton)
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addComponent(saveButton))
        );

        layout.setVerticalGroup(
                layout.createParallelGroup(Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                                        .addComponent(idLabel)
                                        .addComponent(idField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                                        .addComponent(nameLabel)
                                        .addComponent(nameField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                                        .addComponent(telLabel)
                                        .addComponent(telField, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                                .addPreferredGap(ComponentPlacement.RELATED, 40, Short.MAX_VALUE)
                                .addGroup(layout.createParallelGroup(Alignment.BASELINE)
                                        .addComponent(saveButton)
                                        .addComponent(cancelButton)))
        );

        // 添加按钮事件
        saveButton.addActionListener(e -> {
            String id = idField.getText().trim();
            String name = nameField.getText().trim();
            String tel = telField.getText().trim();

            if (name.isEmpty()) {
                JOptionPane.showMessageDialog(dialog, "学校名称不能为空", "输入错误", JOptionPane.ERROR_MESSAGE);
                return;
            }

            controller.updateSchool(new School(id, name, tel));
            dialog.dispose();
        });

        cancelButton.addActionListener(e -> dialog.dispose());

        dialog.setVisible(true);
    }
    /**
     * 删除
     */
    private void performDeleteSchool() {
        int selectedRow = schoolTable.getSelectedRow();
        if (selectedRow == -1) {
            JOptionPane.showMessageDialog(this, "请先选择要删除的学校", "提示", JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        // 获取选中的学校ID
        String schoolId = (String) schoolTable.getValueAt(selectedRow, 0);
        String schoolName = (String) schoolTable.getValueAt(selectedRow, 1);

        // 确认对话框
        int confirm = JOptionPane.showConfirmDialog(
                this,
                "确定要删除学校 [" + schoolName + "] 吗?",
                "确认删除",
                JOptionPane.YES_NO_OPTION,
                JOptionPane.WARNING_MESSAGE
        );

        if (confirm == JOptionPane.YES_OPTION) {
            controller.deleteSchool(schoolId);
        }
    }



    private void loadInitialData() {
        controller.loadSchools(currentSearchTerm, currentPage, pageSize);
    }

    private void performSearch() {
        currentSearchTerm = searchField.getText();
        currentPage = 1;  // 搜索时重置到第一页
        controller.loadSchools(currentSearchTerm, currentPage, pageSize);
    }

    private void initPaginationControls() {
        firstPageBtn = new JButton("首页");
        prevPageBtn = new JButton("上一页");
        nextPageBtn = new JButton("下一页");
        lastPageBtn = new JButton("末页");
        pageInfoLabel = new JLabel("第 1 页,共 0 页");

        firstPageBtn.addActionListener(e -> goToFirstPage());
        prevPageBtn.addActionListener(e -> goToPreviousPage());
        nextPageBtn.addActionListener(e -> goToNextPage());
        lastPageBtn.addActionListener(e -> goToLastPage());
    }

    private JPanel createPaginationPanel() {
        JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER));
        panel.add(firstPageBtn);
        panel.add(prevPageBtn);
        panel.add(pageInfoLabel);
        panel.add(nextPageBtn);
        panel.add(lastPageBtn);
        return panel;
    }



    public void displaySchools(PagedResult<School> result) {
        tableModel.setSchools(result.getItems());
        tableModel.fireTableDataChanged();

        currentPage = result.getCurrentPage();
        updatePageInfo(result);
    }

    private void updatePageInfo(PagedResult<School> result) {
        pageInfoLabel.setText(String.format("第 %d 页,共 %d 页,总计 %d 条记录",
                result.getCurrentPage(),
                result.getTotalPages(),
                result.getTotalItems()));

        // 启用/禁用按钮
        firstPageBtn.setEnabled(result.hasPreviousPage());
        prevPageBtn.setEnabled(result.hasPreviousPage());
        nextPageBtn.setEnabled(result.hasNextPage());
        lastPageBtn.setEnabled(result.hasNextPage());
    }



    // 获取总页数的辅助方法
    private int getTotalPages() {
        String text = pageInfoLabel.getText();
        try {
            // 从"第 X 页,共 Y 页,总计 Z 条记录"中提取Y
            String[] parts = text.split(",");
            if (parts.length >= 2) {
                String totalPagesPart = parts[1].trim();
                // 提取"共 Y 页"中的Y
                String totalPagesStr = totalPagesPart.substring(
                        totalPagesPart.indexOf("共") + 1,
                        totalPagesPart.indexOf("页")
                ).trim(); // 去除可能的空格

                // 增加调试输出
                System.out.println("提取的总页数字符串: '" + totalPagesStr + "'");

                return Integer.parseInt(totalPagesStr);
            }
        } catch (Exception e) {
            System.err.println("解析总页数失败: " + e.getMessage());
            e.printStackTrace();
        }
        return 1; // 默认返回1页
    }


    // 添加获取当前搜索词的方法
    public String getCurrentSearchTerm() {
        return currentSearchTerm;
    }

    // 修复导航方法,传递搜索参数
    private void goToPreviousPage() {
        if (currentPage > 1) {
            controller.loadSchools(currentSearchTerm, currentPage - 1, pageSize);
        }
    }

    // 其他导航方法也需要类似修改
    private void goToNextPage() {
        if (currentPage < getTotalPages()) {
            controller.loadSchools(currentSearchTerm, currentPage + 1, pageSize);
        }
    }

    private void goToFirstPage() {
        controller.loadSchools(currentSearchTerm, 1, pageSize);
    }

    private void goToLastPage() {
        int totalPages = getTotalPages();
        if (totalPages > 0) {
            controller.loadSchools(currentSearchTerm, totalPages, pageSize);
        }
    }


    // Getters for pagination state
    public int getCurrentPage() { return currentPage; }
    public int getPageSize() { return pageSize; }

    // 表格模型
    private static class SchoolTableModel extends AbstractTableModel {
        private List<School> schools = new ArrayList<>();
        private final String[] columnNames = {"学校ID", "学校名称", "联系电话"};

        public void setSchools(List<School> schools) {
            this.schools = schools;
        }

        @Override
        public int getRowCount() {
            return schools.size();
        }

        @Override
        public int getColumnCount() {
            return columnNames.length;
        }

        @Override
        public String getColumnName(int column) {
            return columnNames[column];
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            School school = schools.get(rowIndex);
            switch (columnIndex) {
                case 0: return school.getSchoolId();
                case 1: return school.getSchoolName();
                case 2: return school.getSchoolTelNo();
                default: return null;
            }
        }
    }
}

调用:

java 复制代码
/**
 * encoding: utf-8
 * 版权所有 2025 ©涂聚文有限公司 ®
 * 许可信息查看:言語成了邀功盡責的功臣,還需要行爲每日來值班嗎
 * 描述:
 * Author    : geovindu,Geovin Du 涂聚文.
 * IDE       : IntelliJ IDEA 2024.3.6 Java 17
 * # database  : Oracle21c,MySQL 9.0,SQL Server 2019,PostgreSQL 17.1 Neo4j
 * # OS        : window10
 * Datetime  : 2025 - 2025/7/13 - 17:51
 * User      : geovindu
 * Product   : IntelliJ IDEA
 * Project   : oracleDDDDemo
 * File      : main.java
 * explain   : 学习  类
 **/
 
import presentation.views.SchoolView;
 
 
public class Main {
    public static void main(String[] args) {
 
        // 使用SwingUtilites确保在事件调度线程上创建和操作GUI
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                SchoolView view = new SchoolView();
                view.setVisible(true);
            }
        });
        System.out.println("Hello, Geovin Du!");
    }
}

输出: