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

news2024/12/29 10:13:00

编写测试类(代理模式)

实现示例的代码沙箱

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 {
    @Override
    public 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 {

    // 题目服务
    @Resource
    private QuestionService questionService;

    // 题目提交服务
    @Resource
    private QuestionSubmitService questionSubmitService;


    @Value("${codesandbox.type:example}")
    private String value;

    @Override
    public 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.coloradmin.cn/o/2168468.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 冯诺依曼体系结构与操作系统概念

目录 0.前言 1. 冯诺依曼体系结构概述 1.1 输入单元 1.2 中央处理单元&#xff08;CPU&#xff09; 1.3 输出单元 2. 冯诺依曼体系结构的关键特性 2.1 所有数据流向内存 2.2 数据流动示例&#xff1a;QQ聊天过程 3. 操作系统 3.1 概念 3.2 设计操作系统的目的 3.3 操作系统的“…

华为源NAT技术与目的NAT技术

1&#xff09;源NAT对报文源地址进行转换&#xff0c;分为NAT NO-PAT&#xff0c;NAPT,EASY-IP,三元组NAT&#xff1b; &#xff08;1&#xff09;NAT NO-PAT原理&#xff1a; no-port address translation:非端口地址转换&#xff1a;只转换地址&#xff0c;不转换端口&…

【C++位图】构建灵活的空间效率工具

目录 位图位图的基本概念如何用位图表示数据位图的基本操作setresettest 封装位图的设计 总结 在计算机科学中&#xff0c;位图&#xff08;Bitmap&#xff09;是一种高效的空间管理数据结构&#xff0c;广泛应用于各种场景&#xff0c;如集合操作、图像处理和资源管理。与传统…

使用docker形式部署prometheus+alertmanager+钉钉告警

一、拉取所需要的镜像 docker pull prom/node-exporter docker pull grafana/grafana docker pull prom/prometheus docker pull prom/alertmanager 其中 prom/node-exporter&#xff1a;用于收集主机系统信息和指标的 grafana/grafana&#xff1a;是一个用于可视化和分…

word2vector理论

目录 1.理论 2.公式 3.SkipGram的优化 1.理论 2.公式 3.SkipGram的优化 CBOW的优化, CBOW是用上下文预测中心词. Hirarchical softmax帮助我们最快的找到最大的softmax, 通过建立一个霍夫曼树.

【数据结构】AVL树相关知识详细梳理

1. AVL树的概念 AVL的全称是Adelson-Velsky-Landis&#xff0c;其名称来源于其发明者Adelson、Velsky和Landis&#xff0c; 是平衡二叉树搜索树。 它的出现是由于二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找…

城市轨道交通网络客流大数据可视化分析系统----以某市交通网络客流数据为例

1 引言 1.1研究背景、目的与意义 1.1.1研究背景 城市轨道交通系统是现代城市的重要交通方式之一&#xff0c;随着城市化进程的加速和人口增长&#xff0c;轨道交通系统的客流量不断增加。因此&#xff0c;轨道交通部门和相关企业需要对客流数据进行实时监测和分析&#xff0…

云数据库RDS MySQL性能测试与对比@2024年09月

原创&#xff1a;orczhouninedata 来源&#xff1a;云数据库技术 在不同的云厂商购买相同规格的MySQL实例(如4vCPU-16GB)&#xff0c;获得的性能相同吗&#xff0c;他们的差异如何&#xff1f;本文继续尝试回答这个问题。 详细数据&#xff1a; 测试结果概述 在本次测试中&…

常见的TTL,RS232,RS485,IIC,SPI,UART之间的联系和区别

简单总结 图片来源 RS232,RS485可参考&#xff0c;IIC&#xff0c;SPI,UART可参考 烧录程序中常听到的一句话就是USB转TTL&#xff0c;但严格来说算是USB传输数据的协议转换成TTL&#xff08;Transistor-Transistor Logic&#xff09;协议传输数据。首先&#xff0c;usb是常见…

电脑资料被拷贝了,能查出来吗?5个方法有效防止电脑泄密!

网络快速发展的背景下&#xff0c;电脑资料的安全问题日益凸显。 一旦电脑资料被非法拷贝&#xff0c;不仅可能导致企业核心机密泄露&#xff0c;还可能对个人隐私造成严重影响。 那么&#xff0c;当电脑资料被拷贝时&#xff0c;我们能否查出来&#xff1f;又该如何有效防止…

【Python】必学!教你如何在日志中隐藏明文密码?看完包会的!(附带免费源码)

前言 在项目开发中&#xff0c;有的时候会遇到一些安全需求&#xff0c;用以提升程序整体的安全性&#xff0c;提高外来非法攻击的门槛&#xff0c;而在日志中隐藏明文密码打印便是最典型的安全需求之一。 在Python中&#xff0c;明文密码往往发生于命令执行参数、debug日志、…

施耐德EcoStruxure Machine SCADA Expert(EMSE)数据监测(十八)

通过EMSE与sql数据库连接,可以实现一些过程数据的监测、存档,实现生产过程的可视化。 1.创建sql数据库表单 新建一个名为Table_Monitor的表单,添加三个元素:Re_Index 序号;Re_Date 时间;Re_Temper 温度(需要监测的数据) 2.EMSE内关联变量 2.1 先创建网格 2.2 选择数据…

unity CustomEditor的基本使用

CustomEditor用来自定义脚本的编辑面板 其基本使用方式 先准备一个类&#xff0c;继承MonoBehaviour 定义一个变量&#xff0c;然后准备一个类&#xff0c;继承自Editor 在CustomEditor中指定要去修改的类型&#xff0c;通过serializedObject.FindProperty(变量名)的方式来获…

Ubuntu下安装向日葵:闪退

下载 https://sunlogin.oray.com/download 初次安装 $ sudo dpkg -i SunloginClient_15.2.0.63064_amd64.deb 正在选中未选择的软件包 sunloginclient。 (正在读取数据库 ... 系统当前共安装有 234281 个文件和目录。) 准备解压 SunloginClient_15.2.0.63064_amd64.deb ..…

Java.动态代理

1.创建一个接口 package Mydynamicproxy1;public interface Star {public abstract String sing(String str);public abstract void dance(String str); }2.创建一个BigStar类&#xff0c;要实现Star这个接口 package Mydynamicproxy1;public class BigStar implements Star{…

甘肃非遗文化网站:Spring Boot开发实战

3 系统分析 当用户确定开发一款程序时&#xff0c;是需要遵循下面的顺序进行工作&#xff0c;概括为&#xff1a;系统分析–>系统设计–>系统开发–>系统测试&#xff0c;无论这个过程是否有变更或者迭代&#xff0c;都是按照这样的顺序开展工作的。系统分析就是分析系…

Java EE中的编码问题及解决方案

Java EE中的编码问题及解决方案 在Java EE开发中&#xff0c;处理字符编码是确保数据正确传输和显示的重要环节。不同的编码不一致会导致乱码&#xff0c;影响用户体验。本文将总结在Java EE中可能遇到的编码问题及其解决方案。 1. 输入数据编码问题 在表单提交时&#xff0c…

【中级通信工程师】终端与业务(三):电信业务

【零基础3天通关中级通信工程师】 终端与业务(三)&#xff1a;电信业务 本文是中级通信工程师考试《终端与业务》科目第三章《电信业务》的复习资料和真题汇总。终端与业务是通信考试里最简单的科目&#xff0c;有效复习通过率可达90%以上&#xff0c;本文结合了高频考点和近几…

代码随想录算法训练营第十六天|512.找树左下角的值 112. 路径总和 113. 路径总和ii 106.从中序与后序遍历序列构造二叉树

512.找树左下角的值 给定一个二叉树&#xff0c;在树的最后一行找到最左边的值。 示例 1: 示例 2: 思路&#xff1a; 递归三部曲&#xff1a; 参数和返回值&#xff1a;传入节点是参数&#xff0c;返回值是最终值int终止条件&#xff1a;遇到空节点直接返回&#xff0c;或者…

SD2.0 Specification之写保护

文章目录 1 机械开关写保护&#xff08;由主机负责实现效果&#xff09;2 卡内部写保护&#xff08;由卡负责实现&#xff09;3 密码写保护 本文章主要讲解关于SD2.0写保护功能的内容&#xff0c;基础概念和其它内容请参考以下文章。 SD2.0 Specification简述 SD卡支持3种写保护…