在线OJ个人系统
项目源码
项目描述
类似于牛客网、LeetCode这样的做题网站,能实现代码的编写、运行与提交。
项目功能
- 能够保存题目,用数据库来实现题库存储
- 展示题目列表
- 展示题目的详细信息(标题、难度、题目的描述和代码模板)
- 在线编辑、提交、编译运行代码
项目模块
- 题目的存储
进行数据库的操作:
首先创建DBUtil类,采用单例模式创建一个DataSource 实例。目的是能够快速的获取数据库的连接和关闭。
private static volatile DataSource dataSource = null;
public static DataSource getDataSource(){
if(dataSource == null){
synchronized (DBUtil.class) {
if(dataSource == null){
dataSource = new MysqlDataSource();
((MysqlDataSource)dataSource).setURL(URL);
((MysqlDataSource)dataSource).setUser(USERNAME);
((MysqlDataSource)dataSource).setPassword(PASSWORD);
}
}
}
return dataSource;
}
- 编译运行
模块介绍:给定Java代码文件,控制jdk进行编译和运行
首先创建CommandUtil 类:这个类里主要包含run方法,让Java代码能够去执行一个具体的指令,Runtime类和Process类,创建子进程,让子进程来执行编译和运行。
重定向:使用重定向,把进程执行完输出的内容写到指定的文件中。对标准输出和标准错误进行重定向。
if (stdoutFile != null) {
//getInputStream得到的标准输出
InputStream stdoutFrom = process.getInputStream();
//通过这个对象就可以去读取到当前新进程的标准输出的内容
FileOutputStream stdoutTo = new FileOutputStream(stdoutFile);
//接下来就从新进程这边一次读取每个字节,写入到stdoutTo这个文件里
while (true) {
int ch = stdoutFrom.read();
if (ch == -1) {
break;
}
stdoutTo.write(ch);
}
//文件读取完毕,关闭文件
stdoutFrom.close();
stdoutTo.close();
}
//再针对标准错误进行重定向
if (stderrFile != null) {
//getErrorStream 得到的是标准错误
InputStream stderrFrom = process.getErrorStream();
FileOutputStream stderrTo = new FileOutputStream(stderrFile);
while (true) {
int ch = stderrFrom.read();
if (ch == -1) {
break;
}
stderrTo.write(ch);
}
stderrFrom.close();
stderrTo.close();
}
**进程等待:**父进程和子进程并发执行,为了确保子进程能够先执行完,先让父进程等待,
//等待新进程结束,并获取到退出码
int exitCode = process.waitFor();
return exitCode;
后创建一些类,把整个Java程序的编译和运行过程组合到一起:
Question 类:一次编译运行过程所需的数据(主要是要运行的代码)
Answer 类:一次编译过程产生的数据(运行结果码、错误的原因等)
FileUtil:文件读写工具类,能够方便文件的读写
Task 类:定义compileAndRun,使用这个类来实现整体的编译和运行功能。主要过程为:
(1)创建存放临时文件的目录
(2)构建所需的临时文件
(3)构建编译命令:javac -encoding utf8 ./tmp/Solution.java -d ./tmp/(-d表示在编译命令中,生成的.class文件在哪个目录中),判断编译是否出错(对应的文件是否为空),如果出错,则不再执行
(4)构建运行命令并执行:形如java -classpath ./tmp/ Solution(-classpath来指定加载路径)
判断运行是否出错(是否存在异常),如果不错,不需要去执行,即判断标准错误对应的文件是否为空;
(5)将结果包装成Answer类返回
- 前后端API的实现
(1)首页显示,包含 OJ 系统的题目列表,需要一个能够显示所有题目的API
(2)点击某个具体题目,需要显示某个题目的详细信息的API
(3)能够实现代码的编写和提交到服务器上并编译运行的API
前端与后台的数据格式转换:
使用Gson来实现Java对象和JSON数据之间的转换。可以将一个json字符串转换为一个Java对象,或者将一个Java对象转换为json字符串
ProblemServlet 类作用:
利用重写doGet方法,解析Request对象,如果id字段为空。获取题目列表,只需要知道题目的id title level,通过调用ProblemDAO类里面的selectAll来获取到数据库中的题目列表,将它们转换成json字符串返回到前端
如果id字段不为空,就是显示某个题目的详细信息,根据获取到的id来确定。
CompileServlet 类作用:把编译框中用户编辑并提交的代码进行编译和运行并输出结果。
(1)创建两个类:CompileRequest请求对象和CompileResponse响应对象
(2)重写doPost方法:先读取请求数据中的所有数据——>解析json数据转换为CompileRequest对象——>根据CompileRequest对象的到id,按照id从数据库中读取对应题目的测试用例,再根据CompileRequest对象中用户输入的代码——>把用户代码和测试用来拼接起来,组成一个完整的可执行的代码——>创建Task对象,把组装的完整代码运行行起来——>把运行结果构造成响应数据,并写回客户端。
- 前端界面
需要前端页面把后端逻辑串联起来
系统主要有两个页面
(1)题目列表页:主要有一个表格,显示系统中所有的题目
(2)题目详情页:主要能显示题目的信息信息,以及一个代码编辑框
借助JQuery库,完成从网页访问服务器的操作
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
借助Vue框架,实现数据库的数据渲染到页面
<!--Vue的引入-->
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
项目技术
- HTTP:发送数据请求
- 多进程编程:使用多进程实现代码的编译和运行
- JDBC:实现数据库的操作
- MySQL:使用MySQL数据库作为业务数据的存储
- AJAX:页面发送AJAX请求至后端
- Gson:将Java对象和JSON数据相互转换
项目的核心流程
用户在界面的代码编辑框内输入自己的代码,用户点击提交按钮,就在后台把用户提交的代码和测试用例代码拼接起来得到完整代码,然后调用 CompileUtil 来运行 javac代码,如果代码运行正常,就把运行的相应结果返回页面,如果出现异常,就进行异常捕获,将捕获的异常和相应的结果返回