1. 项目背景与需求分析
在数字化教育快速发展的今天,传统线下考试模式已经无法满足现代教学需求。我们团队最近完成了一个基于ThinkPHP和Laravel双框架的学生在线训练课程考试系统,这个项目源于某高校对在线考试平台的迫切需求。
这个系统需要解决几个核心问题:
- 支持大规模在线考试(500人以上同时在线)
- 实现智能组卷和自动评分
- 提供完善的防作弊机制
- 具备良好的系统稳定性
- 支持多种题型(选择、填空、编程题等)
经过技术选型评估,我们最终决定采用ThinkPHP 6.0作为后台管理框架,Laravel 8.0作为API服务框架。这种混合架构既发挥了ThinkPHP在后台管理开发上的高效性,又利用了Laravel在API开发上的优势。
2. 系统架构设计
2.1 整体架构
系统采用前后端分离架构:
- 前端:Vue.js + Element UI
- 后端API:Laravel 8.0
- 后台管理:ThinkPHP 6.0
- 数据库:MySQL 8.0
- 缓存:Redis 6.2
- 文件存储:阿里云OSS
这种架构设计主要考虑以下几点:
- 前后端分离便于团队协作开发
- 双框架各取所长
- 分布式部署提高系统可用性
2.2 数据库设计
核心表结构设计:
sql复制CREATE TABLE `exams` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
`title` varchar(255) NOT NULL COMMENT '考试名称',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime NOT NULL COMMENT '结束时间',
`duration` int NOT NULL COMMENT '考试时长(分钟)',
`status` tinyint NOT NULL DEFAULT '0' COMMENT '状态',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
特别注意:datetime类型存储时间数据时,需要考虑时区问题。我们统一使用UTC时间存储,前端根据用户时区进行转换。
3. 核心功能实现
3.1 智能组卷模块
采用策略模式实现多种组卷方式:
php复制interface PaperGenerationStrategy {
public function generate(Exam $exam): Paper;
}
class RandomStrategy implements PaperGenerationStrategy {
// 随机组卷实现
}
class FixedStrategy implements PaperGenerationStrategy {
// 固定试卷实现
}
class DifficultyStrategy implements PaperGenerationStrategy {
// 按难度组卷实现
}
组卷流程:
- 教师设置组卷策略和参数
- 系统根据策略从题库筛选题目
- 生成试卷并缓存
- 学生考试时获取对应试卷
3.2 在线考试模块
考试过程状态管理是关键:
php复制class ExamService {
public function startExam($userId, $examId) {
// 检查考试资格
// 初始化考试会话
// 记录开始时间
// 返回试卷内容
}
public function submitAnswer($sessionId, $answers) {
// 验证提交时间
// 保存答案
// 计算已用时间
// 返回剩余时间
}
}
重要提示:考试会话数据需要同时存储在Redis和MySQL中,Redis用于快速访问,MySQL用于持久化。
3.3 防作弊机制
我们实现了多层次的防作弊方案:
- 页面防复制粘贴
- 随机题目顺序
- 页面活动监控
- 异常行为检测
- 人脸识别验证
防作弊检测代码示例:
javascript复制// 监听页面失去焦点事件
document.addEventListener('visibilitychange', function() {
if(document.hidden) {
examService.recordWarning('页面切换');
}
});
// 监听右键菜单
document.addEventListener('contextmenu', function(e) {
e.preventDefault();
examService.recordWarning('右键菜单');
});
4. 性能优化方案
4.1 高并发处理
考试系统面临的最大挑战是高并发场景。我们采用以下优化措施:
-
数据库优化:
- 使用读写分离
- 合理设计索引
- 避免大事务
-
缓存策略:
php复制public function getExamQuestions($examId) { $key = "exam:questions:{$examId}"; if($questions = Redis::get($key)) { return json_decode($questions, true); } $questions = DB::table('exam_questions') ->where('exam_id', $examId) ->get() ->toArray(); Redis::setex($key, 3600, json_encode($questions)); return $questions; } -
队列处理:
- 使用Laravel队列处理耗时操作
- 实现异步日志记录
- 批量处理答案提交
4.2 前端性能优化
- 试题数据分页加载
- 答案自动本地保存
- 减少DOM操作
- 使用Web Worker处理复杂计算
5. 系统部署方案
5.1 服务器配置
我们建议的最低服务器配置:
- Web服务器:4核8G × 2台(负载均衡)
- 数据库服务器:8核16G(主从配置)
- Redis服务器:4核8G
- 文件服务器:按需扩展
5.2 部署流程
使用Docker-compose部署示例:
yaml复制version: '3'
services:
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8000:8000"
volumes:
- .:/var/www/html
depends_on:
- redis
- mysql
redis:
image: redis:6.2
ports:
- "6379:6379"
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: exam_system
ports:
- "3306:3306"
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
6. 常见问题与解决方案
6.1 框架相关问题
Q: Laravel和ThinkPHP如何共享Session?
A: 我们采用Redis作为共享Session存储:
php复制// Laravel配置
SESSION_DRIVER=redis
SESSION_CONNECTION=default
// ThinkPHP配置
'session' => [
'type' => 'redis',
'host' => '127.0.0.1',
'port' => 6379,
'prefix' => 'phpsess_',
'expire' => 1440,
]
Q: 两个框架的ORM如何协同工作?
A: 我们保持各自框架的ORM独立,通过服务层进行数据交互:
php复制class ExamService {
private $laravelExamRepo;
private $thinkUserRepo;
public function __construct() {
$this->laravelExamRepo = new LaravelExamRepository();
$this->thinkUserRepo = new ThinkUserRepository();
}
public function getExamList($userId) {
$user = $this->thinkUserRepo->find($userId);
return $this->laravelExamRepo->getByDepartment($user->department_id);
}
}
6.2 性能问题
Q: 考试提交高峰期系统响应变慢怎么办?
A: 我们采取的优化措施:
- 增加答案提交队列消费者数量
- 使用批量插入代替单条插入
- 临时增加服务器资源
- 客户端实现提交失败重试机制
Q: 如何优化题库查询性能?
A: 我们的解决方案:
- 使用Elasticsearch建立题库索引
- 实现多级缓存(Redis+内存缓存)
- 预生成常用查询结果
7. 项目总结与经验分享
在实际开发过程中,我们积累了一些宝贵经验:
-
框架选择:
- ThinkPHP更适合快速开发后台管理系统
- Laravel更适合构建稳健的API服务
- 两者结合可以发挥各自优势
-
数据库设计:
- 考试系统的核心表不宜过多关联查询
- 适当冗余可以提高查询性能
- 合理使用触发器处理数据一致性
-
安全考虑:
- 所有API请求必须验证签名
- 敏感操作需要二次验证
- 定期进行安全扫描
-
监控体系:
- 实现全链路日志追踪
- 设置关键指标告警
- 定期进行压力测试
这个项目从设计到上线历时6个月,目前已经稳定运行1年多,支持了学校3万多名学生的在线考试需求。最大的收获是认识到合理的架构设计对系统稳定性的重要性,特别是在高并发场景下,前期的设计决策会直接影响后期的运维成本。
