一、项目简介
在线考试是校园信息化建设中非常常见的业务场景。传统纸质考试存在试卷印刷、人工阅卷、成绩统计效率低等问题,而在线考试平台可以把“教师出题、学生答题、系统判分、成绩查询”串成一条完整流程。
本文实现一个可运行的 Python 全栈项目:校园在线考试平台。项目面向两类用户:
- 教师:注册/登录后创建考试、添加选择题、发布试卷。
- 学生:注册/登录后查看已发布考试、在线答题、提交试卷并查看成绩。
本项目不是单纯的算法演示,而是一个包含后端 API、数据库、登录认证、前端交互和部署说明的完整全栈项目。
二、技术栈
| 层级 | 技术 |
|---|---|
| 后端框架 | FastAPI |
| 后端语言 | Python 3 |
| 数据库 | SQLite |
| 数据校验 | Pydantic |
| 认证方式 | Bearer Token + 密码 PBKDF2 哈希 |
| 前端框架 | Vue 3 |
| 前端构建 | Vite |
| 接口通信 | Fetch API |
前端主技术栈为Vue 3 + Vite,后端使用FastAPI + SQLite,适合课程设计、毕业设计原型。
三、系统架构
系统采用前后端分离架构:
浏览器 Vue 3 页面 │ HTTP / JSON / Bearer Token ▼ FastAPI REST API │ sqlite3 ▼ SQLite 数据库后端提供/api/auth/*、/api/exams/*、/api/submissions/*等接口;前端通过src/api.js统一封装请求,并在登录后把 Token 写入localStorage,后续请求自动携带Authorization请求头。
四、功能模块
1. 用户与认证模块
- 用户注册:支持学生、教师两种角色。
- 用户登录:校验密码后签发随机 Token。
- 登录状态:前端保存 Token 和用户角色。
- 退出登录:删除服务端 Token 并清理前端缓存。
- 接口保护:核心接口必须携带有效 Token。
2. 教师考试管理模块
- 创建考试:填写标题、说明、考试时长。
- 添加题目:维护 A/B/C/D 四个选项、正确答案和分值。
- 发布考试:草稿发布后学生可见。
- 查看答案:教师查看自己创建的考试时可以看到正确答案。
3. 学生答题模块
- 查看已发布考试列表。
- 进入考试详情页选择答案。
- 提交试卷后系统自动判分。
- 查看个人历史成绩。
五、数据库/数据模型设计
SQLite 中设计了 5 张核心表。
users 用户表
| 字段 | 说明 |
|---|---|
| id | 用户 ID |
| username | 用户名,唯一 |
| password_hash | 加盐哈希后的密码 |
| role | student 或 teacher |
| created_at | 创建时间 |
tokens 登录令牌表
| 字段 | 说明 |
|---|---|
| token | 登录 Token |
| user_id | 所属用户 |
| created_at | 创建时间 |
exams 考试表
| 字段 | 说明 |
|---|---|
| id | 考试 ID |
| title | 考试标题 |
| description | 考试说明 |
| duration_minutes | 考试时长 |
| published | 是否发布 |
| owner_id | 创建教师 |
questions 题目表
| 字段 | 说明 |
|---|---|
| exam_id | 所属考试 |
| content | 题干 |
| option_a ~ option_d | 四个选项 |
| correct_answer | 正确答案 |
| score | 分值 |
submissions 提交记录表
| 字段 | 说明 |
|---|---|
| exam_id | 考试 ID |
| user_id | 学生 ID |
| score | 得分 |
| total_score | 总分 |
| answers_json | 学生答案 JSON |
| submitted_at | 提交时间 |
六、后端接口设计
| 方法 | 地址 | 说明 | 鉴权 |
|---|---|---|---|
| POST | /api/auth/register | 用户注册 | 否 |
| POST | /api/auth/login | 用户登录 | 否 |
| GET | /api/auth/me | 当前用户 | 是 |
| POST | /api/auth/logout | 退出登录 | 是 |
| GET | /api/exams | 考试列表 | 是 |
| POST | /api/exams | 教师创建考试 | 教师 |
| GET | /api/exams/{exam_id} | 考试详情 | 是 |
| POST | /api/exams/{exam_id}/questions | 教师添加题目 | 教师 |
| POST | /api/exams/{exam_id}/publish | 教师发布考试 | 教师 |
| POST | /api/exams/{exam_id}/submit | 学生提交试卷 | 学生 |
| GET | /api/submissions/me | 我的提交记录 | 是 |
七、前端页面设计
前端使用 Vue 3 单文件组件实现,主要页面区域如下:
- 顶部 Hero 区域:展示系统名称、当前登录用户和退出按钮。
- 登录/注册区域:未登录时展示,支持选择学生或教师角色。
- 考试列表侧栏:已登录用户可查看考试列表;教师看到自己的草稿和已发布考试,学生只看到已发布考试。
- 教师出题台:教师创建考试、添加题目、发布考试。
- 考试详情与答题区:学生选择答案并提交;教师可查看正确答案。
- 我的成绩区域:学生查看历史提交成绩。
八、核心代码讲解
1. 数据库初始化
backend/app/database.py中使用 sqlite3 创建连接,并在应用启动时自动建表:
definit_db():conn=get_connection()cur=conn.cursor()cur.execute("PRAGMA foreign_keys = ON")cur.executescript(""" CREATE TABLE IF NOT EXISTS users (...); CREATE TABLE IF NOT EXISTS exams (...); CREATE TABLE IF NOT EXISTS questions (...); CREATE TABLE IF NOT EXISTS submissions (...); """)conn.commit()conn.close()SQLite 的优点是部署简单,不需要额外安装数据库服务,非常适合教学项目和中小型原型系统。
2. 密码哈希与登录 Token
backend/app/crud.py中没有明文保存密码,而是使用 PBKDF2-SHA256:
defhash_password(password:str)->str:salt=secrets.token_hex(16)digest=hashlib.pbkdf2_hmac('sha256',password.encode(),salt.encode(),120_000)returnf"pbkdf2_sha256$120000${salt}${digest.hex()}"登录成功后生成随机 Token,写入tokens表:
defcreate_token(user_id:int)->str:token=secrets.token_urlsafe(32)conn.execute('INSERT INTO tokens(token, user_id) VALUES (?, ?)',(token,user_id))conn.commit()returntoken3. FastAPI 鉴权依赖
backend/app/main.py通过依赖函数解析请求头:
defget_current_user(authorization:Optional[str]=Header(default=None)):ifnotauthorizationornotauthorization.startswith('Bearer '):raiseHTTPException(status_code=401,detail='缺少登录凭证')token=authorization.removeprefix('Bearer ').strip()user=crud.get_user_by_token(token)ifnotuser:raiseHTTPException(status_code=401,detail='登录已失效')returnuser教师接口再叠加角色校验:
defrequire_teacher(user=Depends(get_current_user)):ifuser['role']!='teacher':raiseHTTPException(status_code=403,detail='仅教师账号可操作')returnuser这样可以保证出题、发布考试等关键操作不会被学生账号调用。
4. 自动判分逻辑
学生提交答案时,后端读取题目正确答案并计算得分:
forqinquestions:total+=q['score']ifanswers.get(str(q['id']))==q['correct_answer']:score+=q['score']提交记录会保存学生答案、得分、总分和提交时间,便于后续成绩查询。
5. Vue 3 API 封装
frontend/src/api.js负责统一添加 Token:
exportasyncfunctionrequest(path,options={}){constheaders={'Content-Type':'application/json',...(options.headers||{})}consttoken=getToken()if(token)headers.Authorization=`Bearer${token}`constres=awaitfetch(`${API_BASE}${path}`,{...options,headers})constdata=awaitres.json().catch(()=>({}))if(!res.ok)thrownewError(data.detail||'请求失败')returndata}页面组件只需要调用api.login()、api.listExams()、api.submitExam()等方法,不必在每个按钮事件里重复拼接请求头。
九、部署与运行步骤
项目目录如下:
project/ backend/ frontend/ README.md1. 启动后端
cdproject/backend python3-mvenv .venvsource.venv/bin/activate pipinstall-rrequirements.txt uvicorn app.main:app--reload--host0.0.0.0--port8000后端默认地址:http://127.0.0.1:8000,接口文档地址:http://127.0.0.1:8000/docs。
2. 启动前端
cdproject/frontendnpminstallnpmrun dev前端默认通过 Vite 启动,浏览器访问http://127.0.0.1:5173。
3. 初始化使用流程
- 打开前端页面,注册教师账号。
- 教师登录,创建考试并添加题目。
- 点击发布考试。
- 注册学生账号并登录。
- 学生进入考试,选择答案并提交。
- 系统返回分数,学生可查看历史成绩。
十、项目总结
本文完成了一个基于FastAPI + SQLite + Vue 3(Vite)的校园在线考试平台。项目覆盖了全栈开发中的常见关键点:
- 后端 RESTful API 设计;
- SQLite 数据库建模;
- 注册、登录、Token 鉴权;
- 角色权限控制;
- Vue 3 前端状态管理和接口调用;
- 在线考试的业务闭环:出题、发布、答题、判分、查成绩。
如果继续扩展,可以增加倒计时、防重复提交、题库管理、主观题阅卷、班级管理、成绩导出、考试监控等功能,使其进一步接近真实校园考试系统。
项目代码
下载链接