耗时一个月开发的OJ在线判题系统,文末有项目地址,目前还在更新代码~
文章目录
项目介绍
OJ = Online Judge 在线判题评测系统
用户可以选择题目,在线做题,编写代码并且提交代码;系统会对用户提交的代码,根据我们出题人设置的答案,来判断用户的提交结果是否正确。
ACM(程序设计竞赛),也是需要依赖判题系统来检测参赛者的答案是否合理
OJ系统最大的难点在于判题系统
用于在线评测编程题目代码的系统,能够根据用户提交的代码,出题人预先设置的题目输入和输出用例,进行编写代码,运行代码,判断代码运行结果是否正确。
判题系统作为一个开发API提供给大家,便于开发者开发自己的OJ系统。
OJ系统的常用概念
ac表示题目通过,结果正确
题目限制:时间限制,内存限制
题目介绍
题目输入
题目输出
题目输入用例
题目输出用例
普通测评:管理员设置题目的输入和输出用例,比如我输入1,你要输入2才是正确的;交给判题机去执行用户的代码,给用户的代码喂输入用例,比如1,看用户程序的执行结果是否和标准答案的输出一致。
特殊测评(SPJ):管理员设置题目的输入和输出,比如我输入1,用户的答案只要是>0或者<2都是正确的,特判程序,不是通过对比用例文件是否一致这种死板的程序来检验,而是要专门根据这道题目写一个特殊的判断程序,程序接收题目的输入(1),标准输出用例(2),用户的结果(1.5),特判程序根据这些值来比较是否正确
交互测评:让用户输入一个例子,就给一个输出结果,交互比较灵活,没办法听过简单的,死板的输入输出文件来搞定
复习做项目的流程
- 项目介绍,项目调研,需求分析
- 核心业务流程
- 项目要做的功能
- 技术选型
- 项目初始化
- 项目开发
- 测试
- 优化
- 代码提交,代码审核
- 产品验收
- 上线
现有OJ系统调研
https://github.com/HimitZH/HOJ(适合学习)
https://github.com/QingdaoU/OnlineJudge(python,不好学,很成熟)
https://github.com/hzxie/voj(星星没那么多,没那么成熟,但相对好学)
https://github.com/vfleaking/uoj(php 实现的)
https://github.com/zhblue/hustoj(成熟,但是 php)
https://github.com/hydro-dev/Hydro(功能强大,Node.js 实现)
实现核心
1)权限校验
谁能提交代码,谁不能提交代码
2)代码沙箱(安全沙箱)
可能会出现的问题
用户代码藏毒问题:写个木马文件,修改系统权限,所以要使用沙箱
资源分配问题:假设系统的内存就2个G,用户疯狂占用资源占满你的内存,其他人就用不了了,所以要限制用户程序的占用资源
沙箱:隔离的,安全的环境,用户的代码不会影响到沙箱之外的系统的运行
3)判题规则
题目用例的比对,结果的验证
4)任务调度
服务器资源有限,用户要排队,按照顺序去依次执行判题,而不是直接拒绝
5)提交之后,会生成一个提交记录,有运行的结果及运行信息(时间消耗,内存消耗等)
核心业务流程
简略流程图
详细时序图
注意:判题服务:获取用户信息,预计的输入输出结果,返回给主业务后端:用户的答案是否准确
代码沙箱:只负责运行代码,给出结果,两个模块实现了解耦
业务功能
题目模块
- 创建题目(管理员)
- 删除题目(管理员)
- 修改题目(管理员)
- 搜索题目(用户)
- 在线做题
- 提交题目代码
用户模块
- 注册
- 登录
判题模块
- 提交判题(结果是正确还是错误)
- 错误处理(内存溢出,安全性,超时)
- 自主实现代码沙箱(安全沙箱)
- 开放接口(提供一个独立的新服务)
项目扩展思路
- 支持多种语言
- Remote Judge
- 完善的评测功能:普通测评,特殊测评,交互测评,在线自测,子任务分组评测,文件IO
- 统计分析用户判题记录
- 权限校验
技术选型
前端
Vue3,Arco Design组件库,手撸项目模版,在线代码编辑器,在线文档浏览
后端
Java进程控制,java安全管理器,部分JVM知识点
虚拟机(云服务器),Docker(代码沙箱实现)
Spring Cloud微服务,消息队列,多种设计模式
架构设计
主流的OJ系统实现方案
开发原则:能用别人现成的,就不要自己写
1、用现成的OJ系统
网上有很多开源的OJ项目,比如青岛OJ,HustOJ等,可以直接下载开源代码自己部署
比较推荐的是judge0,这是一个非常成熟的商业OJ项目,支持60多种编程语言
代码:https://github.com/judge0/judge0
2、用现成的API等服务
如果你不希望完整部署一套大而全的代码,只是想复用他人已经实现的,最复杂的判题逻辑,那么可以直接使用现成的判题API、或者现成的代码沙箱等服务
比如judge0提供的判题API,非常方便易用。只需要通过HTTP调用submissions判题接口,把用户的代码,输入值,预期的执行结果作为请求参数发送给judge0的服务器,他就能自动帮你编译执行程序,并且返回程序的运行结果。
如下图,发送了一段打印“hello world”的程序,得到了程序执行的时间、状态等:
API的作用:接收代码,返回执行结果
Judge0 API 地址:https://rapidapi.com/judge0-official/api/judge0-ce
官方文档:https://ce.judge0.com/#submissions-submission-post
流程
- 先注册
- 开通免费订阅
- 测试language接口
- 测试执行代码接口submissions
示例接口参数:
{
"source_code": "#include <stdio.h>\n\nint main(void) {\n char name[10];\n scanf(\"%s\", name);\n printf(\"hello, %s\n\", name);\n return 0;\n}",
"language_id": "4",
"stdin": "Judge0",
"expected_output": "hello, Judge0"
}
返回结果:
{
"source_code": "includestdiohintmainvoidcharname10scanfsnameprintfhellosname\nreturn0=\n",
"language_id": 76,
"stdin": "Judgew==\n",
"expected_output": "helloJudge0=\n",
"stdout": null,
"status_id": 6,
"created_at": "2023-07-27T13:50:30.433Z",
"finished_at": "2023-07-27T13:50:31.022Z",
"time": null,
"memory": null,
"stderr": null,
"token": "8be000ad-2edb-4262-b367-7095a694e028",
"number_of_runs": 1,
"cpu_time_limit": "5.0",
"cpu_extra_time": "1.0",
"wall_time_limit": "10.0",
"memory_limit": 128000,
"stack_limit": 64000,
"max_processes_and_or_threads": 60,
"enable_per_process_and_thread_time_limit": false,
"enable_per_process_and_thread_memory_limit": false,
"max_file_size": 1024,
"compile_output": "bWFpbi5jcHA6MToxOiBlcnJvcjogc291cmNlIGZpbGUgaXMgbm90IHZhbGlk\nIFVURi04Cjw4QT53JTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p7ZmoPEE3PjxC\nRT48ODg+PDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48RDc+SzxVKzAw\nMUM+anfsnak8OUU+PEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2PlosPDlEPjxB\nOT48OUU+PEFEPjxFQj5uPEFFPn0KXgptYWluLmNwcDoxOjI6IGVycm9yOiB1\nbmtub3duIHR5cGUgbmFtZSAndycKPDhBPnclPEI5PjxVKzA1RUM+PEI1Ptio\nPDg2Pintmag8QTc+PEJFPjw4OD48OUQ+cjxVKzAwMTY+PEFCPjw5RD48QTk+\nPDlFPjxENz5LPFUrMDAxQz5qd+ydqTw5RT48QTY+PEI4PjxBNz48QjU+PEY4\nPl48OTY+Wiw8OUQ+PEE5Pjw5RT48QUQ+PEVCPm48QUU+fQogICAgXgptYWlu\nLmNwcDoxOjM6IGVycm9yOiBleHBlY3RlZCB1bnF1YWxpZmllZC1pZAo8OEE+\ndyU8Qjk+PFUrMDVFQz48QjU+2Kg8ODY+Ke2ZqDxBNz48QkU+PDg4Pjw5RD5y\nPFUrMDAxNj48QUI+PDlEPjxBOT48OUU+PEQ3Pks8VSswMDFDPmp37J2pPDlF\nPjxBNj48Qjg+PEE3PjxCNT48Rjg+Xjw5Nj5aLDw5RD48QTk+PDlFPjxBRD48\nRUI+bjxBRT59CiAgICAgXgptYWluLmNwcDoxOjQ6IGVycm9yOiBzb3VyY2Ug\nZmlsZSBpcyBub3QgdmFsaWQgVVRGLTgKPDhBPnclPEI5PjxVKzA1RUM+PEI1\nPtioPDg2Pintmag8QTc+PEJFPjw4OD48OUQ+cjxVKzAwMTY+PEFCPjw5RD48\nQTk+PDlFPjxENz5LPFUrMDAxQz5qd+ydqTw5RT48QTY+PEI4PjxBNz48QjU+\nPEY4Pl48OTY+Wiw8OUQ+PEE5Pjw5RT48QUQ+PEVCPm48QUU+fQogICAgICBe\nCm1haW4uY3BwOjE6NzogZXJyb3I6IHNvdXJjZSBmaWxlIGlzIG5vdCB2YWxp\nZCBVVEYtOAo8OEE+dyU8Qjk+PFUrMDVFQz48QjU+2Kg8ODY+Ke2ZqDxBNz48\nQkU+PDg4Pjw5RD5yPFUrMDAxNj48QUI+PDlEPjxBOT48OUU+PEQ3Pks8VSsw\nMDFDPmp37J2pPDlFPjxBNj48Qjg+PEE3PjxCNT48Rjg+Xjw5Nj5aLDw5RD48\nQTk+PDlFPjxBRD48RUI+bjxBRT59CiAgICAgICAgICAgICAgICAgIF4KbWFp\nbi5jcHA6MToxMDogZXJyb3I6IHNvdXJjZSBmaWxlIGlzIG5vdCB2YWxpZCBV\nVEYtOAo8OEE+dyU8Qjk+PFUrMDVFQz48QjU+2Kg8ODY+Ke2ZqDxBNz48QkU+\nPDg4Pjw5RD5yPFUrMDAxNj48QUI+PDlEPjxBOT48OUU+PEQ3Pks8VSswMDFD\nPmp37J2pPDlFPjxBNj48Qjg+PEE3PjxCNT48Rjg+Xjw5Nj5aLDw5RD48QTk+\nPDlFPjxBRD48RUI+bjxBRT59CiAgICAgICAgICAgICAgICAgICAgICAgXgpt\nYWluLmNwcDoxOjE1OiBlcnJvcjogc291cmNlIGZpbGUgaXMgbm90IHZhbGlk\nIFVURi04Cjw4QT53JTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p7ZmoPEE3PjxC\nRT48ODg+PDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48RDc+SzxVKzAw\nMUM+anfsnak8OUU+PEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2PlosPDlEPjxB\nOT48OUU+PEFEPjxFQj5uPEFFPn0KICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgXgptYWluLmNwcDoxOjE2OiBlcnJvcjogc291cmNlIGZpbGUgaXMg\nbm90IHZhbGlkIFVURi04Cjw4QT53JTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p\n7ZmoPEE3PjxCRT48ODg+PDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48\nRDc+SzxVKzAwMUM+anfsnak8OUU+PEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2\nPlosPDlEPjxBOT48OUU+PEFEPjxFQj5uPEFFPn0KICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgIF4KbWFpbi5jcHA6MToxNzogZXJyb3I6IHNv\ndXJjZSBmaWxlIGlzIG5vdCB2YWxpZCBVVEYtOAo8OEE+dyU8Qjk+PFUrMDVF\nQz48QjU+2Kg8ODY+Ke2ZqDxBNz48QkU+PDg4Pjw5RD5yPFUrMDAxNj48QUI+\nPDlEPjxBOT48OUU+PEQ3Pks8VSswMDFDPmp37J2pPDlFPjxBNj48Qjg+PEE3\nPjxCNT48Rjg+Xjw5Nj5aLDw5RD48QTk+PDlFPjxBRD48RUI+bjxBRT59CiAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXgptYWluLmNw\ncDoxOjE4OiBlcnJvcjogc291cmNlIGZpbGUgaXMgbm90IHZhbGlkIFVURi04\nCjw4QT53JTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p7ZmoPEE3PjxCRT48ODg+\nPDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48RDc+SzxVKzAwMUM+anfs\nnak8OUU+PEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2PlosPDlEPjxBOT48OUU+\nPEFEPjxFQj5uPEFFPn0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgXgptYWluLmNwcDoxOjIxOiBlcnJvcjogc291cmNlIGZp\nbGUgaXMgbm90IHZhbGlkIFVURi04Cjw4QT53JTxCOT48VSswNUVDPjxCNT7Y\nqDw4Nj4p7ZmoPEE3PjxCRT48ODg+PDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5\nPjw5RT48RDc+SzxVKzAwMUM+anfsnak8OUU+PEE2PjxCOD48QTc+PEI1PjxG\nOD5ePDk2PlosPDlEPjxBOT48OUU+PEFEPjxFQj5uPEFFPn0KICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nIF4KbWFpbi5jcHA6MToyMjogZXJyb3I6IHNvdXJjZSBmaWxlIGlzIG5vdCB2\nYWxpZCBVVEYtOAo8OEE+dyU8Qjk+PFUrMDVFQz48QjU+2Kg8ODY+Ke2ZqDxB\nNz48QkU+PDg4Pjw5RD5yPFUrMDAxNj48QUI+PDlEPjxBOT48OUU+PEQ3Pks8\nVSswMDFDPmp37J2pPDlFPjxBNj48Qjg+PEE3PjxCNT48Rjg+Xjw5Nj5aLDw5\nRD48QTk+PDlFPjxBRD48RUI+bjxBRT59CiAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXgptYWlu\nLmNwcDoxOjIzOiBlcnJvcjogc291cmNlIGZpbGUgaXMgbm90IHZhbGlkIFVU\nRi04Cjw4QT53JTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p7ZmoPEE3PjxCRT48\nODg+PDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48RDc+SzxVKzAwMUM+\nanfsnak8OUU+PEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2PlosPDlEPjxBOT48\nOUU+PEFEPjxFQj5uPEFFPn0KICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXgptYWluLmNw\ncDoxOjI0OiBlcnJvcjogc291cmNlIGZpbGUgaXMgbm90IHZhbGlkIFVURi04\nCjw4QT53JTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p7ZmoPEE3PjxCRT48ODg+\nPDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48RDc+SzxVKzAwMUM+anfs\nnak8OUU+PEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2PlosPDlEPjxBOT48OUU+\nPEFEPjxFQj5uPEFFPn0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIF4KbWFpbi5j\ncHA6MToyNTogZXJyb3I6IHNvdXJjZSBmaWxlIGlzIG5vdCB2YWxpZCBVVEYt\nOAo8OEE+dyU8Qjk+PFUrMDVFQz48QjU+2Kg8ODY+Ke2ZqDxBNz48QkU+PDg4\nPjw5RD5yPFUrMDAxNj48QUI+PDlEPjxBOT48OUU+PEQ3Pks8VSswMDFDPmp3\n7J2pPDlFPjxBNj48Qjg+PEE3PjxCNT48Rjg+Xjw5Nj5aLDw5RD48QTk+PDlF\nPjxBRD48RUI+bjxBRT59CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXgpt\nYWluLmNwcDoxOjMzOiBlcnJvcjogc291cmNlIGZpbGUgaXMgbm90IHZhbGlk\nIFVURi04Cjw4QT53JTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p7ZmoPEE3PjxC\nRT48ODg+PDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48RDc+SzxVKzAw\nMUM+anfsnak8OUU+PEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2PlosPDlEPjxB\nOT48OUU+PEFEPjxFQj5uPEFFPn0KICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgIF4KbWFpbi5jcHA6MTozNDogZXJyb3I6IHNv\ndXJjZSBmaWxlIGlzIG5vdCB2YWxpZCBVVEYtOAo8OEE+dyU8Qjk+PFUrMDVF\nQz48QjU+2Kg8ODY+Ke2ZqDxBNz48QkU+PDg4Pjw5RD5yPFUrMDAxNj48QUI+\nPDlEPjxBOT48OUU+PEQ3Pks8VSswMDFDPmp37J2pPDlFPjxBNj48Qjg+PEE3\nPjxCNT48Rjg+Xjw5Nj5aLDw5RD48QTk+PDlFPjxBRD48RUI+bjxBRT59CiAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nXgptYWluLmNwcDoxOjM1OiBlcnJvcjogc291cmNlIGZpbGUgaXMgbm90IHZh\nbGlkIFVURi04Cjw4QT53JTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p7ZmoPEE3\nPjxCRT48ODg+PDlEPnI8VSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48RDc+SzxV\nKzAwMUM+anfsnak8OUU+PEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2PlosPDlE\nPjxBOT48OUU+PEFEPjxFQj5uPEFFPn0KICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXgptYWluLmNwcDoxOjM2\nOiBlcnJvcjogc291cmNlIGZpbGUgaXMgbm90IHZhbGlkIFVURi04Cjw4QT53\nJTxCOT48VSswNUVDPjxCNT7YqDw4Nj4p7ZmoPEE3PjxCRT48ODg+PDlEPnI8\nVSswMDE2PjxBQj48OUQ+PEE5Pjw5RT48RDc+SzxVKzAwMUM+anfsnak8OUU+\nPEE2PjxCOD48QTc+PEI1PjxGOD5ePDk2PlosPDlEPjxBOT48OUU+PEFEPjxF\nQj5uPEFFPn0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAg\nICAgICAgICAgICAgICAgICAgIF4KZmF0YWwgZXJyb3I6IHRvbyBtYW55IGVy\ncm9ycyBlbWl0dGVkLCBzdG9wcGluZyBub3cgWy1mZXJyb3ItbGltaXQ9XQoy\nMCBlcnJvcnMgZ2VuZXJhdGVkLgo=\n",
"exit_code": null,
"exit_signal": null,
"message": null,
"wall_time": null,
"compiler_options": null,
"command_line_arguments": null,
"redirect_stderr_to_stdout": false,
"callback_url": null,
"additional_files": null,
"enable_network": false,
"status": {
"id": 6,
"description": "Compilation Error"
},
"language": {
"id": 76,
"name": "C++ (Clang 7.0.1)"
}
}
3、自主开发
自主实现判题服务和代码沙箱,适合学习,但不适用于商业项目,本项目即自主开发
4、把AI来当做代码沙箱
直接扔给AI一段代码,输入参数,问他能否得到预期的结果,就实现了在线判题逻辑
5、移花接木大法
让程序来爬虫操作模拟浏览器,用别人已经开发好的OJ系统来帮我们判题
比如使用Puppeteer + 无头浏览器,把我们系统用户提交的代码,想人一样输入到别人的OJ网页,让程序点击提交按钮,并且等别人的OJ系统返回判题结果后,再把这个结果返回给我们自己的用户
这种方式缺点就是把核心流程交给了别人,如果别人服务挂了,你的服务也就挂了,而且别人OJ系统不支持的题目,可能你也支持不了
图标设计
这是chatgpt给出的评价:这里是包含完整“YOJ”文字并采用绿色和黄色组合的单个图标设计。这个图标充满活力和动感,传达了在线编码挑战和代码评估的概念。它现代、简洁、专业,适合代表一个编码平台。
项目地址
(求求大佬们赏个star~)
前端:https://github.com/IMZHEYA/yoj-frontend
后端:https://github.com/IMZHEYA/yoj-backend
代码沙箱:https://github.com/IMZHEYA/yoj-code-sandbox