Student Grade Manager: 学生成绩管理系统 —— Java课程设计项目

项目地址 GitHub:

FrankOu2001/grade_manager: Java课程设计作业 (github.com)

博客地址 Blog:

Student Grade Manager: 学生成绩管理系统 - Frank_Ou - 博客园 (cnblogs.com)

作者 Authors:

  • 计科20-3 王俊越
  • 计科20-2 李振宇

功能要求 Requirement of functions:

  1. 添加学生功能:姓名、学号、性别、出生年月日。(注意:学号自动生成,学号必须唯一)

  2. 添加学生成绩功能:假设每个人都选修了数学、Java与体育。但输入成绩的时候,一般是给所有学生输入某一门课程的成绩。

  3. 根据学生学号查找学生成绩,并在界面上显示姓名、学号和成绩,学号不存在的给出提示信息

  4. 根据学生姓名(支持模糊匹配)查找学生成绩,并在界面上显示姓名、学号和成绩,如果有多个相同姓名学生存在,一起显示出来,姓名不存在的给出提示信息

  5. 生成学生学习情况报表:报表包含学号、姓名、各科目成绩及对应的该科目班级平均值,总成绩以及班级总成绩平均值。最后以总成绩平均值降序在图形界面输出,并可将该排序结果按照输出至"成绩表.txt"文件或者excel文件(输出到Excel文件为特别加分项,可以使用POI技术)。

  6. 支持分别对所有学生各科成绩画出柱状分布图(可选)。

  7. 支持对学生信息的修改与删除(要在文件或数据库中有所体现),不能修改学号。

  8. 测试:支持随机生成10万个学生及其姓名、学号、成绩放入文本文件,以进行测试。(学号不能相同,每颗的成绩以80分为中心成正态分本)(重要加分项)

  9. 支持用户登录、验证操作

界面:GUI

运行环境 Runtime Environment:

OpenJDK11 + MySQL8.0.25 + Windows10

第三方库 Library

  • JFreeChart:JFreeChart is a free 100% Java chart library that makes it easy for developers to display professional quality charts in their applications.
  • Apache POI - the Java API for Microsoft Documents:The Apache POI Project's mission is to create and maintain Java APIs for manipulating various file formats based upon the Office Open XML standards (OOXML) and Microsoft's OLE 2 Compound Document format (OLE2).

应用对象场景 Who to use

本软件面向仅限教师才能对成绩信息进行管理的应用场景,例如小学和中学这类教学场景

部署方法 How to use

  • MySQL建表:

    • src/util/sql目录下的createDB.sql存储了数据库建立信息,执行脚本即可完成数据库的设置
    • src/util/sql目录下的BaseDB.java包含了链接的信息,您可根据本地的配置来做出相应的更改
  • 对于Java部分: 你可以通过Ant部署或通过IntelliJ IDEA来构建

  • 对于Cpp部分: 编译所需的文件都在src/lib文件夹中,本项目自带构建好的程序,在Clang/LLVMWindows10 amd64环境下构建

项目功能架 Function Architectural Patterns

graph LR; Root[学生成绩管理]; Manager[学生信息管理]; Analyzer[学生成绩分析]; Generator[测试数据生成]; Login&Register[用户注册登录]; Root-->Login&Register;Root-->Manager; Root-->Analyzer; Root-->Generator; Manage1[管理功能]; Manage12["能对学生的(信息除学号外)和各科成绩进行录入和修改"]; ManageF1[自动计算总分且支持1000次内的操作撤销]; Manage2["查找功能"]; Manage21["支持指定班级范围查找"]; Manage22["支持姓名的模糊查找,并给予查找结果提示,可显示多个结果"]; Manage23["支持学号的精确查找,并给予查找结果提示"]; Manage24["依照学号升序输出查找内容"]; Manage3["导出功能"]; Manage31["支持学生成绩和信息的Excel导出,方便进行备份"]; Manage32["可指定全校范围(班级自动分表)和指定班级信息的导出"]; Manager-->Manage1;Manager-->Manage2;Manager-->Manage3; Manage1-->Manage12;Manage1-->ManageF1; Manage2-->Manage21;Manage2-->Manage23;Manage2-->Manage22;Manage21-.-Manage24;Manage22-.-Manage24;Manage23-.-Manage24; Manage3-->Manage31;Manage3-->Manage32; AnalyzeChart["数据可视化"]; AnalyzeChart1["根据个人成绩,绘制各科成绩占总成绩的饼状图"]; AnalyzeChart2["各科成绩和总成绩与班级平均成绩和全校总成绩对比,绘制柱状图"]; AnalyzeFind["信息查找"]; AnalyzeFind1["默认输出各科成绩和总成绩,以及对应科目的班级平均分和全校平均分"]; AnalyzeFind2["可指定班级和学号或姓名查找"]; AnalyzeFind3["默认按照班级平均分降序输出所有学生信息"]; AnalyzeExport["信息导出"]; AnalyzeExport1["支持学生成绩和信息的Excel导出"]; AnalyzeExport2["可指定导出的信息"]; AnalyzeExport3["可指定多种导出顺序"]; AnalyzeExport4["可全校(班级自动分表)和指定班级的导出"]; Analyzer-->AnalyzeChart;Analyzer-->AnalyzeFind;Analyzer-->AnalyzeExport; AnalyzeChart-->AnalyzeChart1;AnalyzeChart-->AnalyzeChart2; AnalyzeFind-->AnalyzeFind1;AnalyzeFind-->AnalyzeFind2;AnalyzeFind-->AnalyzeFind3; AnalyzeExport-->AnalyzeExport1;AnalyzeExport-->AnalyzeExport2;AnalyzeExport-->AnalyzeExport3;AnalyzeExport-->AnalyzeExport4; Register["用户注册"]; LRF1["具有容错性"] LRF11["判断用户是否存在"]; LRF12["判断两次密码是否相等"]; LRF13["判断用户名和密码是否为空"]; LRF14["匹配后返回登录结果"]; Login1["用户名密码得到MD5,再AES加密存储"] Register1["解密AES后,判断MD5密文,避免产生明文"]; Login["用户登录"]; Login&Register-->Register; Login&Register-->Login; Register-->Register1; Login-->Login1; Register1-.-LRF1;Login1-.-LRF1; LRF1-->LRF11;LRF1-->LRF12;LRF1-->LRF13;LRF1-->LRF14; Generator1["高效率的随机数据生成"]; Generator2["支持200到一百万数量级"]; Generator3["成绩符合正态分布"]; Generator4["支持学生信息的随机产生"]; Generator-->Generator1;Generator-->Generator2;Generator-->Generator3;Generator-->Generator4;

UML

UML

程序运行截图 Screenshot

登录界面 LoginWindow

image-20210623093827428

注册界面 RegisterWindow

image-20210623093916305

主界面 MainWindow

image-20210623094127385

主界面关闭提示 Tips when closing the MainWindow

image-20210623094344516

信息成绩管理 GrandeManager

image-20210623094406354

信息成绩管理—编辑学生信息

image-20210623094430749

信息成绩管理—导出窗口

image-20210623094500175

综合成绩分析 GrandeAnalyzer

image-20210623094702792

综合成绩分析—个人成绩比例

image-20210623094738636

综合成绩分析—个人成绩分析

image-20210623094806644

综合成绩分析—信息导出窗口

image-20210623094900733

image-20210623094922155

综合成绩分析—导出的Excel Export Data into Excel

image-20210623095001528

测试数据生成 Generate the Random Data

image-20210623100203838

关键部分代码 Code Preview

数据库DAO(BaseDB.java)

/**
 * @author 王俊越
 */
public interface BaseDB {
    DBTools DB = DBTools.getDBTools();

    /**
     * @throws SQLException
     */
    void closeAll() throws SQLException;
}

随机数据生成(Generator.cpp)

#include "header.h"

int class_number, target_number;

int main(int argc, char * argv[]) {
    double x, y;
    
    stringstream stream;
    stream << argv[1];
    stream >> target_number;
    
    random_device r1{}, r2{}, r3{};
    mt19937 g1{r1()}, g2{r2()}, g3{r3()};
    
    
    switch(target_number) {
        case 200: {
            x = 70, y = 6;
        } break;
        case 500: {
            x = 70, y = 7;
        } break;
        case 2000: {
            x = 70, y = 15;
        } break;
        case 5000: {
            x = 68, y = 17;
        } break;
        case 20000: {
            x = 50, y = 25.67;
        } break;
        case 50000: {
            x = 55, y = 27;
        } break;
        case 200000: {
            x = 52, y = 27.3;
        } break;
        case 500000: {
            x = 48, y = 28;
        } break;
        default: 
            x = 44, y = 28.6;
    }
    class_number = target_number / 50;
   
    normal_distribution<> d{x, y};
            
    for (int i = 0; i < target_number; ) {
        int a = round(d(g1)), b = round(d(g2)), c = round(d(g3));
		
        if(a >= 0 &&  b >= 0 && c >= 0 && a <= 100 && b <= 100 && c <= 100) {
            i++;
            const char * class_name = get_class_name();
            printf("INSERT INTO `---` (name, sexual, birthday, classid, math, java, pe, sumscore) ");
            printf("value('%s', '%s', '%s', '%s', %d, %d, %d, %d)
", 
				get_name(), get_sex(), get_data(), class_name, a, b, c, a + b + c);
        }
    }
    
    
    return 0;
}

inline const char* get_sex() {
	random_device r{};
	mt19937 g{r()};
	uniform_real_distribution<> dis(0, SEX_SIZE);
	unsigned int t = dis(g);
	
	return Sex[t];
}

inline const char* get_name() {
	random_device r{};
	mt19937 g{r()};
	uniform_real_distribution<> dis(0, NAME_SIZE);
	unsigned int t = dis(g);
	
	return Name[t];
}

inline const char* get_data() {
	random_device r{};
	mt19937 g{r()};
	uniform_real_distribution<> dis(0, DATA_SIZE);
	unsigned int t = dis(g);
	
	return Data[t];
}

inline const char* get_class_name() {
	random_device r{};
	mt19937 g{r()};
	uniform_real_distribution<> dis(0, class_number);
	int t = dis(g);
	t = (t % class_number + class_number) % class_number;
	
	return Class_name[t];
}

阿里巴巴代码规范检查 Code Check

image-20210623103025287

说明:JFreeChart中的3D图形方法都标记为弃用,因为该项目的作者又写了专门绘制3D图形的项目(收费),所以把该包里的3D图形绘制的方法给弃用了

项目总结、反思、计划

  • 总结:
  1. 使用的时候写了学习了很多Java Swing的组件和知识,同时也巩固了自己的所学
  2. 学习了MySQL数据库的使用,深入理解SQL命令的组合使用和面对不同应用场景下的选择
  3. 对于面向对象有了更深的理解,体会到了面向对象这一哲学的优势和魅力
  4. 巩固了以前所学的git知识
  5. 实现了模块化的设计,对于一些设计模式也有更深的理解和认识
  6. 采用了多线程的方式,提高了程序的响应速度
  • 反思:
  1. 缺少前端知识的学习,Java Swing不是很好的前端选择
  2. 项目初期所编写的文件内容体系较乱,耦合度太高,需要重建项目解耦
  3. SQL命令的高级用法不太熟练
  4. 编写时没采用阿里巴巴的代码规范,用了自己习惯的LLVM的代码规范
  5. POI面对大数据的导出速度太慢,需要优化或耿冠当初方式
  6. 不太熟悉JNI技术,放弃了用Java调用C++程序的方案
  • 计划:
  1. 准备学习JavaScriptJavaFX和其他前端技术
  2. 重构项目,重新设计
  3. 将C++部分用JNI包装
  4. 添加日志文件

感谢 Thanks:

  1. 感谢我的队友振宇,qwq
  2. 感谢我的老朋友longjunyu2 (MC-Long) ,对我的项目进行了测试和修复了一些Bug
  3. 感谢我的女朋友zzh对我一直的陪伴和支持
原文地址:https://www.cnblogs.com/FrankOu/p/14921870.html