使用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 模式的优势
-
解耦业务逻辑与数据存储:主程序只需调用 DAO 接口方法,无需关心数据存储细节(是 List、文本文件还是 Excel)。
-
灵活切换存储模式:仅需修改 DAO 实现类的实例化代码,即可在不同存储方式间切换,无需改动业务逻辑。
-
便于扩展新存储方式:如需添加数据库存储,只需新增
StudentDaoJdbcImpl实现类,原有代码无需修改,符合 "开闭原则"。 -
统一操作规范:接口定义了标准方法,确保所有存储实现类行为一致,提升代码可读性和可维护性。
四、总结与扩展
本次改造通过 DAO 模式成功为系统扩展了多种数据存储方式,优化了项目结构。后续可进一步完善:
-
为 Excel 实现类补充完整的更新和删除功能
-
添加数据库存储实现(如 MySQL)
-
引入工厂模式管理 DAO 实例,进一步简化存储模式切换逻辑

浙公网安备 33010602011771号