1. 项目概述:全栈考试系统技术解析
这个基于SpringBoot+Vue3+MyBatis的全栈考试系统,是我去年为某教育机构开发的核心项目。系统采用经典的前后端分离架构,后端使用SpringBoot 2.7提供RESTful API,前端用Vue3+TypeScript构建响应式界面,数据持久层采用MyBatis-Plus增强MySQL操作。整个系统从登录认证到试卷批改完整实现了在线考试全流程,高峰期可支持3000+考生同时在线答题。
提示:项目源码已去除敏感业务逻辑,保留核心架构设计和技术实现,可直接用于学习或二次开发
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术栈选型与架构设计
2.1 后端技术栈深度解析
SpringBoot 2.7.x 作为基础框架,主要基于以下考量:
- 内嵌Tomcat简化部署(实测启动时间<3s)
- 自动配置机制大幅减少XML配置
- 完善的生态体系(整合MyBatis、Security等只需添加starter)
关键依赖示例:
xml复制<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3</version>
</dependency>
2.2 前端技术栈选型依据
选择Vue3+TypeScript组合主要因为:
- Composition API更适合复杂业务逻辑组织
- Vite构建速度比Webpack快5-8倍(实测冷启动<1s)
- TypeScript类型检查减少35%以上的运行时错误
典型组件结构:
typescript复制// ExamPaper.vue
<script setup lang="ts">
const paper = ref<IPaper>({
id: '',
questions: []
})
interface IQuestion {
id: string
type: 'single' | 'multi'
content: string
options: string[]
}
</script>
2.3 数据库设计要点
MySQL 8.0表结构设计遵循:
- 所有表使用InnoDB引擎+utf8mb4字符集
- 核心表添加全文索引(如试题内容搜索)
- 合理使用JSON类型存储动态结构数据
考试核心表ER图:
code复制[考生表] --1:n--> [考试记录表]
|
n:n
[试题表] <--n:n--> [试卷表]
3. 核心功能实现细节
3.1 考试业务状态机设计
采用状态模式实现考试流程控制:
java复制public interface ExamState {
void start(ExamContext context);
void submit(ExamContext context);
void timeout(ExamContext context);
}
// 具体状态实现
public class ReadyState implements ExamState {
@Override
public void start(ExamContext ctx) {
ctx.changeState(new OngoingState());
// 记录开始时间等逻辑
}
}
3.2 实时防作弊方案
实现三重防护机制:
- 窗口焦点检测(通过Page Visibility API)
- 随机题目顺序+选项乱序
- 行为异常检测算法:
python复制# 伪代码示例
def detect_cheating(actions):
avg_interval = calculate_interval(actions)
if avg_interval < threshold:
trigger_warning()
3.3 高性能批改系统
客观题采用BitMap快速比对:
java复制// 使用BitSet存储正确答案模板
BitSet answerPattern = BitSet.valueOf(new long[]{0b1010});
// 考生答案比对
boolean isCorrect = answerPattern.equals(userAnswer);
主观题使用相似度算法:
java复制// 使用HanLP计算文本相似度
double similarity = HanLP.extractKeyword(standardAnswer, 5)
.stream()
.filter(kw -> userAnswer.contains(kw))
.count() / 5.0;
4. 关键问题解决方案
4.1 高并发考试提交
采用三级缓冲策略:
- 前端本地存储未提交答案
- Redis缓存最近5分钟操作
- MySQL最终持久化
java复制@Transactional
public void submitAnswer(AnswerDTO dto) {
// 1. 写入Redis
redisTemplate.opsForList().rightPush(
"exam:"+dto.getExamId()+":answers",
dto
);
// 2. 异步落库
asyncService.saveAnswerAsync(dto);
}
4.2 试卷动态生成算法
基于遗传算法的组卷实现:
python复制def generate_paper(requirements):
population = init_population()
for _ in range(GENERATIONS):
fitness = evaluate(population)
parents = selection(population, fitness)
offspring = crossover(parents)
population = mutation(offspring)
return best_individual(population)
4.3 跨端渲染一致性
使用共享TypeScript类型定义:
typescript复制// shared/types.ts
export interface Question {
id: string
type: 'single' | 'multi' | 'essay'
content: string
options?: Option[]
}
// 前后端共用该类型
5. 性能优化实战记录
5.1 MySQL查询优化
慢查询优化案例:
sql复制-- 优化前(执行时间>2s)
SELECT * FROM exam_record
WHERE user_id = ? AND status = 1
ORDER BY submit_time DESC;
-- 优化后(添加复合索引)
ALTER TABLE exam_record ADD INDEX idx_user_status (user_id, status);
5.2 MyBatis二级缓存配置
xml复制<settings>
<setting name="cacheEnabled" value="true"/>
</settings>
<cache eviction="LRU"
flushInterval="60000"
size="512"
readOnly="true"/>
5.3 Vue组件性能提升
使用v-memo优化列表渲染:
vue复制<template>
<div v-for="q in questions" v-memo="[q.id]">
<QuestionItem :question="q"/>
</div>
</template>
6. 安全防护方案
6.1 JWT增强方案
自定义claim增加设备指纹:
java复制String fingerprint = request.getHeader("User-[Agent](https://taotoken.net?utm_source=general)")
+ request.getRemoteAddr();
JWT.create()
.withClaim("fp", DigestUtils.md5Hex(fingerprint))
.sign(algorithm);
6.2 SQL注入防护
MyBatis参数严格校验:
java复制@Select("SELECT * FROM user WHERE username = #{username}")
User findByUsername(@Param("username")
@ValidUsername String username);
6.3 XSS防御策略
前端统一过滤:
typescript复制const sanitize = (html: string) => {
return html.replace(/<script.*?>.*?<\/script>/gi, '');
}
7. 部署与监控方案
7.1 Docker-Compose部署
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
backend:
build: ./server
ports:
- "8080:8080"
depends_on:
- mysql
7.2 Prometheus监控配置
SpringBoot Actuator集成:
properties复制management.endpoints.web.exposure.include=*
management.metrics.export.prometheus.enabled=true
7.3 ELK日志方案
Logstash配置示例:
ruby复制input {
tcp {
port => 5044
codec => json_lines
}
}
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level}" }
}
}
8. 典型问题排查实录
8.1 MyBatis懒加载异常
现象:JSON序列化时报LazyInitializationException
解决方案:
java复制@JsonIgnoreProperties({"handler", "fieldHandler"})
public class Exam {
@JsonIgnore
private List<Question> questions;
}
8.2 Vue3内存泄漏
使用DevTools排查:
javascript复制onBeforeUnmount(() => {
clearInterval(timer)
eventBus.off('update')
})
8.3 MySQL连接池耗尽
调整HikariCP配置:
properties复制spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.leak-detection-threshold=30000
9. 扩展功能实现思路
9.1 智能监考系统
基于TensorFlow.js的行为分析:
javascript复制const model = await tf.loadGraphModel('proctoring-model.json');
canvas.addEventListener('mousemove', (e) => {
const input = preprocess(e);
const prediction = model.predict(input);
if (prediction > threshold) {
alert('异常行为检测!');
}
});
9.2 语音答题支持
Web Speech API集成:
typescript复制const recognition = new webkitSpeechRecognition();
recognition.onresult = (event) => {
const transcript = event.results[0][0].transcript;
answer.value = transcript;
};
9.3 区块链存证
Hyperledger Fabric集成方案:
go复制func (s *SmartContract) RecordScore(ctx contractapi.TransactionContextInterface, scoreData string) error {
return ctx.GetStub().PutState("SCORE_"+time.Now().String(), []byte(scoreData))
}
在项目开发过程中,最大的教训是要提前做好压力测试。我们曾在模拟考试时遭遇服务器崩溃,后来通过以下改进解决:
- 使用JMeter提前模拟2000并发
- 引入Redis缓存热点数据
- 数据库查询全部添加EXPLAIN分析
- 前端增加请求队列控制
对于想要学习全栈开发的同学,这个项目涵盖了90%的典型业务场景。建议先从MyBatis基础用法开始,逐步深入到动态SQL和缓存机制,最后再研究SpringBoot与Vue3的深度整合技巧。
