OJ在线评测系统 后端 判题机模块预开发 架构分析 使用工厂模式搭建
判题机模块预开发(架构师)(工厂模式)
判题机模块
是为了把代码交个代码沙箱去处理 得到结果返回
代码沙箱
梳理判题模块和代码沙箱的关系
判题模块:调用代码沙箱 把代码和输入交给代码沙箱去执行
代码沙箱:只负责接受代码和输入 返回编译的结果 不负责判题
这两个模块完全解耦
我们采用API交互
为什么代码沙箱要接受和输出一组运行用例
前提:我们的每道题目有多组测试用例
如果每个用例单独调用一个代码用例 会调用多次接口 需要多次网络运输 程序要多次编译 记录程序的执行状态 重复的代码不重复编译
这是一种常见的性能优化的方法
创建一个新的包
用来放代码沙箱模块

先写一个接口

package com.dduo.dduoj.judge.codesandbox;public interface CodeSandbox {ExecuteCodeRequest executeCode(ExecuteCodeRequest executeCodeRequest);
}
提高通用性
之后我们的项目代码只调用接口
不调用具体的实现类
就不用去修改名称了 便于拓展
写一下实体类
ExecuteCodeRequest请求
package com.dduo.dduoj.judge.codesandbox.model;import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.List;@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExecuteCodeRequest {private List<String> inputList;private String code;private String language;
}

ExecuteCodeResponse响应

package com.dduo.dduoj.judge.codesandbox.model;import com.dduo.dduoj.model.dto.question.JudgeConfig;
import com.dduo.dduoj.model.dto.questionsubmit.JudgeInfo;import java.util.List;public class ExecuteCodeResponse {private List<String> outputList;//执行信息private String message;//执行状态private Integer status;private JudgeInfo judgeInfo;
}
完善

定义不同的代码沙箱实现类
示例代码沙箱

远程代码沙箱

第三方代码沙箱

架构工作
lombok Builder注解

测试一下

package com.dduo.dduoj.judge.codesandbox;import com.dduo.dduoj.judge.codesandbox.impl.ExampleCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.impl.RemoteCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;import com.dduo.dduoj.model.enums.QuestionSubmitLanguageEnum;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;import java.util.Arrays;
import java.util.List;@SpringBootTest
class CodeSandboxTest {@Testvoid executeCode() {CodeSandbox codeSandbox = new RemoteCodeSandbox();String code = "int main() { }";String language = QuestionSubmitLanguageEnum.JAVA.getValue();List<String> inputList = Arrays.asList("1 2", "3 4");ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder().code(code).language(language).inputList(inputList).build();ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);Assertions.assertNotNull(executeCodeResponse);}
}
![]()
工厂模式
但是现在问题是我们把new代码沙箱写死了 如果后面项目要改用其他沙箱
可能要改很多地方的代码
我们要使用工厂模式
根据用具传入的字符串参数 生成对应的代码沙箱实现类


package com.dduo.dduoj.judge.codesandbox;import com.dduo.dduoj.judge.codesandbox.impl.ExampleCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.impl.RemoteCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.impl.ThirdPartyCodeSandbox;//代码沙箱工厂 根据字符串参数 创建指定的代码沙箱示例
public class CodeSandboxFactory {/** 创建代码沙箱示例* @param type 沙箱类型* @return* */public static CodeSandbox NewInstance(String type) {switch (type) {case "example":return new ExampleCodeSandbox();case "remote":return new RemoteCodeSandbox();case "thirdParty":return new ThirdPartyCodeSandbox();default:return new ExampleCodeSandbox();}}
}
如果确定代码沙箱示例不会出现线程安全问题
可复用
那么可以使用单例工厂模式
但是这种方式是不可取的 我们应该把这些东西放到配置里面
配置化 去改配置文件 而不是修改字符串
这就叫参数配置化 开发者只需要去修改配置文件 而不是去看项目代码 就能自定义使用项目的更多功能
先在application.yml里面去设置

再在程序里面去读取

示例

package com.dduo.dduoj.judge.codesandbox;import com.dduo.dduoj.judge.codesandbox.impl.ExampleCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.impl.RemoteCodeSandbox;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;import com.dduo.dduoj.model.enums.QuestionSubmitLanguageEnum;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;import java.util.Arrays;
import java.util.List;@SpringBootTest
class CodeSandboxTest {@Value("${codesandbox.type:example}")private String value;@Testvoid executeCode() {CodeSandbox codeSandbox = CodeSandboxFactory.NewInstance(value);String code = "int main() { }";String language = QuestionSubmitLanguageEnum.JAVA.getValue();List<String> inputList = Arrays.asList("1 2", "3 4");ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder().code(code).language(language).inputList(inputList).build();ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);Assertions.assertNotNull(executeCodeResponse);}
}
我们要增强代码沙箱的能力
在调用代码沙箱前 输出请求参数 在代码沙箱调用后 输出响应结果日志

package com.dduo.dduoj.judge.codesandbox.impl;import com.dduo.dduoj.judge.codesandbox.CodeSandbox;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;
import lombok.extern.slf4j.Slf4j;//示例代码沙箱 (仅供测试 跑通业务流程)
@Slf4j
public class ExampleCodeSandbox implements CodeSandbox {@Overridepublic ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {log.info("请求信息"+executeCodeRequest.toString());System.out.println("示例代码沙箱");return null;}
}
思考
我们每一个代码沙箱类都写一个 log.info ?
难道每次调用代码沙箱前后都要执行log ?
我们使用代理模式 提供一个Proxy 来增强代码沙箱的能力
静态代理模式
中介
调用者调用代理类 代理类去调用代码沙箱
代理类还可以做一些额外的功能
不仅不用改变原本的代码沙箱实现类 而且对调用者来说 基本也没有改变
也不需要在每一个调用代码沙箱的地方去统计代码

package com.dduo.dduoj.judge.codesandbox;import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;@Slf4j
@AllArgsConstructor
public class CodeSandboxProxy implements CodeSandbox{private CodeSandbox codeSandbox;@Overridepublic ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {log.info("代码沙箱的请求信息"+executeCodeRequest.toString());ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);log.info("代码沙箱的响应信息"+executeCodeResponse.toString());return executeCodeResponse;}
}
接下来我们就可以去修改调用方式

@Test
void executeCodeByProxy() {CodeSandbox codeSandbox = CodeSandboxFactory.NewInstance(value);codeSandbox =new CodeSandboxProxy(codeSandbox);String code = "int main() { }";String language = QuestionSubmitLanguageEnum.JAVA.getValue();List<String> inputList = Arrays.asList("1 2", "3 4");ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder().code(code).language(language).inputList(inputList).build();ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);Assertions.assertNotNull(executeCodeResponse);
}相关文章:
OJ在线评测系统 后端 判题机模块预开发 架构分析 使用工厂模式搭建
判题机模块预开发(架构师)(工厂模式) 判题机模块 是为了把代码交个代码沙箱去处理 得到结果返回 代码沙箱 梳理判题模块和代码沙箱的关系 判题模块:调用代码沙箱 把代码和输入交给代码沙箱去执行 代码沙箱:只负责接受代码和输入 返回编译的结果 不负…...
linux 目录文件夹操作
目录 查看文件夹大小: Linux统计文件个数 2.统计文件夹中文件个数ls -l ./|grep "^-"|wc -l 4.统计文件夹下文件个数,包括子文件ls -lR | grep "^-"| wc -l 统计文件个数 移动绝对目录: 移动相对目录 test.py报错…...
(Linux驱动学习 - 4).Linux 下 DHT11 温湿度传感器驱动编写
DHT11的通信协议是单总线协议,可以用之前学习的pinctl和gpio子系统完成某IO引脚上数据的读与写。 一.在设备树下添加dht11的设备结点 1.流程图 2.设备树代码 (1).在设备树的 iomuxc结点下添加 pinctl_dht11 (2).在根…...
前端登录页面验证码
首先,在el-form-item里有两个div,各占一半,左边填验证码,右边生成验证码 <el-form-item prop"code"><div style"display: flex " prop"code"><el-input placeholder"请输入验证…...
【鸿蒙】HarmonyOS NEXT应用开发快速入门教程之布局篇(上)
系列文章目录 【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器(上) 【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器(下) 【鸿蒙】HarmonyOS NEXT应用开发快速入门教程之布局篇(上) 文…...
使用 Nginx 和 Gunicorn 部署 Flask 项目详细教程
使用 Nginx 和 Gunicorn 部署 Flask 项目详细教程 在这篇文章中,我们将介绍如何使用 Nginx 和 Gunicorn 来部署一个 Flask 项目。这种部署方式非常适合在生产环境中使用,因为它能够提供更好的性能和更高的稳定性。 目录 Flask 项目简介环境准备Gunico…...
linux中bashrc和profile环境变量在Shell编程变量的传递作用
在 Linux 系统中,.bashrc文件和.profile文件都是用于配置用户环境的重要文件,它们之间有以下关联: 一、作用相似性 环境设置:两者都用于设置用户的环境变量和启动应用程序的配置。例如,它们可以定义路径变量…...
数据结构-4.2.串的定义和基本操作
一.串的定义: 1.单/双引号不是字符串里的内容,他只是一个边界符,用来表示字符串的头和尾; 2.空串也是字符串的子串,空串长度为0; 3.字符的编号是从1开始,不是0; 4.空格也是字符&a…...
fastzdp_redis第一次开发, 2024年9月26日, Python操作Redis零基础快速入门
提供完整录播课 安装 pip install fastzdp_redisPython连接Redis import redis# 建立链接 r redis.Redis(hostlocalhost, port6379, db0)# 设置key r.set(foo, bar)# 获取key的值 print(r.get(foo))RESP3 支持 简单的理解: 支持更丰富的数据类型 参考文档: https://blog.c…...
文件名:\\?\C:\Windows\system32\inetsrv\config\applicationHost.config错误:无法写入配置文件
文件名: \\?\C:\Windows\system32\inetsrv\config\applicationHost.config 错误:无法写入配置文件 解决办法: 到C:\inetpub\history中找到最近一次的【CFGHISTORY_00000000XX】文件,点击进去找到applicationHost.config文件,用其覆盖C:\Win…...
Optiver股票大赛Top2开源!
Optiver股票大赛Top2开源! ↑↑↑关注后"星标"kaggle竞赛宝典 作者:杰少 Optiver第二名方案解读 简介 Optiver竞赛已经于今天结束了,竞赛也出现了极端情况,中间断崖式的情况,在Kaggle过往的竞赛中&#…...
Maven 实现依赖统一管理
Maven 实现依赖统一管理主要是通过两个关键机制:pom.xml 文件中的 <dependencies> 节点用于声明项目依赖,以及通过继承(Inheritance)和聚合(Aggregation)功能来统一管理和组织这些依赖。此外…...
【最新】微信小程序连接onenet——stm32+esp8266+onenet实现查看温湿度,控制单片机
微信小程序——stm32esp8266onenet实现查看温湿度,控制单片机 (最新已验证)stm32 新版 onenet dht11esp8266/01s mqtt物联网上报温湿度和控制单片机(保姆级教程) :↓↓👇 👇 👇 👇…...
差分(续前缀和)(含一维二维)
题目引入 开发商小 Q 买下了一条街,他想在这条街的一边盖房子。 街道可以抽象为一条数轴,而小 Q 只会在坐标在 1~n 的范围内盖房子。 首先,小 Q 将街上坐标在 1∼ 𝑛1∼ n 范围内的物体全部铲平。也就是说,在正式动工盖…...
【STM32-HAL库】自发电型风速传感器(使用STM32F407ZGT6)(附带工程下载链接)
一、自发电型风速传感器介绍 自发电型风速传感器,也称为风力发电型风速传感器或无源风速传感器,是一种不需要外部电源即可工作的风速测量设备。这种传感器通常利用风力来驱动内部的发电机构,从而产生电能来供电测量风速的传感器部分。以下是自…...
【计算机毕业设计】springboot就业信息管理系统
就业信息管理系统 摘 要 随着信息化时代的到来,管理系统都趋向于智能化、系统化,就业信息管理系统也不例外,但目前国内仍都使用人工管理,市场规模越来越大,同时信息量也越来越庞大,人工管理显然已无法应对时…...
实用工具推荐---- PDF 转换
直接上链接:爱PDF |面向 PDF 爱好者的在线 PDF 工具 (ilovepdf.com) 主要功能如下: 全免费!!!!...
安宝特案例 | 某知名日系汽车制造厂,借助AR实现智慧化转型
案例介绍 在全球制造业加速数字化的背景下,工厂的生产管理与设备维护效率愈发重要。 某知名日系汽车制造厂当前面临着设备的实时监控、故障维护,以及跨地域的管理协作等挑战,由于场地分散和突发状况的不可预知性,传统方式已无法…...
RabbitMQ基本原理
一、基本结构 所有中间件技术都是基于 TCP/IP 协议基础之上进行构建新的协议规范,RabbitMQ遵循的是AMQP协议(Advanced Message Queuing Protocol - 高级消息队列协议)。 生产者发送消息流程: 1、生产者和Broker建立TCP连接&#…...
【NodeJS】npm、yarn、pnpm当前项目设置国内镜像源
全局设置镜像源,可以参考下这篇文章,还挺详细:《npm、yarn、pnpm 最新国内镜像源设置和常见问题解决》 临时设置镜像源:《npm永久或临时切换源》 有时候可能要同时多个开发项目,又不想修改全局的镜像源(具体场景…自行…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...
安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件
在选煤厂、化工厂、钢铁厂等过程生产型企业,其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进,需提前预防假检、错检、漏检,推动智慧生产运维系统数据的流动和现场赋能应用。同时,…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
