实现一个在线编程笔试平台
1、引言及选题
该项目旨在实现一个在线编程笔试平台,主要功能是候选人在线完成代码编写,面试官可查看编程结果。该项目涵盖了前端和后端常用的技术栈。
1.1 项目背景
疫情原因,越来越多的面试、笔试改为线上展开,在线笔试和面试的需求日益增长。寻找一个简单易用的面试和笔试平台的呼声在面试官和参与面试者(以下简称候选者)之间越来越高。
1.2 项目目的
实现一个在线编程笔试平台,主要功能是候选人在线完成代码编写,面试官可查看编程结果。该项目涵盖了前端和后端常用的技术栈。
1.3 项目特色
面试官拥有自己的账户,可以管理属于自己的题库和面试信息;面试官可以随时查看所有由他创建的面试记录,并且可以进行快速搜索;面试官和候选者之间可以进行语音或文字聊天;候选者编写的代码会实时同步到面试官的编辑框。
1.4 项目风险
同类型的产品早已珠玉在前,而且同时有不少设计者正并驾齐驱,竞争激烈。
2、综合描述
2.1 用户类和特性
① 面试官:面试官需要有自己的账号,以管理题库和面试数据;一个面试官可能会创建多个面试,但是同时只能参加一个面试;面试官可以随时结束一个面试;面试官拥有自己的题库,并保有对题库的所有权限;面试官可以通过语音或者文字对候选者进行提问。
② 候选者:候选者只要拿到面试链接并登记个人信息就可以参加面试,不需要注册或登录账号;候选者同一时间只能参加一个面试;候选者可以通过语音或者文字对面试官进行提问;
2.2 运行环境
系统将部署在云服务器上,内存 4G,磁盘 40G,操作系统 CentOS 8.1.1911。
2.3 设计和实现上的限制
技术水平限制,无法实现协同编程以及多人面试;
硬件水平限制,无法实现高并发量下的负载均衡。
2.4 假设和约束(依赖)
假设一个面试官账号同一时刻只在一个地方登录;假设该系统的用户最大并发量不超过 10;假设面试官没有群面的需求。
3、功能性需求分析
- 面试官个人空间管理需求
作为一个在线编程笔试平台,实现面试官(即创建或发起在线笔试的用户)的面试管理、题目管理以及个人账号管理功能是基本需求。
① 个人账号管理:该部分应包含如下功能模块:
|-----------|------|
| 功能模块 | 实现功能 |
| 登录管理 | 登录 |
| 注册 | |
| 登出 | |
| 个人信息管理 | 修改密码 |
| 修改、完善基本信息 | |
| 消息通知 | |
② 题库管理:支持面试官新建面试题和修改面试题目,在选定面试题后可以创建面试邀请,该部分包含如下功能模块:
|---------|--------|
| 功能模块 | 实现功能 |
| 题库管理 | 题库分页展示 |
| 查看题目详情 | |
| 修改现有题目 | |
| 新增/删除题目 | |
| 搜索题目 | |
| 创建面试 | 选定面试题目 |
| 创建面试 | |
| 分享面试链接 | |
√ 题库分页展示:考虑到题库中题目的数量可能会很多,应该将题目分页展示,每次只请求和展示一页的数据,方便用户查看;考虑到不同用户的需求,也要满足用户调整每页的数据量以及跳转到 ×× 页的需求。
√ 搜素题目:除了满足用户对题库的基本的增删改的需求外,当数据量很多时,也要提供搜索的功能,根据题目名或者题目内容进行关键词进行快速查找。
√ 创建面试:创建面试时要选好面试题目,以及参见面试的人数(初步只要实现单人面试即可),另外可选地添加面试描述以方便面试官在面试记录中区分出是哪个面试。
③ 面试管理:一个账号创建的所有面试都将在这里展示。该部分包含如下功能模块:
|--------|--------|
| 功能模块 | 实现功能 |
| 面试记录 | 历史记录展示 |
| 面试详情展示 | |
| 历史记录搜索 | |
√ 历史记录展示:历史记录应该按照时间线顺序展示,同时标记出已经结束的面试和正在进行的面试
√ 面试详情展示:每条记录都应该可以查看详细信息,包括面试开始/结束时间、参加人员、面试介绍等信息,对于还未结束的面试,要提供面试链接以便用户复制分享或者直接前往。
√ 历史记录搜索:至少实现根据面试记录号搜索,同时可以筛选出已经结束/正在进行的面试。
- 面试与笔试功能需求
作为项目的核心部分,该部分应满足在线编程、文字聊天、语音聊天三个核心需求。
|-----------|---------|
| 功能模块 | 实现功能 |
| 在线编程 | 代码同步展示 |
| 编程语言选择 | |
| 代码在线运行 | |
| 主题切换 | |
| 文字聊天 | 微信式聊天界面 |
| 语音聊天 | 实时语音聊天 |
| 进入面试 | 候选人信息登记 |
| 面试官账号登录 | |
| 面试身份选择/展示 | |
√ 代码同步:候选者编写的代码要及时同步到面试官的页面,即使前者的面试页面突然异常关闭也不应该导致后者看不到代码。如果支持协同编程(选择实现),面试官也有权修改代码并同步显示到对方页面。如果不支持,应禁止面试官修改候选者编辑的代码。
√ 代码在线运行:应该支持 JavaScript 语言的在线运行,候选者或面试官都可以运行该代码,并显示结果到双方页面。
√ 文字聊天:仿照微信让用户更容易熟悉界面和操作,用户发送的文字展示在聊天界面右侧,接收的文字展示在聊天界面左侧;当点击发送后,聊天界面要自动滚动到最底部;应该在聊天对话中显示发送/接收时间;页面刷新后聊天记录不应该清空。
√ 语音聊天:要支持双向静音功能,包括不让对方听到和不听到对方声音两种功能。
√ 面试身份选择:在通过面试链接进入面试之前,需要判断参加面试的用户的身份,如果该用户近期以面试官身份登录过,则以面试官身份进入面试;否则让用户自行选择身份,如果是面试官,则要求登录,否则要登记候选者姓名、联系方式等信息并以候选者身份进入。
4、非功能需求分析
除了上述功能需求,本项目还要考虑以下非功能需求:
4.1 性能需求
处理能力方面,主要考虑系统能承载的最大用户并发数,这取决于系统将要部署的云服务器的负载能力,系统至少能承载 10 个面试同时进行;响应时间方面,系统应该能够快速响应数据请求以及实时聊天(包括文字和语音),用户最终得到的结果的响应时间除了与系统响应时间有关外,还与网络状况有关。
4.2 可靠性需求
系统在设计开发时候,充分考虑用户的具体情况及使用操作,不但要理论上可行,更重要的是实际上可用,更好地适应用户需求,同时要把故障率降到较低,确保系统稳定可靠。系统不应该因为用户的误操作或故意操作而导致数据丢失、单向面试终止、代码同步失败等问题。在支持的并发数和用户正常的使用频率下,任意操作都不应该导致系统崩溃。
4.3 安全性需求
系统严禁未经许可的用户访问和操作,用户登录和注册时应该对面试官用户的邮箱进行查重和验证;候选者在进入面试前需要登记姓名和联系方式以便面试官核时信息;面试房间号不应该在链接中直接暴露给用户,需要进行加密处理。
4.4 可维护性需求
系统应该方便前后端技术人员调试。
4.5 可扩展性需求
系统应该具有良好的分层设计,整体系统扩充性能良好,能够根据业务的发展或变更,在保持现有业务处理不受影响的前提下,具有持续扩充功能、适度变化的能力。
4.6 数据一致性
本项目较少设计数据一致性。
5、项目进度安排
|---------------|---------|-----------------------------------|
| 具体时间 | 时长 | 内容 |
| 2021 年 4 月中下旬 | 2 Week | 学习前后端相关技术(vue+elementUI、nodejs 等) |
| 4 月-5 月 | 1 Month | 需求分析、概要设计、详细设计 |
| 5 月-6 月 | 1 Month | 代码编写,前后端同时进行 |
| 6 月 | 1 Week | 测试、优化、报告 |
6、概要设计
在需求分析阶段,项目需求被分解为如下模块:登录/注册模块、面试题模块、在线编程模块、沟通交流模块。

6.1 前端设计
注册界面

个人中心页面

面试题库页面

面试记录页面

面试编码页面
6.2 后端设计
针对需求中涉及的各个模块,后端主要完成数据库表的设计以及对前端路由请求的相应。
项目中,数据库包含 4 个表:Interviewers(面试官的相关信息)、Records(面试的相关信息)、Message(聊天记录的相关信息)、Question(面试题库的相关信息)。
模块与接口的大致的对应关系如下:
登录/注册模块(登录验证接口、用户注册接口、信息完善接口、密码修改接口、加载信息接口)。
面试题模块(加载题库接口、新增题目接口、删除题目接口、修改题目接口)。
在线编程模块(信息填写接口、创建面试接口、请求历史数据接口、信息请求接口、候选者离开告知接口、进入面试页面请求判断接口、请求题目接口、请求代码接口、运行 JS 代码接口、保存提交代码接口)。
沟通交流模块(请求聊天记录接口、WebSocket 接口)。

6.3 业务流程图

面试官注册与登录流程图
面试官主页面操作流程图

面试官/面试者面试流程图
7、类图及接口设计
项目围绕需求主要进行了接口设计和数据表设计,在类设计方面应用较少。
7.1 通用返回状态说明
|-----|---------------------|---------------------------------|
| 状态码 | 含义 | 说明 |
| 200 | OK | 请求成功 |
| 404 | NOT FOUND | 请求的资源不存在 |
| 500 | INTERNASERVER ERROR | 内部服务端错误 (如:传入的参数或者文件格式错误、其他错误等) |
| 403 | FORBIDDEN | 被禁止访问 |
| 401 | UNAUTHORIZED | 未授权 (登录状态过期或未登录时返回) |
7.2 用户信息页面
7.2.1 登录验证接口
请求路径:/users/login
请求方法:POST
提交数据类型:JSON
是否进行 token 验证:否
提交参数
|----------------|--------|--------|------|
| 参数名 | 参数说明\ | 数据类型 | 备注 |
| interviewer_id | 邮箱 | string | 不能为空 |
| password | 密码 | string | 不能为空 |
响应数据:
登录成功:返回该用户除密码外的所有信息,包含{token:值}
登录失败:返回空数据
请使用如下状态码:
|-------------|---------------------|------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 登录成功,前端将转入个人中心页面 |
| 204 | No Content | 该邮箱未注册 |
| 403 | Forbidden | 密码错误 |
| 500 | InternaServer Error | 其他原因造成的登录失败 |
7.2.2 用户注册接口
请求路径:/users/register
请求方法:POST
提交数据类型:JSON
是否进行 token 验证:否
提交参数:
|----------------|------|---------|-----------------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| interviewer_id | 邮箱 | string | 必填 |
| password | 密码 | string | 必填,经过前端验证 length<=20 |
| username | 用户名 | string | 必填,经过前端验证 length<=30 |
| company | 公司 | string | 选填,经过前端验证 length<=30 |
| sex | 性别 | integer | 选填(1=>♂,2=>♀) |
注:发送的 JSON 数据中除了上述键值对外还有 checkPass 关键字,即密码重复输入确认,只用于前端验证。
响应数据:
修改成功:返回空数据
修改失败:返回空数据
请使用如下状态码:
|-------------|---------------------|----------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 注册成功,前端将转入登录页面 |
| 403 | Forbidden | 该邮箱已经占用 |
| 500 | InternaServer Error | 其他原因造成的注册失败 |
7.2.3 信息完善接口
请求路径:/users/update
请求方法:PUT
请求数据类型:JSON
是否进行 token 验证:是
请求参数:
|----------|------|---------|--------------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| username | 用户名 | string | 经过前端验证 length<=30 |
| company | 公司 | string | 经过前端验证 length<=30 |
| sex | 性别 | integer | 1=>♂,2=>♀ |
| phone | 手机号 | string | 经过前端验证 length==11 |
| other | 备注 | string | 经过前端验证 length<=50 |
| job | 职业 | string | 经过前端验证 length<=30 |
响应数据:
修改成功:返回修改后的个人信息(JSON 格式)
修改失败:返回空数据
请使用如下状态码:
|-------------|---------------------|---------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 信息更新成功 |
| 401 | UNAUTHORIZED | 登录状态过期或未登录时返回 |
| 500 | InternaServer Error | 其他原因造成的信息更新失败 |
7.2.4 密码修改接口
请求路径:/users/modifyPwd
请求方法:PUT
请求数据类型:JSON
是否进行 token 验证:是
请求参数:
|--------|------|--------|-----------------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| oldPwd | 旧密码 | string | 必填,经过前端验证 length<=20 |
| newPwd | 新密码 | string | 必填,经过前端验证 length<=20 |
响应参数:
修改成功:返回空数据
修改失败:返回空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 密码修改成功 |
| 401 | UNAUTHORIZED | 登录状态过期或未登录时返回 |
| 403 | Forbidden | 旧密码错误 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
注意事项:修改密码后,用户需要重新登录,浏览器端存储的 token 值将被删除
7.2.5 加载信息接口
请求路径:/users/info
请求方法:GET
是否进行 token 验证:是
请求参数:无
响应参数:
成功:返回个人信息(JSON 格式)
失败:返回空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 密码修改成功 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
7.3 题库页面
7.3.1 加载题库接口
请求路径:/question/load
请求方法:get
请求数据类型:JSON
是否进行 token 验证:是
请求参数:
|-------|------------------------|------|-----------------------------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| beg | 从 question_id 开始请求(不含) | int | beg 为 null 时从最小的 question_id 开始返回 |
| count | 请求的题目数 | int | count 为 null 时返回所有数据 |
响应参数:
修改成功:返回对应数目的题库的信息
修改失败:返回空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 401 | UNAUTHORIZED | 登录状态过期或未登录时返回 |
| 403 | Forbidden | 请求数据不存在 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
注意事项:返回的题目应该按照问题的 question_id 排好序、
7.3.2 新增题目接口
请求路径:/question/add
请求方法:post
提交数据类型:JSON
是否进行 token 验证:是
提交参数:
|---------|------|--------|----------------------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| title | 题目名 | string | 必填,经过前端验证 length<=30 |
| degree | 题目难度 | int | 选填,1=> 简单,2=> 中等,3=> 困难 |
| content | 题目内容 | string | 必填 |
| input | 测试输入 | string | 选填 |
| output | 测试输出 | string | 选填 |
响应参数:
修改成功:返回空数据
修改失败:返回空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 401 | UNAUTHORIZED | 登录状态过期或未登录时返回 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
注意事项:新增的题目要增加 question_id 和 date 项,注意前者作为主键是不能跟现有的 question_id 重复的
7.3.3 删除题目接口
请求路径:/question/delete
请求方法:delete
是否进行 token 验证:是
请求参数:
|-----|---------------------|-------|-----------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| ids | 要删除的题目的 question_id | array | 必填,且保证不为空 |
响应参数:
修改成功:返回空数据
修改失败:返回空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 401 | UNAUTHORIZED | 登录状态过期或未登录时返回 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
7.3.4 修改题目接口
请求路径:/question/modify/:qid
请求方法:put
请求数据类型:JSON
是否进行 token 验证:是
请求参数:
|-----|---------------------|------|----|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| qid | 要修改的题目的 question_id | int | 必填 |
提交数据:同 3.3.2
响应参数:
修改成功:返回空数据
修改失败:返回空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 401 | UNAUTHORIZED | 登录状态过期或未登录时返回 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
7.3.5 创建面试接口
请求路径:/create
请求方法:post
请求数据类型:JSON
是否进行 token 验证:是
提交参数:
|----------------|--------------------|--------|-----------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| question_id | 选中的题目的 question_id | int | 必填 |
| question_title | 选中的题目的 title | string | 必填 |
| joinCount | 参加面试的人数,默认为 1 | int | 扩展用(大概率不用) |
| description | 面试描述 | string | 可选,不大于 1024 个字符 |
响应参数:
修改成功:返回面试 record_id
修改失败:返回空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 401 | UNAUTHORIZED | 登录状态过期或未登录时返回 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
7.4 历史记录页面
7.4.1 请求历史数据
请求路径:/history/load
请求方法:get
是否进行 token 验证:是
请求参数:
|-------|------------------------|------|-----------------------------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| beg | 从 question_id 开始请求(不含) | int | beg 为 null 时从最小的 question_id 开始返回 |
| count | 请求的题目数 | int | count 为 null 时返回所有数据 |
响应参数:
获取成功:返回相应数量的面试信息(为节省带宽,不应该包含 interviewer_id、code、coding_language 三个字段)
获取失败:返回空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 401 | UNAUTHORIZED | 登录状态过期或未登录时返回 |
| 403 | Forbidden | 请求数据不存在 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
7.5 面试页面
get 请求(params 字段存数据),后端 req.query 获得数据
post 请求(data 字段存数据),后端 req.body 获得数据
7.5.1 主页面
7.5.1.1 信息请求接口
请求路径:/interview/userInformation
请求方法:get
请求数据类型:JSON
是否进行 token 验证:是 (token 附在请求头中)
请求参数:
|-----------|-------|--------|----|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| record_id | 面试记录号 | string | |
注意事项:后端通过面试 id 找到该面试记录,并通过 token 解析 data,data 是请求者的邮箱(如果是面试官的话)或手机号(如果是候选者的话),然后知道身份返回数据。
响应参数:
成功:返回数据:{name: ,isInterview: ,over: }(over 字段为 true 表示结束)
失败:面试 record_id 不存在或者(我身份是面试官,但是这个 record_id 对应的面试官不是我,token 判断),返回空数据,设 404 状态码
请使用如下状态码:
|-------------|---------------------|------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 404 | NOT FOUND | 数据不存在 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因 |
7.5.1.2 候选者离开告知接口
请求路径:/interview/intervieweeLeave
请求方法:get
请求数据类型:JSON
是否进行 token 验证:否
请求参数:
|-----------|-------|--------|----|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| record_id | 面试记录号 | string | |
响应参数:
成功:返回 OK 状态码
请使用如下状态码:
|-------------|------|--------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
7.5.1.3 进入面试页面请求判断接口
请求路径:/interview/canIn
请求方法:get
请求数据类型:JSON
是否进行 token 验证:是
请求参数:
|-----------|-------|--------|----|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| record_id | 面试记录号 | string | |
响应参数:
成功:根据 token,如果是面试官则返回{canIn:1},如果是候选者,解析 token,判断该 token 中记录的面试号是否与当前一致,一致则返回{canIn:1},否则{canIn:0}
请使用如下状态码:
|-------------|------|--------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
7.5.2 题目展示
7.5.2.1 请求题目接口
请求路径:/interview/question
请求方法:get
请求数据类型:JSON
是否进行 token 验证:否
请求参数:
|-----------|-------|--------|----|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| record_id | 面试记录号 | string | |
响应参数:
成功:返回 record_id 面试记录号对应的题号=> 对应的题目信息
失败:返回空数据
请使用如下状态码:
|-------------|---------------------|------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 404 | NOT FOUND | 数据不存在(该题目已删除) |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因 |
7.5.3 在线编程
7.5.3.1 请求代码接口
请求路径:/interview/reqCode
请求方法:get
请求数据类型:JSON
是否进行 token 验证:否
请求参数:
|-----------|-------|--------|----|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| record_id | 面试记录号 | string | |
响应参数:
成功:返回 record_id 面试记录号=> 对应的面试信息【代码、编程语言】
失败:返回空数据
请使用如下状态码:
|-------------|---------------------|------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因 |
7.5.3.2 运行 JS 代码接口
请求路径:/interview/runJScode
请求方法:post
请求数据类型:JSON
是否进行 token 验证:否
请求参数:
|------|-------|--------|----|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| code | JS 代码 | string | |
响应参数:
成功:返回 JSON 数据 {result: 运行结果}
失败:返回 JSON 数据 {result: "运行失败"}(如果知道错误再后面加上错误信息)
请使用如下状态码:
|-------------|---------------------|------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 运行成功或者失败 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因 |
7.5.3.3 保存提交代码接口
请求路径:/interview/saveCode
请求方法:post
请求数据类型:JSON
是否进行 token 验证:否
请求参数:
|-----------|-------|--------|----|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| record_id | 面试记录号 | string | |
| code | 代码 | string | |
| lang | 编程语言 | string | |
响应参数:
成功(保存代码到 record_id 对应的记录):返回空数据
失败:空数据
请使用如下状态码:
|-------------|---------------------|-------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 成功 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
7.5.4 聊天
7.5.4.1 请求聊天记录接口
请求路径:/interview/chatRecord
请求方法:get
请求数据类型:JSON
是否进行 token 验证:否
请求参数:
|-----------|-------|--------|-----------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| record_id | 面试记录号 | string | 必填,且保证不为空 |
响应参数:
成功:返回 record_id 对应的聊天记录表中的所有信息(保存聊天记录时需要确保同 record_id 的记录后 来的排在后面,确保时间顺序,如果不能保证,需要对获得的数据按时间排序)
失败:返回空数据
注意:数据库查找结果是数组形式,成功以数组返回就行
请使用如下状态码:
|-------------|---------------------|------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因 |
7.5.4.2websocket 接口
注意事项:获得对应面试号 req.params.wid
后端接收数据 msg=> 解析成 JSON 数据格式 data:{type: 类型,.....}
(1) type=="code"
表示代码更新,需要自动保存和实时同步到面试官页面,data 数据如下:
|------|------|--------|------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| type | 类型 | string | code |
| code | 代码 | string | |
(2) type=="message"
表示聊天记录,需要保存到数据库和转发,data 数据如下:
|---------|------|--------|---------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| type | 类型 | string | message |
| message | 聊天信息 | JSON | 如下字段 |
message: {record_id: ,isInterviewer: ,name: ,time: ,content: }
(3) type=="interviewOver"
表示面试结束,需要更新数据库表中对应面试记录信息和转发,data 数据如下:
|------|------|--------|---------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| type | 类型 | string | interviewOver |
注意事项:数据库表对应记录更新两个字段【是否结束,结束时间】
(4) 其他
作为信令服务器转发信息,配合 webRTC 实现实时语音聊天功能
7.6 其它页面
7.6.1 信息填写接口(middle)
请求路径:/interview/enter
请求方法:post
请求数据类型:JSON
是否进行 token 验证:否
请求参数:
|----------------|------------|--------|-------------------|
| 参数名 | 参数说明 | 数据类型 | 备注 |
| role | 面试官 or 候选者 | int | 1=> 面试官,2=> 候选者 |
| interviewer_id | 面试官邮箱 | string | 当 role 为 1 时才考虑 |
| password | 面试官密码 | string | 当 role 为 1 时才考虑 |
| candidate_name | 候选者名字 | string | 当 role 为 2 时才考虑 |
| phone | 候选者电话 | string | 当 role 为 2 时才考虑 |
| record_id | 面试记录号 | string | |
响应参数:
成功:返回 token(如果是 role 是候选者,服务器向数据库中面试信息添加数据(候选者信息),同时禁止别的候选者进入(一个时间只允许一个候选者在房间);如果是 role 是面试官,服务器向数据库检查该面试是否为他创建,否则禁止进入;验证通过后才返回,一个 token 给前端,候选者用手机号码 +/面试 id(候选者唯一标识)生成 token,而面试官用邮箱生成 token,和 login 的时候一样)
失败:返回空数据
请使用如下状态码:
|-------------|---------------------|--------------------------|
| status code | 官方说明 | 备注 |
| 200 | OK | 数据请求成功 |
| 403 | Forbidden | 密码错误(官)||面试已结束(候) |
| 412 | Precondition Failed | 面试非你创建(官)||别人已经进入面试(候) |
| 500 | InternaServer Error | 服务器原因造成修改失败(其他原因) |
8、数据库设计
数据库用户/密码:root/root
8.1 面试官 [Interviewers]
|----------------|--------|------------|-------------------|
| 字段名 | 含义 | 数据类型 | 说明 |
| interviewer_id | 邮箱 | string | primary key |
| username | 姓名 | string | not null |
| password | 密码 | string | not nul(20 字符以内) |
| head | 头像缩略图 | mediumtext | (可不使用)(默认) |
| sex | 性别 | int | 1:男,2:女 |
| company | 公司/学校 | string | 30 字符以内 |
| job | 职业 | string | 30 字符以内 |
| other | 备注 | string | 50 字符以内 |
| createtime | 用户创建时间 | date-time | CURRENT_TIMESTAMP |
| phone | 手机号码 | string | |
8.2 面试信息 [Records]
|-----------------|---------|-----------|-----------------|
| 字段名 | 含义 | 数据类型 | 说明 |
| record_id | 记录号 | string | primary key |
| interviewer_id | 面试官 id | string | foreign key |
| candidate_name | 候选人姓名 | string | |
| candidate_phone | 候选人电话号码 | string | unique |
| question_id | 题目 id | int | 不作为外键(因为题目可能被删) |
| coding_language | 编程语言 | string | (或者枚举) |
| code | 代码 | string | |
| description | 面试简介 | string | 长度不大于 1024 字符 |
| over | 是否结束 | bool | not null |
| start_time | 开始时间 | date-time | |
| end_time | 结束时间 | date-time | |
8.3 聊天记录 [ Message ]
|---------------|-------|-----------|-------------|
| 字段名 | 含义 | 数据类型 | 说明 |
| record_id | 记录号 | string | foreign key |
| name | 发送者姓名 | string | not null |
| isInterviewer | 是面试官? | boolean | not null |
| time | 时间 | date-time | not null |
| content | 内容 | string | not null |
8.4 题库 [Question]
|--------------|--------|--------|-------------------------|
| 字段名 | 含义 | 数据类型 | 说明 |
| question_id | 题目 id | int | primary key |
| interview_id | 面试官 id | string | foreign key |
| title | 题目标题 | string | not null |
| content | 题目描述 | string | not null |
| degree | 难度 | int | 1=> 简单,2=> 中等,3=> 困难 |
| input | 测试样例 | string | |
| output | 预期输出 | string | |
| date | 题目创建日期 | string | not null |
9、编码实现
整体上,项目分为前端与后端,通过路由地址进行 JSON 格式的数据传输。
前端采用 VUE3 和 element plus. 用户直接同前端交互,前端对输入数据进行预处理,向后端发起相应的路由请求,并使用功能性组件对数据进行展示。具体而言,在关键部分采用了如下技术:编程界面(ace-build)、聊天(WebSocket)、语音聊天(webRTC)、富文本形式的面试题目(CKEditor 4)。
后端采用 NodeJS, express 和 MySQL. 后端响应前端的路由请求,与数据库交互,完成对数据表的增删改查。
具体参考源代码。
10、测试
10.1 测试策略
对输入数据的功能输入不同数据进行测试,其他功能按不同功能大块进行测试。具体功能按设计文档和需求说明书测试
10.2 测试原则
以不同功能为区分对项目进行测试,每个项目的测试提供一到两组标准数据以及若干组不符合标准的数据,在有修改项目时也提供与现有数据冲突的数据进行测试。
10.3 测试用例设计
10.3.1 测试用面试官信息
|----|--------------------------------------------------------|--------------|----------|----|
| 姓名 | 邮箱 | 密码 | 公司 | 性别 |
| 大一 | 17163330115@qq.commailto:17163330115@qq.com | a1234567890_ | 华南理工大学 | 男 |
| 大二 | scut123@scut.commailto:scut123@scut.com | a1234567890_ | 计算机科学与工程 | 女 |
| 大三 | 219000000 | a1234567890_ | 华南理工大学 | 男 |
| | 17163330116@qq.commailto:17163330116@qq.com | a1234567890_ | 华南理工大学 | 男 |
| 大五 | 17163330117@qq.commailto:17163330117@qq.com | 1234567890_ | 华南理工大学 | 男 |
| 大六 | 17163330118@qq.commailto:17163330118@qq.com | a1234567890_ | | 男 |
| 大七 | 17163330119@qq.commailto:17163330119@qq.com | a1234567890_ | 华南理工大学 | |
10.3.2 测试用题目样例
|-----|----|--------|------|------|
| 题目名 | 难度 | 题目内容 | 测试输入 | 测试输出 |
| 1 | 简单 | 标准用例 1 | 输入 1 | 输出 1 |
| 1 | 中等 | 重复名称 1 | 输入 1 | 输出 1 |
| 2 | 困难 | | 输入 2 | 输出 2 |
| 3 | 简单 | 测试用例 3 | | 输出 3 |
| 4 | 中等 | 测试用例 4 | 输入 4 | |
| 5 | 困难 | 标准用例 5 | 输入 5 | 输出 5 |
10.3.3 测试用候选者信息
|----|-------------|--------|
| 姓名 | 手机 | 备注 |
| 小一 | 13627770000 | |
| 小二 | 13627770000 | 重复电话测试 |
| 小一 | 13628880000 | 重复姓名测试 |
| 小三 | 13629990000 | |
10.4 测试过程
10.4.1 注册功能测试
|--------------|---------------|---------------|
| 测试操作 | 预期结果 | 实际结果 |
| 使用标准样例注册 | 注册成功 | 注册成功 |
| 使用重复邮箱注册 | 注册失败,提示邮箱已被注册 | 注册失败,没有提示信息 |
| 使用不符合格式要求的密码 | 注册失败,提示密码不合规范 | 注册失败,提示密码不合规范 |
| 不输入公司注册 | 注册成功 | 注册成功 |
| 不输入姓名注册 | 注册失败,提示输入姓名 | 注册失败,提示输入姓名 |
| 熟入重复姓名注册 | 注册成功 | 注册成功 |
| 不输入性别注册 | 注册成功 | 注册成功 |
10.4.2 题库功能测试
|-------------|---------------|---------------|
| 测试操作 | 预期结果 | 实际结果 |
| 使用标准样例添加题目 | 添加成功,显示在题库中 | 添加成功,显示在题库中 |
| 使用重复题目名添加题目 | 添加成功,显示在题库中 | 添加成功,显示在题库中 |
| 不输入题目内容添加题目 | 添加失败 | 添加失败 |
| 不输入测试输入添加题目 | 添加成功,显示在题库中 | 添加成功,显示在题库中 |
| 不输入测试输出添加题目 | 添加成功,显示在题库中 | 添加成功,显示在题库中 |
| 查看题库(单项) | 显示题目信息 | 显示题目信息 |
| 查看题库(选择多项) | 查看失败,提示只能选择单项 | 查看失败,提示只能选择单项 |
| 题目编辑 | 题目信息修改,显示在题库中 | 题目信息修改,显示在题库中 |
| 题目编辑(删除必填项) | 修改失败,提示添加必填项 | 修改失败,提示添加必填项 |
10.4.3 面试功能测试
|-----------------|-------------------------|-------------------------|
| 测试操作 | 预期结果 | 实际结果 |
| 单个题目创建面试 | 创建成功 | 创建成功 |
| 面试者输入姓名和手机号加入面试 | 加入成功 | 加入成功 |
| 面试者与面试官实时文字对话 | 可以实时显示对方发送的消息 | 可以实时显示对方发送的消息 |
| 面试者与面试官语音通话 | 可以互相进行通话 | 无法进行在线通话 |
| 编程语言选择功能 | 面试者可选择不同编程语言作答 | 面试者可选择不同编程语言作答 |
| 编辑器主题切换 | 可切换不同编辑器主题 | 可切换不同编辑器主题 |
| 面试时间记录 | 可记录面试的持续时间 | 面试官和面试者时间显示不一致 |
| 代码支持多种语言高亮 | 代码支持多种语言高亮 | 代码支持多种语言高亮 |
| 代码自动刷新 | 面试者的代码会在面试官处持续更新 | 面试者的代码会在面试官处持续更新 |
| 协同编程 | 面试官可以与候选人共同编写代码 | 面试官处代码只读,未实现协同编程 |
| 代码运行与输出 | 候选人和面试官可在线运行 JS 代码并查看输出 | 候选人和面试官可在线运行 JS 代码并查看输出 |
| 候选人侧提交最终编程代码 | 候选人侧提交最终编程代码 | 候选人侧提交最终编程代码 |
| 面试官侧刷新能看到最终代码 | 面试官侧刷新能看到最终代码 | 面试官侧刷新能看到最终代码 |
| 面试结束功能 | 结束面试,面试者强制退出,面试官处记录 | 结束面试,面试者强制退出,面试官处记录 |
| 面试官查看记录 | 面试官可查看面试相关信息 | 可查看相关信息,但在页面内面试时间会重新计时 |
10.4.4 其他
|------|------|------|
| 测试操作 | 预期结果 | 实际结果 |
| 退出登录 | 退出登录 | 成功退出 |
10.5 测试结论
本次课设基本达到了预先设计的功能需求,但在少部分地方存在 bug 以及可以改进的部分。在面试时语音通话的功能仍存在一定问题,由于语音功能部署在服务器上时只能在 https 协议下才支持获得音频流 getUserMedia,因此此处还有一定优化空间。另外存在部分功能正常而可优化的地方,如用户使用重复邮箱注册时可添加一定提示信息,以及面试官与候选者的协同编程功能。除此之外该编程平台的可用性较好,UI 引导也较为明显,基础功能也大都得以实现。
11、最后完成效果
11.1 最终实现功能
1. 登录/注册模块
- 支持邮箱登录和注册
- 支持退出登录
2.面试题模块
- 面试官可填写面试题
- 每个面试题有固定链接
- 支持新建面试题和修改面试题目
- 支持邀请一个候选人编程
- 面试题目支持富文本格式
4.在线编程模块
- 候选人可在线编写代码
- 代码支持多种语言高亮
- 候选人侧代码支持自动保存
- 面试官侧代码自动刷新
5.实时文字聊天
- 候选人和面试官可实时文字聊天
- 聊天内容内容长期保存
6.在线编程模块
1..支持运行 JS 代码
2.候选人和面试官可在线运行 JS 代码并查看输出
11.2 部分效果展示

登录页面

注册页面

个人中心

笔试题库
笔试

记录信息

候选者进去信息填写界面

面试页面
♻️ 资源
大小: 21.3MB
➡️ 资源下载: https://download.csdn.net/download/s1t16/87415794
注:更多内容可关注微信公众号【神仙别闹】,如当前文章或代码侵犯了您的权益,请私信作者删除!
