使用DAO模式改造学生信息管理系统

学生信息管理系统的 DAO 模式改造:实现多数据存储切换

项目改造背景

在原始的学生信息管理系统中,学生数据仅通过 List 进行存储,存在数据持久化能力不足、存储方式单一的问题。本次改造采用 DAO(Data Access Object)模式,为系统扩展文本文件存储和 Excel 文件存储功能,并保证主程序可自由切换存储模式,同时优化项目包结构以提升代码可维护性。

一、项目包结构设计

为实现模块化管理,采用以下包结构组织代码:

stumanagement/

├── model/                // 数据模型层

│   └── Student.java      // 学生实体类

├── dao/                  // 数据访问接口层

│   └── StudentDao.java   // 学生数据操作接口

├── dao.impl/             // 数据访问实现层

│   ├── StudentDaoListImpl.java    // List存储实现

│   ├── StudentDaoFileImpl.java    // 文本文件存储实现

│   └── StudentDaoExcelImpl.java   // Excel文件存储实现(进阶功能)

└── test/                 // 测试层

    └── Main.java         // 主程序入口

二、核心代码实现

1. 实体类(model/Student.java)

保持学生实体类简洁,封装姓名、学号等核心属性:

package stumanagement.model;

public class Student {

private String id;   // 新增学号属性

private String name;

public Student(String id, String name) {

       this.id = id;

       this.name = name;

  }

  // Getter和Setter方法

 public String getId() { return id; }

 public void setId(String id) { this.id = id; }

 public String getName() { return name; }

 public void setName(String name) { this.name = name; }

@Override

public String toString() {

      return "Student{id='" + id + "', name='" + name + "'}";

 }

}

2. DAO 接口(dao/StudentDao.java)

定义统一的数据操作规范,所有存储实现类必须遵循:

package stumanagement.dao;

import stumanagement.model.Student;

import java.util.List;

public interface StudentDao {

 boolean addStudent(Student student);       // 添加学生

 Student getStudentById(String id);         // 按学号查询

  List\<Student> getAllStudents();            // 获取所有学生

  boolean updateStudent(Student student);    // 更新学生信息

  boolean deleteStudent(String id);          // 删除学生

}

3. 存储实现类

(1)List 存储实现(dao.impl/StudentDaoListImpl.java)

基于内存集合的临时存储,适合快速测试:

package stumanagement.dao.impl;

import stumanagement.dao.StudentDao;

import stumanagement.model.Student;

import java.util.ArrayList;

import java.util.List;

public class StudentDaoListImpl implements StudentDao {

private List\<Student> students = new ArrayList<>();

 @Override

 public boolean addStudent(Student student) {

  // 避免重复添加相同学号的学生

 if (getStudentById(student.getId()) != null) {

          return false;

    }

      students.add(student);

     return true;

 }

 @Override

 public Student getStudentById(String id) {

       for (Student s : students) {

          if (s.getId().equals(id)) {

              return s;

           }

      }

      return null;

  }

  @Override

 public List\<Student> getAllStudents() {

      return new ArrayList<>(students);  // 返回副本避免外部修改

  }

   @Override

   public boolean updateStudent(Student student) {

      Student exist = getStudentById(student.getId());

      if (exist != null) {

          exist.setName(student.getName());

         return true;

      }

      return false;

   }

  @Override

   public boolean deleteStudent(String id) {

       Student exist = getStudentById(id);

     if (exist != null) {

           students.remove(exist);

           return true;

      }

      return false;

  }

}

(2)文本文件存储实现(dao.impl/StudentDaoFileImpl.java)

使用文本文件持久化存储,每行一条学生信息(学号,姓名):

package stumanagement.dao.impl;

import stumanagement.dao.StudentDao;

import stumanagement.model.Student;

import java.io.\*;

import java.util.ArrayList;

import java.util.List;

public class StudentDaoFileImpl implements StudentDao {

    private String filePath;  // 数据文件路径

    public StudentDaoFileImpl(String filePath) {

        this.filePath = filePath;

        // 确保文件存在

        try {

            File file = new File(filePath);

            if (!file.exists()) {

                file.createNewFile();

            }

        } catch (IOException e) {

            e.printStackTrace();

        }

    }

    @Override

    public boolean addStudent(Student student) {

        if (getStudentById(student.getId()) != null) {

            return false;

        }

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) {

            writer.write(student.getId() + "," + student.getName());

            writer.newLine();

            return true;

        } catch (IOException e) {

            e.printStackTrace();

            return false;

        }

    }

    @Override

    public Student getStudentById(String id) {

        for (Student s : getAllStudents()) {

            if (s.getId().equals(id)) {

                return s;

            }

        }

        return null;

    }

    @Override

    public List\<Student> getAllStudents() {

        List\<Student> students = new ArrayList<>();

        try (BufferedReader reader = new BufferedReader(new FileReader(filePath))) {

            String line;

            while ((line = reader.readLine()) != null) {

                String\[] parts = line.split(",");

                if (parts.length == 2) {

                    students.add(new Student(parts\[0], parts\[1]));

                }

            }

        } catch (IOException e) {

            e.printStackTrace();

        }

        return students;

    }

    // 更新和删除方法需要先读取所有数据,修改后重新写入文件

    @Override

    public boolean updateStudent(Student student) {

        List\<Student> students = getAllStudents();

        for (Student s : students) {

            if (s.getId().equals(student.getId())) {

                s.setName(student.getName());

                // 重新写入所有数据

                return rewriteFile(students);

            }

        }

        return false;

    }

    @Override

    public boolean deleteStudent(String id) {

        List\<Student> students = getAllStudents();

        boolean removed = students.removeIf(s -> s.getId().equals(id));

        if (removed) {

            return rewriteFile(students);

        }

        return false;

    }

    // 辅助方法:重写文件内容

    private boolean rewriteFile(List\<Student> students) {

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath))) {

            for (Student s : students) {

                writer.write(s.getId() + "," + s.getName());

                writer.newLine();

            }

            return true;

        } catch (IOException e) {

            e.printStackTrace();

            return false;

        }

    }

}

(3)Excel 文件存储实现(dao.impl/StudentDaoExcelImpl.java)

使用 Apache POI 库实现 Excel 存储(需引入 poi 依赖):

package stumanagement.dao.impl;

import org.apache.poi.ss.usermodel.\*;

import stumanagement.dao.StudentDao;

import stumanagement.model.Student;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.util.ArrayList;

import java.util.List;

public class StudentDaoExcelImpl implements StudentDao {

    private String filePath;

    private static final String SHEET\_NAME = "students";

    public StudentDaoExcelImpl(String filePath) {

        this.filePath = filePath;

        initFile();  // 初始化Excel文件

    }

    // 初始化Excel文件(创建表头)

    private void initFile() {

        File file = new File(filePath);

        if (!file.exists()) {

            try (Workbook workbook = WorkbookFactory.create(true)) {

                Sheet sheet = workbook.createSheet(SHEET\_NAME);

                // 创建表头行

                Row headerRow = sheet.createRow(0);

                headerRow.createCell(0).setCellValue("学号");

                headerRow.createCell(1).setCellValue("姓名");

                try (FileOutputStream fos = new FileOutputStream(filePath)) {

                    workbook.write(fos);

                }

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

    @Override

    public boolean addStudent(Student student) {

        if (getStudentById(student.getId()) != null) {

            return false;

        }

        try (Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath))) {

            Sheet sheet = workbook.getSheet(SHEET\_NAME);

            int lastRowNum = sheet.getLastRowNum();

            Row row = sheet.createRow(lastRowNum + 1);

            row.createCell(0).setCellValue(student.getId());

            row.createCell(1).setCellValue(student.getName());

            try (FileOutputStream fos = new FileOutputStream(filePath)) {

                workbook.write(fos);

            }

            return true;

        } catch (IOException e) {

            e.printStackTrace();

            return false;

        }

    }

    @Override

    public Student getStudentById(String id) {

        for (Student s : getAllStudents()) {

            if (s.getId().equals(id)) {

                return s;

            }

        }

        return null;

    }

    @Override

    public List\<Student> getAllStudents() {

        List\<Student> students = new ArrayList<>();

        try (Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath))) {

            Sheet sheet = workbook.getSheet(SHEET\_NAME);

            for (int i = 1; i <= sheet.getLastRowNum(); i++) {  // 从1开始跳过表头

                Row row = sheet.getRow(i);

                if (row == null) continue;

                String sid = getCellValue(row.getCell(0));

                String name = getCellValue(row.getCell(1));

                students.add(new Student(sid, name));

            }

        } catch (IOException e) {

            e.printStackTrace();

        }

        return students;

    }

    // 辅助方法:获取单元格内容(兼容不同数据类型)

    private String getCellValue(Cell cell) {

        if (cell == null) return "";

        switch (cell.getCellType()) {

            case STRING: return cell.getStringCellValue();

            case NUMERIC: return String.valueOf((int) cell.getNumericCellValue());

            default: return "";

        }

    }

    // 更新和删除方法省略(实现逻辑类似文本文件,需重写整个工作表)

    @Override

    public boolean updateStudent(Student student) {

        // 实现逻辑:读取所有学生 -> 更新目标学生 -> 重写Excel

        return false;

    }

    @Override

    public boolean deleteStudent(String id) {

        // 实现逻辑:读取所有学生 -> 删除目标学生 -> 重写Excel

        return false;

    }

}

4. 主程序(test/Main.java)

通过切换 DAO 实现类,自由选择存储模式:

package stumanagement.test;

import stumanagement.dao.StudentDao;

import stumanagement.dao.impl.StudentDaoListImpl;

import stumanagement.dao.impl.StudentDaoFileImpl;

import stumanagement.dao.impl.StudentDaoExcelImpl;

import stumanagement.model.Student;

public class Main {

public static void main(String\[] args) {

// 1. 使用List存储

// StudentDao dao = new StudentDaoListImpl();

        // 2. 使用文本文件存储(指定文件路径)

        // StudentDao dao = new StudentDaoFileImpl("students.txt");

        

        // 3. 使用Excel文件存储(指定文件路径)

        StudentDao dao = new StudentDaoExcelImpl("students.xlsx");

        // 测试数据操作

        dao.addStudent(new Student("001", "张三"));

        dao.addStudent(new Student("002", "李四"));

        

        System.out.println("所有学生:");

        dao.getAllStudents().forEach(System.out::println);

        

        System.out.println("查询学号001:" + dao.getStudentById("001"));

    }

}

三、DAO 模式的优势

  1. 解耦业务逻辑与数据存储:主程序只需调用 DAO 接口方法,无需关心数据存储细节(是 List、文本文件还是 Excel)。

  2. 灵活切换存储模式:仅需修改 DAO 实现类的实例化代码,即可在不同存储方式间切换,无需改动业务逻辑。

  3. 便于扩展新存储方式:如需添加数据库存储,只需新增StudentDaoJdbcImpl实现类,原有代码无需修改,符合 "开闭原则"。

  4. 统一操作规范:接口定义了标准方法,确保所有存储实现类行为一致,提升代码可读性和可维护性。

四、总结与扩展

本次改造通过 DAO 模式成功为系统扩展了多种数据存储方式,优化了项目结构。后续可进一步完善:

  • 为 Excel 实现类补充完整的更新和删除功能

  • 添加数据库存储实现(如 MySQL)

  • 引入工厂模式管理 DAO 实例,进一步简化存储模式切换逻辑

posted @ 2025-10-19 20:53  叶Y  阅读(9)  评论(0)    收藏  举报