飞算Java在线学生成绩综合统计分析系统的设计与实现

发布于:2025-09-05 ⋅ 阅读:(19) ⋅ 点赞:(0)

在这里插入图片描述

引言

在教育信息化深度推进的背景下,学校对成绩数据的管理需求已从 “简单存储” 转向 “智能分析”—— 传统手工统计不仅耗时耗力,更无法快速挖掘成绩背后的教学问题(如班级薄弱学科、学生成绩波动趋势)。本次设计与实现的在线学生成绩综合统计分析系统,基于飞算 JavaAI 平台搭建,旨在解决成绩管理效率低、分析维度单一的痛点,为管理员、教师、学生三类角色提供差异化的数据服务,既保障成绩数据的安全管理,又能通过可视化看板输出教学决策依据,贴合现代化教学的实际业务场景。

技术栈

  • 后端:采用Spring Boot 3.x框架,简化项目配置与依赖管理,快速实现RESTful接口;结合MyBatis-Plus增强工具,减少数据库操作代码冗余,支持复杂查询与批量处理。
  • 数据库:使用MySQL 8.0,存储学生信息、成绩数据、课程信息等核心数据,其支持的复合索引与事务特性,能满足10万+条成绩记录的高效存储与安全读写。
  • 前端可视化:集成ECharts图表库与Vue.js框架,实现班级成绩分布直方图、个人成绩趋势折线图等可视化看板,提升数据可读性;采用Element UI组件库构建页面,保证交互体验一致性。
  • 开发工具:依赖IntelliJ IDEA 2024.3.2作为开发环境,搭配飞算JavaAI插件实现“自然语言转代码”,大幅缩短开发周期。

在这里插入图片描述

一.需求分析与规划

功能需求

系统需覆盖三类角色的核心业务场景,具体功能如下:

  • 管理员:成绩Excel批量导入(支持5000条/次)、课程信息增删改查、用户角色权限配置、全校成绩统计报表导出(PDF/Excel格式)。
  • 教师:单条成绩录入与修改、所带班级成绩分布分析(按分数段统计)、学生成绩波动预警(分数下降超20分自动提示)、学科平均分排名查询。
  • 学生:个人成绩明细查询、单科年级排名查看、学期成绩趋势图展示、薄弱学科(低于班级平均分10分)标注。

核心模块

按“高内聚、低耦合”原则,将系统划分为三大核心模块,模块间通过接口交互,便于后续扩展:

  1. 用户权限模块:管理用户注册、登录、角色分配,基于RBAC模型控制数据访问权限。
  2. 成绩管理模块:负责成绩的录入、导入、修改与存储,核心是保证成绩数据的准确性与安全性。
  3. 统计分析模块:实现成绩的多维度分析(班级、个人、分数段),输出可视化结果与统计报表。

技术选型

综合考虑开发效率、系统性能与教育场景适配性,技术栈选择逻辑如下:

  • 后端框架:Spring Boot 3.x(轻量化、社区支持丰富)+ MyBatis-Plus(简化SQL操作,支持批量插入)。
  • 数据库:MySQL 8.0(开源免费、支持大规模数据存储,兼容教育行业预算需求)。
  • 可视化:ECharts(开源图表库,支持多类型图表,适配成绩分析场景)。
  • 开发工具:飞算JavaAI(通过自然语言生成代码,降低重复编码工作量)。

从该图可清晰看到系统四大模块的功能拆解与技术支撑关系,为后续开发明确了执行路径。
在这里插入图片描述

二.环境准备

1. 下载IntelliJ IDEA

选择IntelliJ IDEA作为开发环境,其对Java项目的兼容性与插件生态更适配飞算JavaAI工具:

  1. 进入IntelliJ IDEA官网,根据操作系统选择“Windows 64-bit”版本(本文以Windows为例)。
    在这里插入图片描述
  2. 点击“Download”下载安装包,等待约5-10分钟(视网络速度而定)。

2. 安装IntelliJ IDEA

按照安装向导逐步操作,重点配置如下:

  1. 选择安装路径(建议非C盘,如D:\Program Files\JetBrains\IntelliJ IDEA 2024.3.2)。
  2. 勾选“Create Desktop Shortcut”(创建桌面快捷方式)与“Add launchers dir to PATH”(添加环境变量)。
  3. 点击“Install”开始安装,完成后勾选“Run IntelliJ IDEA”启动软件。
    启动后界面如下,选择“New Project”进入项目创建流程:
    在这里插入图片描述

3. 安装飞算JavaAI插件

飞算JavaAI插件是实现“自然语言转代码”的核心工具,安装步骤如下:

  1. 打开IDEA,点击顶部菜单栏“File → Settings → Plugins”,进入插件市场。
    在这里插入图片描述
  2. 在搜索框输入“飞算”,找到“Feisuan JavaAI”插件,点击“Install”下载(需等待1-2分钟)。
    在这里插入图片描述
  3. 下载完成后,点击“Restart IDE”重启IDEA,插件生效。重启后左侧工具栏会出现“飞算JavaAI”图标,即为安装成功:
    在这里插入图片描述

4. 登录飞算JavaAI

需登录飞算账号绑定项目,才能使用代码生成功能:

  1. 点击左侧“飞算JavaAI”图标,打开插件面板,点击“登录”按钮。
    在这里插入图片描述
  2. 在弹出的登录窗口中,输入飞算开发者中心账号(无账号需先到飞算官网注册),点击“登录”。
  3. 登录成功后,插件面板会显示“已绑定项目”,选择本次开发的项目(项目ID:EDU-2025-09),完成环境对接:
    在这里插入图片描述

三.模块设计与编码

1. 飞算JavaAI生成基础模块

通过飞算插件输入自然语言需求,自动生成项目骨架与核心代码,步骤如下:

  1. 在飞算插件面板的“需求编辑器”中,输入以下指令:
    “生成在线学生成绩综合统计分析系统基础模块,包含:学生实体(学号、姓名、班级、入学年份)、成绩实体(成绩ID、关联学号、课程编码、分数、考试时间、考试类型)、课程实体(课程编码、课程名称、学分);实现用户登录/注册、成绩录入/导入、班级平均分统计、个人排名查询功能;技术栈:Spring Boot 3.x + MyBatis-Plus + MySQL 8.0。”
  2. 点击“提交需求”,按照指引一步步进行;
  3. 最后生成的项目结构如下,核心包与类已自动创建:
    在这里插入图片描述

2. 核心代码展示

entity包下实体类示例

Student.java(学生实体)
package com.feisuan.edu.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDate;

/**
 * <p>
 * 学生实体类:映射student表
 * </p>
 * @author feisuan-javaai
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("student") // 关联数据库表名
public class Student {

    /**
     * 学号:主键,自增
     */
    @TableId(type = IdType.AUTO)
    private Long studentNo;

    /**
     * 学生姓名:非空
     */
    private String studentName;

    /**
     * 班级ID:格式如2024-01(2024级1班)
     */
    private String classId;

    /**
     * 入学年份:如2024
     */
    private Integer enrollmentYear;

    /**
     * 创建时间:自动填充
     */
    private LocalDate createTime;
}
Score.java(成绩实体)
package com.feisuan.edu.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.time.LocalDate;

/**
 * <p>
 * 成绩实体类:映射score表
 * </p>
 * @author feisuan-javaai
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("score")
public class Score {

    /**
     * 成绩ID:主键,自增
     */
    @TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 关联学号:外键,关联student表的studentNo
     */
    private Long studentNo;

    /**
     * 课程编码:关联course表的courseCode
     */
    private String courseCode;

    /**
     * 分数:保留2位小数,范围0-100
     */
    private BigDecimal score;

    /**
     * 考试时间:如2024-06-20
     */
    private LocalDate examDate;

    /**
     * 考试类型:期中/期末/月考
     */
    private String examType;
}

dto包下数据传输对象示例

ScoreAddDTO.java(成绩录入请求DTO)
package com.feisuan.edu.dto;

import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;

import java.math.BigDecimal;
import java.time.LocalDate;

/**
 * <p>
 * 成绩录入请求DTO:接收前端传入的成绩数据,含参数校验
 * </p>
 * @author feisuan-javaai
 */
@Data
public class ScoreAddDTO {

    /**
     * 关联学号:必填
     */
    @NotNull(message = "学号不能为空")
    private Long studentNo;

    /**
     * 课程编码:必填
     */
    @NotBlank(message = "课程编码不能为空")
    private String courseCode;

    /**
     * 分数:必填,0-100分
     */
    @NotNull(message = "分数不能为空")
    @DecimalMin(value = "0.00", message = "分数不能低于0分")
    @DecimalMax(value = "100.00", message = "分数不能高于100分")
    private BigDecimal score;

    /**
     * 考试时间:必填
     */
    @NotNull(message = "考试时间不能为空")
    private LocalDate examDate;

    /**
     * 考试类型:必填,只能是期中/期末/月考
     */
    @NotBlank(message = "考试类型不能为空")
    private String examType;
}
StudentRankQueryDTO.java(个人排名查询DTO)
package com.feisuan.edu.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;

/**
 * <p>
 * 个人排名查询DTO:接收前端查询参数
 * </p>
 * @author feisuan-javaai
 */
@Data
public class StudentRankQueryDTO {

    /**
     * 学号:必填
     */
    @NotNull(message = "学号不能为空")
    private Long studentNo;

    /**
     * 课程编码:必填
     */
    @NotBlank(message = "课程编码不能为空")
    private String courseCode;

    /**
     * 学期:必填,格式如2024-2025-1
     */
    @NotBlank(message = "学期不能为空")
    private String term;
}

vo包下视图对象示例

StudentRankVO.java(个人排名返回VO)
package com.feisuan.edu.vo;

import lombok.Data;

import java.math.BigDecimal;

/**
 * <p>
 * 个人排名返回VO:封装前端需要的排名数据,隐藏数据库字段细节
 * </p>
 * @author feisuan-javaai
 */
@Data
public class StudentRankVO {

    /**
     * 学号
     */
    private Long studentNo;

    /**
     * 学生姓名
     */
    private String studentName;

    /**
     * 课程名称
     */
    private String courseName;

    /**
     * 分数
     */
    private BigDecimal score;

    /**
     * 年级排名
     */
    private Integer rank;

    /**
     * 年级总人数
     */
    private Integer gradeTotal;

    /**
     * 排名百分比:如30.50%
     */
    private String rankPercentage;
}

mapper包下数据访问接口示例

ScoreMapper.java
package com.feisuan.edu.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.feisuan.edu.entity.Score;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

import java.util.List;

/**
 * <p>
 * 成绩Mapper接口:继承MyBatis-Plus的BaseMapper,自带CRUD方法
 * </p>
 * @author feisuan-javaai
 */
@Mapper
public interface ScoreMapper extends BaseMapper<Score> {

    /**
     * 自定义查询:按班级、课程、学期查询成绩列表
     */
    @Select("SELECT * FROM score s JOIN student st ON s.student_no = st.student_no " +
            "WHERE st.class_id = #{classId} AND s.course_code = #{courseCode} AND s.term = #{term}")
    List<Score> selectByClassAndCourse(String classId, String courseCode, String term);

    /**
     * 自定义查询:统计年级内某课程分数高于目标分数的人数
     */
    @Select("SELECT COUNT(*) FROM score WHERE course_code = #{courseCode} AND term = #{term} AND score > #{targetScore}")
    Long countHigherScore(String courseCode, String term, BigDecimal targetScore);
}

service包下接口及实现类示例

ScoreService.java(成绩服务接口)
package com.feisuan.edu.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.feisuan.edu.dto.ScoreAddDTO;
import com.feisuan.edu.dto.StudentRankQueryDTO;
import com.feisuan.edu.entity.Score;
import com.feisuan.edu.vo.ScoreDistributionVO;
import com.feisuan.edu.vo.StudentRankVO;

/**
 * <p>
 * 成绩服务接口:定义成绩相关业务逻辑
 * </p>
 * @author feisuan-javaai
 */
public interface ScoreService extends IService<Score> {

    /**
     * 录入成绩
     * @param scoreAddDTO 成绩录入参数
     * @return 录入成功的成绩实体
     */
    Score addScore(ScoreAddDTO scoreAddDTO);

    /**
     * 查询个人年级排名
     * @param queryDTO 排名查询参数
     * @return 个人排名信息VO
     */
    StudentRankVO getStudentGradeRank(StudentRankQueryDTO queryDTO);

    /**
     * 统计班级成绩分布(按分数段)
     * @param classId 班级ID
     * @param courseCode 课程编码
     * @param term 学期
     * @return 成绩分布VO
     */
    ScoreDistributionVO getClassScoreDistribution(String classId, String courseCode, String term);
}
ScoreServiceImpl.java(成绩服务实现类)
package com.feisuan.edu.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.feisuan.edu.dto.ScoreAddDTO;
import com.feisuan.edu.dto.StudentRankQueryDTO;
import com.feisuan.edu.entity.Course;
import com.feisuan.edu.entity.Score;
import com.feisuan.edu.entity.Student;
import com.feisuan.edu.mapper.CourseMapper;
import com.feisuan.edu.mapper.ScoreMapper;
import com.feisuan.edu.mapper.StudentMapper;
import com.feisuan.edu.service.ScoreService;
import com.feisuan.edu.vo.ScoreDistributionVO;
import com.feisuan.edu.vo.StudentRankVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 成绩服务实现类:实现成绩相关业务逻辑
 * </p>
 * @author feisuan-javaai
 */
@Slf4j
@Service
@RequiredArgsConstructor // 构造器注入,替代@Autowired
public class ScoreServiceImpl extends ServiceImpl<ScoreMapper, Score> implements ScoreService {

    private final ScoreMapper scoreMapper;
    private final StudentMapper studentMapper;
    private final CourseMapper courseMapper;

    @Override
    @Transactional // 事务控制:确保成绩录入失败时回滚
    public Score addScore(ScoreAddDTO scoreAddDTO) {
        log.info("开始录入成绩:学号={}, 课程编码={}", scoreAddDTO.getStudentNo(), scoreAddDTO.getCourseCode());

        // 1. 校验学生与课程是否存在
        Student student = studentMapper.selectById(scoreAddDTO.getStudentNo());
        Course course = courseMapper.selectById(scoreAddDTO.getCourseCode());
        if (student == null) {
            throw new RuntimeException("学号不存在:" + scoreAddDTO.getStudentNo());
        }
        if (course == null) {
            throw new RuntimeException("课程编码不存在:" + scoreAddDTO.getCourseCode());
        }

        // 2. 转换DTO为实体
        Score score = new Score();
        BeanUtils.copyProperties(scoreAddDTO, score);
        // 补充学期(从考试时间推导,如2024-06属于2023-2024-2学期)
        String term = getTermByExamDate(scoreAddDTO.getExamDate());
        score.setTerm(term);

        // 3. 保存成绩
        save(score);
        log.info("成绩录入成功:成绩ID={}", score.getId());
        return score;
    }

    @Override
    public StudentRankVO getStudentGradeRank(StudentRankQueryDTO queryDTO) {
        log.info("查询个人排名:学号={}, 课程编码={}, 学期={}", 
                 queryDTO.getStudentNo(), queryDTO.getCourseCode(), queryDTO.getTerm());

        // 1. 查询学生、课程与成绩信息
        Student student = studentMapper.selectById(queryDTO.getStudentNo());
        Course course = courseMapper.selectById(queryDTO.getCourseCode());
        Score score = lambdaQuery()
                .eq(Score::getStudentNo, queryDTO.getStudentNo())
                .eq(Score::getCourseCode, queryDTO.getCourseCode())
                .eq(Score::getTerm, queryDTO.getTerm())
                .one();
        if (score == null) {
            throw new RuntimeException("未查询到该学生的成绩记录");
        }

        // 2. 统计排名(高于当前分数的人数+1)
        Long higherCount = scoreMapper.countHigherScore(
                queryDTO.getCourseCode(), queryDTO.getTerm(), score.getScore()
        );
        Integer rank = higherCount.intValue() + 1;

        // 3. 统计年级总人数
        Integer gradeTotal = lambdaQuery()
                .eq(Score::getCourseCode, queryDTO.getCourseCode())
                .eq(Score::getTerm, queryDTO.getTerm())
                .list()
                .size();

        // 4. 封装VO返回
        StudentRankVO rankVO = new StudentRankVO();
        rankVO.setStudentNo(student.getStudentNo());
        rankVO.setStudentName(student.getStudentName());
        rankVO.setCourseName(course.getCourseName());
        rankVO.setScore(score.getScore());
        rankVO.setRank(rank);
        rankVO.setGradeTotal(gradeTotal);
        // 计算排名百分比(保留2位小数)
        String rankPercentage = String.format("%.2f%%", (double) rank / gradeTotal * 100);
        rankVO.setRankPercentage(rankPercentage);

        return rankVO;
    }

    @Override
    public ScoreDistributionVO getClassScoreDistribution(String classId, String courseCode, String term) {
        // 1. 查询班级成绩列表
        List<Score> scoreList = scoreMapper.selectByClassAndCourse(classId, courseCode, term);

        // 2. 按分数段分组统计
        Map<String, Long> distributionMap = scoreList.stream()
                .collect(Collectors.groupingBy(
                        s -> {
                            double scoreValue = s.getScore().doubleValue();
                            if (scoreValue < 60) return "0-59";
                            else if (scoreValue < 70) return "60-69";
                            else if (scoreValue < 80) return "70-79";
                            else if (scoreValue < 90) return "80-89";
                            else return "90-100";
                        },
                        Collectors.counting()
                ));

        // 3. 封装VO
        ScoreDistributionVO distributionVO = new ScoreDistributionVO();
        distributionVO.setClassId(classId);
        distributionVO.setCourseCode(courseCode);
        distributionVO.setTerm(term);
        distributionVO.setSegment0_59(distributionMap.getOrDefault("0-59", 0L));
        distributionVO.setSegment60_69(distributionMap.getOrDefault("60-69", 0L));
        distributionVO.setSegment70_79(distributionMap.getOrDefault("70-79", 0L));
        distributionVO.setSegment80_89(distributionMap.getOrDefault("80-89", 0L));
        distributionVO.setSegment90_100(distributionMap.getOrDefault("90-100", 0L));

        return distributionVO;
    }

    /**
     * 辅助方法:根据考试时间推导学期
     */
    private String getTermByExamDate(java.time.LocalDate examDate) {
        int year = examDate.getYear();
        int month = examDate.getMonthValue();
        if (month >= 9 && month <= 12) {
            return year + "-" + (year + 1) + "-1"; // 9-12月属于下学年第一学期
        } else {
            return (year - 1) + "-" + year + "-2"; // 1-8月属于本学年第二学期
        }
    }
}

3.网页展示

在这里插入图片描述
登录进去之后,我们可以看到很详细的页面:在这里插入图片描述

四.自我感想

在开发在线学生成绩综合统计分析系统的过程中,我对“教育信息化”的理解从“技术落地”转向了“业务适配”。比如最初仅关注成绩的增删改查,后来发现教师更需要“成绩波动预警”来定位待辅导学生,学生需要“薄弱学科标注”来明确学习方向——这让我意识到,技术开发必须围绕用户实际需求展开。

技术层面,飞算JavaAI平台的“自然语言转代码”功能大幅降低了重复编码工作量,原本需要2天编写的Entity、Mapper层代码,现在20分钟即可生成,让我有更多精力投入到业务逻辑优化(如排名算法、缓存策略)。同时,通过解决“数据重复导入”“可视化加载慢”等问题,我对数据库索引优化、Redis缓存使用的理解也更加深入,不再是单纯“会用”,而是“能用好”。

这次开发也让我明白,一个合格的系统不仅要“功能能用”,更要“体验好用”——比如为成绩录入添加参数校验,避免教师输入错误分数;为统计报表提供多格式导出,方便管理员汇报使用。这些细节虽小,却直接影响用户对系统的认可程度。

总结

本次在线学生成绩综合统计分析系统的设计与实现,完整覆盖了“需求分析→环境搭建→模块开发→问题优化”的全流程,成功构建了支持多角色、多维度分析的成绩管理系统。系统的核心价值在于:通过飞算JavaAI提升开发效率,通过可视化分析挖掘成绩数据价值,通过权限控制保障数据安全,切实解决了传统成绩管理的痛点。

后续,我计划进一步扩展系统功能:一是添加AI成绩预测模块,基于历史数据预测学生期末成绩;二是对接区域教育大数据平台,实现跨学校成绩对比分析。


网站公告

今日签到

点亮在社区的每一天
去签到