数据库表

-- 创建库
create database if not exists oj;
 
-- 切换库
use oj;
 
-- 用户表
create table if not exists user
(
    id           bigint auto_increment comment 'id' primary key,
    userAccount  varchar(256)                           not null comment '账号',
    userPassword varchar(512)                           not null comment '密码',
    unionId      varchar(256)                           null comment '微信开放平台id',
    mpOpenId     varchar(256)                           null comment '公众号openId',
    userName     varchar(256)                           null comment '用户昵称',
    userAvatar   varchar(1024)                          null comment '用户头像',
    userProfile  varchar(512)                           null comment '用户简介',
    userRole     varchar(256) default 'user'            not null comment '用户角色:user/admin/ban',
    createTime   datetime     default CURRENT_TIMESTAMP not null comment '创建时间',
    updateTime   datetime     default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    isDelete     tinyint      default 0                 not null comment '是否删除',
    index idx_unionId (unionId)
) comment '用户' collate = utf8mb4_unicode_ci;
 
-- 题目表
create table if not exists question
(
    id         bigint auto_increment comment 'id' primary key,
    title      varchar(512)                       null comment '标题',
    content    text                               null comment '内容',
    tags       varchar(1024)                      null comment '标签列表(json 数组)',
    answer     text                               null comment '题目答案',
    submitNum  int  default 0 not null comment '题目提交数',
    acceptedNum  int  default 0 not null comment '题目通过数',
    judgeCase text null comment '判题用例(json 数组)',
    judgeConfig text null comment '判题配置(json 对象)',
    thumbNum   int      default 0                 not null comment '点赞数',
    favourNum  int      default 0                 not null comment '收藏数',
    userId     bigint                             not null comment '创建用户 id',
    createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
    updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    isDelete   tinyint  default 0                 not null comment '是否删除',
    index idx_userId (userId)
) comment '题目' collate = utf8mb4_unicode_ci;
 
-- 题目提交表
create table if not exists question_submit
(
    id         bigint auto_increment comment 'id' primary key,
    language   varchar(128)                       not null comment '编程语言',
    code       text                               not null comment '用户代码',
    judgeInfo  text                               null comment '判题信息(json 对象)',
    status     int      default 0                 not null comment '判题状态(0 - 待判题、1 - 判题中、2 - 成功、3 - 失败)',
    questionId bigint                             not null comment '题目 id',
    userId     bigint                             not null comment '创建用户 id',
    createTime datetime default CURRENT_TIMESTAMP not null comment '创建时间',
    updateTime datetime default CURRENT_TIMESTAMP not null on update CURRENT_TIMESTAMP comment '更新时间',
    isDelete   tinyint  default 0                 not null comment '是否删除',
    index idx_questionId (questionId),
    index idx_userId (userId)
) comment '题目提交';

生成代码编写业务逻辑

  1. 使用 mybatisX 生成生成entity、service、mapper层以及xml代码,并复制到对应的包
|--------------|-------------------------------|
| annotation   | None [ ]                      |
|              | Mybatis-Plus 2 [ ]            |
|              | Mybatis-Plus 3 [x]            |
|              | JPA [ ]                       |
|--------------|-------------------------------|
| options      | Comment [x]                   |
|              | Actual Column [x]             |
|              | Model [x]                     |
|              | toString/hashCode/equals [ ]  |
|              | Actual Column Annotation [ ]  |
|              | Lombok [x]                    |
|              | JSR310: Date API [ ]          |
|--------------|-------------------------------|
| template     | custom-model-swagger [ ]      |
|              | mybatis-plus2 [ ]             |
|              | default-all [ ]               |
|              | mybatis-plus3 [x]             |
|              | default-empty [ ]             |
|--------------|-------------------------------|
  1. 从功能相似的 controller 基础上创建所需要的 QuestionController 和 QuestionSubmitController 单表复制单表、多表复制多表
  2. 创建对应的 DTO VO,直接复制实体类,在实体类的基础上修改
  3. JudgeConfig、JudgeCase、JudgeInfo 定义为单独的类。需要复用时不加业务前缀
  4. 校验 controller 层代码
  5. 实现 service 层代码(复制,全局替换)
  6. 编写枚举类
  7. 编写 questionSubmitQueryController

@EqualsAndHashCode(callSuper = true)

判题机框架

  1. 定义代码沙箱的接口
  2. 使用工厂模式,根据字符串生成代码沙箱实例;通过读取 application.yml 获得配置
  3. 单例模式(如果保证线程安全可使用)
  4. 代理模式
  5. 策略模式

重新创建项目

Java 原生代码沙箱

执行原理:

javac .\Main.java
java Main

linux 查看系统的字符集

locale

StopWatch 计算运行时间

StopWatch stopWatch = new StopWatch();
stopWatch.start();
// 代码
stopWatch.stop();
stopWatch.getTotalTimeMillis();

ProcessUtils 工具类:process 实例和输入,返回包含 状态、标准输出、错误输出 的封装类

根据系统编码调整输出流和错误流的解析编码 System.getProperty("sun.jnu.encoding")

怎样在Java中获取系统默认字符集? - 知乎

public class ProcessUtils {
 
    private static String readAllCharacters(InputStream inputStream) throws IOException {
        Charset charset = Charset.forName(System.getProperty("sun.jnu.encoding"));
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, charset));
        StringBuffer stringBuffer = new StringBuffer();
        String lineString;
        while ((lineString = bufferedReader.readLine()) != null) {
            stringBuffer.append(lineString).append("\n");
        }
        String output = stringBuffer.toString();
        return output;
    }
 
 
    public static ExecuteMessage runProcess(Process process, String input) throws IOException, InterruptedException {
        ExecuteMessage executeMessage = new ExecuteMessage();
        InputStream inputStream = process.getInputStream();
        InputStream errorStream = process.getErrorStream();
        OutputStream outputStream = process.getOutputStream();
        // 输入数据
        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
        outputStreamWriter.write(input + '\n');
        outputStreamWriter.flush();
        // 退出码
        int exitCode = process.waitFor();
        executeMessage.setExitCode(exitCode);
        // 输出数据
        String output = readAllCharacters(inputStream);
        executeMessage.setOutput(output);
        // 错误数据
        String error = readAllCharacters(errorStream);
        executeMessage.setError(error);
        return executeMessage;
    }
}

恶意代码处理

时间超限

内存超限

读写文件、运行程序和高危命令

java 操作 docker

https://github.com/docker-java/docker-java

maven 依赖

<!-- https://mvnrepository.com/artifact/com.github.docker-java/docker-java -->
<dependency>
    <groupId>com.github.docker-java</groupId>
    <artifactId>docker-java</artifactId>
    <version>3.3.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.docker-java/docker-java-transport-httpclient5 -->  
<dependency>  
    <groupId>com.github.docker-java</groupId>  
    <artifactId>docker-java-transport-httpclient5</artifactId>  
    <version>3.3.6</version>  
</dependency>