在线 OJ
项目源代码
在线oj系统类似于LeetCode, 牛客这样的网站, 实现在页面上编写代码, 并提交运行~~
1. 实现功能
- 能够保存题目(数据库)
- 展示题目列表
- 展示题目详细信息(标题, 难度, 题目的描述, 题目代码的模板)
- 能够在线编辑代码, 并提交运行
2. java多线程编程
编译运行 java 程序
- javac 命令进行编译
- java 命令进行运行
当我们输入 javac, 或者 java 这些命令的时候, 其实操作系统也是创建出了一个相应进程 (javac 和 java 命令是两个进程), 去执行对应的编译或者运行任务
Process process= Runtime.getRuntime().exec(cmd);
在 OJ 系统中, 用户在网页输入代码通过 HTTP 请求发送到服务器, 服务器就需要创建出一个 javac 进程, 通过 javac 进程把这段代码编译成 .class 文件。 在创建出一个 java 进程, 通过 java 进程来执行这个 .class 文件, 并运行里面的测试用例
3. 准备工作
3.1 创建一些新的类
- Question类: 表示要进行编译运行的代码
- Answer类: 表示运行的结果
- Task类: 执行过程中需要的临时文件 (编译执行过程中的中间结果)
以文件的方式保存, 目的是为了方便 "进程间通信"
3.2 唯一ID
(1) 针对多个用户一起给服务器提交代码, 给这些文件写到不同的目录里面
用户 A 写入的文件目录 ./tmp1/
用户 B 写入的文件目录 ./tmp2/
(2) 自增主键
时间戳 + 机器编号 + 机房序号 + 随机因子
(3) UUID
自动生成一个唯一的ID
创建目录使用 mkdir (这个命令只能创建一级目录)
如果一次要创建多级目录, 要是用 mkdirs
每处理一个请求, 都生成一个新的目录以及一堆新的文件, 请求多了内存会不会就不够了?
- 一定会, 在实际开发中, 这些临时文件是必要保存的, 不管是为了进程间通信, 也是为了未来解决 BUG 的重要依据
- 数据是要保留的, 但是定期清理, 定期备份即可
3.3 Task.compileAndRun
- 先创建出目录, 为了让每个用户每次请求的目录都不同, 互不影响, 使用了 UUID 来辅助生成目录
- 把用户提交的代码构建成 .java 文件
- 构建编译指令, 创建子进程执行编译的过程, 把编译出错的结果生成到 compile_error.txt 文件中,
通过判定这个文件是否为空来感知到当前编译是否出错~~ - 构建运行命令, 创建子进程执行代码, 把运行的结果放到 stdout.txt 和 stderr.txt 中, 如果程序抛出异常,
异常信息就会通过标准错误写入到 stderr.txt 里, 然后父进程读取该文件, 就能知道异常信息是什么了 - 把运行结果包装成 Answer 对象, 返回到前端网页
3.4 数据库的建立
create database if not exists oj;
use oj;
drop table if exists oj_table;
create table oj_table (
id int primary