基于Java开发的在线OJ项目


建议大家直接看springboot+mybatis+vue版本的,个人感觉更简单明了,在SE版本的基础上扩展了一些功能。 码云地址

一、项目说明

1.1 项目目标

  • 巩固JDBC、Http、Servlet和Java基础等内容
  • 实现一个在线做题、判题系统

1.2 项目平台与技术栈

  • 技术栈:Servlet、Mysql、Runtime
  • 平台与环境:Windows、IDEA、Maven、Tomcat

1.3 项目功能

  • 进入题目列表页,展示当前系统中的所有题目
  • 进入题目详情页,展示题目的具体要求和代码模块,提供一个编辑框来供用户编辑
  • 对Java代码的编译/运行/测试功能,针对用户提交的代码进行编译运行,并自动执行测试用例、返回测试结果

二、项目演示

2.1 进入题目列表页

在这里插入图片描述

2.2 进入题目详情页

在这里插入图片描述

2.3 编写代码

在这里插入图片描述

2.4 提交运行

点击提交之后,服务器最终会将结果会返给客户端。

在这里插入图片描述

三、系统流程(核心)

起初,我们需要在后台录入题目和测试用例。

四、系统设计

4.1 执行指令设计

通过Runtime对象下的exec()方法能让Java代码去执行一个具体的指令,并且将标准输出和标准错误进行重定向。

4.2 编译和运行设计

  • 一次编译过程中依赖要编译的代码,和标准输入中的内容
  • 一次编译运行过程中会产生:状态码、出错原因、标准输出对应的内容、标准错误对应的内容
  • 编译过程中依赖临时文件:要编译运行的文件、编译错误对应的文件、标准输出对应的文件、标准错误对应的文件

4.3 读写文件的设计

  • 将指定文件中的内容读到String中
  • 将String中的内容写到指定文件中

4.4 数据库设计

需要保存题目id、标题、难易程度、描述信息、模板代码和测试用例

4.5 JDBC工具类

  • 获取数据库连接
  • 释放资源

4.6 题目增删查的设计

4.6.1 查

用sql语句直接去数据库中查询

  • 获取题目列表
    • 获取所有题目id、标题、难易程度
  • 获取一道题目详细信息
    • 获取指定id题目的id、标题、难易程度、描述信息、模板代码、测试用例;测试用例不提供给客户端。

4.6.2 增

插入题目的id、标题、难易程度、描述信息、模板代码、测试用例信息到数据库中

4.6.3 删

删除数据库中指定id的行

4.7 题目信息API

4.7.1 获取题目列表页

系统流程橘色部分对应模块

4.7.2 获取题目详情页

系统流程黄色部分对应模块

4.8 提交运行API

系统流程绿色部分对应模块

4.9 前端设计

五、开发步骤

5.1 创建maven项目

在pom.xml文件中引入依赖包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>haozhang</groupId>
    <artifactId>online_oj</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <!-- <name>blogdemo Maven Webapp</name> -->
    <!-- FIXME change it to the project's website -->
    <!-- <url>http://www.example.com</url> -->

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <!--    servlet和tomcat版本有对应关系        -->
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <!--这个意思是我们只在开发阶段使用servlet,部署到tomcat上的时候就不需要了-->
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.49</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <finalName>online_oj</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
            <plugins>
                <plugin>
                    <artifactId>maven-clean-plugin</artifactId>
                    <version>3.1.0</version>
                </plugin>
                <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
                <plugin>
                    <artifactId>maven-resources-plugin</artifactId>
                    <version>3.0.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>3.8.0</version>
                </plugin>
                <plugin>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.22.1</version>
                </plugin>
                <plugin>
                    <artifactId>maven-war-plugin</artifactId>
                    <version>3.2.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.5.2</version>
                </plugin>
                <plugin>
                    <artifactId>maven-deploy-plugin</artifactId>
                    <version>2.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
    </build>
</project>

5.2 编译模块设计

5.2.1 设计类让Java代码可以执行一条指令

package compile;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * 
 * 借助这个类让Java代码能够去执行一个具体的命令
 * 如 javac Test.java
 *
 * @author haozhang
 * @date 2020/09/04
 */
public class CommandUtil {
   

    /**
     *
     * @param cmd 要执行的命令
     * @param stdoutFile 表示标准输出结果重定向到那个文件中  如果为null表示不需要重定向
     * @param stderrFile 表示标准错误结果重定向到哪个文件中
     * @throws IOException
     */
    public static int run(String cmd, String stdoutFile, String stderrFile) throws IOException, InterruptedException {
   
        //1.获取Runtime对象,Runtime对象是一个单例的
        Runtime runtime = Runtime.getRuntime();

        //2.通过Runtime中的 exec 方法来执行一个指令 相当于在命令行中执行cmd命令
        Process process = runtime.exec(cmd);

        //3.针对标准输出进行重定向
        if (stdoutFile != null) {
   
            InputStream stdoutFrom = process.getInputStream();
            OutputStream stdoutTo = new FileOutputStream(stdoutFile);

            int ch = -1;
            while ((ch = stdoutFrom.read()) != -1) {
   
                stdoutTo.write(ch);
            }

            stdoutFrom.close();
            stdoutTo.close();
        }

        //4.针对标准错误重定向
        if (stderrFile != null) {
   
            InputStream stderrFrom = process.getErrorStream();
            OutputStream stderrTo = new FileOutputStream(stderrFile);

            int ch = -1;
            while ((ch = stderrFrom.read()) != -1) {
   
                stderrTo.write(ch);
            }

            stderrFrom.close();
            stderrTo.close();
        }

        //5.为了确保子进程先执行完  就需要加上进程等待的逻辑
        //父进程会在这里阻塞,直到子进程执行结束,才继续往下执行
        int exitCode = process.waitFor();
        return exitCode;

    }

    public static void main(String[] args) throws IOException, InterruptedException {
   
        run("javac", "d:/oj/stdout.txt", "d:/oj/stderr.txt");
    }
}

5.2.2 一次编译过程中的依赖

package compile;

/**
 * 
 * 一次编译运行过程中都依赖哪写数据
 *
 * @author haozhang
 * @date 2020/09/04
 */
public 
  • 28
    点赞
  • 162
    收藏
    觉得还不错? 一键收藏
  • 25
    评论
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值