You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ExamSystem/doc/examsystem.md

22 KiB

数学学习考试系统 - 项目说明

项目简介

一个基于C++和Qt框架开发的跨平台数学学习考试系统支持小学、初中、高中三个学段的数学题目生成、在线答题、成绩统计等功能。系统采用前后端分离架构。

功能特性

🔐 用户管理

  • 用户注册(邮箱验证码验证)
  • 用户登录/登出
  • 密码修改
  • 个人信息查看

📚 题目生成

  • 小学:基础四则运算,确保结果非负
  • 初中:包含平方、开根号运算
  • 高中:包含三角函数运算
  • 智能查重,避免重复题目
  • 历史题目保存和加载

🎯 考试功能

  • 自定义题目数量5-50题
  • 实时答题进度显示
  • 上一题/下一题导航
  • 自动批改和成绩统计
  • 错题回顾

💾 数据管理

  • 用户数据持久化存储
  • 题目历史记录保存
  • 自动备份和恢复

技术栈

前端

  • 框架Qt 5/6
  • 语言C++
  • UI组件QWidget、QStackedWidget、QPushButton等

后端

  • 核心架构:模块化设计,工厂模式
  • 数学计算:表达式解析和求值
  • 文件管理CSV格式用户数据TXT格式题目存储
  • 邮件服务libcurl + SMTP协议

开发工具

  • 编译器支持C++11的编译器gcc/clang/MSVC
  • 构建工具CMake
  • 版本控制Git

项目结构

MathExamSystem/
├── frontend/                  # 前端界面
│   ├── base_widget.h/.cc     # 基础窗口组件
│   ├── login_widget.h/.cc    # 登录注册界面
│   ├── selection_widget.h/.cc # 难度选择界面
│   ├── question_widget.h/.cc # 答题界面
│   ├── result_widget.h/.cc   # 成绩显示界面
│   ├── main_window.h/.cc     # 主窗口管理
│   └── change_password_dialog.h/.cc # 修改密码对话框
├── backend/                   # 后端核心
│   ├── exam_system/          # 考试系统核心
│   │   ├── exam_system.h/.cc # 系统控制层
│   │   ├── problem_generator.h/.cc # 题目生成器
│   │   ├── duplicate_checker.h/.cc # 重复检查器
│   │   └── input_validator.h/.cc   # 输入验证器
│   ├── file_manager/         # 文件管理
│   │   └── file_manager.h/.cc
│   └── logger/               # 日志系统
│       └── logger.h/.cc
├── shared/                   # 共享接口
│   └── backend_interface.h/.cc # 前后端通信接口
├── main.cc                   # 程序入口
└── CMakeLists.txt           # 构建配置

环境要求

系统要求

  • Windows: Windows 10/11, Visual Studio 2019+
  • Linux: Ubuntu 18.04+, CentOS 7+
  • macOS: macOS 10.14+

依赖库

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install build-essential cmake qt6-base-dev libcurl4-openssl-dev

# CentOS/RHEL
sudo yum groupinstall "Development Tools"
sudo yum install cmake qt6-qtbase-devel libcurl-devel

# macOS (Homebrew)
brew install cmake qt6 curl

编译和运行

1. 克隆项目

git clone <repository-url>
cd MathExamSystem

2. 创建构建目录

mkdir build
cd build

3. 配置项目

cmake ..

4. 编译项目

# Linux/macOS
make -j4

# Windows (Visual Studio)
cmake --build . --config Release

5. 运行程序

# Linux/macOS
./MathExamSystem

# Windows
./Release/MathExamSystem.exe

使用指南

首次使用

  1. 启动程序:运行编译后的可执行文件

  2. 注册账号

    • 点击"注册新账号"
    • 输入邮箱地址,点击"发送验证码"
    • 检查邮箱获取验证码并填写
    • 设置用户名和密码6-10位包含大小写字母和数字
    • 点击"注册"
  3. 登录系统

    • 输入用户名和密码
    • 点击"登录"

开始学习

  1. 选择难度

    • 小学:基础四则运算
    • 初中:包含平方、开根号
    • 高中:包含三角函数
  2. 设置题目数量通过数字选择框设置5-50题

  3. 开始测试:点击"开始测试"进入答题界面

答题流程

  1. 阅读题目:仔细阅读题目内容
  2. 选择答案从A、B、C、D四个选项中选择
  3. 导航题目
    • 使用"上一题"、"下一题"按钮切换
    • 最后一题显示"提交试卷"按钮
  4. 提交答案:完成所有题目后提交

查看结果

  • 系统自动批改并显示得分
  • 查看正确题目数量和总题目数
  • 可选择"继续做题"或"退出"

配置说明

邮件服务配置

如需使用邮箱验证功能,请编辑 backend_interface.cc 中的邮箱配置:

email_config_.smtp_server = "smtp.163.com";
email_config_.smtp_port = 587;
email_config_.username = "your_email@163.com";
email_config_.password = "your_authorization_code";

注意

  • 使用163邮箱需要开启SMTP服务并获取授权码
  • 授权码不是登录密码
  • 其他邮箱服务商配置类似

数据文件说明

  • users.csv:用户数据文件(自动生成)
  • 用户名/ 目录:用户题目历史记录
  • 日志输出到控制台

常见问题

Q: 编译时找不到Qt库

A: 确保已安装Qt开发包并设置正确的CMAKE_PREFIX_PATH

cmake -DCMAKE_PREFIX_PATH=/path/to/qt ..

Q: 邮件发送失败

A:

  1. 检查邮箱配置是否正确
  2. 确认网络连接正常
  3. 检查防火墙设置

Q: 题目生成失败

A:

  1. 检查是否有写入权限
  2. 确认磁盘空间充足

Q: 程序崩溃

A:

  1. 检查依赖库版本兼容性
  2. 查看控制台输出的错误信息

开发指南

添加新的题目类型

  1. problem_generator.h 中定义新的生成器类
  2. 实现 GenerateProblem() 方法
  3. 在工厂类中注册新的生成器

扩展用户界面

  1. 继承 BaseWidget 创建新的界面组件
  2. main_window.h 中声明新的界面
  3. main_window.cc 中管理界面切换

数学学习考试系统 - 系统框架和设计说明

系统架构概览

graph TB
    subgraph Frontend[<b>前端界面层</b>]
        A1[LoginWidget]
        A2[SelectionWidget]
        A3[QuestionWidget]
        A4[ResultWidget]
    end

    subgraph Interface[<b>接口适配层</b>]
        B1[BackendInterface]
        B2[BackendImpl]
    end

    subgraph Business[<b>业务逻辑层</b>]
        C1[ExamSystem]
    end

    subgraph Services[<b>服务组件层</b>]
        D1[ProblemGenerator]
        D2[UserManager]
        D3[FileManager]
        D4[DuplicateChecker]
    end

    A1 & A2 & A3 & A4 --> B1
    B1 --> B2
    B2 --> C1
    C1 --> D1 & D2 & D3 & D4
    
    classDef frontend fill:#e1f5fe,stroke:#01579b,stroke-width:2px
    classDef interface fill:#f3e5f5,stroke:#4a148c,stroke-width:2px
    classDef business fill:#e8f5e8,stroke:#1b5e20,stroke-width:2px
    classDef services fill:#fff3e0,stroke:#e65100,stroke-width:2px

    class A1,A2,A3,A4 frontend
    class B1,B2 interface
    class C1 business
    class D1,D2,D3,D4 services

详细架构设计

1. 前端界面层 (Frontend Layer)

1.1 界面组件架构

MainWindow (主窗口容器)
    ├── QStackedWidget (页面堆栈管理器)
    │   ├── LoginWidget (登录注册界面)
    │   ├── SelectionWidget (难度选择界面)
    │   ├── QuestionWidget (答题界面)
    │   └── ResultWidget (成绩显示界面)
    └── ChangePasswordDialog (修改密码对话框)

1.2 界面状态流转

登录界面 → 选择界面 → 答题界面 → 结果界面
    ↑         │          │         │
    └─────────┴──────────┴─────────┘
         (重新开始/退出登录)

1.3 前端设计模式

  • 组合模式: BaseWidget作为所有界面的基类
  • 观察者模式: Qt信号槽机制实现组件间通信
  • 状态模式: 通过QStackedWidget管理不同界面状态

2. 接口适配层 (Interface Layer)

2.1 接口设计原则

// 抽象接口 - 面向抽象编程
class BackendInterface {
public:
    virtual bool UserLogin(...) = 0;
    virtual bool UserRegister(...) = 0;
    virtual std::vector<QuestionInfo> GenerateQuestions(...) = 0;
    // ... 其他接口方法
};

// 具体实现 - 委托给业务层
class BackendImpl : public BackendInterface {
private:
    std::unique_ptr<ExamSystem> exam_system_;
    // 实现所有接口方法委托给exam_system_
};

2.2 数据转换职责

  • 将前端数据结构转换为后端可处理格式
  • 将后端返回数据转换为前端显示格式
  • 处理验证码管理和邮件发送

3. 业务逻辑层 (Business Layer)

3.1 ExamSystem 核心控制器

class ExamSystem {
    // 用户会话管理
    std::map<std::string, UserSession> user_sessions_;
    
    // 业务组件
    DuplicateChecker duplicate_checker_;
    SystemConfig config_;
    
    // 核心业务方法
    LoginResponse Login(const LoginRequest& request);
    GenerateResponse GenerateProblems(const GenerateRequest& request);
    // ... 其他业务方法
};

3.2 用户会话管理

struct UserSession {
    std::unique_ptr<ProblemGenerator> generator;  // 题目生成器
    std::string current_type;                     // 当前类型
    bool history_loaded = false;                  // 历史加载状态
};

4. 服务组件层 (Service Components)

4.1 题目生成子系统

ProblemGenerator (抽象基类)
    ├── PrimarySchoolGenerator (小学生成器)
    ├── MiddleSchoolGenerator (初中生成器)
    └── HighSchoolGenerator (高中生成器)
    
ProblemGeneratorFactory (工厂类)

题目生成策略:

  • 小学: 确保运算结果不为负数
  • 初中: 包含平方(²)和开根号(√)运算
  • 高中: 包含三角函数(sin/cos/tan)运算

4.2 重复检查子系统

class DuplicateChecker {
private:
    std::map<std::string, std::vector<std::string>> user_problems_;
    std::set<std::string> loaded_users_;
    
public:
    bool CheckDuplicate(const std::string& username, const std::string& problem);
    void LoadUserHistory(const std::string& username);
};

4.3 文件管理子系统

class FileManager {
public:
    // 用户目录管理
    static bool CreateUserDirectory(const std::string& username);
    
    // 题目持久化
    static bool SaveProblemsToFile(const std::string& username, 
                                  const std::vector<std::string>& problems);
    
    // 历史记录加载
    static std::vector<std::string> LoadUserHistoryProblems(const std::string& username);
};

4.4 邮件服务子系统

class EmailService {
private:
    EmailConfig config_;
    
public:
    bool SendVerificationCode(const std::string& email, const std::string& code);
    bool SendEmailViaCurl(const std::string& recipient,
                         const std::string& subject,
                         const std::string& body);
};

核心设计模式详解

1. 分层架构模式 (Layered Architecture)

表现层 (Presentation) → 应用层 (Application) → 领域层 (Domain) → 基础设施层 (Infrastructure)
    前端界面                接口适配             业务逻辑           文件/邮件/日志

2. 工厂模式 (Factory Pattern)

// 题目生成器工厂
std::unique_ptr<ProblemGenerator> ProblemGeneratorFactory::CreateGenerator(
    const std::string& type) {
    if (type == "小学") return std::make_unique<PrimarySchoolGenerator>();
    if (type == "初中") return std::make_unique<MiddleSchoolGenerator>();
    if (type == "高中") return std::make_unique<HighSchoolGenerator>();
    return nullptr;
}

3. 策略模式 (Strategy Pattern)

// 不同难度的题目生成策略
class ProblemGenerator {
public:
    virtual std::string GenerateProblem() = 0;  // 策略接口
};

class PrimarySchoolGenerator : public ProblemGenerator {
    std::string GenerateProblem() override {
        // 小学题目生成策略
    }
};

4. 门面模式 (Facade Pattern)

// BackendImpl作为门面简化复杂后端系统的使用
class BackendImpl : public BackendInterface {
public:
    bool UserLogin(...) override {
        // 内部协调多个子系统完成登录
        return exam_system_->Login(request).success;
    }
};

数据流设计

1. 用户登录数据流

1. 用户输入 → LoginWidget → BackendInterface → BackendImpl
2. BackendImpl → ExamSystem → 用户验证 → 创建会话
3. 返回结果 → 前端界面更新

2. 题目生成数据流

1. 用户选择 → SelectionWidget → GenerateQuestions请求
2. BackendImpl → ExamSystem → ProblemGeneratorFactory
3. 生成题目 → DuplicateChecker查重 → 保存到文件
4. 返回题目列表 → 前端显示

3. 答案提交数据流

1. 用户答案 → QuestionWidget → SubmitAnswers请求
2. BackendImpl → 答案验证 → 成绩计算
3. 返回TestResult → ResultWidget显示

持久化设计

1. 用户数据存储

# users.csv 格式
username,password,user_type,email
zhangsan1,123,小学,zhangsan1@example.com
lisi1,123,初中,lisi1@example.com

2. 题目历史存储

用户名目录/
    ├── 2024-01-15-10-30-25.txt
    ├── 2024-01-16-14-20-10.txt
    └── ...

3. 会话状态管理

  • 内存中维护用户会话
  • 验证码有时效性(5分钟)
  • 题目缓存提高性能

数学学习考试系统 - 类说明

前端界面类

BaseWidget (基础窗口组件)

文件: base_widget.h, base_widget.cc

  • 职责: 所有前端窗口组件的基类,提供公共功能和成员变量
  • 继承关系: 继承自 QWidget
  • 主要成员:
    • backend: 指向后端接口的指针
  • 主要方法:
    • BaseWidget(): 构造函数,初始化后端接口
    • showMessage(): 显示消息对话框的公共方法
    • setupUI(): 纯虚方法,子类必须实现的界面初始化方法

LoginWidget (登录注册界面)

文件: login_widget.h, login_widget.cc

  • 职责: 处理用户登录和注册功能
  • 继承关系: 继承自 BaseWidget
  • 主要成员:
    • loginPage, registerPage: 登录和注册页面组件
    • stackedWidget: 页面堆栈,用于切换登录/注册页面
    • 各种输入框和按钮组件
  • 主要方法:
    • onLoginClicked(): 处理登录按钮点击
    • onRegisterClicked(): 处理注册按钮点击
    • onSendCodeClicked(): 发送验证码
    • validatePassword(): 验证密码格式

SelectionWidget (难度选择界面)

文件: selection_widget.h, selection_widget.cc

  • 职责: 提供难度选择和系统菜单功能
  • 继承关系: 继承自 BaseWidget
  • 主要成员:
    • primaryBtn, juniorBtn, seniorBtn: 难度选择按钮
    • countSpinBox: 题目数量选择框
    • menuBar: 菜单栏,包含用户和系统菜单
  • 主要方法:
    • onPrimaryClicked(): 选择小学难度
    • onJuniorClicked(): 选择初中难度
    • onSeniorClicked(): 选择高中难度
    • onStartClicked(): 开始测试
    • onChangePasswordClicked(): 修改密码

QuestionWidget (答题界面)

文件: question_widget.h, question_widget.cc

  • 职责: 显示题目和选项,处理用户答题过程
  • 继承关系: 继承自 BaseWidget
  • 主要成员:
    • questionLabel: 题目显示标签
    • optionButtons[4]: 选项单选按钮
    • progressLabel: 进度显示标签
    • questions_: 题目列表
    • user_answers_: 用户答案列表
  • 主要方法:
    • startTest(): 开始测试
    • showQuestion(): 显示指定题目
    • onNextClicked(): 下一题
    • onPrevClicked(): 上一题
    • onSubmitClicked(): 提交答案

ResultWidget (成绩显示界面)

文件: result_widget.h, result_widget.cc

  • 职责: 显示测试结果和提供后续操作
  • 继承关系: 继承自 BaseWidget
  • 主要成员:
    • scoreLabel: 分数显示标签
    • detailLabel: 详细信息标签
    • restartBtn, exitBtn: 操作按钮
  • 主要方法:
    • showResult(): 显示测试结果
    • 信号: restartTest(), exitTest()

MainWindow (主窗口)

文件: main_window.h, main_window.cc

  • 职责: 管理所有界面的切换和协调
  • 继承关系: 继承自 QMainWindow
  • 主要成员:
    • stackedWidget: 堆栈窗口,管理所有界面
    • 各个界面组件的指针
  • 主要方法:
    • showSelection(): 显示选择界面
    • showQuestions(): 显示答题界面
    • showResult(): 显示结果界面
    • logout(): 用户登出

ChangePasswordDialog (修改密码对话框)

文件: change_password_dialog.h, change_password_dialog.cc

  • 职责: 处理用户修改密码功能
  • 继承关系: 继承自 QDialog
  • 主要方法:
    • onChangePasswordClicked(): 确认修改密码
    • validatePassword(): 实时验证密码格式

后端核心类

ExamSystem (考试系统核心)

文件: exam_system.h, exam_system.cc

  • 职责: 系统的核心控制层,协调所有业务逻辑
  • 主要成员:
    • config_: 系统配置信息
    • user_sessions_: 用户会话映射表
    • duplicate_checker_: 重复检查器实例
  • 主要方法:
    • Login(): 用户登录
    • Logout(): 用户登出
    • GenerateProblems(): 生成题目
    • ChangePassword(): 修改密码
    • CalculateAnswer(): 计算表达式答案

ProblemGenerator (题目生成器基类)

文件: problem_generator.h, problem_generator.cc

  • 职责: 定义题目生成器的统一接口
  • 主要方法:
    • GenerateProblem(): 生成单个题目(纯虚)
    • GetCurrentType(): 获取生成器类型(纯虚)
    • ValidateProblem(): 验证题目有效性(纯虚)

PrimarySchoolGenerator (小学题目生成器)

职责: 生成小学难度的数学题目

  • 特点: 基础四则运算,确保结果不为负数
  • 主要方法:
    • GenerateNonNegativeExpression(): 生成非负表达式

MiddleSchoolGenerator (初中题目生成器)

职责: 生成初中难度的数学题目

  • 特点: 包含平方和开根号运算
  • 主要方法:
    • GenerateSquareOrRoot(): 生成平方或开根号表达式

HighSchoolGenerator (高中题目生成器)

职责: 生成高中难度的数学题目

  • 特点: 包含三角函数运算
  • 主要方法:
    • GenerateTrigonometricFunction(): 生成三角函数表达式

ProblemGeneratorFactory (生成器工厂)

职责: 创建指定类型的题目生成器

  • 主要方法:
    • CreateGenerator(): 根据类型创建生成器实例

DuplicateChecker (重复检查器)

文件: duplicate_checker.h, duplicate_checker.cc

  • 职责: 管理用户已生成的题目,防止重复
  • 主要成员:
    • user_problems_: 用户题目映射表
    • loaded_users_: 已加载历史的用户集合
  • 主要方法:
    • AddProblem(): 添加题目到用户记录
    • CheckDuplicate(): 检查题目是否重复
    • LoadUserHistory(): 加载用户历史题目

FileManager (文件管理器)

文件: file_manager.h, file_manager.cc

  • 职责: 负责文件的创建、保存和加载操作
  • 主要方法:
    • CreateUserDirectory(): 创建用户目录
    • SaveProblemsToFile(): 保存题目到文件
    • LoadUserHistoryProblems(): 加载用户历史题目

Logger (日志记录器)

文件: logger.h, logger.cc

  • 职责: 提供分级日志记录功能
  • 日志级别: DEBUG, INFO, WARNING, ERROR
  • 主要方法:
    • Log(): 记录日志
    • Debug(), Info(), Warning(), Error(): 便捷方法

InputValidator (输入验证器)

文件: input_validator.h, input_validator.cc

  • 职责: 提供各种输入数据的验证功能
  • 主要方法:
    • ValidateUsername(): 验证用户名格式
    • ValidatePassword(): 验证密码格式
    • ValidateUserType(): 验证用户类型

接口和数据类

BackendInterface (后端接口)

文件: backend_interface.h

  • 职责: 定义前后端通信的抽象接口
  • 主要方法:
    • UserLogin(), UserRegister(): 用户认证
    • GenerateQuestions(): 生成题目
    • SubmitAnswers(): 提交答案
    • SendVerificationCode(): 发送验证码

BackendImpl (后端实现)

文件: backend_interface.cc

  • 职责: 实现BackendInterface具体处理后端逻辑
  • 主要成员:
    • exam_system_: ExamSystem核心实例
    • verification_codes_: 验证码管理
    • user_questions_: 用户题目缓存
  • 主要方法:
    • GenerateOptions(): 生成选择题选项
    • SendEmailViaCurl(): 通过libcurl发送邮件

数据结构

UserInfo (用户信息)

struct UserInfo {
  std::string username;
  std::string password;
  std::string user_type;  // 小学/初中/高中
  std::string email;
};

QuestionInfo (题目信息)

struct QuestionInfo {
    int id;
    std::string content;
    std::vector<std::string> options;
    int correct_answer;  // 0-3 对应ABCD
};

TestResult (测试结果)

struct TestResult {
    int total_questions;
    int correct_answers;
    double score;
    std::string difficulty;
};

VerificationCode (验证码信息)

struct VerificationCode {
    std::string code;
    std::time_t generate_time;
    std::string email;
};

设计模式应用

  1. 工厂模式: ProblemGeneratorFactory 创建不同类型的题目生成器
  2. 策略模式: 不同难度的题目生成器实现相同的接口
  3. 观察者模式: Qt的信号槽机制实现组件间通信
  4. 单例模式: Logger 提供全局日志服务
  5. 门面模式: BackendImpl 封装复杂后端逻辑,提供简单接口

数据流说明

用户操作 → 前端界面 → BackendInterface → BackendImpl → ExamSystem
    ↓                                                            ↓
界面更新 ←   信号槽     ←   返回结果   ←   业务处理   ←   题目生成器

这个类结构体现了清晰的分层架构,前端负责用户交互,后端处理业务逻辑,接口层负责通信协调,使得系统具有良好的可维护性和可扩展性。