1. 项目概述:在线考试与学习平台的架构设计
这个基于SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0的Java Web在线考试系统,是我在2022年为一个编程培训机构开发的核心教学平台。系统主要解决三个痛点:一是传统纸质考试效率低下,二是学员缺乏实时学习反馈,三是师生互动渠道单一。
平台采用前后端分离架构,后端使用SpringBoot2提供RESTful API,前端用Vue3构建响应式界面,数据层采用MyBatis-Plus简化CRUD操作,MySQL8.0负责数据存储。这种技术组合在当前Java Web开发中属于主流方案,既能保证系统性能,又便于团队协作开发。
提示:选择MySQL8.0而非5.7版本,主要是看中其JSON字段支持和窗口函数等特性,这对考试题目存储和成绩分析报表生成非常有用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心技术栈解析
2.1 SpringBoot2后端框架
我们选用SpringBoot2.7.3版本(当前最新稳定版),相比旧版主要优化了:
- 启动速度提升30%(实测空项目启动仅1.8秒)
- 内存占用减少约20%
- 更好的GraalVM原生镜像支持
关键配置示例:
java复制@SpringBootApplication
@EnableTransactionManagement // 启用注解式事务
@MapperScan("com.exam.mapper") // MyBatis-Plus扫描
public class ExamApplication {
public static void main(String[] args) {
SpringApplication.run(ExamApplication.class, args);
}
}
2.2 Vue3前端架构
前端采用Vue3+TypeScript+Pinia的组合,相比Vue2主要优势:
- Composition API使代码组织更灵活
- 性能提升约40%(虚拟DOM重写)
- 更好的TypeScript支持
典型组件结构:
javascript复制<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
</script>
<template>
<button @click="count++">Clicked {{ count }} times</button>
</template>
2.3 MyBatis-Plus数据层
MyBatis-Plus 3.5.2提供的主要便利:
- 自动生成基础CRUD代码
- 强大的条件构造器
- 分页插件零配置
实体类注解示例:
java复制@Data
@TableName("exam_paper")
public class ExamPaper {
@TableId(type = IdType.AUTO)
private Long id;
private String title;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
}
3. 核心功能实现细节
3.1 在线考试模块设计
考试流程采用状态机模式:
- 未开始 → 2. 进行中 → 3. 已提交 → 4. 已批改
关键数据库表:
sql复制CREATE TABLE `exam_session` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`paper_id` bigint NOT NULL,
`start_time` datetime DEFAULT NULL,
`submit_time` datetime DEFAULT NULL,
`status` tinyint NOT NULL COMMENT '0-未开始 1-进行中 2-已提交 3-已批改',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
3.2 实时交流功能实现
使用WebSocket实现三种消息类型:
- 全局公告(管理员→全体)
- 私聊消息(用户→用户)
- 题目讨论(关联具体试题)
前端关键代码:
javascript复制const socket = new WebSocket('wss://yourdomain.com/ws')
socket.onmessage = (event) => {
const msg = JSON.parse(event.data)
switch(msg.type) {
case 'ANNOUNCEMENT':
showAnnouncement(msg.content)
break
case 'PRIVATE':
addPrivateMessage(msg)
break
}
}
4. 部署与性能优化
4.1 生产环境部署方案
推荐使用Docker Compose部署:
yaml复制version: '3'
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: yourpassword
volumes:
- mysql_data:/var/lib/mysql
backend:
build: ./backend
ports:
- "8080:8080"
depends_on:
- mysql
frontend:
build: ./frontend
ports:
- "80:80"
4.2 性能优化实践
-
数据库层面:
- 为常用查询字段添加索引
- 使用EXPLAIN分析慢查询
- 配置合理的连接池参数
-
后端层面:
- 启用Spring Cache
- 使用@Async处理耗时操作
- 配置合理的线程池
-
前端层面:
- 组件懒加载
- 路由懒加载
- 使用keep-alive缓存组件
5. 常见问题解决方案
5.1 MyBatis-Plus租户隔离问题
当需要临时取消租户过滤时:
java复制// 方法一:使用ignore方法
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>()
.ignore(TenantLineInnerInterceptor.class)
.eq(User::getStatus, 1);
// 方法二:使用@InterceptorIgnore注解
@InterceptorIgnore(tenantLine = "true")
public List<User> selectAll() {
return mapper.selectList(null);
}
5.2 Vue3 Edge浏览器兼容性问题
针对Edge浏览器最小化按钮异常,解决方案:
- 检查CSS样式是否被浏览器默认样式覆盖
- 添加特定前缀:
css复制/* 针对Edge的样式修复 */
@supports (-ms-ime-align:auto) {
.minimize-btn {
padding: 2px 8px !important;
}
}
5.3 考试并发提交处理
使用Redis分布式锁防止重复提交:
java复制public boolean submitExam(Long examId, Long userId) {
String lockKey = "exam:submit:" + examId + ":" + userId;
try {
// 尝试获取锁,有效期30秒
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 30, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
// 执行业务逻辑
return examService.doSubmit(examId, userId);
}
throw new RuntimeException("操作太频繁");
} finally {
redisTemplate.delete(lockKey);
}
}
6. 项目文档要点
完整项目文档应包含:
- 接口文档(Swagger或YAPI)
- 数据库字典
- 部署手册
- 二次开发指南
- 常见问题排查
Swagger配置示例:
java复制@Configuration
@EnableOpenApi
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.select()
.apis(RequestHandlerSelectors.basePackage("com.exam.controller"))
.paths(PathSelectors.any())
.build();
}
}
7. 开发环境搭建指南
7.1 后端环境准备
- JDK17(LTS版本)
- IDEA Ultimate(社区版缺少JPA支持)
- Lombok插件(必须安装)
- Maven 3.8+
7.2 前端环境配置
- Node.js 16+
- VSCode或WebStorm
- 推荐插件:
- Volar(Vue3官方推荐)
- ESLint
- Prettier
7.3 数据库初始化
使用Flyway管理数据库迁移:
sql复制-- V1__init_schema.sql
CREATE TABLE IF NOT EXISTS `user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL,
`password` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
);
8. 扩展功能建议
- 接入第三方登录(微信、GitHub)
- 增加代码在线执行功能(使用Docker沙箱)
- 实现AI自动批改简答题
- 添加学习进度可视化
- 集成即时通讯SDK
代码沙箱实现思路:
java复制public class CodeRunner {
public String execute(String code, Language language) {
// 1. 创建临时目录
// 2. 写入源代码文件
// 3. 使用Docker运行
// 4. 获取输出结果
// 5. 清理资源
}
}
9. 安全防护措施
9.1 常见攻击防护
-
SQL注入:
- 始终使用MyBatis-Plus的条件构造器
- 禁止拼接SQL语句
-
XSS攻击:
- 前端使用vue-dompurify-html
- 后端对富文本内容进行过滤
-
CSRF防护:
- 启用Spring Security的CSRF保护
- 重要操作使用二次确认
9.2 数据加密方案
- 密码加密:
java复制// 使用BCryptPasswordEncoder
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
- 敏感数据加密:
java复制// 使用Jasypt加密
@Bean
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
encryptor.setConfig(new SimpleStringPBEConfig());
return encryptor;
}
10. 监控与日志
10.1 监控方案
- Spring Boot Admin监控服务状态
- Prometheus + Grafana监控指标
- ELK收集分析日志
监控配置示例:
yaml复制management:
endpoints:
web:
exposure:
include: "*"
metrics:
tags:
application: ${spring.application.name}
10.2 日志规范
- 使用Logback+SLF4J
- 按天归档日志
- 敏感信息脱敏
日志格式配置:
xml复制<pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n</pattern>
11. 测试策略
11.1 单元测试
使用JUnit5+Mockito:
java复制@ExtendWith(MockitoExtension.class)
class UserServiceTest {
@Mock
private UserMapper userMapper;
@InjectMocks
private UserService userService;
@Test
void testGetUserById() {
when(userMapper.selectById(1L))
.thenReturn(new User(1L, "admin"));
User user = userService.getById(1L);
assertEquals("admin", user.getUsername());
}
}
11.2 集成测试
使用Testcontainers:
java复制@Testcontainers
@SpringBootTest
class ExamIntegrationTest {
@Container
static MySQLContainer<?> mysql = new MySQLContainer<>("mysql:8.0");
@DynamicPropertySource
static void configureProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", mysql::getJdbcUrl);
}
}
12. 项目经验总结
在实际开发中,有几个关键点值得注意:
- 考试计时功能要使用服务器时间而非客户端时间,防止作弊
- 题目随机算法要考虑性能,大数据量时避免内存溢出
- WebSocket连接需要处理断线重连
- 批量导入试题时要做好事务管理
- 前端大文件上传要支持分片和断点续传
对于想深入学习此技术栈的开发者,我的建议是:
- 先掌握各组件基础用法
- 再研究其设计思想
- 最后尝试自己造轮子
例如实现一个简化版的MyBatis-Plus,会让你对ORM有更深理解。这个项目完整源码已做好注释,特别适合作为SpringBoot+Vue3全栈开发的进阶学习案例。
