Skip to content

一个学生成绩管理系统,使用 Go 语言和 Gin 框架实现,具备并发处理、异常处理、单元测试和接口文档等功能

Notifications You must be signed in to change notification settings

J-jxr/StuManagementSystem

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

StuManagementSystem

This is a simple Student Grade Management System implemented using Go language and the Gin framework. The system supports CRUD (Create, Read, Update, Delete) operations for student information and grades, with features such as concurrent processing, error handling, unit testing, and API documentation. It also supports batch importing of student data from CSV files, ensuring atomicity and thread-safe concurrency.

这是一个简单的学生成绩管理系统,使用 Go 语言和 Gin 框架实现。系统支持学生信息和成绩的增删改查(CRUD),并具备并发处理、异常处理、单元测试和接口文档等功能。系统还支持从 CSV 文件批量导入学生信息,确保操作的原子性和并发安全。

功能要求

1. 学生信息和成绩管理

  • 功能:实现学生信息和成绩的录入、删除、修改和查询功能

    • :可以添加新的学生信息(包括姓名、学号、性别、班级等)以及每个学生的课程成绩。

    • :可以根据学号删除学生信息,或者根据学号和课程名称删除特定学生的成绩。

    • :可以根据学号修改学生的基本信息,或者根据学号和课程名称修改学生的成绩。

    • :可以根据学号查询学生的基本信息及所有课程成绩,或者根据学号和课程名称查询特定课程成绩。

  • 要求

    • 定义学生结构体,包含姓名、学号、性别、班级等基本信息。

       type Student struct {
       	ID     string             `json:"id"`
       	Name   string             `json:"name"`
       	Gender string             `json:"gender"`
       	Class  string             `json:"class"`
       	Scores map[string]float64 `json:"scores"`
       }
    • 使用Gin框架搭建一个简单的HTTP Web服务

    • 实现增删改查接口。

    • 数据存储在程序本身的内存中,不需要持久化存到数据库里,使用合适的数据结构(使用map)来保存学生信息和成绩信息

       // 定义一个map用来存储学生信息,key 为学号,value 为学生信息
       var Students = make(map[string]Student)

2. 并发处理

  • 功能:从CSV文件中批量导入学生信息到系统中

    • 支持从 CSV 文件中批量导入学生信息。

    • 使用 goroutines 和 channels 处理每一条学生信息,并确保数据安全传递。

    • 使用互斥锁(sync.RWMutex)保证原子性,确保在并发情况下数据不被错误修改。

    • 处理 CSV 文件时,支持错误处理和数据验证,避免格式错误导致的异常。

  • 要求

    • 并发处理

      1. 使用 goroutines 并发处理每一条学生信息是合理的,可以有效提高处理速度。
      2. 通过 channel 传递解析后的学生信息,确保数据在 goroutines 之间安全传递。
    • 原子性

      1. 每次添加或修改学生信息的过程需要保证原子性,这意味着在更新学生信息时,需要确保没有其他 goroutine 同时修改或读取同一学号的学生信息。
      2. 可以使用互斥锁(sync.Mutex)或读写锁(sync.RWMutex)来保证原子性。
    • 错误处理

      1. 需要处理文件格式错误、数据验证错误等可能的错误情况。
      2. 可以在解析 CSV 文件时进行数据验证,并在发现错误时记录错误信息或跳过错误数据。
    • 你认为文件过大会出现什么情况?如何解决?

      1. 内存消耗过大

        • 如果文件大小过大(例如,超过几百MB或几GB),将整个文件一次性加载到内存中可能导致内存消耗过大,甚至导致程序崩溃。

        解决方法

        • 分片处理(Chunking):将文件分成较小的块,每次只加载一部分数据,避免将整个文件加载到内存中。可以使用流式读取(streaming)处理文件,通过一定的缓冲区分批读取数据。
        • 分段处理与并发处理:根据文件大小,合理划分数据块的大小(例如,200~400行一片),并使用多个 goroutine 分别处理每一块数据。
      2. I/O操作速度瓶颈

        • 文件读取可能成为性能瓶颈,特别是当文件较大时,读取速度会显著影响整体处理效率。

        解决方法

        • 并发读取:使用多个 goroutines 同时读取文件的不同部分,通过分片和 offset 来控制每个线程读取的文件片段。可以利用文件的随机读取来加速读取过程(在多线程环境下)。
        • 缓冲读取:通过缓冲区(如 bufio.Scannerbufio.Reader)分块读取文件,提高文件读取的效率。
      3. …….补充ing

3. 异常处理

  • 功能:在现有系统中添加异常处理机制,确保系统在遇到错误时能够返回适当的错误信息。

    • 系统通过 Gin 框架的错误处理机制,捕获常见错误并返回适当的 HTTP 状态码。

    • 对于无效输入、格式错误、未找到学生等情境,系统返回相应的错误信息。

  • 要求

    • 捕获并处理常见的错误,如输入数据格式错误、数据验证错误等。
    • 使用Gin框架的错误处理机制返回适当的HTTP状态码和错误信息。
      • 比如对于不存在的学生或成绩信息,API应返回适当的错误消息和状态码(如404 Not Found)
      • 或者对于无效的输入数据,API应返回适当的错误消息和状态码(如400 Bad Request)

4. 单元测试

  • 功能:为系统中的关键功能(如学生信息和成绩的增删改查)编写单元测试。

  • 要求

    • 使用 Go 的 testing 包为系统中的关键功能编写了单元测试。
  • 包括对学生信息和成绩的增删改查操作的测试,确保系统的正确性。

  • 项目中的单元测试代码文件均可正常运行

5. 接口文档

6. 加分项:反射

  • 通过反射(主要考查反射的理解与使用)实现了动态处理不同类型的学生信息,如本科生和研究生。

    •   // TestReflection 测试反射功能
        func TestReflection(c *gin.Context) {
        	// 创建本科生和研究生实例
        	undergraduate := models.Undergraduate{
        		ID:     "U001",
        		Name:   "Alice",
        		Gender: "Female",
        		Class:  "Class A",
        		Scores: map[string]float64{"Math": 90},
        		Major:  "Computer Science",
        	}
        
        	graduate := models.Graduate{
        		ID:            "G001",
        		Name:          "Bob",
        		Gender:        "Male",
        		Class:         "Class B",
        		Scores:        map[string]float64{"Algorithm": 85},
        		ResearchTopic: "Machine Learning",
        	}
        
        	// 将实例存储在一个切片中
        	students := []models.StudentInterface{undergraduate, graduate}
        
        	// 使用反射动态调用 GetInfo 方法
        	for _, student := range students {
        		// 获取对象的反射值
        		value := reflect.ValueOf(student)
        		// 获取对象的反射类型
        		typeOf := value.Type()
        
        		// 调用 GetInfo 方法
        		method := value.MethodByName("GetInfo")
        		if method.IsValid() {
        			// 调用方法并获取返回值
        			results := method.Call(nil)
        			// 打印类型和信息
        			fmt.Printf("Type: %s, Info: %s\n", typeOf, results[0])
        		}
        	}
        
        	c.JSON(200, gin.H{"message": "Reflection test completed"})
        }
        
  • 本科生和研究生结构体实现了相同的接口,通过反射动态调用不同类型的方法。

    •   // StudentInterface 定义一个共同的接口
        type StudentInterface interface {
        	GetInfo() string
        }
        
        // Undergraduate 本科生结构体
        type Undergraduate struct {
        	ID     string             `json:"id"`
        	Name   string             `json:"name"`
        	Gender string             `json:"gender"`
        	Class  string             `json:"class"`
        	Scores map[string]float64 `json:"scores"`
        	// 本科生特有的属性
        	Major string `json:"major"`
        }
        
        // GetInfo 实现 StudentInterface 接口的方法
        func (u Undergraduate) GetInfo() string {
        	return fmt.Sprintf("Undergraduate: ID=%s, Name=%s, Major=%s", u.ID, u.Name, u.Major)
        }
        
        // Graduate 研究生结构体
        type Graduate struct {
        	ID     string             `json:"id"`
        	Name   string             `json:"name"`
        	Gender string             `json:"gender"`
        	Class  string             `json:"class"`
        	Scores map[string]float64 `json:"scores"`
        	// 研究生特有的属性
        	ResearchTopic string `json:"researchTopic"`
        }
        
        // GetInfo 实现 StudentInterface 接口的方法
        func (g Graduate) GetInfo() string {
        	return fmt.Sprintf("Graduate: ID=%s, Name=%s, ResearchTopic=%s", g.ID, g.Name, g.ResearchTopic)
        }
        

7.加分项:分片处理

  • 功能:从 CSV 文件中批量导入大量学生信息到系统中。
    • CSV 文件学生信息不会超过 100000 条。每个学生信息各不相同。
    • 如果出现内存中已有的学生学号信息,则针对此学号的学生信息进行覆写修改。
  • 要求
    • 分片处理:
      1. 假设性能瓶颈在文件读取的 I/O 上,所以可以用多个线程对文件进行分片读取。
      2. 分片算法采用平均分片即可,每片大小自定,200~400为佳。
      3. 需要在程序里计算文件大小,并针对每一个线程维护一个 offset ,即每个线程的“读取位置变量”(用来标志将要读取的这一页)
    • 并发处理
      1. 使用 goroutines 并发处理每一片学生信息,简单起见可以一片一个 goroutine。针对每一条数据可以使用同步的批处理。
  • 尝试写出了代码,但是并没有进行实际的测试……哎哎
  • 功能待完善,等Go语言并发编程我更加熟练掌握以后,再来战胜你!!目前自己缺少很多前置知识。

技术栈

  • 编程语言:Go语言
    • IDE使用 Goland 即可
  • Web框架:Gin 框架
  • CSV 文件解析
    • 了解CSV文件以及解析过程
  • 并发控制
    • Goroutine 和 Channels
    • sync包下的锁机制与同步原语。
  • 异常处理
    • 利用err, defer, panic, recover等关键字和类型进行异常处理,增强系统的健壮性
  • 单元测试:Go的 testing 包

项目结构

StuManagementSystem
├── config	-- 项目的配置文件
│   └── config.go
├── controllers	-- 存放控制器相关代码文件
│   ├── ChunkProcessingController.go	-- 分片处理导入的CSV文件
│   ├── ImportStuCsvController.go	-- 并发处理导入的CSV文件 
│   ├── ImportStuCsvController_test.go -- 测试代码文件
│   ├── ReflectionController.go	   -- 测试反射功能
│   ├── StudentController.go	-- 处理学生信息相关的CRUD
│   └── StudentController_test.go	-- 测试代码文件
├── docs	-- 存放 Swagger 接口文档文件
│   ├── docs.go
│   ├── swagger.json
│   └── swagger.yaml
├── models	-- 存放数据模型相关代码文件
│   └── student.go	-- 学生数据模型
├── routes	-- 存放路由相关代码文件
│   └── routes.go	-- 路由配置代码文件
├── utils	-- 存放工具函数相关代码文件
│   ├── chunkUtil.go	-- 分片处理工具函数
│   └── csvUtil.go	-- CSV文件解析工具函数
├── go.mod	-- Go模块依赖管理文件
└── main.go	-- 项目的入口文件

使用用例

  • 项目运行图

    image-20250128174516817

  • AddStudent——添加学生信息

    • 请求

       {
         "class": "Class A",
         "gender": "Male",
         "id": "001",
         "name": "John Doe",
         "scores": {
           "Math": 95,
           "English": 88
         }
       }
    • 响应

       {
         "message": "Student added successfully"
       }
  • ImportStudents——批量导入学生信息CSV文件

    • test.csv文件内容

       123,John Doe,Male,Class A,Math,90,English,85
       456,Jane Smith,Female,Class B,Math,95,English,88
       789,Emily Davis,Female,Class C,Math,92,English,89
       101,Michael Brown,Male,Class A,Math,85,English,82
       112,Amy Wilson,Female,Class B,Math,94,English,91
      
    • 接口测试结果image-20250128173921242

  • TestReflection——测试反射

     {"message": "Reflection test completed"}

安装与运行

  1. 克隆本项目:

    git clone https://github.com/J-jxr/StuManagementSystem.git
    
    cd StuManagementSystem
  2. 安装 Go 依赖

    go mod tidy
  3. 启动服务器

    go run cmd/main.go

贡献

欢迎贡献代码,提供您的建议!!你可以通过提交 Pull Request 来改进这个项目。

Feel free to contribute code and provide your suggestions! You can improve this project by submitting a Pull Request.

About

一个学生成绩管理系统,使用 Go 语言和 Gin 框架实现,具备并发处理、异常处理、单元测试和接口文档等功能

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages