基于 SpringBoot + Vue3 学生成绩管理系统

目录

一、绪论

1. 编写目的

2. 项目背景

3. 项目调查

4. 定义

二、需求分析

1. 处理流程

1.1 顶层数据流图

1.2 第一层数据流图

1.3 第二层数据流图

2. 性能需求

3. 运行需求

4. 其他需求

三、概要设计

1. 系统定义

1.2 系统边界

3. 运行环境

4. 子系统模块顺序图

四、详细设计

1. 功能需求

2. 数据字典

3. 概念模型设计

3.1 E-R图

4. 数据库逻辑模型

4.1 外模式设计

5. 数据库物理模型

5.1 数据库物理设计准则

5.2 数据库物理结构分析

5.3 数据库的存储结构

5.4 物理模型设计

五、具体实现

1. 系统结构设计

2. 模块设计

3. 接口设计

4. 页面设计

5. 安全设计

6. 性能设计

7. 测试策略

8. 部署方案

9. 维护和运维

六、测试 

1. 测试方法 

2. 测试用例 

3. 测试结论 

七、系统界面演示

八、代码附录

1. 数据库创建

(1) 创建管理员表admin:

(2)创建课程表course:

(3)创建成绩表grade:

(4)创建学生表student:

(5)创建教师表teacher:

2. 前端

(1)系统主界面Manager.vue

(2)登录界面Login.vue

(3)课程信息管理界面Course.vue

(4)成绩信息管理界面(教师端)Grade.vue

(5)成绩信息管理界面(学生端)Grades.vue

(6)系统首页界面Home.vue

(7)学生个人资料界面Person.vue

(8)学生信息管理界面Student.vue

(9)教师个人资料界面Teacher.vue

(10)路由index.js

(11)请求request.js

(12)main.js

3. 后台

​编辑

(1)跨域配置CorsConfig.java

(2)Result.java

(3)角色枚举RoleEnum.java

(4)CourseController.java

(5)GradeController.java

(6)StudentController.java

(7)TeacherController.java

(8)WebController.java

(10)管理员Admin.java

(11)课程Course.java

(12)成绩Grade.java

(13)学生Student.java

(14)教师Teacher.java

(15)AdminMapper.java

(16)CourseMapper.java

(17)GradeMapper.java

(18)StudentMapper.java

(19)TeacherMapper.java

(20)AdminService.java

(21)CourseService.java

(22)GradeService.java

(23)StudentService.java

(24)TeacherService.java


一、绪论

1. 编写目的

        学生成绩管理系统是一款针对学校、教育机构或在线学习平台,用于管理学生成绩的软件系统。该系统旨在提供一种高效、便捷的方式来存储、查询、编辑和打印学生成绩,从 而减轻教师和管理人员的工作负担,提高工作效率。

2. 项目背景

        随着教育行业的不断发展,学生数量和课程种类的增加,学生成绩管理已成为一项重要且繁琐的工作。传统的学生成绩管理方式,如纸质记录和简单的电子表格,已无法满足现代教育的需求。同时,随着信息化技术的不断进步,教育行业对于数字化管理的需求也日益增长。该系统与高校教务系统属于被包含关系。

3. 项目调查

        学生信息管理工作是各大高校必不可少的管理工作之一,在学校占据重要的地位,它涉及到学生、老师和管理员等多方面。由于各大高校学生人数日益增长,因此研发出一款具有操作灵活且人性化的管理系统成为了迫切需要。从国外看来许多高校一般是由技术强大稳定的队伍来完成该系统程序的设计与研制,或者是本校的某个院系。在西方电子管理系统的概念早已被学生引入,他们可以通过网络浏览学校的管理系统网站,以及学校的学术信息等。可以查看个人信息、考试成绩和课程,这种方式大大地减轻了人力和时间。从国内研究现状来看,国内的起步相对较晚,在信息安全和更新方面尚有欠缺,且建立单独的资料共享性差。随着数字校园理论的逐步应用,各高校不断地开发研制各种办公和教学管理等系统,已经成为了一种全面信息化建设体系。但是由于程序开发者对于这方面缺少感性认识,基本的工作思路还不是很熟悉,以及各工作环节的内在联系也不是很了解,因此系统功能有受到一定的制约。整体信息化也相对落后,在购置硬件设施上经费短缺,配套系统不完善使得系统功能得不到全面应用,留下了障碍和瓶颈。

4. 定义

  • 学生:在册学习的学生。
  • 教师:负责授课的教师。
  • 管理员:负责系统管理和维护的人员。
  • 成绩:学生的学业表现评估。
  • 学号:学生的唯一标识。
  • 课程号:课程的唯一标识。

二、需求分析

1. 处理流程

1.1 顶层数据流图

图 1 顶层数据流图

1.2 第一层数据流图

图 2 第一层数据流图

1.3 第二层数据流图

图 3 细化的学生数据流图

图 4 细化的教师数据流图

图 5 细化的管理员数据流图

2. 性能需求

  • 数据精确度:成绩数据应精确到小数点后一位。
  • 时间特性:系统响应时间应在2秒内。
  • 适应性:系统应适应不同的主流浏览器(chrome,edge)和主流的操作系统。

3. 运行需求

  • 操作方式:支持鼠标和键盘操作。
  • 硬件要求:系统应能在普通配置的计算机上运行。
  • 硬件接口:系统应支持常用的硬件设备接口。
  • 系统软件:应与常见的浏览器和数据库软件兼容。
  • 软件接口:应提供与其他系统的数据接口。
  • 网络环境:系统应支持局域网和广域网环境。
  • 数据传输:应支持数据的安全传输。
  • 系统应具备容错功能,能在出现故障时自动恢复。
  • 当发生硬件或软件故障时,系统应提供故障提示和应急处理方案。

4. 其他需求

  • 可使用性:系统应易于使用,无需专门培训即可上手。
  • 安全性:系统应具备高度的数据安全性和保密性,防止数据泄露和非法访问。
  • 可维护性:系统应易于维护和升级,方便进行功能扩展和缺陷修复。
  • 可移植性:系统应具备良好的可移植性,能够在不同的硬件和软件平台上运行。

三、概要设计

1. 系统定义

系统目标:本学生成绩管理系统旨在满足学校、教育机构或在线学习平台对学生成绩进行高效、便捷、安全管理的需求。

用户身份认证规则:所有用户必须通过系统的身份认证才能访问系统。管理员可设置不同的用户角色和权限,确保系统的安全性。

数据录入规则:教师需按照规定的格式和要求录入学生成绩数据,确保数据的准确性和完整性。同时,教师只能录入自己所教课程号的课程成绩。 

数据查询与导出规则:用户可根据一定条件查询和导出学生成绩数据。查询条件可包括学生姓名、学号、课程等。同时,学生只能查询自己所修课程的成绩。

1.2 系统边界

(1)用户角色与权限

  • 学生:能够查询自己的成绩。
  • 教师:能够录入、查询和修改学生的成绩,并进行成绩分析。
  • 管理员:拥有所有权限,包括对学生、教师和系统的全面管理。

(2)功能范围

  • 学生信息管理:录入、修改、查询和删除学生信息。
  • 课程管理:添加、修改、查询课程信息。
  • 成绩录入与查询:录入、查询学生成绩,支持按学号、姓名、课程等查询。
  • 成绩分析:对学生成绩进行统计和分析,生成成绩报告。
  • 报表生成与导出:根据需要生成成绩报表,并支持导出为Excel等格式。
  • 系统设置与维护:设置系统参数,管理用户权限,进行数据备份和恢复等。

(3)数据范围

  • 学生信息:包括学号、姓名、性别、联系方式等。
  • 课程信息:课程名称、课程代码、学分、教师等。
  • 成绩数据:学生各科目的考试成绩、平时成绩等。

(4)技术实现要求

  • 系统应具备良好的可扩展性和可维护性。
  • 用户界面友好,易于操作。
  • 系统应具备数据备份和恢复功能。
  • 应采取必要的安全措施,保护数据安全。

(5)与其他系统的集成

  • 应提供与其他系统的接口,如学校官网、教务系统等,实现数据交换和信息共享。

3. 运行环境

  • 硬件设备:服务器应具备2.4Ghz以上处理器,1TB的存储设备和备份设备,确保同时为1000人服务。
  • 操作系统:Windows 7及以上版本的Windows系统。
  • 支撑软件:兼容性良好、安全性高的Web浏览器,如Google Chrome,Edge。数据库管理系统:SQL server。
  • 数据环境:采用高性能的存储设备来存储学生信息、成绩数据和其他相关资料。
  • 网络环境:使用稳定,高速的以太网,支持1000人同时在线。

4. 子系统模块顺序图

图 6 学生信息管理模块顺序图

图 7 教师信息管理顺序图

图 8 用户管理顺序图

四、详细设计

1. 功能需求

  • 学生管理:系统应具备添加、编辑、删除和搜索学生信息的功能,包括姓名、学号等基本信息。
  • 成绩录入与查询:教师能够录入和修改所教科目的成绩,并能够按学期、课程、学生等条件查询和导出成绩。
  • 成绩查询:学生可以查询自己的成绩,教师和管理员可以查询所有学生的成绩。
  • 报表生成:根据需要,系统应能生成各类成绩报表,如个人成绩单、课程成绩单等。
  • 权限管理:系统应具备完善的权限管理功能,对不同用户(如管理员、教师、学生)设置不同的访问和操作权限。
  • 数据备份与恢复:为确保数据安全,系统应支持定期数据备份和数据恢复功能。
  • 用户界面:系统界面应友好、直观,便于用户操作。
  • 兼容性与扩展性:系统应具备良好的兼容性,支持多种操作系统和浏览器;同时,应具备可扩展性,以便未来添加新功能或与其他系统集成。

图 9 功能模块图

2. 数据字典

        数据字典在帮助用户理解模型时起到了作用分别是统一数据描述:确保所有人对学生成绩的描述和理解保持一致,还需要保证数据库完整性,老师学生和课程的信息是完整的,同时方便追踪和审计学生成绩的变动,提高数据的安全性和可信度,通过数据字典学生成绩管理系统能够更加高效、准确地处理和管理学生成绩数据,为学生、教师和管理员提供更好的服务,最后还能起到标准统一化数据库的作用。

数据字典如下:

表 1 数据项规格定义-学生

属性

规格描述

类型

学号

学生内部标识,不能为空值

char

姓名

学生外部标识,不能为空值

char

性别

学生外部标识,不能为空值

char

联系方式

学生外部标识,不能为空值

char

学生密码

学生外部标识,不能为空值

char

说明:主码:学号

表 2 数据项规格定义-教师

属性

规格描述

类型

工号

教师内部标识,不能为空值

char

姓名

教师外部标识,不能为空值

char

性别

教师外部标识,不能为空值

char

联系方式

教师外部标识,不能为空值

char

教师密码

教师外部标识,不能为空值

char

说明:主码:工号

表 3 数据项规格定义-成绩

属性

规格描述

类型

学号

学生内部标识,不能为空值

char

课程号

课程内部标识,不能为空值

char

平时成绩

成绩外部标识,不能为空值

Double

期中成绩

成绩外部标识,不能为空值

Double

期末成绩

成绩外部标识,不能为空值

Double

总成绩

成绩外部标识,不能为空值

Double

说明:主码:(学号,课程号)

表 4 数据项规格定义-课程

属性

规格描述

类型

课程号

课程内部标识,不能为空值

char

课程名

课程外部标识,不能为空值

char

学分

课程外部标识,不能为空值

Double

工号

教师内部标识,不能为空值

char

说明:主码:课程号

表 5 数据项规格定义-管理员

属性

规格描述

类型

账号

管理员内部标识,不能为空值

char

密码

管理员外部标识,不能为空值

char

说明:主码:账号

表 6 数据结构

名称

属性

学生

学号、学生姓名、性别、联系方式、学生密码

教师

工号、教师姓名、性别、联系方式、教师密码

课程

课程号、课程名、学分、工号

管理员

账号、密码

成绩

学号、课程号、平时成绩、期中成绩、期末成绩、总成绩

表 7 数据流

名称

描述

输入

输出

成绩数据

学生成绩信息

教师

学生

密码信息

登录密码信息

管理员

成绩管理系统

选课信息

学生选课信息

教务系统

学生成绩数据库

账号数据

登录账号信息

账号管理

账号数据库

账号权限数据

账号的权限信息

管理员

账号权限数据库

学生信息数据

学生的个人信息

学生信息管理

学生信息数据库

修改信息

修改的个人信息

管理员

学生信息数据库

表 8 数据存储

数据存储

说明

提供

获取

学生成绩数据库

存储学生成绩信息

教务系统

学生、教师

学生信息数据库

存储学生个人信息

学生信息管理

管理员

账号数据库

存储账号信息

账号管理

管理员

表 9 数据处理

数据处理

作用

输入

输出

选课信息录入

录入学生选课信息

教务系统

学生成绩数据库

成绩查询

查询学生成绩信息

学生数据库

学生、教师

成绩录入

  录入学生成绩信息

教师

学生成绩数据库

成绩编辑

编辑学生成绩信息

教师

学生成绩数据库

账号管理

管理用户账号信息

管理员

账号数据库

权限管理

管理用户权限信息

管理员

账号数据库

密码重置

重置用户的登录密码

学生、教师、管理员

账号数据库

学生信息管理

管理学生的个人信息

管理员

学生信息数据库

3. 概念模型设计

3.1 E-R图

        E-R图,也称为实体-联系图或实体关系图,是一种用于描述现实世界概念模型的方法。在数据库设计中,E-R图是一种重要的工具,特别是在概念设计阶段。

        在成绩管理系统中,E-R图的作用主要体现在以下几个方面:

        描述概念模型:E-R图提供了一种简洁明了的表示方法,用于描述学生、课程、成绩等实体以及它们之间的关系。通过图形化的方式,E-R图能够清晰地表达出实体和它们之间的联系,有助于设计人员和开发人员更好地理解系统的结构和功能。

        数据完整性:E-R图可以定义实体之间的关联规则和约束条件,确保数据的准确性和一致性。例如,学生和课程之间的关系可能是一对多的关系,这意味着一个学生可以选修多门课程,但一门课程只能被一个学生选修。通过E-R图的约束条件,可以防止数据的异常和冲突,提高数据的质量和可靠性。

        提高开发效率:使用E-R图进行设计,可以快速生成数据库的结构,例如表、视图、存储过程等。通过将设计转化为实际的数据库结构,可以大大提高开发效率,减少开发时间和成本。

        文档化:E-R图可以作为系统的文档和说明,方便开发人员、管理员和维护人员理解和使用系统。通过查看E-R图,可以快速了解系统的结构和功能,以及实体之间的关系和约束条件。

        辅助数据库设计:通过E-R图的设计和优化,可以发现和解决数据冗余、关联问题等常见问题。同时,通过合理地设计实体之间的关系和属性,可以提高系统的性能和效率。

        总的来说,E-R图在成绩管理系统中起到了重要的辅助作用,它有助于更好地理解和管理学生成绩数据,保证数据的准确性和一致性,并提高系统的性能和效率。

E-R图设计:

图 10 E-R图

4. 数据库逻辑模型

此E-R图符合关系转换条件,为更好规划实体数据库,进行E-R图向关系模型的转换,以便参照关系模式建立数据库。

将E-R图转换成关系模型:

  • 学生<U,F>

U= {学号,密码,姓名,性别,联系方式}

F= {学号 姓名 ,学号 密码,学号 性别 ,学号 联系方式}

此为学生实体对应的关系模式。

  • 教师<U,F>

U= {工号,密码,姓名,性别,联系方式}

F= {工号 姓名 ,工号 密码,工号 性别 ,工号 联系方式}

此为教师实体对应的关系模式。

  • 成绩<U,F>

U= {学号,课程号,平时成绩,期中成绩,期末成绩,总成绩}

F= {学号 课程号,学号 平时成绩 ,学号 期中成绩,学号 期末成绩,学号 总成绩}

此为成绩实体对应的关系模式。

  • 课程<U,F>

U= {课程号,课程名,学分,教师工号}

F= {课程号 课程名,课程号 课程名,课程号 教师工号}

此为课程实体对应的关系模式。

  • 管理员<U,F>

U= {账号,密码}

F= {账号 密码 }

此为管理员实体对应的关系模式。

        在数据库设计中,范式是用来评估和优化数据库表结构的一种标准,在这里,下面是分析本数据库关系模型的范式情况:

1.每个列都是原子的,不可再分,且没有重复的列,属于第一范式(1NF)。

2.没有部分依赖,主键完全决定其他非主键列。属于第二范式(2NF)

3.没有传递依赖,所有非主键列都直接依赖于主键。属于第三范式(3NF)

综上所述,该数据库关系模型基本上符合第一、第二、第三范式的要求,数据表的冗余少,数据的一致性和完整性较高。

4.1 外模式设计

        外模式是关系数据库中的一个概念,它是用户或应用程序能够直接看到和访问的数据表的子集。外模式定义了特定用户或应用程序的数据视图,隐藏了底层的数据存储细节,使得用户只能访问他们所需的数据,而无需了解整个数据库的结构。

下面是每个关系模型的外模式设计的文字描述

(1)学生外模式:

CREATE VIEW student_view AS

SELECT 学号, 姓名,性别,联系方式

FROM 学生;

(2)教师外模式:

CREATE VIEW teacher_view AS

SELECT 工号,姓名,性别,联系方式

FROM 教师;

(3)成绩外模式:

CREATE VIEW score_view AS

SELECT 学号,课程号,平时成绩,期中成绩,期末成绩,总成绩

FROM 成绩;

(4)课程外模式:

CREATE VIEW lesson_view AS

SELECT 课程号,课程名,学分

FROM 课程;

(5)管理员外模式:

CREATE VIEW admin_view AS

SELECT 账号

FROM 管理员;

5. 数据库物理模型

        学生成绩管理系统的物理模型的作用主要是指导系统的设计和实施,定义数据的存储结构,提高系统性能和效率,以及提供系统的扩展和维护指南。通过物理模型,可以建立一个高效、可靠和易于管理的成绩管理系统。

5.1 数据库物理设计准则

        数据库物理设计阶段的任务是根据具体计算机系统(dbms和硬件等)的特点,为给定的逻辑数据模型确定合理的存储结构和存取方法。所谓的“合理”主要有两个含义:一个是要使设计出的物理数据库占用比较少的存储空间,另一个对数据库的操作具有尽可能高的速度。

5.2 数据库物理结构分析

        数据库的物理结构主要指存储结构和存取方法,存储结构主要指确定数据的存放位置和存储结构,包括关系、索引、日志、备份等的存储安排及存储结构,以及确定系统参数的配置。设计优化的物理数据库结构,使得在数据库上运行的各种事物响应时间小,存储空间利用率高,事物吞吐率大,为此:

        对运行的事物进行详细分析。

(1)查询事务

查询用户信息。查询条件是帐号密码,输入账号密码,查询个人的所有属性。

查询成绩。学生端查询条件是学号课程号,输入学号课程号,查询本人的所选课成绩。教师端查询条件是工号课程号,输入工号课程号,查询本人所教课程的学生成绩。

(2)更新事务

个人信息修改。用户输入账号密码,更新个人信息。

成绩录入。教师登录后,根据工号课程号更新所教课程的学生成绩。

5.3 数据库的存储结构

数据的存放位置

将日志文件和数据库对象(表、索引等)分别放在不同的磁盘,可以改进系统性能,提高系统安全性。所以,系统应将日志文件和数据文件存放在不同磁盘上,将数据库对象放在E:/roll中,日志文件放在D:/roll-log中。

5.4 物理模型设计

表 10 学生表(student)设计

数据项名

数据项代码

类型

长度

说明

Id

Id

Char

255

自增 主码

学号

Username

char

255

可空

姓名

name

char

255

可空

性别

sex

char

255

可空

联系方式

phone

char

255

可空

密码

password

char

255

可空

角色

Role

Char

255

可空

表 11 教师表(teacher)设计

数据项名

数据项代码

类型

长度

说明

Id

Id

Char

255

自增 主码

工号

Tno

char

255

可空

姓名

name

char

255

可空

性别

sex

char

255

可空

联系方式

phone

char

255

可空

密码

password

char

255

可空

角色

Role

Char

255

可空

表 12 管理员表(admin)设计

数据项名

数据项代码

类型

长度

说明

Id

Id

Char

255

自增 主码

工号

Ano

Char

255

主码

密码

password

char

255

可空

名称

name

char

255

可空

角色

role

Char

255

可空

表 13 课程表(course)设计

数据项名

数据项代码

类型

长度

说明

Id

Id

Char

255

自增 主码

课程编号

No

char

255

可空

任课教师工号

Tno

char

255

外码,非空

课程名

name

char

255

可空

学分

credit

double

255

可空

14 成绩表(grade)设计

数据项名

数据项代码

类型

长度

说明

Id

Id

Char

255

自增 主码

学号

sno

Char

255

可空

课程号

cno

Char

255

可空

平时成绩

daily_grade

double

255

可空

期中成绩

midterm_grade

double

255

可空

期末成绩

final_grade

double

255

可空

总成绩

overall_grade

double

255

可空

五、具体实现

1. 系统结构设计

技术栈:

   - 后端:SpringBoot+Mybatis

   - 前端:Vue3+Element-plus

   - 数据库:MySQL

   - 开发环境:

   - 操作系统:Windows11

   - 数据库管理工具:Navicat

   - 编码工具:IDEA

   - 接口测试工具:Postman

2. 模块设计

学生管理模块

   - 学生信息录入:包括学生的姓名、性别、年龄等信息的录入功能。

   - 学生信息查询:可以按照学生学号、姓名条件进行学生信息查询。

   - 学生信息编辑:对学生信息进行编辑和更新操作。

   - 学生信息删除:可以删除学生信息。

课程管理模块

   - 课程信息录入:包括课程的名称、编号、授课教师等信息的录入功能。

   - 课程信息查询:可以按照课程名称条件进行课程信息查询。

   - 课程信息编辑:对课程信息进行编辑和更新操作。

   - 课程信息删除:可以删除课程信息。

成绩管理模块

   - 成绩录入:教师可以录入学生的课程成绩。

   - 成绩查询:学生可以查询自己的课程成绩。

3. 接口设计

学生管理接口

   - GET /api/students:获取所有学生信息列表

   - GET /api/students/{id}:获取指定id的学生信息

   - POST /api/students:新增学生信息

   - PUT /api/students/{id}:更新指定id的学生信息

   - DELETE /api/students/{id}:删除指定id的学生信息

课程管理接口

   - GET /api/courses:获取所有课程信息列表

   - GET /api/courses/{id}:获取指定id的课程信息

   - POST /api/courses:新增课程信息

   - PUT /api/courses/{id}:更新指定id的课程信息

   - DELETE /api/courses/{id}:删除指定id的课程信息

成绩管理接口

   - POST /api/scores:录入学生的课程成绩

   - GET /api/scores/{studentId}:查询指定学生的课程成绩列表

   - GET /api/scores/{courseId}:查询指定课程的学生成绩列表

   - GET /api/scores/statistics:获取成绩统计信息

4. 页面设计

   - 登录界面:包括账号、密码、角色选择。

   - 管理员系统页面:包括课程管理、学生信息管理功能。

   - 教师系统页面:包括成绩管理、教师资料管理功能。

   - 学生系统页面:包括成绩管理、学生资料管理功能。

   - 课程管理页面:包括课程信息增加、删除、修改、查询功能。

   - 成绩管理页面:包括成绩录入、查询功能。

   - 资料管理页面:包括个人信息展示、修改密码功能。

5. 安全设计

   - 用户权限管理:通过角色和权限控制用户对系统的访问权限。

   - 数据加密:对敏感数据进行加密存储和传输。

6. 性能设计

   - 数据库优化:合理设计数据库表结构,建立适当的索引。

   - 代码优化:避免冗余代码,减少不必要的计算和IO操作。

7. 测试策略

    - 单元测试:使用JUnit等工具进行单元测试。

    - 集成测试:对系统各个模块进行集成测试。

    - 系统测试:对整个系统进行功能测试、性能测试等。

8. 部署方案

    - 服务器环境:部署在阿里云服务器,采用Nginx作为反向代理。

    - 数据库部署:采用MySQL数据库,进行主从复制,保证数据的高可用性。

    - 代码部署:使用Docker容器化部署,结合Jenkins实现持续集成、持续部署。

9. 维护和运维

    - 系统监控:使用Prometheus、Grafana等工具进行系统监控。

    - 日志管理:使用ELK(Elasticsearch、Logstash、Kibana)进行日志管理和分析。

    - 故障处理:建立故障处理流程,保证系统能够及时恢复。

六、测试 

1. 测试方法 

针对本系统在功能、目的、用途、性能已经运行环境等方面的具体要求,在测试时 主要采用了白盒测试和黑盒测试两种方法。

白盒测试立足于开发者的角度进行测试,所有的功能、结构、模块等内容对于测试者而言都是了解的,测试者既可以根据正常的运行流程进行测试,也可以通过插入桩数据的形式来模拟测试其中的某个部分流程,这样的测试也会更加有针对性。

而黑盒测试则是立足于用户的角度进行测试,假定测试者对于整个系统的实现细节完全不了解,即便是开发人员也要如此认为。在测试时模拟真实用户的使用方法,从整体上、功能上、操作上进行全方位的测试。

2. 测试用例 

(1)信息管理子系统

学生信息的必填项全部填写,选填项全部填写进行测试。

学生信息的必填项全部填写,选填项全部不写进行测试。

(2)成绩管理子系统测试

成绩信息的字段全部填写,填写内容全部正确进行测试。

成绩信息的字段全部填写,填写内容部分正确进行测试。

(3)考试管理子系统测试

考试信息的字段全部填写,填写内容全部正确进行测试。

考试信息的字段全部填写,填写内容部分正确进行测试。

(4)系统管理子系统测试

对用户在权限范围内访问合法资源的情况进行测试。

对用户在权限范围内访问非法资源的情况进行测试。

3. 测试结论 

        整个系统的测试分为了三个阶段:首先在每个功能模块完成后,都要对其进行白盒测试和黑盒测试。其次在全部的功能模块都完成后,会把所有的模块集中起来进行集成测试。最后当修正所出现的问题以后,还会对系统进行回归测试。经过这些轮次的测试,可以认为整个系统在功能上已经满足了系统分析所要实现的目标,在性能上能够满足实际运行环境的使用要求,整个系统已经可以交付使用。

七、系统界面演示

  1. 管理员端

图 11 登录界面

图 12 系统首页

图 13 课程信息管理界面

图 14 增加课程界面

图 15 提示增加成功界面

图 16 删除课程功能演示

图 17 选择删除课程

图 18 提示删除成功界面

图 19 修改课程功能

图 20 修改成功提示界面

图 21 查询课程功能演示

图 22 重置功能

图 23 学生信息管理界面功能演示

    1. 教师端

图 24 登录界面演示

图 25 教师端系统首页演示

图 26 成绩信息管理界面演示

图 27 修改教师资料界面演示

    1. 学生端

图 28 学生登录界面演示

图 29 学生端系统首页界面

图 30 成绩信息查询界面演示

图 31 学生资料管理演示

八、代码附录

1. 数据库创建

(1) 创建管理员表admin:

CREATE TABLE `admin` (

  `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',

  `username` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '账号',

  `password` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码',

  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '名称',

  `role` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '角色',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='管理员\r\n';

(2)创建课程表course:

CREATE TABLE `course` (

  `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',

  `no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '课程编号',

  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '课程名称',

  `credit` int DEFAULT NULL COMMENT '课程学分',

  `tno` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '任课教师工号',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=25 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='课程信息';

(3)创建成绩表grade:

CREATE TABLE `grade` (

  `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',

  `sno` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '学号',

  `cno` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '课程号',

  `grade1` int DEFAULT NULL COMMENT '平时成绩',

  `grade2` int DEFAULT NULL COMMENT '期中成绩',

  `grade3` int DEFAULT NULL COMMENT '期末成绩',

  `grade4` int DEFAULT NULL COMMENT '总成绩',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=741 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='成绩信息表';

(4)创建学生表student:

CREATE TABLE `student` (

  `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',

  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '学号/账号',

  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码',

  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '姓名',

  `sex` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '性别',

  `phone` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '电话',

  `role` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '角色',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=124 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='学生信息';

(5)创建教师表teacher:

CREATE TABLE `teacher` (

  `id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',

  `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '工号',

  `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '密码',

  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '姓名',

  `sex` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '性别',

  `phone` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '电话',

  `role` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '角色',

  PRIMARY KEY (`id`)

) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='教师信息表'

2. 前端

(1)系统主界面Manager.vue

<template>

  <div>

    <div style="height: 60px; background-color: #fff; display: flex; align-items: center; border-bottom: 1px solid #ddd">

      <div style="flex: 1">

        <div style="padding-left: 20px; display: flex; align-items: center">

          <img src="@/assets/imgs/logo.png" alt="" style="width: 40px">

          <div style="font-weight: bold; font-size: 24px; margin-left: 5px">学生成绩管理系统</div>

        </div>

      </div>

      <div style="width: fit-content; padding-right: 10px; display: flex; align-items: center;">

        <img src="https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png" alt="" style="width: 40px; height: 40px">

        <span style="margin-left: 5px">{{user.name}}</span>

      </div>

    </div>



    <div style="display: flex">

      <div style="width: 200px; border-right: 1px solid #ddd; min-height: calc(100vh - 60px)">

        <el-menu

            router

            style="border: none"

            :default-active="$route.path"

            :default-openeds="['/home', '2','3']"

        >

          <el-menu-item index="/home">

            <el-icon><HomeFilled /></el-icon>

            <span>系统首页</span>

          </el-menu-item>

          <el-sub-menu index="2">

            <template #title>

              <el-icon><Memo /></el-icon>

              <span>课程管理</span>

            </template>

            <el-menu-item index="/course" v-if="user.role === 'ADMIN'">

              <el-icon><Document /></el-icon>

              <span>课程信息</span>

            </el-menu-item>

            <el-menu-item index="/grade" v-if="user.role === 'TEACHER'">

              <el-icon><Document /></el-icon>

              <span>成绩信息</span>

            </el-menu-item>

            <el-menu-item index="/grades" v-if="user.role === 'STUDENT'">

              <el-icon><Document /></el-icon>

              <span>成绩信息</span>

            </el-menu-item>

          </el-sub-menu>

          <el-sub-menu index="3" v-if="user.role === 'ADMIN'">

            <template #title>

              <el-icon><User /></el-icon>

              <span>用户管理</span>

            </template>

            <el-menu-item index="/student">

              <el-icon><UserFilled /></el-icon>

              <span>学生信息</span>

            </el-menu-item>

          </el-sub-menu>

          <el-menu-item index="/person" v-if="user.role === 'STUDENT'">

            <el-icon><User /></el-icon>

            <span>学生资料</span>

          </el-menu-item>

          <el-menu-item index="/teacher" v-if="user.role === 'TEACHER'">

            <el-icon><User /></el-icon>

            <span>教师资料</span>

          </el-menu-item>

          <el-menu-item index="login" @click="logout">

            <el-icon><SwitchButton /></el-icon>

            <span>退出系统</span>

          </el-menu-item>

        </el-menu>

      </div>



      <div style="flex: 1; width: 0; background-color: #f8f8ff; padding: 10px">

        <router-view />

      </div>

    </div>



  </div>

</template>



<script setup>

import { useRoute } from 'vue-router'

const $route = useRoute()

const user = JSON.parse(localStorage.getItem('student-user') || '{}')



const logout = () => {

  localStorage.removeItem('student-user')

}

</script>



<style scoped>

.el-menu-item.is-active {

  background-color: #dcede9 !important;

}

.el-menu-item:hover {

  color: #11A983;

}

:deep(th)  {

  color: #333;

}

</style>

(2)登录界面Login.vue

<template>

    <div>

        <div class="login-container">

            <div style="width: 350px" class="login-box">

                <div style="font-weight: bold; font-size: 24px; text-align: center; margin-bottom: 30px">登 录</div>

                <el-form :model="data.form" ref="formRef" :rules="rules">

                    <el-form-item prop="username">

                        <el-input prefix-icon="User" v-model="data.form.username" placeholder="请输入账号" />

                    </el-form-item>

                    <el-form-item prop="password">

                        <el-input show-password prefix-icon="Lock" v-model="data.form.password" placeholder="请输入密码"  />

                    </el-form-item>

                    <el-form-item prop="role">

                        <el-select style="width:100%" v-model="data.form.role">

                            <el-option value="ADMIN" label="管理员"></el-option>

                            <el-option value="STUDENT" label="学生"></el-option>

                            <el-option value="TEACHER" label="教师"></el-option>

                        </el-select>

                    </el-form-item>

                    <el-form-item>

                        <el-button type="primary" style="width: 100%" @click="login">登 录</el-button>

                    </el-form-item>



                </el-form>

            </div>

        </div>

    </div>

</template>



<script setup>

    import {reactive,ref} from "vue"

    import request from "../utils/request";

    import {ElMessage} from "element-plus";

    import router from "../router";



    const data = reactive({

    form: {role:'ADMIN'} //默认

    })

    const rules = reactive({

        username:[

            {required:true,message:'请输入账号',trigger:'blur'},

        ],

        password:[

            {required:true,message:'请输入密码',trigger:'blur'},

        ],

    })

const formRef = ref()

    const login = () => {

    formRef.value.validate((valid) => {

        if(valid) {

            request.post('/login',data.form).then(res => {

                if (res.code === '200') {

                    localStorage.setItem('student-user',JSON.stringify(res.data))

                    localStorage.setItem('teacher-user',JSON.stringify(res.data))

                    ElMessage.success('登录成功')

                    console.log(res.data)

                    router.push('/home') //跳转到主页

                } else {

                    ElMessage.error(res.msg)

                }

            })

        }

    })

    }

</script>



<style scoped>

    .login-container {

        min-height: 100vh;

        overflow: hidden;

        display: flex;

        align-items: center;

        justify-content: center;

    }

    .login-box {

        background-color: #fff;

        box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);

        padding: 30px;

    }

</style>

(3)课程信息管理界面Course.vue

<template>

  <div>

    <div class="card" style="margin-bottom: 10px">

      <el-input style="width: 260px" v-model="data.name" class="w-50 m-2" placeholder="请输入课程名称进行查询" :prefix-icon="Search"/>

      <el-button type="primary" style="margin-left: 10px" @click="load">查询</el-button>

      <el-button type="info" @click="reset">重置</el-button>

    </div>



    <div class="card" style="margin-bottom: 10px">

    <div style="margin-bottom: 10px">

      <el-button type="primary" @click="handleAdd">新增</el-button>

    </div>



    <div>

      <el-table :data="data.tableData" style="width: 100%">

        <el-table-column prop="id" label="序号" width="100"/>

        <el-table-column prop="no" label="课程编号" width="150"/>

        <el-table-column prop="name" label="课程名称" width="200"/>

        <el-table-column prop="credit" label="课程学分" width="120"/>

        <el-table-column prop="tno" label="任课教师工号" width="120"/>

        <el-table-column label="操作" >

          <template #default="scope" >

            <el-button type="primary" size="small" plain @click="handleEdit(scope.row)" >编辑</el-button>

            <el-button type="danger" size="small" plain @click="del(scope.row.id)">删除</el-button>

          </template>

        </el-table-column>

      </el-table>

    </div>



    </div>



    <div class="card">

      <el-pagination v-model:current-page="data.pageNum" v-model:page-size="data.pageSize"

                     @current-change="handelCurrentChange"

                     background layout="prev, pager, next" :total="data.total" />

    </div>



    <el-dialog width="35%" v-model="data.formVisible" title="课程信息">

      <el-form :model="data.form" label-width="100px" label-position="right" style="padding-right: 40px">

        <el-form-item label="课程名称">

          <el-input v-model="data.form.name" autocomplete="off" />

        </el-form-item>

        <el-form-item label="课程编号">

          <el-input v-model="data.form.no" autocomplete="off" />

        </el-form-item>

        <el-form-item label="课程学分">

          <el-input v-model="data.form.credit" autocomplete="off" />

        </el-form-item>

        <el-form-item label="任课教师工号">

          <el-input v-model="data.form.tno" autocomplete="off" />

        </el-form-item>

      </el-form>

      <template #footer>

      <span class="dialog-footer">

        <el-button @click="data.formVisible = false">取 消</el-button>

        <el-button type="primary" @click="save">保 存</el-button>

      </span>

      </template>

    </el-dialog>



  </div>

</template>



<script setup>

import {reactive} from "vue"

import { Search } from '@element-plus/icons-vue'

import request from "@/utils/request";

import {ElMessage} from "element-plus";



const data = reactive({

  name:'',

  tableData:[],

  total:0,

  pageNum:1, //当前页码

  pageSize:10, //每页个数

  formVisible:false,

  form:{}

})



  const load = () => {

  request.get('/course/selectPage',{

    params: {

      pageNum:data.pageNum,

      pageSize:data.pageSize,

      name:data.name

    }

  }).then(res => {

    data.tableData = res.data?.list || []

    data.total = res.data.total || 0

  })

  }

  //调用方法获取后台数据

  load()



  const handelCurrentChange = (pageNum) => {

    //当翻页的时候重新加载数据即可

    load()

  }



  const reset = () => {

  data.name = ''

    load()

  }



  const handleAdd = () => {

    data.form = {}

    data.formVisible = true

  }



  //保存数据到后台

  const save = () => {

  request.request({

    url: data.form.id ? '/course/update' : '/course/add',

    method: data.form.id ? 'PUT' : 'POST',

    data: data.form

  }).then(res => {

    if (res.code === '200') {

    load() //重新获取数据

      data.formVisible = false //关闭弹窗

      ElMessage.success("操作成功")

    } else {

      ElMessage.error(res.msg)

    }

  })

  }



  const handleEdit = (row) => {

  data.form = JSON.parse(JSON.stringify(row))

    data.formVisible = true

  }



  const del = (id) => {

    ElMessageBox.confirm('删除数据后无法恢复,请确认是否删除','删除确认',{type:'warning'}).then(res => {

      request.delete('course/delete/' + id).then(res => {

        if (res.code === '200') {

          load() //重新获取数据

          data.formVisible = false //关闭弹窗

          ElMessage.success("删除成功")

        } else {

          ElMessage.error(res.msg)

        }

      })

    }).catch(res => {

      ElMessage({

        type: 'info',

        message: '取消删除',

      })

    })

  }

</script>

(4)成绩信息管理界面(教师端)Grade.vue

<template>

    <div>

        <div class="card" style="margin-bottom: 10px">

            <el-input style="width: 260px" v-model="data.sno" class="w-50 m-2" placeholder="请输入学号进行查询" :prefix-icon="Search"/>

            <el-button type="primary" style="margin-left: 10px" @click="load">查询</el-button>

            <el-button type="info" @click="reset">重置</el-button>

        </div>



        <div class="card" style="margin-bottom: 10px">



            <div>

                <el-table :data="data.tableData" style="width: 100%">

                    <el-table-column prop="id" label="序号" width="100"/>

                    <el-table-column prop="sno" label="学号" width="150"/>

                    <el-table-column prop="cno" label="课程号" width="150"/>

                    <el-table-column prop="grade1" label="平时成绩" width="120"/>

                    <el-table-column prop="grade2" label="期中成绩" width="120"/>

                    <el-table-column prop="grade3" label="期末成绩" width="120"/>

                    <el-table-column prop="grade4" label="总成绩" width="120"/>

                    <el-table-column label="操作">

                        <template #default="scope">

                            <el-button type="primary" size="small" plain @click="handleEdit(scope.row)">评分</el-button>

                        </template>

                    </el-table-column>

                </el-table>

            </div>



        </div>



        <div class="card">

            <el-pagination v-model:current-page="data.pageNum" v-model:page-size="data.pageSize"

                           @current-change="handelCurrentChange"

                           background layout="prev, pager, next" :total="data.total" />

        </div>



        <el-dialog width="35%" v-model="data.formVisible" title="成绩信息">

            <el-form :model="data.form" label-width="100px" label-position="right" style="padding-right: 40px">

                <el-form-item label="平时成绩">

                    <el-input v-model="data.form.grade1" autocomplete="off" />

                </el-form-item>

                <el-form-item label="期中成绩">

                    <el-input v-model="data.form.grade2" autocomplete="off" />

                </el-form-item>

                <el-form-item label="期末成绩">

                    <el-input v-model="data.form.grade3" autocomplete="off" />

                </el-form-item>

                <el-form-item label="总成绩">

                    <el-input v-model="data.form.grade4" autocomplete="off" />

                </el-form-item>

            </el-form>

            <template #footer>

      <span class="dialog-footer">

        <el-button @click="data.formVisible = false">取 消</el-button>

        <el-button type="primary" @click="save">保 存</el-button>

      </span>

            </template>

        </el-dialog>



    </div>

</template>



<script setup>

    import {reactive} from "vue"

    import { Search } from '@element-plus/icons-vue'

    import request from "@/utils/request";

    import {ElMessage} from "element-plus";





    const data = reactive({

        sno:'',

        tableData:[],

        total:0,

        pageNum:1, //当前页码

        pageSize:10, //每页个数

        formVisible:false,

        form:{}

    })



    const load = () => {

        request.get('/grade/selectPage',{

            params: {

                pageNum:data.pageNum,

                pageSize:data.pageSize,

                sno:data.sno

            }

        }).then(res => {

            data.tableData = res.data?.list || []

            data.total = res.data.total || 0

        })

    }

    //调用方法获取后台数据

    load()



    const handelCurrentChange = (pageNum) => {

        //当翻页的时候重新加载数据即可

        load()

    }



    const reset = () => {

        data.sno = ''

        load()

    }



    const handleAdd = () => {

        data.form = {}

        data.formVisible = true

    }



    //保存数据到后台

    const save = () => {

        request.request({

            url: data.form.id ? '/grade/update' : '{}',

            method: data.form.id ? 'PUT' : 'POST',

            data: data.form

        }).then(res => {

            if (res.code === '200') {

                load() //重新获取数据

                data.formVisible = false //关闭弹窗

                ElMessage.success("操作成功")

            } else {

                ElMessage.error(res.msg)

            }

        })

    }



    const handleEdit = (row) => {

        data.form = JSON.parse(JSON.stringify(row))

        data.formVisible = true

    }



    const del = (id) => {

        ElMessageBox.confirm('删除数据后无法恢复,请确认是否删除','删除确认',{type:'warning'}).then(res => {

            request.delete('course/delete/' + id).then(res => {

                if (res.code === '200') {

                    load() //重新获取数据

                    data.formVisible = false //关闭弹窗

                    ElMessage.success("删除成功")

                } else {

                    ElMessage.error(res.msg)

                }

            })

        }).catch(res => {

            ElMessage({

                type: 'info',

                message: '取消删除',

            })

        })

    }

</script>

(5)成绩信息管理界面(学生端)Grades.vue

<template>

    <div>

        <div class="card" style="margin-bottom: 10px">

            <el-input style="width: 260px" v-model="data.sno" class="w-50 m-2" placeholder="请输入学号进行查询" :prefix-icon="Search"/>

            <el-button type="primary" style="margin-left: 10px" @click="load">查询</el-button>

            <el-button type="info" @click="reset">重置</el-button>

        </div>



        <div class="card" style="margin-bottom: 10px">



            <div>

                <el-table :data="data.tableData" style="width: 100%">

                    <el-table-column prop="id" label="序号" width="100"/>

                    <el-table-column prop="sno" label="学号" width="150"/>

                    <el-table-column prop="cno" label="课程号" width="150"/>

                    <el-table-column prop="grade1" label="平时成绩" width="120"/>

                    <el-table-column prop="grade2" label="期中成绩" width="120"/>

                    <el-table-column prop="grade3" label="期末成绩" width="120"/>

                    <el-table-column prop="grade4" label="总成绩" width="120"/>

                </el-table>

            </div>



        </div>



        <div class="card">

            <el-pagination v-model:current-page="data.pageNum" v-model:page-size="data.pageSize"

                           @current-change="handelCurrentChange"

                           background layout="prev, pager, next" :total="data.total" />

        </div>

    </div>

</template>



<script setup>

    import {reactive} from "vue"

    import { Search } from '@element-plus/icons-vue'

    import request from "@/utils/request";

    import {ElMessage} from "element-plus";





    const data = reactive({

        sno:'',

        tableData:[],

        total:0,

        pageNum:1, //当前页码

        pageSize:10, //每页个数

        formVisible:false,

        form:{}

    })



    const load = () => {

        request.get('/grade/selectPage',{

            params: {

                pageNum:data.pageNum,

                pageSize:data.pageSize,

                sno:data.sno

            }

        }).then(res => {

            data.tableData = res.data?.list || []

            data.total = res.data.total || 0

        })

    }

    //调用方法获取后台数据

    load()



    const handelCurrentChange = (pageNum) => {

        //当翻页的时候重新加载数据即可

        load()

    }



    const reset = () => {

        data.sno = ''

        load()

    }



    const handleAdd = () => {

        data.form = {}

        data.formVisible = true

    }



    //保存数据到后台

    const save = () => {

        request.request({

            url: data.form.id ? '/grade/update' : '{}',

            method: data.form.id ? 'PUT' : 'POST',

            data: data.form

        }).then(res => {

            if (res.code === '200') {

                load() //重新获取数据

                data.formVisible = false //关闭弹窗

                ElMessage.success("操作成功")

            } else {

                ElMessage.error(res.msg)

            }

        })

    }



    const handleEdit = (row) => {

        data.form = JSON.parse(JSON.stringify(row))

        data.formVisible = true

    }



    const del = (id) => {

        ElMessageBox.confirm('删除数据后无法恢复,请确认是否删除','删除确认',{type:'warning'}).then(res => {

            request.delete('course/delete/' + id).then(res => {

                if (res.code === '200') {

                    load() //重新获取数据

                    data.formVisible = false //关闭弹窗

                    ElMessage.success("删除成功")

                } else {

                    ElMessage.error(res.msg)

                }

            })

        }).catch(res => {

            ElMessage({

                type: 'info',

                message: '取消删除',

            })

        })

    }

</script>

(6)系统首页界面Home.vue

<template>

  <div>



    <div class="card" style="line-height: 30px">

      <div>欢迎您,<span style="color: dodgerblue;">{{ user.name }} </span> 祝您今天过得开心!</div>

    </div>



  </div>

</template>



<script setup>

  import request from "@/utils/request";

  const user = JSON.parse(localStorage.getItem('student-user') || '{}')

</script>

(7)学生个人资料界面Person.vue

<template>

    <div>

        <div class="card" style="width:50%" padding="40px" >

            <el-form :model="data.form" label-width="100px" label-position="right" style="padding-right: 40px">

                <el-form-item label="学号">

                    <el-input v-model="data.form.username" autocomplete="off" disabled />

                </el-form-item>

                <el-form-item label="密码">

                    <el-input show-password v-model="data.form.password" autocomplete="off" />

                </el-form-item>

                <el-form-item label="姓名">

                    <el-input v-model="data.form.name" autocomplete="off" disabled/>

                </el-form-item>

                <el-form-item label="性别">

                    <el-radio-group v-model="data.form.sex" disabled>

                        <el-radio label="男"></el-radio>

                        <el-radio label="女"></el-radio>

                    </el-radio-group>

                </el-form-item>

                <el-form-item label="电话">

                    <el-input v-model="data.form.phone" autocomplete="off" disabled/>

                </el-form-item>

                <el-form-item>

                    <el-button type="primary" @click="update">保 存</el-button>

                </el-form-item>

            </el-form>

        </div>

    </div>

</template>



<script setup>

    import {reactive} from "vue";

    import request from "../../utils/request";

    import {ElMessage} from "element-plus";

    import router from "../../router";



    const data = reactive({

        form:JSON.parse(localStorage.getItem('student-user') || "{}")

    })



    const update = () => {

        request.put('/student/update', data.form).then(res => {

            if (res.code === '200') {

                router.push('/login')

                ElMessage.success("操作成功")

            } else {

                ElMessage.error(res.msg)

            }

        })

    }

</script>

(8)学生信息管理界面Student.vue

<template>

    <div>

        <div class="card" style="margin-bottom: 10px">

            <el-input style="width: 260px; margin-right: 10px" v-model="data.username" class="w-50 m-2" placeholder="请输入学号进行查询" :prefix-icon="Search"/>

            <el-input style="width: 260px" v-model="data.name" class="w-50 m-2" placeholder="请输入名称进行查询" :prefix-icon="Search"/>

            <el-button type="primary" style="margin-left: 10px" @click="load">查询</el-button>

            <el-button type="info" @click="reset">重置</el-button>

        </div>



        <div class="card" style="margin-bottom: 10px">

            <div style="margin-bottom: 10px">

                <el-button type="primary" @click="handleAdd">新增</el-button>

            </div>



            <div>

                <el-table :data="data.tableData" style="width: 100%">

                    <el-table-column prop="id" label="序号" width="80"/>

                    <el-table-column prop="username" label="学号" width="150"/>

                    <el-table-column prop="name" label="姓名" width="100"/>

                    <el-table-column prop="sex" label="性别" width="80"/>

                    <el-table-column prop="phone" label="电话" width="150"/>

                    <el-table-column label="操作">

                        <template #default="scope">

                            <el-button type="primary" size="small" plain @click="handleEdit(scope.row)">编辑</el-button>

                            <el-button type="danger" size="small" plain @click="del(scope.row.id)">删除</el-button>

                        </template>

                    </el-table-column>

                </el-table>

            </div>



        </div>



        <div class="card">

            <el-pagination v-model:current-page="data.pageNum" v-model:page-size="data.pageSize"

                           @current-change="handelCurrentChange"

                           background layout="prev, pager, next" :total="data.total" />

        </div>



        <el-dialog width="35%" v-model="data.formVisible" title="学生信息">

            <el-form :model="data.form" label-width="100px" label-position="right" style="padding-right: 40px">

                <el-form-item label="学号">

                    <el-input v-model="data.form.username" autocomplete="off" />

                </el-form-item>

                <el-form-item label="密码">

                    <el-input show-password v-model="data.form.password" autocomplete="off" />

                </el-form-item>

                <el-form-item label="姓名">

                    <el-input v-model="data.form.name" autocomplete="off" />

                </el-form-item>

                <el-form-item label="性别">

                    <el-radio-group v-model="data.form.sex">

                        <el-radio label="男"></el-radio>

                        <el-radio label="女"></el-radio>

                    </el-radio-group>

                </el-form-item>

                <el-form-item label="电话">

                    <el-input v-model="data.form.phone" autocomplete="off" />

                </el-form-item>

            </el-form>

            <template #footer>

      <span class="dialog-footer">

        <el-button @click="data.formVisible = false">取 消</el-button>

        <el-button type="primary" @click="save">保 存</el-button>

      </span>

            </template>

        </el-dialog>



    </div>

</template>



<script setup>

    import {reactive} from "vue"

    import { Search } from '@element-plus/icons-vue'

    import request from "@/utils/request";

    import {ElMessage} from "element-plus";



    const baseUrl = '/student'



    const data = reactive({

        username:'',

        name:'',

        tableData:[],

        total:0,

        pageNum:1, //当前页码

        pageSize:10, //每页个数

        formVisible:false,

        form:{}

    })



    const load = () => {

        request.get(baseUrl + '/selectPage',{

            params: {

                pageNum:data.pageNum,

                pageSize:data.pageSize,

                username:data.username,

                name:data.name

            }

        }).then(res => {

            data.tableData = res.data?.list || []

            data.total = res.data.total || 0

        })

    }

    //调用方法获取后台数据

    load()



    const handelCurrentChange = (pageNum) => {

        //当翻页的时候重新加载数据即可

        load()

    }



    const reset = () => {

        data.username = ''

        data.name = ''

        load()

    }



    const handleAdd = () => {

        data.form = {}

        data.formVisible = true

    }



    //保存数据到后台

    const save = () => {

        request.request({

            url: data.form.id ? baseUrl + '/update' : baseUrl + '/add',

            method: data.form.id ? 'PUT' : 'POST',

            data: data.form

        }).then(res => {

            if (res.code === '200') {

                load() //重新获取数据

                data.formVisible = false //关闭弹窗

                ElMessage.success("操作成功")

            } else {

                ElMessage.error(res.msg)

            }

        })

    }



    const handleEdit = (row) => {

        data.form = JSON.parse(JSON.stringify(row))

        data.formVisible = true

    }



    const del = (id) => {

        ElMessageBox.confirm('删除数据后无法恢复,请确认是否删除','删除确认',{type:'warning'}).then(res => {

            request.delete(baseUrl + '/delete/' + id).then(res => {

                if (res.code === '200') {

                    load() //重新获取数据

                    data.formVisible = false //关闭弹窗

                    ElMessage.success("删除成功")

                } else {

                    ElMessage.error(res.msg)

                }

            })

        }).catch(res => {

            ElMessage({

                type: 'info',

                message: '取消删除',

            })

        })

    }

</script>

(9)教师个人资料界面Teacher.vue

<template>

    <div>

        <div class="card" style="width:50%" padding="40px" >

            <el-form :model="data.form" label-width="100px" label-position="right" style="padding-right: 40px">

                <el-form-item label="工号">

                    <el-input v-model="data.form.username" autocomplete="off" disabled />

                </el-form-item>

                <el-form-item label="密码">

                    <el-input show-password v-model="data.form.password" autocomplete="off" />

                </el-form-item>

                <el-form-item label="姓名">

                    <el-input v-model="data.form.name" autocomplete="off" disabled/>

                </el-form-item>

                <el-form-item label="性别">

                    <el-radio-group v-model="data.form.sex" disabled>

                        <el-radio label="男"></el-radio>

                        <el-radio label="女"></el-radio>

                    </el-radio-group>

                </el-form-item>

                <el-form-item label="电话">

                    <el-input v-model="data.form.phone" autocomplete="off" disabled/>

                </el-form-item>

                <el-form-item>

                    <el-button type="primary" @click="update">保 存</el-button>

                </el-form-item>

            </el-form>

        </div>

    </div>

</template>

<script setup>

    import {reactive} from "vue";

    import request from "../../utils/request";

    import {ElMessage} from "element-plus";

    import router from "../../router";



    const data = reactive({

        form:JSON.parse(localStorage.getItem('teacher-user') || "{}")

    })

    const update = () => {

        request.put('/teacher/update', data.form).then(res => {

            if (res.code === '200') {

                router.push('/login')

                ElMessage.success("操作成功")

            } else {

                ElMessage.error(res.msg)

            }

        })

    }

</script>

(10)路由index.js

import {createRouter, createWebHistory} from 'vue-router'



const router = createRouter({

  history: createWebHistory(import.meta.env.BASE_URL),

  routes: [

    {

      path: '/',

      name: 'Manager',

      component: () => import('@/views/Manager.vue'),

      redirect: '/home',

      children: [

        { path: 'home', name: 'Home', component: () => import('@/views/manager/Home.vue')},

        { path: 'course', name: 'Course', component: () => import('@/views/manager/Course.vue')},

        { path: 'student', name: 'Student', component: () => import('@/views/manager/Student.vue')},

        { path: 'person', name: 'Person', component: () => import('@/views/manager/Person.vue')},

        { path: 'grade', name: 'Grade', component: () => import('@/views/manager/Grade.vue')},

        { path: 'grades', name: 'Grades', component: () => import('@/views/manager/Grades.vue')},

        { path: 'teacher', name: 'Teacher', component: () => import('@/views/manager/Teacher.vue')},

      ]

    },

    {

      path: '/login',

      name: 'Login',

      component: () => import('@/views/Login.vue'),

    }

  ]

})

export default router

(11)请求request.js

import { ElMessage } from 'element-plus'

import router from '../router'

import axios from "axios";



const request = axios.create({

    baseURL: import.meta.env.VITE_BASE_URL,

    timeout: 30000  // 后台接口超时时间设置

})



// request 拦截器

// 可以自请求发送前对请求做一些处理

request.interceptors.request.use(config => {

    config.headers['Content-Type'] = 'application/json;charset=utf-8';

    return config

}, error => {

    return Promise.reject(error)

});



// response 拦截器

// 可以在接口响应后统一处理结果

request.interceptors.response.use(

    response => {

        let res = response.data;

        // 如果是返回的文件

        if (response.config.responseType === 'blob') {

            return res

        }

        // 兼容服务端返回的字符串数据

        if (typeof res === 'string') {

            res = res ? JSON.parse(res) : res

        }

        // 当权限验证不通过的时候给出提示

        if (res.code === '401') {

            ElMessage.error(res.msg);

            router.push("/login")

        }

        return res;

    },

        error => {

        console.log('err' + error)

        return Promise.reject(error)

    }

)

export default request

(12)main.js

import { createApp } from 'vue'

import App from './App.vue'

import router from './router'

import ElementPlus from 'element-plus'

import zhCn from 'element-plus/dist/locale/zh-cn.mjs'

import * as ElementPlusIconsVue from '@element-plus/icons-vue'

import '@/assets/css/global.css'

const app = createApp(App)

app.use(router)

app.use(ElementPlus, {

    locale: zhCn,

})

app.mount('#app')

for (const [key, component] of Object.entries(ElementPlusIconsVue)) {

    app.component(key, component)

}

3. 后台

(1)跨域配置CorsConfig.java

package com.example.common;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.web.cors.CorsConfiguration;

import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import org.springframework.web.filter.CorsFilter;



@Configuration

public class CorsConfig {



    @Bean

    public CorsFilter corsFilter() {

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration = new CorsConfiguration();

        corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址

        corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头

        corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法

        source.registerCorsConfiguration("/**", corsConfiguration); // 4 对接口配置跨域设置

        return new CorsFilter(source);

    }

}

(2)Result.java

package com.example.common;



public class Result {

    private String code;

    private String msg;

    private Object data;



    private Result(Object data) {

        this.data = data;

    }



    public Result() {

    }



    public static Result success() {

        Result result = new Result();

        result.setCode("200");

        result.setMsg("请求成功");

        return result;

    }



    public static Result success(Object data) {

        Result result = success();

        result.setData(data);

        return result;

    }



    public static Result error() {

        Result result = new Result();

        result.setCode("500");

        result.setMsg("请求失败");

        return result;

    }



    public static Result error(String msg) {

        Result result = new Result();

        result.setCode("500");

        result.setMsg(msg);

        return result;

    }



    public String getCode() {

        return code;

    }



    public void setCode(String code) {

        this.code = code;

    }



    public String getMsg() {

        return msg;

    }



    public void setMsg(String msg) {

        this.msg = msg;

    }



    public Object getData() {

        return data;

    }



    public void setData(Object data) {

        this.data = data;

    }

}

(3)角色枚举RoleEnum.java

package com.example.common;



public enum RoleEnum {

    ADMIN, //管理员

    STUDENT, //学生

    TEACHER //教师

}



(4)CourseController.java
package com.example.controller;



import com.example.common.Result;

import com.example.entity.Course;

import com.example.service.CourseService;

import com.github.pagehelper.PageInfo;

import org.springframework.web.bind.annotation.*;



import javax.annotation.Resource;



@RestController

@RequestMapping("/course")

public class CourseController {



    @Resource

    private CourseService courseService;



    //分页条件查询

    @GetMapping("/selectPage")

    public Result selectPage(@RequestParam(defaultValue = "1") Integer pageNum,

                             @RequestParam(defaultValue = "5") Integer pageSize,

                             @RequestParam String name) {

        PageInfo<Course> pageInfo = courseService.selectPage(pageNum, pageSize, name);

        return Result.success(pageInfo);



    }



    //新增

    @PostMapping("/add")

    public Result add(@RequestBody Course course) {

    courseService.add(course);

    return Result.success();

    }



    //更新

    @PutMapping("/update")

    public Result update(@RequestBody Course course) {

        courseService.updateById(course);

        return Result.success();

    }



    //删除

    @DeleteMapping("/delete/{id}")

    public Result delete(@PathVariable Integer id) {

        courseService.deleteById(id);

        return Result.success();

    }

}

(5)GradeController.java

package com.example.controller;



import com.example.common.Result;

import com.example.entity.Course;

import com.example.entity.Grade;

import com.example.service.GradeService;

import com.github.pagehelper.PageInfo;

import org.springframework.web.bind.annotation.*;



import javax.annotation.Resource;



@RestController

@RequestMapping("/grade")

public class GradeController {



    @Resource

    private GradeService gradeService;



    //分页条件查询

    @GetMapping("/selectPage")

    public Result selectPage(@RequestParam(defaultValue = "1") Integer pageNum,

                             @RequestParam(defaultValue = "5") Integer pageSize,

                             @RequestParam String sno) {

        PageInfo<Grade> pageInfo = gradeService.selectPage(pageNum, pageSize, sno);

        return Result.success(pageInfo);



    }



    //更新

    @PutMapping("/update")

    public Result update(@RequestBody Grade grade) {

        gradeService.updateById(grade);

        return Result.success();

    }

}

(6)StudentController.java

package com.example.controller;



import com.example.common.Result;

import com.example.entity.Student;

import com.example.service.StudentService;

import com.github.pagehelper.PageInfo;

import org.apache.ibatis.annotations.Delete;

import org.springframework.web.bind.annotation.*;



import javax.annotation.Resource;



@RestController

@RequestMapping("/student")

public class StudentController {



    @Resource

    StudentService studentService;



    //新增

    @PostMapping("/add")

    public Result add(@RequestBody Student student) {

        studentService.add(student);

        return Result.success();

    }



    //删除

    @DeleteMapping("/delete/{id}")

    public Result delete(@PathVariable Integer id) {

        studentService.deleteById(id);

        return Result.success();

    }



    //更新

    @PutMapping("/update")

    public Result update(@RequestBody Student student) {

        studentService.updateById(student);

        return Result.success();

    }



    //分页查询

    @GetMapping("/selectPage")

    public Result selectPage(@RequestParam(defaultValue = "1") Integer pageNum,

                             @RequestParam(defaultValue = "10") Integer pageSize,

                             Student student) {

        PageInfo<Student> pageInfo = studentService.selectPage(pageNum,pageSize,student);

        return Result.success(pageInfo);

    }

}

(7)TeacherController.java

package com.example.controller;



import com.example.common.Result;

import com.example.entity.Student;

import com.example.entity.Teacher;

import com.example.service.TeacherService;

import org.springframework.web.bind.annotation.PutMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;



import javax.annotation.Resource;



@RestController

@RequestMapping("/teacher")

public class TeacherController {



    @Resource

    TeacherService teacherService;



    //更新

    @PutMapping("/update")

    public Result update(@RequestBody Teacher teacher) {

        teacherService.updateById(teacher);

        return Result.success();

    }



}



(8)WebController.java
package com.example.controller;



import com.example.common.Result;

import com.example.common.RoleEnum;

import com.example.entity.Account;

import com.example.service.AdminService;

import com.example.service.StudentService;

import com.example.service.TeacherService;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PostMapping;

import org.springframework.web.bind.annotation.RequestBody;

import org.springframework.web.bind.annotation.RestController;



import javax.annotation.Resource;



@RestController

public class WebController {



    @Resource

    private AdminService adminService;



    @Resource

    private StudentService studentService;



    @Resource

    private TeacherService teacherService;



    /**

     * 默认请求接口

     */

    @GetMapping("/")

    public Result hello() {

        return Result.success();

    }



    /**

     * 登录接口

     */

    @PostMapping("/login")

    public Result login(@RequestBody Account account) {

        Account dbAccount;

        if (RoleEnum.ADMIN.name().equals(account.getRole())) {//管理员登录

            dbAccount = adminService.login(account);

        }

        else if (RoleEnum.STUDENT.name().equals(account.getRole())) {//学生登录

            dbAccount = studentService.login(account);

        }

        else if (RoleEnum.TEACHER.name().equals(account.getRole())) {//教师登录

            dbAccount = teacherService.login(account);

        }

        else {

            return Result.error("角色错误");

        }



        return Result.success(dbAccount);

    }

}

(9)账户Account.java

package com.example.entity;



public class Account {

    private String username;

    private String password;

    private String name;

    private String role;



    public String getRole() {

        return role;

    }



    public void setRole(String role) {

        this.role = role;

    }



    public String getUsername() {

        return username;

    }



    public void setUsername(String username) {

        this.username = username;

    }



    public String getPassword() {

        return password;

    }



    public void setPassword(String password) {

        this.password = password;

    }



    public String getName() {

        return name;

    }



    public void setName(String name) {

        this.name = name;

    }

}

(10)管理员Admin.java

package com.example.entity;



public class Admin extends Account{

    private Integer id;

    //账号

    private String username;

    //密码

    private String password;

    private String name;

    public Integer getId() {

        return id;

    }



    public void setId(Integer id) {

        this.id = id;

    }



    public String getUsername() {

        return username;

    }



    public void setUsername(String username) {

        this.username = username;

    }



    public String getPassword() {

        return password;

    }



    public void setPassword(String password) {

        this.password = password;

    }



    public String getName() {

        return name;

    }



    public void setName(String name) {

        this.name = name;

    }

}

(11)课程Course.java

package com.example.entity;



public class Course {

    private Integer id;

    private String no;

    private String name;

    private int credit;

    private String Tno;



    public Integer getId() {

        return id;

    }



    public void setId(Integer id) {

        this.id = id;

    }



    public String getNo() {

        return no;

    }



    public void setNo(String no) {

        this.no = no;

    }



    public String getName() {

        return name;

    }



    public void setName(String name) {

        this.name = name;

    }



    public int getCredit() {

        return credit;

    }



    public void setCredit(int credit) {

        this.credit = credit;

    }



    public String getTno() {

        return Tno;

    }



    public void setTno(String tno) {

        Tno = tno;

    }

}

(12)成绩Grade.java

package com.example.entity;



public class Grade {

    private Integer id;

    private String sno;

    private String cno;

    private Integer grade1;

    private Integer grade2;

    private Integer grade3;

    private Integer grade4;



    public Integer getId() {

        return id;

    }



    public void setId(Integer id) {

        this.id = id;

    }



    public String getSno() {

        return sno;

    }



    public void setSno(String sno) {

        this.sno = sno;

    }



    public String getCno() {

        return cno;

    }



    public void setCno(String cno) {

        this.cno = cno;

    }



    public Integer getGrade1() {

        return grade1;

    }



    public void setGrade1(Integer grade1) {

        this.grade1 = grade1;

    }



    public Integer getGrade2() {

        return grade2;

    }



    public void setGrade2(Integer grade2) {

        this.grade2 = grade2;

    }



    public Integer getGrade3() {

        return grade3;

    }



    public void setGrade3(Integer grade3) {

        this.grade3 = grade3;

    }



    public Integer getGrade4() {

        return grade4;

    }



    public void setGrade4(Integer grade4) {

        this.grade4 = grade4;

    }

}

(13)学生Student.java

package com.example.entity;



public class Student extends Account{

    private Integer id;

    private String username;

    private String password;

    private String name;

    private String sex;

    private String phone;



    public Integer getId() {

        return id;

    }



    public void setId(Integer id) {

        this.id = id;

    }



    public String getUsername() {

        return username;

    }



    public void setUsername(String username) {

        this.username = username;

    }



    public String getPassword() {

        return password;

    }



    public void setPassword(String password) {

        this.password = password;

    }



    public String getName() {

        return name;

    }



    public void setName(String name) {

        this.name = name;

    }



    public String getSex() {

        return sex;

    }



    public void setSex(String sex) {

        this.sex = sex;

    }



    public String getPhone() {

        return phone;

    }



    public void setPhone(String phone) {

        this.phone = phone;

    }

}

(14)教师Teacher.java

package com.example.entity;



public class Teacher extends Account{

    private Integer id;

    private String tno;

    private String password;

    private String sex;

    private String phone;



    public Integer getId() {

        return id;

    }



    public void setId(Integer id) {

        this.id = id;

    }



    public String getTno() {

        return tno;

    }



    public void setTno(String tno) {

        this.tno = tno;

    }



    public String getPassword() {

        return password;

    }



    public void setPassword(String password) {

        this.password = password;

    }



    public String getSex() {

        return sex;

    }



    public void setSex(String sex) {

        this.sex = sex;

    }



    public String getPhone() {

        return phone;

    }



    public void setPhone(String phone) {

        this.phone = phone;

    }

}

(15)AdminMapper.java

package com.example.mapper;



import com.example.entity.Admin;

import org.apache.ibatis.annotations.Select;



public interface AdminMapper {

    @Select("select * from admin where username = #{username}")

    Admin selectByUsername(String username);

}

(16)CourseMapper.java

package com.example.mapper;



import com.example.entity.Course;

import org.apache.ibatis.annotations.Delete;

import org.apache.ibatis.annotations.Insert;

import org.apache.ibatis.annotations.Select;

import org.apache.ibatis.annotations.Update;



import java.util.List;



public interface CourseMapper {



    @Select("select * from course where name like concat('%', #{name} ,'%') order by id desc")

    List<Course> selectAll(String name);



    @Insert("insert into course (no,name,credit,tno) values(#{no},#{name},#{credit},#{tno})")

    void insert(Course course);



    @Update("update course set no = #{no}, name = #{name}, credit = #{credit}, tno = #{tno} where id = #{id}")

    void updateById(Course course);



    @Delete("delete from course where id = #{id}")

    void deleteById(Integer id);

}

(17)GradeMapper.java

package com.example.mapper;



import com.example.entity.Course;

import com.example.entity.Grade;

import org.apache.ibatis.annotations.Delete;

import org.apache.ibatis.annotations.Insert;

import org.apache.ibatis.annotations.Select;

import org.apache.ibatis.annotations.Update;



import java.util.List;



public interface GradeMapper {



    @Select("select * from grade where sno like concat('%',#{sno},'%') order by id desc")

    List<Grade> selectAll(String sno);



    @Update("update grade set  grade1 = #{grade1}, grade2 = #{grade2}, grade3 = #{grade3}, grade4 = #{grade4} where id = #{id}")

    void updateById(Grade grade);

}

(18)StudentMapper.java

package com.example.mapper;



import com.example.entity.Student;

import org.apache.ibatis.annotations.Delete;

import org.apache.ibatis.annotations.Insert;

import org.apache.ibatis.annotations.Select;

import org.apache.ibatis.annotations.Update;



import java.util.List;



public interface StudentMapper {



    @Select("select * from student where username = #{username}")

    Student selectByUsername(String username);



    @Insert("insert into student (username,password,name,sex,phone,role)" +

            "values (#{username},#{password},#{name},#{sex},#{phone},#{role})")

    void insert(Student student);



    @Delete("delete from student where id = #{id}")

    void deleteById(Integer id);



    @Update("update student set username = #{username}, password = #{password}, name = #{name}, sex = #{sex}, phone = #{phone} where id = ${id}")

    void updateById(Student student);



    @Select("select * from student where username like concat('%',#{username},'%') and name like concat('%',#{name},'%') order by id desc" )

    List<Student> selectAll(Student student);

}

(19)TeacherMapper.java

package com.example.mapper;



import com.example.entity.Student;

import com.example.entity.Teacher;

import org.apache.ibatis.annotations.Select;

import org.apache.ibatis.annotations.Update;



public interface TeacherMapper {



    @Select("select * from teacher where username = #{username}")

    Teacher selectByUsername(String username);



    @Update("update teacher set username = #{username}, password = #{password}, name = #{name}, sex = #{sex}, phone = #{phone} where id = ${id}")

    void updateById(Teacher teacher);

}

(20)AdminService.java

package com.example.service;



import com.example.entity.Account;

import com.example.entity.Admin;

import com.example.exception.CustomException;

import com.example.mapper.AdminMapper;

import org.springframework.stereotype.Service;



import javax.annotation.Resource;



@Service

public class AdminService {



    @Resource

    private AdminMapper adminMapper;

    /**

     * 登录

     */

    public Account login(Account account){

        Account dbAdmin = adminMapper.selectByUsername(account.getUsername());

        if(dbAdmin == null){

            //没有用户

            throw  new CustomException("账号或密码错误");

        }

        //比较密码

        if(!account.getPassword().equals(dbAdmin.getPassword())){

            throw new CustomException("账号或密码错误");

        }

        //登录成功

        return dbAdmin;

    }

}

(21)CourseService.java

package com.example.service;



import com.example.entity.Course;

import com.example.mapper.CourseMapper;

import com.github.pagehelper.PageHelper;

import com.github.pagehelper.PageInfo;

import org.springframework.stereotype.Service;



import javax.annotation.Resource;

import java.util.List;



@Service

public class CourseService {



    @Resource

    private CourseMapper courseMapper;



    //total 查询总数 list 数据列表

    public PageInfo<Course> selectPage(Integer pageNum, Integer pageSize, String name) {

        PageHelper.startPage(pageNum,pageSize);

        List<Course> courseList = courseMapper.selectAll(name);

        return PageInfo.of(courseList);

    }



    //新增数据

    public void add(Course course) {

        courseMapper.insert(course);

    }



    public void updateById(Course course) {

        courseMapper.updateById(course);

    }



    public void deleteById(Integer id) {

        courseMapper.deleteById(id);

    }

}

(22)GradeService.java

package com.example.service;



import com.example.entity.Course;

import com.example.entity.Grade;

import com.example.mapper.GradeMapper;

import com.github.pagehelper.PageHelper;

import com.github.pagehelper.PageInfo;

import org.springframework.stereotype.Service;



import javax.annotation.Resource;

import java.util.List;



@Service

public class GradeService {



    @Resource

    private GradeMapper gradeMapper;



    //total 查询总数 list 数据列表

    public PageInfo<Grade> selectPage(Integer pageNum, Integer pageSize, String sno) {

        PageHelper.startPage(pageNum,pageSize);

        List<Grade> gradeList = gradeMapper.selectAll(sno);

        return PageInfo.of(gradeList);

    }



    public void updateById(Grade grade) {

        gradeMapper.updateById(grade);

    }

}

(23)StudentService.java

package com.example.service;



import cn.hutool.core.util.ObjectUtil;

import com.example.common.RoleEnum;

import com.example.entity.Account;

import com.example.entity.Student;

import com.example.exception.CustomException;

import com.example.mapper.StudentMapper;

import com.github.pagehelper.PageHelper;

import com.github.pagehelper.PageInfo;

import org.springframework.stereotype.Service;



import javax.annotation.Resource;

import java.util.List;



@Service

public class StudentService {



    @Resource

    private StudentMapper studentMapper;

    /**

     * 登录

     */

    public Account login(Account account){

        Account dbStudent = studentMapper.selectByUsername(account.getUsername());

        if(dbStudent == null){

            //没有用户

            throw  new CustomException("账号或密码错误");

        }

        //比较密码

        if(!account.getPassword().equals(dbStudent.getPassword())) {

            throw new CustomException("账号或密码错误");

        }

        //登录成功

        return dbStudent;

    }



    public void add(Student student){

        Student dbStudent = studentMapper.selectByUsername(student.getUsername());

        if(dbStudent != null) {

            throw new CustomException("账号已存在");

        }

        if(ObjectUtil.isEmpty(student.getName())){

            student.setName(student.getUsername());

        }

        student.setRole(RoleEnum.STUDENT.name());

        studentMapper.insert(student);

    }



    public void deleteById(Integer id) {

        studentMapper.deleteById(id);

    }



    public void updateById(Student student) {

        studentMapper.updateById(student);

    }



    public PageInfo<Student> selectPage(Integer pageNum,Integer pageSize, Student student) {

        PageHelper.startPage(pageNum,pageSize);

        List<Student> studentList = studentMapper.selectAll(student);

        return PageInfo.of(studentList);

    }

}

(24)TeacherService.java

package com.example.service;



import com.example.entity.Account;

import com.example.entity.Student;

import com.example.entity.Teacher;

import com.example.exception.CustomException;

import com.example.mapper.TeacherMapper;

import org.springframework.stereotype.Service;



import javax.annotation.Resource;



@Service

public class TeacherService {





    @Resource

    private TeacherMapper teacherMapper;



    public Account login(Account account){

        Account dbTeacher = teacherMapper.selectByUsername(account.getUsername());

        if(dbTeacher == null){

            //没有用户

            throw  new CustomException("账号或密码错误");

        }

        //比较密码

        if(!account.getPassword().equals(dbTeacher.getPassword())){

            throw new CustomException("账号或密码错误");

        }

        //登录成功

        return dbTeacher;

    }



    public void updateById(Teacher teacher) {

        teacherMapper.updateById(teacher);

    }

}

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值