OJ在线评测系统 后端 使用代理模式编写测试类 并 实现核心业务判题流程

server/2024/10/19 23:25:23/

编写测试类(代理模式)

实现示例的代码沙箱

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 com.dduo.dduoj.model.dto.questionsubmit.JudgeInfo;
import com.dduo.dduoj.model.enums.JudgeInfoMessageEnum;
import com.dduo.dduoj.model.enums.QuestionSubmitStatusEnum;
import lombok.extern.slf4j.Slf4j;import java.util.List;//示例代码沙箱 (仅供测试 跑通业务流程)
@Slf4j
public class ExampleCodeSandbox implements CodeSandbox {@Overridepublic ExecuteCodeResponse executeCode(ExecuteCodeRequest executeCodeRequest) {List<String> inputList = executeCodeRequest.getInputList();String code = executeCodeRequest.getCode();String language = executeCodeRequest.getLanguage();ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();executeCodeResponse.setOutputList(inputList);executeCodeResponse.setMessage("测试执行成功");executeCodeResponse.setStatus(QuestionSubmitStatusEnum.SUCCESS.getValue());JudgeInfo judgeInfo=new JudgeInfo();judgeInfo.setMessage(JudgeInfoMessageEnum.Accepted.getText());judgeInfo.setMemoryLimit(100L);judgeInfo.setTime(100L);executeCodeResponse.setJudgeInfo(judgeInfo);return executeCodeResponse;}
}

我们先把示例代码沙箱跑通 然后再直接把远程代码沙箱接进去

我们在调用代码沙箱前 输出请求参数日志 在代码沙箱调用后 输出响应结果日志 便于管理员去分析

每一个代码沙箱类都会写一遍log.info 难道每次调用代码沙箱前后都要执行log吗

我的理解是使用代理模式 提供一个Proxy 来增强代码沙箱的能力

代理模式的本质就是增强能力

原本:需要用户自己去调用多次

实现核心业务判题流程

在之前问题提交实现类里面加上判题服务

先写一个JudgeService

梳理一下判题服务的逻辑

第一步是获取到传入题目的id 获取到对应的题目信息 提交信息(代码 编程语言

第二步调用沙箱 获取到执行结果

第三步是根据沙箱的执行结果 设置题目的判题状态

我们接下来在实现类里面补全代码

根据沙箱的执行结果 我们设置题目的判题状态和信息

节约系统资源 解决一些不一致的问题

更改判题(题目提交)状态为判题中 防止重复执行

判断逻辑

先判断沙箱的执行结果输出数量是否和预期输出的数量相等

依次判断每一项输出和预期输出是否相等

判断题目的限制是否满足要求

可能还有其他的情况

首先我们拿到题目提交信息 拿到题目

进行简单的判断

证明了题目存在 我们开始判题 首先我们要更改题目的状态

之后我我们要把我们代码放入代码沙箱

根据代码沙箱的执行结果

我们首先要设置题目的判题状态和信息是否正确

从之前注入的两个对象中拿到输入用例 和预计输出用例

开始校验

首先我们校验输出的用例数量和预计输出是否相等

再去判断每一项输出的具体内容和预计输出是否相等

通过循环校验

到最后拿到题目限制

进行判断

可能还会有其他的异常情况

package com.dduo.dduoj.judge;import cn.hutool.json.JSONUtil;
import com.dduo.dduoj.common.ErrorCode;
import com.dduo.dduoj.exception.BusinessException;
import com.dduo.dduoj.judge.codesandbox.CodeSandbox;
import com.dduo.dduoj.judge.codesandbox.CodeSandboxFactory;
import com.dduo.dduoj.judge.codesandbox.CodeSandboxProxy;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeRequest;
import com.dduo.dduoj.judge.codesandbox.model.ExecuteCodeResponse;
import com.dduo.dduoj.model.dto.question.JudgeCase;
import com.dduo.dduoj.model.dto.question.JudgeConfig;
import com.dduo.dduoj.model.dto.questionsubmit.JudgeInfo;
import com.dduo.dduoj.model.entity.Question;
import com.dduo.dduoj.model.entity.QuestionSubmit;
import com.dduo.dduoj.model.enums.JudgeInfoMessageEnum;
import com.dduo.dduoj.model.enums.QuestionSubmitLanguageEnum;
import com.dduo.dduoj.model.enums.QuestionSubmitStatusEnum;
import com.dduo.dduoj.model.vo.QuestionSubmitVO;
import com.dduo.dduoj.service.QuestionService;
import com.dduo.dduoj.service.QuestionSubmitService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;@Service
public class JudgeServiceImpl implements JudgeService {// 题目服务@Resourceprivate QuestionService questionService;// 题目提交服务@Resourceprivate QuestionSubmitService questionSubmitService;@Value("${codesandbox.type:example}")private String value;@Overridepublic QuestionSubmitVO doJudge(Long questionSubmitId) {QuestionSubmit questionSubmit = questionSubmitService.getById(questionSubmitId);if (questionSubmit == null) {throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "提交信息不存在");}//拿到题目提交信息Long questionId = questionSubmit.getQuestionId();//拿到题目Question question = questionService.getById(questionId);if (question == null) {throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");}// 题目存在// 开始判题// 更改题目的状态 status// 如果不为等待状态if (questionSubmit.getStatus().equals(QuestionSubmitStatusEnum.WAITING.getValue())) {throw new BusinessException(ErrorCode.OPERATION_ERROR, "题目正在判题中");}// 重新设置QuestionSubmit questionSubmitUpdate = new QuestionSubmit();questionSubmitUpdate.setId(questionSubmitId);questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());boolean judge = questionSubmitService.updateById(questionSubmitUpdate);if (!judge) {throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");}// 接下来放代码沙箱CodeSandbox codeSandbox = CodeSandboxFactory.NewInstance(value);codeSandbox = new CodeSandboxProxy(codeSandbox);// 拿出数据String code = questionSubmit.getCode();String language = questionSubmit.getLanguage();// 获取输入用例String judgeCaseStr = question.getJudgeCase();List<JudgeCase> judgeCaselist = JSONUtil.toList(judgeCaseStr, JudgeCase.class);List<String> inputList = judgeCaselist.stream().map(JudgeCase::getInput).collect(Collectors.toList());ExecuteCodeRequest executeRequest = ExecuteCodeRequest.builder().code(code).language(language).inputList(inputList).build();ExecuteCodeResponse executeCodeResponse=codeSandbox.executeCode(executeRequest);// 根据沙箱的执行结果 设置题目的判题状态和信息是否正确JudgeInfoMessageEnum judgeInfoMessageEnum=JudgeInfoMessageEnum.Waiting;// 校验输出数量是否和预计输出数量相等List<String> outputList = executeCodeResponse.getOutputList();if(outputList.size()!=inputList.size()){judgeInfoMessageEnum=judgeInfoMessageEnum.Wrong_Answer;return null;}// 校验每一项输出和预期输出是否相等for(int i=0;i<judgeCaselist.size();i++){JudgeCase judgeCase = judgeCaselist.get(i);if(judgeCase.getOutput().equals(outputList.get(i))){judgeInfoMessageEnum=JudgeInfoMessageEnum.Wrong_Answer;return null;}}// 判断题目的限制JudgeInfo judgeInfo = executeCodeResponse.getJudgeInfo();Long memory = judgeInfo.getMemoryLimit();Long time = judgeInfo.getTime();String judgeConfigStr = question.getJudgeConfig();JudgeConfig judgeConfig = JSONUtil.toBean(judgeConfigStr, JudgeConfig.class);Long memoryLimit = judgeConfig.getMemoryLimit();Long timeLimit = judgeConfig.getTimeLimit();// 内存限制if(memory>memoryLimit){judgeInfoMessageEnum=JudgeInfoMessageEnum.Memory_Limit_Exceeded;return null;}// 时间限制if(time>timeLimit){judgeInfoMessageEnum=JudgeInfoMessageEnum.Time_Limit_Exceeded;return null;}return null;}
}

http://www.ppmy.cn/server/126453.html

相关文章

基于单片机电容测量仪仿真设计

文章目录 前言资料获取设计介绍设计程序具体实现截图设计获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师&#xff0c;一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们…

Redis 实现分布式锁时需要考虑的问题

引言 分布式系统中的多个节点经常需要对共享资源进行并发访问&#xff0c;若没有有效的协调机制&#xff0c;可能会导致数据竞争、资源冲突等问题。分布式锁应运而生&#xff0c;它是一种保证在分布式环境中多个节点可以安全地访问共享资源的机制。而在Redis中&#xff0c;使用…

Pytorch基本知识

model.state_dict()、model.parameters()和model.named_parameters()的区别 parameters()只包含模块的参数,即weight和bias(包括BN的)。 named_parameters()返回包含模块名和模块的参数的列表,列表的每个元素均是包含layer name和layer param的元组。layer param就是param…

根据给定的相机和镜头参数,估算相机的内参。

1. 相机分辨率和传感器尺寸 最高分辨率&#xff1a;6000 4000 像素传感器尺寸&#xff1a;22.3 mm 14.9 mm 2. 计算像素大小 需要计算每个像素对应的实际尺寸&#xff08;mm/pixel&#xff09;&#xff1a; 水平方向像素大小&#xff1a; 垂直方向像素大小&#xff1a; …

Goland使用SSH远程Linux进行断点调试 (兼容私有库)

① 前置需求 ssh远程的 Linux 服务器必须安装 高于本地的 Go推荐golang 安装方式使用 apt yum snap 等系统自管理方式&#xff0c;&#xff08;要安装最新版本的可以找找第三方源&#xff09;&#xff0c;如无特殊需求不要自行编译安装golang ② Goland设置 2.1、设置项处理…

树莓派5:换源(针对Debian12)+安装包管理器Archiconda(图文教程+详细+对初学者超级友好)

目录 一、安装官方发行版系统&#xff08;Debian&#xff09;二、换源&#xff08;记得参考上述教程ssh连接到树莓派Terminal&#xff0c;or外接一块Hdmi显示屏&#xff09;2.1 查看自己安装的树莓派镜像架构2.2 查询自己的系统版本2.3 打开清华大学开源软件镜像站网站2.3.1 传…

Kafka 面试题

参考&#xff1a; https://javabetter.cn/interview/kafka-40.htmlhttps://javaguide.cn/high-performance/message-queue/kafka-questions-01.html Kafka 架构 名词概念 Producer&#xff08;生产者&#xff09; : 产生消息的一方。 Consumer&#xff08;消费者&#xff09; …

D3.js数据可视化基础——基于Notepad++、IDEA前端开发

实验:D3.js数据可视化基础 1、实验名称 D3数据可视化基础 2、实验目的 熟悉D3数据可视化的使用方法。 3、实验原理 D3 的全称是(Data-Driven Documents),是一个被数据驱动的文档,其实就是一个 JavaScript 的函数库,使用它主要是用来做数据可视化的。本次实…