前言
在教育数字化、企业内部培训、职业认证考试全面普及的今天,考试题库系统已经成为刚需产品。作为全栈开发者,掌握一套稳定、可扩展、高性能的考试题库开发方案,无论是接外包、做内部系统、还是打造 SaaS 产品,都极具价值。
当前市面上的考试系统要么臃肿难用,要么收费昂贵,要么接口难以定制化。而基于 NestJS 开发后端,搭配现代化前端框架,能快速搭建出支持百万题库、高并发、权限严密、自动组卷、在线考试的企业级系统。
本文是一篇纯原创、可直接落地、从零到一的全栈实战教程,从需求分析、架构设计、后端接口开发、数据库设计、前端实现、部署上线全覆盖,代码干净、注释完整,适合全栈开发者、后端工程师、学生学习,也可直接作为毕业设计、企业项目模板。
一、系统需求与功能规划(真实企业级标准)
1.1 核心使用角色
- 超级管理员:系统配置、权限管理、题库管理、用户管理
- 教师 / 管理员:题目管理、试卷管理、考试管理、成绩管理
- 学生 / 考生:在线考试、查看成绩、错题练习、个人中心
1.2 核心功能模块
- 用户权限模块:登录、注册、JWT 鉴权、RBAC 权限控制
- 题库管理模块:单选、多选、判断、简答、材料题全题型支持
- 试卷管理模块:固定组卷、随机组卷、难度控制、知识点分类
- 考试管理模块:发布考试、时间限制、防切屏、自动阅卷
- 答题模块:在线答题、自动保存、倒计时、交卷评分
- 成绩统计模块:考试排名、正确率统计、错题分析
- 系统管理模块:日志、参数配置、数据备份
1.3 技术栈选型(2026 最稳全栈组合)
后端
- NestJS(企业级 Node 框架)
- TypeORM / Prisma(数据库 ORM)
- MySQL / PostgreSQL(关系型数据库)
- Redis(缓存、登录状态、考试限流)
- JWT(身份鉴权)
- Swagger(自动接口文档)
前端
- Vue3 / React 二选一
- Vite
- Element Plus / Ant Design
- Pinia/Vuex
- TypeScript
部署
- Docker + Docker Compose
- Nginx 反向代理
- PM2 进程守护
二、数据库设计(考试系统核心)
考试系统的数据库设计直接决定扩展性,以下是生产环境可用的核心表结构:
2.1 用户表(user)
id、username、password、nickname、role、phone、email、status、create_time、update_time
2.2 角色权限表(role、permission)
RBAC 权限模型,支持菜单权限、接口权限细粒度控制
2.3 题库分类表(question_category)
id、name、parent_id、sort、status
2.4 题目表(question)
id、type(单选 / 多选 / 判断 / 简答)、title、content、category_id、difficulty、answer、analysis、score、creator、create_time
2.5 试卷表(exam_paper)
id、title、duration、total_score、pass_score、random_question(是否随机)、status、create_time
2.6 试卷题目关联表(paper_question)
id、paper_id、question_id、sort
2.7 考试记录表(exam_record)
id、user_id、paper_id、score、status、start_time、submit_time、use_time
2.8 答题详情表(exam_record_detail)
id、record_id、question_id、user_answer、is_correct、score
三、NestJS 后端项目搭建与初始化
3.1 环境搭建
bash
运行
# 安装 Nest CLI
npm i -g @nestjs/cli
# 创建项目
nest new exam-system-backend
# 安装核心依赖
npm install @nestjs/typeorm typeorm mysql2 redis @nestjs/jwt @nestjs/passport passport-jwt bcryptjs class-validator class-transformer swagger-ui-express @nestjs/swagger
3.2 项目结构(企业级标准)
plaintext
src
├── auth 认证模块
├── user 用户模块
├── question 题目模块
├── paper 试卷模块
├── exam 考试模块
├── record 考试记录
├── common 通用工具
├── config 配置
├── entity 数据库实体
└── main.ts
3.3 配置数据库与 ORM
typescript
运行
// app.module.ts
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'root',
database: 'exam_system',
entities: [__dirname + '/**/*.entity{.ts,.js}'],
synchronize: true,
autoLoadEntities: true,
})
3.4 配置 JWT 认证
typescript
运行
JwtModule.register({
secret: 'exam-system-2026',
signOptions: { expiresIn: '24h' },
})
3.5 启用 Swagger 接口文档
typescript
运行
// main.ts
const config = new DocumentBuilder()
.setTitle('考试题库系统 API')
.setDescription('NestJS 全栈考试系统')
.setVersion('1.0')
.build();
const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);
启动后访问:http://localhost:3000/api 即可看到自动生成的接口文档。
四、核心模块开发(代码可直接复制使用)
4.1 认证模块(登录 + JWT)
登录逻辑
- 校验用户名密码
- 生成 JWT Token
- 返回用户信息 + 权限
核心代码
typescript
运行
async login(loginDto: LoginDto) {
const user = await this.userService.findByUsername(loginDto.username);
if (!user) throw new BadRequestException('用户不存在');
const isMatch = await bcrypt.compare(loginDto.password, user.password);
if (!isMatch) throw new BadRequestException('密码错误');
const token = this.jwtService.sign({ id: user.id, username: user.username });
return { token, user };
}
4.2 题目管理模块(支持 5 种题型)
支持:
- 单选
- 多选
- 判断
- 简答
- 材料题
新增题目接口
typescript
运行
@Post()
async create(@Body() createDto: CreateQuestionDto) {
return await this.questionService.create(createDto);
}
题目列表(分页 + 筛选 + 分类 + 难度)
typescript
运行
async findAll(query: QueryQuestionDto) {
const { page = 1, size = 10, categoryId, type, difficulty } = query;
const qb = this.questionRepository.createQueryBuilder('q');
if (categoryId) qb.andWhere('q.categoryId = :categoryId', { categoryId });
if (type) qb.andWhere('q.type = :type', { type });
if (difficulty) qb.andWhere('q.difficulty = :difficulty', { difficulty });
const total = await qb.getCount();
const list = await qb.skip((page - 1) * size).take(size).getMany();
return { total, list };
}
4.3 试卷模块(随机组卷 + 固定组卷)
随机组卷逻辑
typescript
运行
async randomPaper(dto: RandomPaperDto) {
const { categoryId, radioCount, radioScore, multiCount, multiScore, judgeCount, judgeScore } = dto;
// 随机抽取单选题
const radios = await this.questionRepository
.createQueryBuilder('q')
.where('q.type = 1 AND q.categoryId = :categoryId', { categoryId })
.orderBy('RAND()')
.limit(radioCount)
.getMany();
// 多选、判断同理...
// 组装试卷并保存
return await this.paperService.createWithQuestions({ ...dto, questions: [...radios, ...multis, ...judges] });
}
4.4 考试模块(开始考试 + 自动保存 + 交卷)
核心逻辑
- 校验是否参加过考试
- 生成考试记录
- 返回题目列表
- 交卷自动阅卷、算分、判断是否通过
自动阅卷代码
typescript
运行
async autoGrade(recordId: number, answers: AnswerItem[]) {
let totalScore = 0;
const details = [];
for (const item of answers) {
const question = await this.questionService.findById(item.questionId);
let isCorrect = 0;
let score = 0;
if (question.type === 1 || question.type === 3) {
// 单选、判断
if (item.userAnswer === question.answer) {
isCorrect = 1;
score = question.score;
totalScore += score;
}
}
details.push({ recordId, questionId: item.questionId, userAnswer: item.userAnswer, isCorrect, score });
}
// 保存成绩
await this.recordRepository.update(recordId, { score: totalScore, status: 2 });
await this.recordDetailRepository.save(details);
return { score: totalScore };
}
五、前端项目搭建(Vue3 + Element Plus)
5.1 项目创建
bash
运行
npm create vite@latest exam-system-frontend
cd exam-system-frontend
npm install element-plus pinia axios vue-router
5.2 核心页面
- 登录页
- 首页(数据看板)
- 题库管理(增删改查、批量导入)
- 试卷管理(随机组卷、固定组卷)
- 考试管理(发布、列表)
- 在线考试页面(答题、倒计时、自动保存)
- 成绩详情、错题本
5.3 在线考试答题页(核心体验)
包含:
- 顶部倒计时
- 题目选项渲染
- 答题卡定位
- 自动保存
- 禁止刷新、防切屏提示
- 交卷确认
vue
<template>
<div class="exam-page">
<div class="timer">{{ formatTime(time) }}</div>
<div v-for="q in questionList" :key="q.id" class="question-item">
<h3>{{ q.title }}</h3>
<el-radio-group v-model="answers[q.id]" v-if="q.type === 1">
<el-radio label="A">A. {{ q.optionA }}</el-radio>
<el-radio label="B">B. {{ q.optionB }}</el-radio>
</el-radio-group>
</div>
<el-button @click="submitExam">交卷</el-button>
</div>
</template>
六、Excel 批量导入题库(企业必备功能)
NestJS 轻松实现 Excel 导入:
- 安装
xlsx - 上传 Excel → 解析 → 批量入库
typescript
运行
@Post('import')
@UseInterceptors(FileInterceptor('file'))
async import(@UploadedFile() file) {
const workbook = XLSX.read(file.buffer);
const sheet = workbook.Sheets[workbook.SheetNames[0]];
const data = XLSX.utils.sheet_to_json(sheet);
const list = data.map(item => ({
title: item['题目'],
type: item['类型'],
optionA: item['选项A'],
answer: item['答案'],
score: item['分值'],
}));
await this.questionRepository.save(list);
return { count: list.length };
}
七、权限控制(RBAC 细粒度)
- 接口守卫
- 菜单权限
- 按钮权限
- 前端动态路由
typescript
运行
@Get('admin/list')
@Roles('admin')
async adminList() {
return await this.userService.findAll();
}
八、部署上线(Docker Compose 一键部署)
yaml
version: '3'
services:
mysql:
image: mysql:8
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: exam_system
redis:
image: redis
backend:
build: ./backend
ports:
- 3000:3000
frontend:
build: ./frontend
ports:
- 80:80
一行命令启动整套系统:
bash
运行
docker-compose up -d
九、系统亮点与扩展方向
9.1 本系统亮点
- 纯 NestJS 企业级架构
- 支持 5 种考试题型
- 随机 + 固定组卷
- 自动阅卷、自动算分
- 防切屏、考试监控
- 错题本、成绩统计
- RBAC 权限、接口安全
- Excel 批量导入题库
- Docker 一键部署
- 支持高并发、百万题库
9.2 可扩展方向
- 人脸识别防作弊
- 视频监考
- 主观题 AI 批改
- 微信小程序、公众号
- 多租户 SaaS 版本
- 刷题模式、模拟考试
十、总结
这套 NestJS 全栈考试题库系统 是一套真正能上线、能赚钱、能当毕设、能进企业项目的完整方案。
相比市面上的速成项目,本系统:
- 架构更清晰
- 代码更规范
- 功能更完整
- 体验更流畅
- 安全性更高
- 可直接用于商业开发
无论你是前端想转全栈,还是后端想练手,或是学生做毕业设计,这套系统都能让你快速掌握 NestJS 全栈开发思想,轻松拿下各类考试系统类需求。