18_学生管理系统源码开发
1、项目目的
1.1 MVC设计模式
Model 模块
View 视图
Controller 控制器
1.2 主要业务逻辑
增 add
删 remove
改 modifyStudent
查 findStudent
2、项目主要功能
学生管理系统
学生信息:
学号、姓名、性别、Java成绩、数据库成绩、Web成绩、总分
实现功能:
1、添加新学生
2、修改学生信息
3、删除学生信息
4、查询指定名称的学生
5、查询所有学生信息
6、根据成绩排序学生信息
3、项目分析
3.1 学生实体类实现和学号自动生成
ID自动生成:
1、当前数据存在一定的持久性和共享特征 需要一个 static 关键字修饰的静态成员变量 用于存储赋值 id 的数据内容
2、id 在实例化对象的过程中产生 使用构造代码块 给予所有实例化对象国策灰姑娘统一 id自增赋值操作
3.2 学生信息代码运行存储问题
分析:
1、数据类型确定为 Student 学生类型
2、数据个数不确定 每个班人数不固定
准备一个类 属于 Model 模块
1、成员变量为学生类型的数组
2、针对于学生类型的数组中的数据信息 完成增删改查操作
public class StudentModel {
private Student[] arr;
}
3.3 StudentModel 底层数组容量和构造方法
分析:
1、目前只定义了一个底层 Student 类型数组 需要进行数组容量初始化操作
2、无参构造方法和有参构造方法
构造方法给予数组容量初始化操作
无参构造方法 直接使用【固定默认】的容量给予数组容量初始化操作
有参构造方法 将底层数组的容量交给调用者决定 给予调用者参数信息 参数决定数组容量
//导入当前项目中其它package 内的类 这里导入的是 Student 实体类
import com.qfedu.stusys.entity.Student;
/**
* 学生模块
*
* @author Echo
*
*/
public class StudentModel {
/**
* 私有化成员变量 学生对象数组
* 一个数组为一个班级
* 【注意】
* 当前数组没有分配容量空间
*/
private Student[] allStudents;
/**
* 私有化 static final 修饰成员变量 用于描述当前底层 Student 类型数组的默认容量
* 默认容量
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* 数组允许的最大容量 Integer.MAX_VALUE - 8
* 数组允许的最大容量
*/
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/**
* 底层数组容量 初始化为 0
*/
private int size = 0;
/**
* 无参数构造方法 初始化底层数组容量DEFAULT_CAPACITY 保证用户的基本使用
*/
public StudentModel() {
allStudents = new Student[DEFAULT_CAPACITY];
}
/**
* 根据用户提供的初始化容量来决定当前底层数组的容量数据
*
* @param initCapacity 用户提供的初始化容量
*/
public StudentModel(int initCapacity) {
if (initCapacity < 0 || initCapacity > MAX_ARRAY_SIZE) {
// TODO 无法利用返回值操作提示用户错误信息 后期需要异常处理
}
allStudents = new Student[initCapacity];
}
/**
* 展示数组元素内容
*/
public void show() {
for (int i = 0; i < size; i++) {
System.out.println(allStudents[i]);
}
}
}
3.4 添加学生信息
/**
* 添加学生对象到当前 StudentModel 底层数组中
* @param student student对象
* @return 添加成功返回 true 否则返回 false
*/
public boolean add(Student student) {
//底层数组添加学生 采用的方式为尾插法 size 是数组有效元素个数
allStudents[size++] = student;
return true;
}
3.5 StudentModel 底层数组容量扩容操作
扩容方法流程
1、获取原数组容量 oldCapacity
2、计算得到新数组容量 newCapacity 是原数组容量的 1.5 倍左右
3、判断新数组容量是否满足最小容量需求 minCapacity
4、判断新数组容量是否在数组允许最大容量范围内 MAX_ARRAY_SIZE 即 Integer.MAX_VALUE - 8
5、创建一个新数组
6、将原数组中的数据移动到新数组
7、保存新数组地址
/**
* 私有化成员方法 用于在添加操作中发现容量不足的情况 对底层数组进行扩容操作
* 所需参数是当前扩容最小容量需求
* @param minCapacity 最小容量
*/
private void grow(int minCapacity) {
//1、获取原数组容量
int oldCapacity = allStudents.length;
//2、计算得到的新数组 是原数组容量的 1.5 倍左右
int newCapacity = oldCapacity + oldCapacity / 2;
//3、判断新数组容量是否满足最小容量需求(miniCapacity)原数组数据个数 + 新添加数据个数
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
//4、判断新数组容量是否超出数组允许的最大容量范围 是否大于 MAX_ARRAY_SIZE
if (newCapacity > MAX_ARRAY_SIZE) {
// TODO 通过异常处理操作 当前数组无法满足存储需求
}
//5、创建一个新数组
Student[] temp = new Student[newCapacity];
//6、将原数组中的数据移动到新数组
for (int i = 0; i < allStudents.length; i++) {
temp[i] = allStudents[i];
}
//7、保存新数组地址
allStudents = temp;
}
3.6 删除指定 id 的学生信息
流程:
1、根据指定 id 找到对应学生对象在数组中的下标位置
2、如果下标不存在 终止删除操作 如果下标存在 进入删除操作流程
3、删除流程
3.1 定义一个临时局部变量保留学生对象
3.2 从删除位置之后的数据 整体前移一位
3.3 原本最后一个下标位置 赋值为 null 表示空
3.4 有效元素个数减一 size -= 1
/**
* 根据 id 删除对应的学生对象 并返回被删除的对象
* @param id 被删除学生对象对应的 id
* @return 删除成功返回被删除的学生对象 否则返回 null
*/
public Student remove(int id) {
int index = findIndexById(id);
//如果 index 结果为 -1 当前指定 id 信息的学生不存在 返回 null
if (-1 == index) {
return null;
}
//删除操作
//定义一个局部变量 存储被删除的元素
Student student = allStudents[index];
/*
* 使用循环从被删除下标位置开始 到最后一个有效元素下标位置 - 1结束
* 数组中被删除的元素之后的元素整体前移一位
*/
for (int i = index; i < size - 1; i++) {
allStudents[i] = allStudents[i + 1];
}
/*
* 数组中最后一个有效元素位置前移 原先的位置赋空值
* 有效元素个数 - 1
*/
allStudents[--size] = null;
return student;
}
【补充方法】找出指定 id 对应的学生对象在数组中的下标位置
/**
* 根据学生对象的 id 找出学生对象在数组中对应的下标位置
* @param id 学生 id
* @return 找到后返回指定 id 对应的学生对象在数组中的下标位置 否则返回 -1
*/
private int findIndexById(int id) {
//判断 id 是否在合法范围内
if (id <= 0) {
return -1;
}
int index = -1;
for (int i = 0; i < size; i++) {
//获取学生类型数组中 下标为 i 的学生对象 和当前目标数据 id 对比
if (allStudents[i].getId() == id) {
index = i;
break;
}
}
return index;
}
3.7 修改指定 id 对应的学生对象信息
流程:
1、根据 id 找到对应的学生对象
2、如果找到对应学生对象 展示数据提示信息 实例化 Scanner 扫描器对象 进行输入修改操作
3、修改完成 退出修改
/**
* 修改学生对象
* 根据 id 修改对应学生对象
* @param id
*/
public void modifyStudent(int id) {
int index = findIndexById(id);
if (-1 == index) {
return;
}
//使用局部变量存储学生对象信息 方便展示
Student stu = allStudents[index];
//退出标记变量
boolean flag = true;
//用于存储用户的选择
int choose = 0;
//扫描器
Scanner sc = new Scanner(System.in);
while(flag) {
System.out.println("ID:" + stu.getId());
System.out.println("Name:" + stu.getName());
System.out.println("Age:" + stu.getAge());
System.out.println("Gender:" + stu.getGender());
System.out.println("JavaScore:" + stu.getJavaScore());
System.out.println("DbScore:" + stu.getDbScore());
System.out.println("WebScore:" + stu.getWebScore());
System.out.println("TotalScore:" + stu.getTotalScore());
System.out.println("1. 修改学生姓名");
System.out.println("2. 修改学生年龄");
System.out.println("3. 修改学生性别");
System.out.println("4. 修改学生Java成绩");
System.out.println("5. 修改学生Database成绩");
System.out.println("6. 修改学生Web成绩");
System.out.println("7. 退出修改");
System.out.println("----------------");
System.out.println("请输入序号:");
//存储用户输入的选项
choose = sc.nextInt();
//换行字符
sc.nextLine();
switch(choose) {
case 1:
System.out.println("请输入学生姓名:");
//获取用户输入的姓名 String 类型
String name = sc.nextLine();
//修改姓名
stu.setName(name);
break;
case 2:
System.out.println("请输入学生年龄:");
//获取用户输入的年龄 int 类型
int age = sc.nextInt();
//修改年龄
if (checkAge(age)) {
stu.setAge(age);
}
break;
case 3:
System.out.println("请输入学生性别:");
//获取用户输入的性别 char 类型
char gender = sc.nextLine().charAt(0);
//修改性别
if (checkGender(gender)) {
stu.setGender(gender);
}
break;
case 4:
System.out.println("请输入学生Java成绩:");
//获取用户输入的Java成绩
int javaScore = sc.nextInt();
//修改javaScore成绩
if (checkScore(javaScore)) {
stu.setJavaScore(javaScore);
}
break;
case 5:
System.out.println("请输入学生Database成绩:");
//获取用户输入的Database成绩
int dbScore = sc.nextInt();
//修改dbScore成绩
if (checkScore(dbScore)) {
stu.setDbScore(dbScore);
}
break;
case 6:
System.out.println("请输入学生Web成绩:");
//获取用户输入的Web成绩
int webScore = sc.nextInt();
//修改webScore成绩
if (checkScore(webScore)) {
stu.setJavaScore(webScore);
}
break;
case 7:
flag = true;
break;
default:
System.out.println("输入错误");
break;
}
//结束 while 循环
if (flag) {
break;
}
}
sc.close();
}
【补充方法】用户输入合法性判断
/**
* 用户输入成绩合法性判断
* @param score 用户提供的成绩分数
* @return 如果在合法范围内返回 true 否则返回 false
*/
private boolean checkScore(int score) {
return score >= 0 && score <= 100;
}
/**
* 用户输入性别合法性判断
* @param gender 用户提供的性别
* @return 如果合法返回 true 否则返回 false
*/
private boolean checkGender(char gender) {
return '男' == gender || '女' == gender;
}
/**
* 用户输入年龄合法性判断
* @param age 用户提供的年龄
* @return 如果合法返回 true 否则返回 false
*/
private boolean checkAge(int age) {
return age >= 0 && age <= 120;
}
3.8 根据指定 id 查询对应学生对象
/**
* 根据学生对象 id 信息 查询学生对象详情
* @param id 指定学生 id
* @return 找到后返回该 id 对应的学生对象 否则返回 null
*/
public Student findStudent(int id) {
int index = findIndexById(id);
return index != -1 ? allStudents[index] : null;
}