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
使用指南
首次使用
-
启动程序:运行编译后的可执行文件
-
注册账号:
- 点击"注册新账号"
- 输入邮箱地址,点击"发送验证码"
- 检查邮箱获取验证码并填写
- 设置用户名和密码(6-10位,包含大小写字母和数字)
- 点击"注册"
-
登录系统:
- 输入用户名和密码
- 点击"登录"
开始学习
-
选择难度:
- 小学:基础四则运算
- 初中:包含平方、开根号
- 高中:包含三角函数
-
设置题目数量:通过数字选择框设置(5-50题)
-
开始测试:点击"开始测试"进入答题界面
答题流程
- 阅读题目:仔细阅读题目内容
- 选择答案:从A、B、C、D四个选项中选择
- 导航题目:
- 使用"上一题"、"下一题"按钮切换
- 最后一题显示"提交试卷"按钮
- 提交答案:完成所有题目后提交
查看结果
- 系统自动批改并显示得分
- 查看正确题目数量和总题目数
- 可选择"继续做题"或"退出"
配置说明
邮件服务配置
如需使用邮箱验证功能,请编辑 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:
- 检查邮箱配置是否正确
- 确认网络连接正常
- 检查防火墙设置
Q: 题目生成失败
A:
- 检查是否有写入权限
- 确认磁盘空间充足
Q: 程序崩溃
A:
- 检查依赖库版本兼容性
- 查看控制台输出的错误信息
开发指南
添加新的题目类型
- 在
problem_generator.h中定义新的生成器类 - 实现
GenerateProblem()方法 - 在工厂类中注册新的生成器
扩展用户界面
- 继承
BaseWidget创建新的界面组件 - 在
main_window.h中声明新的界面 - 在
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;
};
设计模式应用
- 工厂模式:
ProblemGeneratorFactory创建不同类型的题目生成器 - 策略模式: 不同难度的题目生成器实现相同的接口
- 观察者模式: Qt的信号槽机制实现组件间通信
- 单例模式:
Logger提供全局日志服务 - 门面模式:
BackendImpl封装复杂后端逻辑,提供简单接口
数据流说明
用户操作 → 前端界面 → BackendInterface → BackendImpl → ExamSystem
↓ ↓
界面更新 ← 信号槽 ← 返回结果 ← 业务处理 ← 题目生成器
这个类结构体现了清晰的分层架构,前端负责用户交互,后端处理业务逻辑,接口层负责通信协调,使得系统具有良好的可维护性和可扩展性。