项目案例作业3:使用DAO模式改造学生信息管理系统

项目案例作业3:使用DAO模式改造学生信息管理系统

项目名称 内容
课程名称 java
班级 网安2413
学生姓名 王璐
学号 202421336068

一、项目修改简述

将原有的基于 List 存储的学生信息管理系统,通过 DAO(Data Access Object)模式进行重构,实现多种数据存取方式的灵活切换。
改造后系统支持两种数据存取模式:基于 List 的内存存储、和基于 Excel 文件的持久化存储。同时,通过合理的包结构设计,提升代码的可读性、可维护性和扩展性。
DAO 模式的核心思想是分离数据访问逻辑与业务逻辑,通过定义统一的数据访问接口,为不同的数据存储方式提供具体实现,从而使业务层无需关注数据的具体存储细节,只需通过接口操作数据。

二、包结构设计

设计分层包结构如下:

code/
├── model/                // 数据模型层:封装实体信息
│   └── Student.java      // 学生实体类(存储学生姓名、年龄等核心属性)
├── dao/                  // 数据访问层:定义接口与实现
│   ├── StudentDAO.java   // 学生数据访问统一接口(规范核心操作)
│   └── impl/             // 具体存储实现类(接口的落地实现)
│       ├── ListStudentDAO.java    // 基于List的内存存储实现
│       └── ExcelStudentDAO.java   // 基于Excel的持久化存储实现
├── service/              // 业务逻辑层:处理业务规则
│   └── StudentManagementService.java  // 学生管理服务(衔接DAO与用户交互)
├── util/                 // 工具类层:提供通用辅助功能
│   └── ExcelUtil.java    // Excel文件操作工具(封装POI库操作,简化DAO实现)
└── Main.java             // 主程序入口:用户交互与模式切换

三、各模块详细实现

(一)model 层:实体类定义(Student.java)

package code.model;

public class Student {
    private String name;
    private int age;
    private String gender;
    private String id;
    private String major;
    private double gpa;
    
    public Student(String name, int age, String gender, String id, String major, double gpa) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        this.id = id;
        this.major = major;
        this.gpa = gpa;
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
    public String getGender() { return gender; }
    public void setGender(String gender) { this.gender = gender; }
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    public String getMajor() { return major; }
    public void setMajor(String major) { this.major = major; }
    public double getGpa() { return gpa; }
    public void setGpa(double gpa) { this.gpa = gpa; }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                ", id='" + id + '\'' +
                ", major='" + major + '\'' +
                ", gpa=" + gpa +
                '}';
    }
}

(二)DAO层:数据访问接口与实现

1. 统一接口:StudentDAO.java

定义学生数据操作的核心接口,所有存储方式(List/Excel)均需实现此接口,确保业务层操作的一致性,屏蔽不同存储的差异。

package code.dao;

import code.model.Student;
import java.util.List;

public interface StudentDAO {
    void addStudent(Student student);
    boolean removeStudent(String id);
    List<Student> searchByName(String name);
    List<Student> searchByMajor(String major);
    List<Student> searchByGpa(double gpa);
    List<Student> getAllStudents();
}

2. 基于 List 的实现:ListStudentDAO.java

使用 ArrayList 作为内存存储容器,所有操作均在内存中完成,适合临时数据管理(程序退出后数据丢失),操作效率高。

package code.dao.impl;

import code.dao.StudentDAO;
import code.model.Student;
import java.util.ArrayList;
import java.util.List;

public class ListStudentDAO implements StudentDAO {
    // 内存存储容器:存储所有学生对象
    private final List<Student> students;

    // 构造方法:初始化内存容器
    public ListStudentDAO() {
        this.students = new ArrayList<>();
    }

    @Override
    public void addStudent(Student student) {
        students.add(student); // 直接添加到内存列表
    }

    @Override
    public boolean removeStudent(String id) {
        // 遍历列表,按学号匹配并删除
        for (Student student : students) {
            if (student.getId().equals(id)) {
                students.remove(student);
                return true; // 删除成功
            }
        }
        return false; // 未找到匹配学生
    }

    @Override
    public List<Student> searchByName(String name) {
        List<Student> result = new ArrayList<>();
        for (Student student : students) {
            if (student.getName().equals(name)) {
                result.add(student);
            }
        }
        return result;
    }

    @Override
    public List<Student> searchByMajor(String major) {
        List<Student> result = new ArrayList<>();
        for (Student student : students) {
            if (student.getMajor().equals(major)) {
                result.add(student);
            }
        }
        return result;
    }

    @Override
    public List<Student> searchByGpa(double gpa) {
        List<Student> result = new ArrayList<>();
        for (Student student : students) {
            if (student.getGpa() == gpa) {
                result.add(student);
            }
        }
        return result;
    }

    @Override
    public List<Student> getAllStudents() {
        return new ArrayList<>(students); // 返回列表副本,避免外部修改内部数据
    }
}

3. 基于 Excel 的实现:ExcelStudentDAO.java

使用 Excel 文件作为持久化存储介质,借助 Apache POI 工具库实现 Excel 的读写操作,数据在程序退出后仍可保留。约定 Excel 文件规则:

  • 文件路径:students.xlsx(项目根目录)
  • 工作表名:学生信息
  • 表头:第一行固定为 “姓名、年龄、性别、学号、专业、GPA”
  • 数据行:从第二行开始存储学生信息

java

运行

package code.dao.impl;

import code.dao.StudentDAO;
import code.model.Student;
import code.util.ExcelUtil;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import java.util.ArrayList;
import java.util.List;

public class ExcelStudentDAO implements StudentDAO {
    // Excel文件路径与工作表名(固定配置)
    private static final String EXCEL_PATH = "students.xlsx";
    private static final String SHEET_NAME = "学生信息";

    @Override
    public void addStudent(Student student) {
        // 1. 获取Excel工作簿(不存在则自动创建)
        Workbook workbook = ExcelUtil.getWorkbook(EXCEL_PATH);
        // 2. 获取工作表(不存在则自动创建并添加表头)
        Sheet sheet = ExcelUtil.getOrCreateSheet(workbook, SHEET_NAME);
        // 3. 在最后一行插入新学生数据
        int lastRowNum = sheet.getLastRowNum(); // 获取当前最后一行索引
        Row newRow = sheet.createRow(lastRowNum + 1); // 创建新行
        // 4. 填充学生数据到单元格
        newRow.createCell(0).setCellValue(student.getName());
        newRow.createCell(1).setCellValue(student.getAge());
        newRow.createCell(2).setCellValue(student.getGender());
        newRow.createCell(3).setCellValue(student.getId());
        newRow.createCell(4).setCellValue(student.getMajor());
        newRow.createCell(5).setCellValue(student.getGpa());
        // 5. 写入数据到Excel文件并关闭资源
        ExcelUtil.writeAndCloseWorkbook(workbook, EXCEL_PATH);
    }

    @Override
    public boolean removeStudent(String id) {
        Workbook workbook = ExcelUtil.getWorkbook(EXCEL_PATH);
        Sheet sheet = ExcelUtil.getOrCreateSheet(workbook, SHEET_NAME);
        int lastRowNum = sheet.getLastRowNum();
        boolean isRemoved = false;

        // 遍历数据行(从第二行开始,跳过表头)
        for (int i = 1; i <= lastRowNum; i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue; // 跳过空行
            // 匹配学号(第三列:索引3)
            String studentId = row.getCell(3).getStringCellValue();
            if (studentId.equals(id)) {
                // 删除行:将后续行上移一行,覆盖当前行
                sheet.shiftRows(i + 1, lastRowNum, -1);
                isRemoved = true;
                break;
            }
        }

        // 若删除成功,保存文件
        if (isRemoved) {
            ExcelUtil.writeAndCloseWorkbook(workbook, EXCEL_PATH);
        } else {
            ExcelUtil.closeWorkbook(workbook); // 未删除则直接关闭资源
        }
        return isRemoved;
    }

    @Override
    public List<Student> searchByName(String name) {
        List<Student> result = new ArrayList<>();
        Workbook workbook = ExcelUtil.getWorkbook(EXCEL_PATH);
        Sheet sheet = ExcelUtil.getOrCreateSheet(workbook, SHEET_NAME);
        int lastRowNum = sheet.getLastRowNum();

        // 遍历数据行,匹配姓名(第一列:索引0)
        for (int i = 1; i <= lastRowNum; i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue;
            String studentName = row.getCell(0).getStringCellValue();
            if (studentName.equals(name)) {
                // 解析行数据为Student对象
                Student student = parseRowToStudent(row);
                result.add(student);
            }
        }

        ExcelUtil.closeWorkbook(workbook);
        return result;
    }

    @Override
    public List<Student> searchByMajor(String major) {
        List<Student> result = new ArrayList<>();
        Workbook workbook = ExcelUtil.getWorkbook(EXCEL_PATH);
        Sheet sheet = ExcelUtil.getOrCreateSheet(workbook, SHEET_NAME);
        int lastRowNum = sheet.getLastRowNum();

        // 遍历数据行,匹配专业(第四列:索引4)
        for (int i = 1; i <= lastRowNum; i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue;
            String studentMajor = row.getCell(4).getStringCellValue();
            if (studentMajor.equals(major)) {
                Student student = parseRowToStudent(row);
                result.add(student);
            }
        }

        ExcelUtil.closeWorkbook(workbook);
        return result;
    }

    @Override
    public List<Student> searchByGpa(double gpa) {
        List<Student> result = new ArrayList<>();
        Workbook workbook = ExcelUtil.getWorkbook(EXCEL_PATH);
        Sheet sheet = ExcelUtil.getOrCreateSheet(workbook, SHEET_NAME);
        int lastRowNum = sheet.getLastRowNum();

        // 遍历数据行,匹配GPA(第五列:索引5)
        for (int i = 1; i <= lastRowNum; i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue;
            double studentGpa = row.getCell(5).getNumericCellValue();
            if (Math.abs(studentGpa - gpa) < 0.001) { // 浮点数比较,避免精度问题
                Student student = parseRowToStudent(row);
                result.add(student);
            }
        }

        ExcelUtil.closeWorkbook(workbook);
        return result;
    }

    @Override
    public List<Student> getAllStudents() {
        List<Student> allStudents = new ArrayList<>();
        Workbook workbook = ExcelUtil.getWorkbook(EXCEL_PATH);
        Sheet sheet = ExcelUtil.getOrCreateSheet(workbook, SHEET_NAME);
        int lastRowNum = sheet.getLastRowNum();

        // 遍历所有数据行,解析为Student列表
        for (int i = 1; i <= lastRowNum; i++) {
            Row row = sheet.getRow(i);
            if (row == null) continue;
            Student student = parseRowToStudent(row);
            allStudents.add(student);
        }

        ExcelUtil.closeWorkbook(workbook);
        return allStudents;
    }

    // 辅助方法:将Excel行数据解析为Student对象
    private Student parseRowToStudent(Row row) {
        String name = row.getCell(0).getStringCellValue();
        int age = (int) row.getCell(1).getNumericCellValue();
        String gender = row.getCell(2).getStringCellValue();
        String id = row.getCell(3).getStringCellValue();
        String major = row.getCell(4).getStringCellValue();
        double gpa = row.getCell(5).getNumericCellValue();
        return new Student(name, age, gender, id, major, gpa);
    }
}

(三)util 层:Excel 工具类(ExcelUtil.java)

封装 Apache POI 库的复杂操作,提供 “获取工作簿、创建工作表、写入文件、关闭资源” 等通用方法,简化 ExcelStudentDAO 的代码逻辑,避免重复代码。

package code.util;

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import java.io.*;

public class ExcelUtil {
    // 1. 获取Excel工作簿:不存在则创建新工作簿
    public static Workbook getWorkbook(String filePath) {
        File excelFile = new File(filePath);
        // 若文件不存在,返回新的空白工作簿
        if (!excelFile.exists()) {
            return new XSSFWorkbook();
        }
        // 若文件存在,读取并返回工作簿
        try (InputStream inputStream = new FileInputStream(excelFile)) {
            return WorkbookFactory.create(inputStream);
        } catch (Exception e) {
            e.printStackTrace();
            return new XSSFWorkbook(); // 异常时返回空白工作簿
        }
    }

    // 2. 获取或创建工作表:不存在则创建,并添加默认表头
    public static Sheet getOrCreateSheet(Workbook workbook, String sheetName) {
        Sheet sheet = workbook.getSheet(sheetName);
        if (sheet == null) {
            sheet = workbook.createSheet(sheetName);
            addDefaultHeader(sheet); // 为新工作表添加表头
        }
        return sheet;
    }

    // 3. 添加默认表头:姓名、年龄、性别、学号、专业、GPA
    private static void addDefaultHeader(Sheet sheet) {
        Row headerRow = sheet.createRow(0); // 第一行作为表头
        String[] headers = {"姓名", "年龄", "性别", "学号", "专业", "GPA"};
        for (int i = 0; i < headers.length; i++) {
            headerRow.createCell(i).setCellValue(headers[i]);
        }
        // 自动调整列宽(优化显示效果)
        for (int i = 0; i < headers.length; i++) {
            sheet.autoSizeColumn(i);
        }
    }

    // 4. 写入工作簿到文件并关闭资源
    public static void writeAndCloseWorkbook(Workbook workbook, String filePath) {
        try (OutputStream outputStream = new FileOutputStream(filePath)) {
            workbook.write(outputStream); // 写入数据到文件
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeWorkbook(workbook); // 确保资源关闭
        }
    }

    // 5. 关闭工作簿资源
    public static void closeWorkbook(Workbook workbook) {
        try {
            if (workbook != null) {
                workbook.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

(四)service 层:业务逻辑服务(StudentManagementService.java)

作为业务逻辑的核心层,依赖 StudentDAO 接口完成数据操作,隔离 “业务逻辑” 与 “数据访问逻辑”。提供 DAO 切换接口,支持动态改变存储模式,同时可扩展数据校验、权限控制等业务规则。

package code.service;

import code.dao.StudentDAO;
import code.model.Student;
import java.util.List;

public class StudentManagementService {
    private StudentDAO studentDAO; // 依赖DAO接口(面向接口编程)

    // 构造方法:初始化时注入DAO实现
    public StudentManagementService(StudentDAO studentDAO) {
        this.studentDAO = studentDAO;
    }

    // 切换存储模式:动态修改DAO实现(核心功能)
    public void switchStorageMode(StudentDAO newStudentDAO) {
        this.studentDAO = newStudentDAO;
    }

    // 添加学生:调用DAO接口,无额外业务规则(可扩展数据校验)
    public void addStudent(Student student) {
        // 可扩展:添加数据合法性校验(如年龄>0、GPA在0-4之间)
        studentDAO.addStudent(student);
    }

    // 按学号删除学生:返回删除结果
    public boolean removeStudent(String id) {
        return studentDAO.removeStudent(id);
    }

    // 按姓名查询学生
    public List<Student> searchByName(String name) {
        return studentDAO.searchByName(name);
    }

    // 按专业查询学生
    public List<Student> searchByMajor(String major) {
        return studentDAO.searchByMajor(major);
    }

    // 按GPA查询学生
    public List<Student> searchByGpa(double gpa) {
        return studentDAO.searchByGpa(gpa);
    }

    // 获取所有学生
    public List<Student> getAllStudents() {
        return studentDAO.getAllStudents();
    }
}

(五)主程序入口:Main.java

负责用户交互,提供 “存储模式切换” 和 “学生管理功能” 的入口,通过控制台菜单引导用户操作,动态切换 List/Excel 存储模式,调用业务服务完成具体功能。

package code;

import code.dao.StudentDAO;
import code.dao.impl.ExcelStudentDAO;
import code.dao.impl.ListStudentDAO;
import code.model.Student;
import code.service.StudentManagementService;
import java.util.List;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 1. 初始化:默认使用List内存存储模式
        StudentDAO defaultDAO = new ListStudentDAO();
        StudentManagementService service = new StudentManagementService(defaultDAO);
        boolean isRunning = true;

        System.out.println("===== 学生信息管理系统(DAO模式)=====");
        System.out.println("当前默认存储模式:内存List模式(数据临时存储,退出后丢失)\n");

        // 2. 主循环:处理用户操作
        while (isRunning) {
            // 打印菜单
            System.out.println("请选择操作:");
            System.out.println("1. 切换存储模式(List/Excel)");
            System.out.println("2. 添加学生");
            System.out.println("3. 删除学生(按学号)");
            System.out.println("4. 按姓名查询学生");
            System.out.println("5. 按专业查询学生");
            System.out.println("6. 按GPA查询学生");
            System.out.println("7. 显示所有学生");
            System.out.println("8. 退出系统");
            System.out.print("输入操作编号:");

            // 读取用户输入
            int choice = scanner.nextInt();
            scanner.nextLine(); // 吸收换行符,避免后续读取字符串异常

            // 处理用户选择
            switch (choice) {
                case 1:
                    // 切换存储模式
                    System.out.println("\n请选择目标存储模式:");
                    System.out.println("1. 内存List模式(临时存储)");
                    System.out.println("2. Excel文件模式(持久化存储)");
                    System.out.print("输入模式编号:");
                    int modeChoice = scanner.nextInt();
                    switch (modeChoice) {
                        case 1:
                            service.switchStorageMode(new ListStudentDAO());
                            System.out.println("存储模式切换成功:内存List模式\n");
                            break;
                        case 2:
                            service.switchStorageMode(new ExcelStudentDAO());
                            System.out.println("存储模式切换成功:Excel文件模式(文件路径:students.xlsx)\n");
                            break;
                        default:
                            System.out.println("无效的模式编号,切换失败\n");
                            break;
                    }
                    break;

                case 2:
                    // 添加学生:读取用户输入的学生信息
                    System.out.println("\n===== 添加学生 =====");
                    System.out.print("姓名:");
                    String name = scanner.nextLine();
                    System.out.print("年龄:");
                    int age = scanner.nextInt();
                    scanner.nextLine(); // 吸收换行符
                    System.out.print("性别:");
                    String gender = scanner.nextLine();
                    System.out.print("学号:");
                    String id = scanner.nextLine();
                    System.out.print("专业:");
                    String major = scanner.nextLine();
                    System.out.print("GPA:");
                    double gpa = scanner.nextDouble();

                    // 调用服务添加学生
                    Student newStudent = new Student(name, age, gender, id, major, gpa);
                    service.addStudent(newStudent);
                    System.out.println("学生添加成功!\n");
                    break;

                case 3:
                    // 删除学生:按学号删除
                    System.out.println("\n===== 删除学生 =====");
                    System.out.print("输入要删除的学生学号:");
                    String removeId = scanner.nextLine();
                    boolean isRemoved = service.removeStudent(removeId);
                    if (isRemoved) {
                        System.out.println("学生删除成功!\n");
                    } else {
                        System.out.println("未找到该学号的学生,删除失败!\n");
                    }
                    break;

                case 4:
                    // 按姓名查询
                    System.out.println("\n===== 按姓名查询 =====");
                    System.out.print("输入查询姓名:");
                    String searchName = scanner.nextLine();
                    List<Student> nameResults = service.searchByName(searchName);
                    printStudentResults(nameResults);
                    break;

                case 5:
                    // 按专业查询
                    System.out.println("\n===== 按专业查询 =====");
                    System.out.print("输入查询专业:");
                    String searchMajor = scanner.nextLine();
                    List<Student> majorResults = service.searchByMajor(searchMajor);
                    printStudentResults(majorResults);
                    break;

                case 6:
                    // 按GPA查询
                    System.out.println("\n===== 按GPA查询 =====");
                    System.out.print("输入查询GPA:");
                    double searchGpa = scanner.nextDouble();
                    List<Student> gpaResults = service.searchByGpa(searchGpa);
                    printStudentResults(gpaResults);
                    break;

                case 7:
                    // 显示所有学生
                    System.out.println("\n===== 所有学生信息 =====");
                    List<Student> allStudents = service.getAllStudents();
                    printStudentResults(allStudents);
                    break;

                case 8:
                    // 退出系统
                    isRunning = false;
                    System.out.println("\n系统退出成功,感谢使用!");
                    break;

                default:
                    System.out.println("\n无效的操作编号,请重新输入!\n");
                    break;
            }
        }

        scanner.close(); // 关闭输入流
    }

    // 辅助方法:打印学生查询结果(统一格式)
    private static void printStudentResults(List<Student> students) {
        if (students.isEmpty()) {
            System.out.println("未查询到学生信息!\n");
            return;
        }
        // 遍历打印每个学生信息
        for (Student student : students) {
            System.out.println(student);
        }
        System.out.println("(共查询到 " + students.size() + " 名学生)\n");
    }
}

四、依赖说明

Excel 存储模式依赖 Apache POI 库(处理 Excel 文件),需在项目中引入以下依赖(以 Maven 项目为例):

<dependencies>
    <!-- Apache POI:处理Excel 2003及以下(.xls) -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi</artifactId>
        <version>4.1.2</version>
    </dependency>
    <!-- Apache POI-OOXML:处理Excel 2007及以上(.xlsx) -->
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>4.1.2</version>
    </dependency>
</dependencies>

若使用非 Maven 项目,需手动下载以下 JAR 包并添加到项目类路径:

  1. poi-4.1.2.jar
  2. poi-ooxml-4.1.2.jar
  3. 依赖的辅助 JAR 包

五、系统功能测试

(一)模式切换测试

  1. 默认模式(List):启动系统后,添加 2 名学生(如 “张三,20,男,001,计算机,3.8”),查询可正常显示;退出系统后重新启动,数据丢失(符合临时存储特性)。
  2. 切换到 Excel 模式:选择 “1. 切换存储模式”→“2. Excel 文件模式”,添加学生后,在项目根目录生成students.xlsx文件,打开文件可看到学生数据;退出系统后重新启动,切换回 Excel 模式,查询可恢复之前添加的学生(符合持久化特性)。

(二)核心功能测试

功能 测试步骤 预期结果
添加学生 选择 “2. 添加学生”,输入合法信息(如 “李四,21,女,002,数学,3.5”) 提示 “添加成功”,Excel 文件中新增该行数据
删除学生 选择 “3. 删除学生”,输入存在的学号(如 001) 提示 “删除成功”,Excel 文件中该行数据消失
按姓名查询 选择 “4. 按姓名查询”,输入已添加的姓名(如 “张三”) 显示该姓名对应的所有学生(支持同名)
按专业查询 选择 “5. 按专业查询”,输入已添加的专业(如 “计算机”) 显示该专业的所有学生
按 GPA 查询 选择 “6. 按 GPA 查询”,输入已添加的 GPA(如 3.8) 显示 GPA 匹配的所有学生(浮点数精度正常)
显示所有学生 选择 “7. 显示所有学生” 按统一格式显示所有学生,包含数量统计

六、改造总结

(一)核心优势

  1. 解耦与灵活性:DAO 模式分离业务逻辑与数据访问,业务层无需关注存储细节,可通过switchStorageMode方法动态切换 List/Excel 模式,适应不同场景(临时操作 / 持久化存储)。
  2. 可扩展性强:若后续需新增存储方式(如数据库存储),只需实现StudentDAO接口,无需修改业务层与主程序代码,符合 “开闭原则”。
  3. 代码可维护性高:分层包结构使职责清晰(model 存实体、dao 管访问、service 处理业务),便于定位问题与迭代升级。
  4. 用户体验优化:主程序提供清晰的菜单引导,统一的结果打印格式,支持存储模式切换提示,降低用户操作成本。

(二)不足与改进方向

  1. 数据校验缺失:当前未对用户输入的学生信息(如年龄为负数、GPA 超出 0-4 范围、学号重复)进行合法性校验,可在StudentManagementServiceaddStudent方法中添加校验逻辑。
  2. Excel 性能优化:当学生数据量较大(如千级以上)时,Excel 文件读写效率较低,可引入 “内存缓存 + 批量写入” 机制,减少文件 IO 次数。
  3. 异常处理增强:当前异常处理仅打印堆栈信息,可优化为用户友好提示(如 “Excel 文件被占用,请关闭后重试”),提升系统健壮性。
posted @ 2025-10-20 21:26  hohohoho---  阅读(5)  评论(0)    收藏  举报