Java - 校园类型系统班级升年级

校园背景的项目系统,往往存在每年都要给学生更换年级的需求。此文章用于记录部分实现思路。

需求:
1.创建班级时仅选择学段与入学年份,不选择年级。
2.每年自动更新一次班级升年级。
3.升学至下一学段时,入学年份需要变更。

一、表设计与示例数据

1.study_section 学段表
字段名字段类型字段注释
section_idint学段id
section_namevchar学段名称
sortint排序序号
gradeNumint有效年级数
学段示例数据
学段id学段名称排序序号有效年级数
1小学16
2初中23
3高中33
2.study_grade 年级表
字段名字段类型字段注释
grade_idint年级id
section_idint学段id
grade_namevchar年级名称
sortint排序序号
年级示例数据
年级id学段id年级名称排序序号
11一年级1
21二年级2
31三年级3
41四年级4
51五年级5
61六年级5
71未安排6
81已毕业-1
92初一1
102初二2
112初三3
122未安排4
132已毕业-1
143高一1
153高二2
163高三3
173未安排4
183已毕业-1
3.study_class 班级表
字段名字段类型字段注释
class_idint班级id
enrollment_yearint入学年份
grade_idint年级id
class_numint班号
class_namevchar班级名称
班级示例数据 (当前是2022年10月)
班级id入学年份年级id班号班级名称
12022112022级小学1班(一年级)
22019312019级小学1班(三年级)
32020222020级初中2班 (初三)
42021242021级初中4班(初二)
52022352022级高中5班 (高一)

二、逻辑代码

1.创建班级

不可存在同入学年份、同学段、同班号的班级

public void addClass(StudyClassDTO classDTO) {

	// 1.先根据入学年份、学段获取年级
	Long gradeId = getGradeIdBySectionAndYear(classDTO.getSectionId(), classDTO.getEnrollmentYear());
	
	// 2.判断入学年份、年级、班号是否存在重复数据
	QueryWrapper<StudyClass> queryCla = new QueryWrapper<>();
	queryCla.lambda().eq(StudyClass::getEnrollmentYear, classDTO.getEnrollmentYear());
	queryCla.lambda().eq(StudyClass::getClassNum, classDTO.getCalssNum());
	queryCla.lambda().eq(StudyClass::getGradeId, gradeId);
	List<StudyClass> classList = studyClassMapper.selectList(queryCla);
	if (CollectionUtils.isNotEmpty()) {
		throw new ServiceException("已存在同年份、同学段、同班号班级!");
	}
	
	// 3.插入数据
	StudyClass addClass = new StudyClass();
	BeanUtils.copy(classDTO, param);
	param.setGradeId(gradeId);
	studyClassMapper.insert(addClass);
}

/**
 * 根据传入的年份、学段获取年级
 * 默认按传入年份的九月开始算有效学期
 */
 public Long getGradeIdBySectionAndYear(Long sectionId, Integer enrollmentYear) {
	
		// 1.查询入学年份与当前年份的间隔年数
        // 获取当前年份、月份,不可传入今年之后的年份
        int nowYear = Calendar.getInstance().get(Calendar.YEAR);
        int yearNum = nowYear - enrollmentYear.intValue();	// 同年则为0

		// 判断入学年份是否正确,根据学段查询有效的年级范围
		QueryWrapper<StudySection> querySec = new QueryWrapper<>();
		querySec.lambda().eq(StudySection::getSectionId, sectionId);
		StudySection studeySection = studySectionMapper.selectOne(querySec);
		Integer gradeNum = studeySection.getGradeNum();
        if(yearNum < 0 || yearNum > gradeNum-1){
            throw new ServiceException("入学年份不正确!");
        }

		// 根据学段查询年级id数组
		querySec.lambda().orderByAsc(StudyGrade::getSort);
        List<StudyGrade> gradeList = studyGradeMapper.selectList(querySec)
		if (CollectionUtils.isEmpty(gradeList)) {
			throw new ServiceException("该学段下暂无年级信息!");
		}
		
        if(yearNum >= gradeList.size()-1){
            throw new ServiceException("该学生已经毕业!");
        }
        return gradeList.get(yearNum);
 }
2.自动升年级定时器

思路:计算出班级当前年级的下一级,并批量替换。毕业年级排序为-1

(1) 待升级班级对象

// 待升级班级对象
public class UpClassInfo {

	private Long classId;		//班级id
	private Long gradeId;		//年级id
	private Integer gradeNumber;	//班级当前年级排序 -1代表已毕业
	private Long sectionId;		// 学段id
	private Integer gradeNum;		// 学段的有效年级数
	
}

(2)定时任务代码

public void upClassLevel() {

	List<StudyClass> updateClassList = new ArrayList<>();
	
	// 1. 查询当前有效的班级列表(含当前年级排序、当前年级学段有效年数)
	List<UpClassInfo> upClassList = {查询sql...};
	if (CollectionUtils.isNotEmpty(upClassList)) {

		// 2.查询各学段年级的学段、年级排序以及年级id对应Map
		Map<String, Long> sectionGradeMap = new HashMap<>();
		// 偷懒复用一下对象
		List<UpClassInfo> sectionGradeList = {查询sql...};
		if (CollectionUtils.isNotEmpty(sectionGradeList)) {
			sectionGradeMap  = sectionGradeList.stream().collect(Collectors.toMap(sg -> sg.getSectionId() + "_" + sg.getGradeNumber, UpClassInfo::getGradeId, (sg1, sg2) -> sg1));
		}
		
		for (UpClassInfo upClass : upClassList) {
			Integer nextGradeNumber = upClass.getGradeNumber();
			if (upClass.getGradeNumber() + 1 > upClass.getGradeNum) {
				// 如果班级当前的年级排序已超过学段年级数范围,则判断为毕业(排序为-1)
				nextGradeNumber = -1;
			} else {
				// 否则正常取下一级年级
				nextGradeNumber = nextGradeNumber + 1;
			}
			
			StudyClass updateClass = new StudyClass();
			updateClass.setClassId(upClass.getClassId());
			updateClass.setGradeId(sectionGradeMap.get(upClass.getSectionId() + "_" + -1));

			// 加入待更新班级列表
			updateClassList.add(updateClass);

			// 记录班级年级变更日志
			...
		}

		if (CollectionUtils.isNotEmpty(upateClassList)) {
			// 批量更新
			studyClass.updateBatch(upateClassList);
		}
	}
}

三、问题拓展

如果是含多个学段的学校应该如何处理?

基础教育学校包含:小学、初中、高中三个学段。部分学校含有多个学段。
查询学校关联的学段范围,如果有小学、初中、高中任意相邻学段(怎么样算相邻学段?),则不处理毕业?而是继续升学至下一学段的年级,并修改入学年份。
相邻学段:学段的排序相邻

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值