OJ判题系统第6期之判题逻辑开发——设计思路、实现步骤、代码实现(策略模式)

news2025/5/17 4:33:57

在看这期之前,建议先看前五期:

Java 原生实现代码沙箱(OJ判题系统第1期)——设计思路、实现步骤、代码实现-CSDN博客

Java 原生实现代码沙箱之Java 程序安全控制(OJ判题系统第2期)——设计思路、实现步骤、代码实现-CSDN博客

Java 原生实现代码沙箱之代码沙箱 Docker 实现(OJ判题系统第3期)——设计思路、实现步骤、代码实现-CSDN博客

OJ判题系统第4期之判题机模块架构——设计思路、实现步骤、代码实现(工厂模式、代理模式的实践)-CSDN博客 

OJ判题系统第5期之判题服务开发——设计思路、实现步骤、代码实现-CSDN博客 

判题逻辑的主要指责

定义

  • 判题逻辑 是具体判断用户提交的代码是否正确的核心算法或规则集。它专注于解析沙箱返回的结果,并根据预定义的标准(如测试用例、时间限制、内存限制等)判断代码的正确性。
  • 这是一个低层次的模块,主要关注具体的判题细节。

主要职责

  1. 解析沙箱输出:从沙箱返回的结果中提取关键信息(如输出、错误信息、耗时、内存占用等)。
  2. 比对测试用例:将沙箱的输出与题目提供的标准答案进行比对,判断每个测试用例是否通过。
  3. 生成判题报告:根据比对结果生成详细的判题报告(如哪些测试用例通过了,哪些失败了,失败的原因是什么)。
  4. 性能评估:根据资源消耗情况(如时间、内存)评估代码的效率。

策略模式优化

什么是策略模式(Strategy Pattern)?

策略模式是一种行为型设计模式,它定义了一系列算法或策略,并将每一个算法封装起来,使它们可以互相替换,独立于使用它们的客户端。

简单理解:

  • 把不同的“处理方式”封装成一个个独立的类。
  • 客户端在运行时决定使用哪一种策略。
  • 这样可以让程序更灵活、更易扩展、更易维护。

问题背景:判题逻辑复杂,存在多种判断方式 

在你的在线判题系统中,可能会遇到以下几种情况:

情况描述
Java 执行较慢Java 程序启动沙箱需要额外耗时(如 10 秒),总执行时间不能只看用户代码运行时间
Python 内存限制宽松不同语言对内存的消耗不同,判题标准也要变化
C++ 要求输出完全一致对输出格式要求严格,必须完全匹配才算通过
时间/内存限制动态调整根据题目难度、语言类型等自动调整阈值

❌ 如果不用策略模式,会出现什么问题?

  • 判题逻辑中会充斥大量 if...else 或 switch...case
  • 新增一个语言或规则时,要修改原有逻辑,违反开闭原则
  • 各种语言规则混在一起,可读性差,容易出错
  • 难以复用、难以测试、难以维护

解决方案:使用策略模式统一管理判题规则 

🔧 设计思路

我们将“如何根据沙箱执行结果和语言特性来判定是否通过”的逻辑抽象为一个接口,然后为每种语言提供一个具体的实现类。

这样做的好处是:

  • 每个语言的判题规则彼此隔离,互不干扰
  • 可以随时新增、修改某种语言的判题规则,不影响其他逻辑
  • 在运行时可以根据提交的语言类型动态选择对应的策略

总结一句话 

策略模式就像给系统装上了一个“可插拔的大脑”,你可以根据不同情况(比如语言类型)自动选择最合适的判题规则,而无需改动主流程代码。

策略模式的优势总结 

优势描述
✅ 解耦将判题逻辑与业务流程分离
✅ 易扩展新增语言只需添加策略类,符合开闭原则
✅ 易维护每种语言的规则独立,便于阅读和调试
✅ 动态切换支持运行时根据条件选择不同策略
✅ 清晰结构每个策略职责单一,符合单一职责原则

 实现步骤

定义判题策略接口,让代码更加通用化:

/**
 * 判题策略
 */
public interface JudgeStrategy {

    /**
     * 执行判题
     * @param judgeContext
     * @return
     */
    JudgeInfo doJudge(JudgeContext judgeContext);
}

定义判题上下文对象,用于定义在策略中传递的参数(可以理解为一种 DTO):

/**
 * 上下文类(Context Class)
 *
 * JudgeContext 用于封装和传递在不同判题策略中需要用到的所有参数。
 * 它作为数据容器,确保各个判题策略能够访问到所需的信息,而不必直接依赖外部对象。
 */
@Data // Lombok 注解,自动生成 getter 和 setter 方法
public class JudgeContext {

    /**
     * 沙箱执行结果信息
     *
     * 包含了用户提交代码在沙箱中运行时的各项指标,如耗时、内存占用等。
     * 这些信息对于判断代码的正确性和性能至关重要。
     */
    private JudgeInfo judgeInfo;

    /**
     * 测试用例输入列表
     *
     * 包含了题目定义的所有测试用例的输入数据。
     * 在判题过程中,这些输入将被传入用户提交的代码,并与输出结果进行比对。
     */
    private List<String> inputList;

    /**
     * 用户代码的实际输出列表
     *
     * 当用户提交的代码在沙箱中运行时,根据不同的测试用例输入,会生成相应的输出结果。
     * 这些输出结果会被收集起来,用于后续的比对和判断。
     */
    private List<String> outputList;

    /**
     * 题目定义的标准测试用例列表
     *
     * 每个标准测试用例包含了输入和期望的输出。
     * 判题逻辑需要将用户的实际输出与这些期望输出进行比对,以确定是否通过该测试用例。
     */
    private List<JudgeCase> judgeCaseList;

    /**
     * 当前题目对象
     *
     * 包含了题目的所有相关信息,如题目描述、难度等级、附加说明等。
     * 虽然在大多数情况下,具体的判题逻辑可能不会直接使用这些信息,但它们可能会在某些特定场景下有用。
     */
    private Question question;

    /**
     * 用户提交记录对象
     *
     * 包含了用户提交的详细信息,如提交时间、编程语言、用户代码等。
     * 这些信息对于跟踪和记录用户的提交历史非常重要。
     */
    private QuestionSubmit questionSubmit;
}

实现默认判题策略

DefaultJudgeStrategy.java

/**
 * 默认判题策略实现类
 *
 * 该策略用于处理通用语言(如 C++、JavaScript 等)的标准判题逻辑。
 * 包括:
 * - 判断输出数量是否匹配
 * - 判断每个测试用例的输出是否与预期一致
 * - 检查内存和时间是否超出题目限制
 */
public class DefaultJudgeStrategy implements JudgeStrategy {

    /**
     * 执行判题逻辑的核心方法
     *
     * @param judgeContext 判题上下文对象,包含所有需要的数据
     * @return 返回最终的判题结果信息(是否通过、错误类型、耗时、内存等)
     */
    @Override
    public JudgeInfo doJudge(JudgeContext judgeContext) {

从上下文中提取关键数据

        // 从上下文中获取沙箱返回的执行信息(如时间、内存)
        JudgeInfo judgeInfo = judgeContext.getJudgeInfo();
        Long memory = judgeInfo.getMemory();   // 用户程序使用的内存大小(单位:字节)
        Long time = judgeInfo.getTime();       // 用户程序运行的时间(单位:毫秒)

        // 获取输入列表和输出列表
        List<String> inputList = judgeContext.getInputList();   // 测试用例的输入数据
        List<String> outputList = judgeContext.getOutputList(); // 用户程序的实际输出结果

        // 获取题目信息和测试用例列表
        Question question = judgeContext.getQuestion();                     // 当前题目对象
        List<JudgeCase> judgeCaseList = judgeContext.getJudgeCaseList();    // 题目定义的标准测试用例

        // 初始化判题结果为“接受”状态
        JudgeInfoMessageEnum judgeInfoMessageEnum = JudgeInfoMessageEnum.ACCEPTED;

        // 创建一个新的 JudgeInfo 对象用于封装最终的判题结果
        JudgeInfo judgeInfoResponse = new JudgeInfo();
        judgeInfoResponse.setMemory(memory); // 设置实际使用内存
        judgeInfoResponse.setTime(time);     // 设置实际运行时间

初步校验输出数量是否与输入一致

        // 如果输出数量不等于输入数量,说明至少有一个测试用例没有正确输出
        if (outputList.size() != inputList.size()) {
            // 设置为“答案错误”
            judgeInfoMessageEnum = JudgeInfoMessageEnum.WRONG_ANSWER;
            judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());
            return judgeInfoResponse; // 直接返回错误结果
        }

举例说明:
假设题目有 3 个测试用例,但用户只输出了 2 条结果,说明至少有一个用例未通过,无需继续比对。

 逐条比对输出与预期是否一致

        // 遍历所有测试用例,检查每一条输出是否与期望输出相等
        for (int i = 0; i < judgeCaseList.size(); i++) {
            JudgeCase judgeCase = judgeCaseList.get(i); // 获取第 i 个标准测试用例
            String expectedOutput = judgeCase.getOutput(); // 期望输出
            String actualOutput = outputList.get(i);       // 实际输出

            // 如果两者不一致,则判定为“答案错误”
            if (!expectedOutput.equals(actualOutput)) {
                judgeInfoMessageEnum = JudgeInfoMessageEnum.WRONG_ANSWER;
                judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());
                return judgeInfoResponse; // 只要有一个测试用例失败,就直接返回错误
            }
        }

检查是否超过题目设定的资源限制

        // 从题目对象中获取判题配置(例如内存限制、时间限制)
        String judgeConfigStr = question.getJudgeConfig(); // JSON 字符串格式的配置
        JudgeConfig judgeConfig = JSONUtil.toBean(judgeConfigStr, JudgeConfig.class);

        // 获取题目要求的最大内存和最大运行时间
        Long needMemoryLimit = judgeConfig.getMemoryLimit(); // 内存限制(单位:MB)
        Long needTimeLimit = judgeConfig.getTimeLimit();     // 时间限制(单位:毫秒)

        // 将 MB 转换为字节进行比较(注意单位一致性)
        if (memory > needMemoryLimit * 1024L * 1024L) { // 1 MB = 1024 KB = 1024*1024 bytes
            judgeInfoMessageEnum = JudgeInfoMessageEnum.MEMORY_LIMIT_EXCEEDED;
            judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());
            return judgeInfoResponse;
        }

        // 检查是否超时
        if (time > needTimeLimit) {
            judgeInfoMessageEnum = JudgeInfoMessageEnum.TIME_LIMIT_EXCEEDED;
            judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());
            return judgeInfoResponse;
        }

全部通过,返回成功结果

        // 所有条件都满足,设置最终消息为“接受”
        judgeInfoResponse.setMessage(judgeInfoMessageEnum.getValue());

        // 返回完整的判题结果
        return judgeInfoResponse;
    }
}

总结一下这个类的职责:

步骤功能
1️⃣ 提取参数从 JudgeContext 中提取所有判题所需的信息
2️⃣ 输出数量校验判断输出数量是否与输入数量一致
3️⃣ 输出内容比对比较每个测试用例的实际输出与期望输出是否一致
4️⃣ 资源限制判断判断是否超出内存或时间限制
5️⃣ 返回结果构建并返回最终的判题结果

定义 JudgeManager

为什么要定义 JudgeManager

1. 集中管理判题逻辑

  • 问题背景: 在没有 JudgeManager 的情况下,每个地方调用判题逻辑时都需要手动判断使用哪种策略,这会导致大量的重复代码,增加维护成本。
  • 解决方案JudgeManager 将所有的判题逻辑集中管理,使得外部调用者只需传递 JudgeContext 对象即可完成判题操作,无需关心具体的实现细节。

2. 提高代码的可维护性和扩展性

  • 问题背景: 如果未来需要支持更多的编程语言或引入新的判题规则,直接修改现有代码容易引发潜在的风险。
  • 解决方案: 使用 JudgeManager 和策略模式,可以轻松地添加新的策略类而不需要修改原有代码,符合开闭原则(对扩展开放,对修改封闭)。

3. 简化客户端调用

  • 问题背景: 客户端代码如果直接与各种判题策略打交道,会显得非常复杂且不易于理解。
  • 解决方案JudgeManager 提供了一个统一的接口,客户端只需要知道如何构建 JudgeContext 并调用 doJudge 方法,极大地简化了调用过程。

4. 增强系统的灵活性

  • 问题背景: 不同编程语言可能有不同的运行环境要求(如启动时间、内存限制等),这些差异需要在判题时特别处理。
  • 解决方案JudgeManager 可以根据编程语言动态选择最适合的判题策略,确保每种语言都能得到公平准确的评判。
/**
 * 判题管理器
 *
 * JudgeManager 是整个判题系统的核心组件之一,负责根据用户提交的编程语言,
 * 动态选择并调用相应的判题策略(JudgeStrategy)。这有助于将复杂的判题逻辑
 * 进行模块化封装,便于后续维护和扩展。
 */
@Service // Spring 注解,标识该类为一个服务层组件
public class JudgeManager {

    /**
     * 执行判题操作
     *
     * 该方法接收一个包含所有必要信息的上下文对象(JudgeContext),
     * 根据用户提交的编程语言动态选择合适的判题策略,并返回最终的判题结果。
     *
     * @param judgeContext 包含了题目、用户提交、沙箱执行结果等信息的对象
     * @return 判题结果信息(如是否通过、错误类型、耗时、内存等)
     */
    public JudgeInfo doJudge(JudgeContext judgeContext) {
        
        // 从上下文中获取用户提交的信息
        QuestionSubmit questionSubmit = judgeContext.getQuestionSubmit();
        
        // 获取用户提交的编程语言类型
        String language = questionSubmit.getLanguage();

        // 初始化默认的判题策略
        JudgeStrategy judgeStrategy = new DefaultJudgeStrategy();

        // 根据编程语言选择不同的判题策略
        if ("java".equals(language)) {
            judgeStrategy = new JavaLanguageJudgeStrategy(); // Java 特有的判题策略
        }

        // 调用选定的策略执行判题操作
        return judgeStrategy.doJudge(judgeContext);
    }
}

执行判题:

整体流程图

用户点击提交按钮
│
├─→ 校验编程语言是否合法
│
├─→ 校验题目是否存在
│
├─→ 构造提交记录对象(包含代码、语言、用户ID、题目ID)
│
├─→ 插入数据库,设置初始状态为 WAITING
│
├─→ 获取提交记录 ID
│
├─→ 异步调用 judgeService.doJudge(questionSubmitId)
│
└─→ 返回 questionSubmitId 给前端

具体实现

方法签名与基本说明

/**
 * 提交题目
 *
 * 用户提交代码进行判题的核心方法。
 * 主要流程包括:
 * 1. 参数校验(语言合法性、题目是否存在)
 * 2. 构建提交记录对象并保存到数据库
 * 3. 异步调用判题服务进行判题
 *
 * @param questionSubmitAddRequest 提交请求参数封装类
 * @param loginUser 当前登录用户信息
 * @return 返回提交记录的 ID,用于后续查询判题结果
 */
@Override
public long doQuestionSubmit(QuestionSubmitAddRequest questionSubmitAddRequest, User loginUser) {

获取并校验编程语言是否合法

    // 从请求中获取用户提交的编程语言
    String language = questionSubmitAddRequest.getLanguage();

    // 使用枚举工具类判断该语言是否在支持的语言列表中
    QuestionSubmitLanguageEnum languageEnum = QuestionSubmitLanguageEnum.getEnumByValue(language);

    // 如果语言不合法,抛出异常
    if (languageEnum == null) {
        throw new BusinessException(ErrorCode.PARAMS_ERROR, "编程语言错误");
    }

为什么需要这一步?

  • 防止用户输入非法或不受支持的编程语言(如 Python3、PHP 等非白名单语言)。
  • 增强系统安全性,避免后续处理出现不可控问题。

检查题目是否存在

    // 获取题目 ID
    long questionId = questionSubmitAddRequest.getQuestionId();

    // 查询题目实体是否存在
    Question question = questionService.getById(questionId);
    if (question == null) {
        throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
    }

为什么需要这一步?

  • 确保用户提交的是一个真实存在的题目,防止攻击者通过伪造 ID 操作不存在的数据。
  • 同时也为后续判题逻辑提供必要的题目信息(如测试用例、限制条件等)。

 构造提交记录对象,并设置默认状态

    // 获取当前用户的 ID
    long userId = loginUser.getId();

    // 创建一个新的提交记录对象
    QuestionSubmit questionSubmit = new QuestionSubmit();
    questionSubmit.setUserId(userId);               // 设置用户 ID
    questionSubmit.setQuestionId(questionId);       // 设置题目 ID
    questionSubmit.setCode(questionSubmitAddRequest.getCode()); // 设置用户提交的代码内容
    questionSubmit.setLanguage(language);           // 设置编程语言

    // 设置初始状态为“等待中”
    questionSubmit.setStatus(QuestionSubmitStatusEnum.WAITING.getValue());

    // 初始 judgeInfo 字段为空 JSON,表示还未判题
    questionSubmit.setJudgeInfo("{}");

为什么设置初始状态?

  • 表示当前提交正在排队等待判题,前端或其他模块可以根据此状态判断是否已开始执行。
  • 判题完成后会异步更新状态为“成功”或“失败”。

将提交记录保存到数据库 

    // 尝试将提交记录插入数据库
    boolean save = this.save(questionSubmit);
    if (!save){
        throw new BusinessException(ErrorCode.SYSTEM_ERROR, "数据插入失败");
    }

为什么需要持久化?

  • 记录每一次提交的历史,便于后续查询、统计、审计。
  • 即使系统重启或发生异常,也可以根据数据库恢复状态。

获取提交记录 ID 并异步触发判题服务

    // 获取刚刚插入的提交记录 ID
    Long questionSubmitId = questionSubmit.getId();

    // 异步执行判题逻辑,避免阻塞主线程
    CompletableFuture.runAsync(() -> {
        judgeService.doJudge(questionSubmitId);
    });

为什么要异步执行?

  • 判题是一个耗时操作(可能涉及启动沙箱、运行代码、比对输出等),如果同步执行会影响接口响应速度。
  • 使用 CompletableFuture 实现异步处理,提高系统吞吐量和用户体验。

 返回提交记录 ID

    // 返回提交记录 ID,供前端或其他服务使用
    return questionSubmitId;
}

这个 ID 的用途是什么?

  • 前端可以通过这个 ID 轮询或 WebSocket 监听判题结果。
  • 判题服务也依赖这个 ID 来查找对应的提交记录和题目信息。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2377338.html

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

相关文章

高并发内存池(三):TLS无锁访问以及Central Cache结构设计

目录 前言&#xff1a; 一&#xff0c;thread cache线程局部存储的实现 问题引入 概念说明 基本使用 thread cache TLS的实现 二&#xff0c;Central Cache整体的结构框架 大致结构 span结构 span结构的实现 三&#xff0c;Central Cache大致结构的实现 单例模式 thr…

在Taro中开发一个跨端Svg组件,同时支持小程序、H5、React Native

Taro系列中一直没有跨端的绘图工具&#xff0c;小程序端支持canvas但是不支持svg&#xff0c;RN端有 react-native-svg 支持svg&#xff0c;但是没有很好原生的canvas插件&#xff0c;社区的canvas都是基于WebView实现的&#xff0c;或者skia&#xff0c;这个插件的书写方式和c…

【办公类-100-01】20250515手机导出教学照片,自动上传csdn+最大化、最小化Vs界面

背景说明&#xff1a; 每次把教学照片上传csdn&#xff0c;都需要打开相册&#xff0c;一张张截图&#xff0c;然后ctrlV黏贴到CSDN内&#xff0c;我觉得太烦了。 改进思路&#xff1a; 是否可以先把所有照片都上传到csdn&#xff0c;然后再一张张的截图&#xff08;去掉幼儿…

Python零基础入门到高手8.4节: 元组与列表的区别

目录 8.4.1 不可变数据类型 8.4.2 可变数据类型 8.4.3 元组与列表的区别 8.4.4 今天彩票没中奖 8.4.1 不可变数据类型 不可变数据类型是指不可以对该数据类型进行原地修改&#xff0c;即只读的数据类型。迄今为止学过的不可变数据类型有字符串&#xff0c;元组。 在使用[]…

深度学习入门:深度学习(完结)

目录 1、加深网络1.1 向更深的网络出发1.2 进一步提高识别精度1.3 加深层的动机 2、深度学习的小历史2.1 ImageNet2.2 VGG2.3 GoogleNet2.4 ResNet 3、深度学习的高速化3.1 需要努力解决的问题3.2 基于GPU的高速化3.3 分布式学习3.4 运算精度的位数缩减 4、深度学习的应用案例4…

使用Scrapeless Scraping Browser的自动化和网页抓取最佳实践

引言&#xff1a;人工智能时代浏览器自动化和数据收集的新范式 随着生成性人工智能、人工智能代理和数据密集型应用程序的快速崛起&#xff0c;浏览器正在从传统的“用户互动工具”演变为智能系统的“数据执行引擎”。在这一新范式中&#xff0c;许多任务不再依赖单一的API端点…

java数组题(5)

&#xff08;1&#xff09;&#xff1a; 思路&#xff1a; 1.首先要对数组nums排序&#xff0c;这样两数之间的差距最小。 2.题目要求我们通过最多 k 次递增操作&#xff0c;使数组中某个元素的频数&#xff08;出现次数&#xff09;最大化。经过上面的排序&#xff0c;最大数…

物联网无线传感方向专业词汇解释

涡旋电磁波(VEMW)&#xff1a;一种具有轨道角动量的电磁波&#xff0c;其特性在于能够在传播过程中携带额外的相位信息&#xff0c;从而增加通信系统的容量和灵活性。波前&#xff1a;波动传播过程中&#xff0c;同一时刻振动相位相同的所有点构成的几何曲面&#xff0c;代表波…

Maven 插件参数注入与Mojo开发详解

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…

2024年全国青少年信息素养大赛——算法创意实践挑战赛复赛真题(小学组)——玫瑰花地的面积

2024年全国青少年信息素养大赛——算法创意实践挑战赛复赛真题(小学组)——玫瑰花地的面积 上面试卷可点下方&#xff0c;支持在线编程&#xff0c;在线测评&#xff5e; 2024年全国信息素养大赛 算法创意实践挑战赛复赛(小学组)_c_少儿编程题库学习中心-嗨信奥 5月17号 全国青…

【补充笔记】修复“NameError: name ‘ZhNormalizer‘ is not defined”的直接方法

#工作记录 一、问题描述 在运行CosyVoice_For_Windows项目时&#xff0c;出现以下报错&#xff1a; File "F:\PythonProjects\CosyVoice_For_Windows\cosyvoice\cli\frontend.py", line 74, in __init__ self.zh_tn_model ZhNormalizer(remove_erhuaFalse, fu…

预训练模型实战手册:用BERT/GPT-2微调实现10倍效率提升,Hugging Face生态下的迁移学习全链路实践

更多AI大模型应用开发学习内容&#xff0c;尽在聚客AI学院。 一. 预训练模型&#xff08;PTM&#xff09;核心概念 1.1 什么是预训练模型&#xff1f; 预训练模型&#xff08;Pre-trained Model, PTM&#xff09;是在大规模通用数据上预先训练的模型&#xff0c;通过自监督学…

mac docker弹窗提示Docker 启动没有响应

一、原因分析 这台笔记电脑是Mac M3操作系统,安装Docker之后,Docker应用程序一直启动不起来。 二、解决办法 sudo rm /Library/PrivilegedHelperTools/com.docker.vmnetd sudo cp /Applications/Docker.app/Contents/Library/LaunchServices/com.docker.vmnetd /Library/Pri…

Ubuntu 22.04搭建OpenStreeMap地址解析服务(保姆级教程)

1.数据准备 1.1.全球数据 下载地址&#xff1a;https://planet.openstreetmap.org/ 1.2.特定区域的数据 下载地址&#xff1a;Geofabrik Download Server 2.安装必要的软件包 2.1.更新系统软件包 sudo apt updatesudo apt upgrade 2.2.安装所需要的软件包 执行下面的命…

sqli—labs第五关——报错注入

一&#xff1a;判断输入类型 首先测试 ?id1 回显You are in... 渐进测试?id1 报错分析&#xff1a; 出现引号提示——“”&#xff0c;可能是字符型 继续测试?id1--&#xff08;用注释符修复了语法错误&#xff09; 回显You are in... 说明就是字符型 因为能用注释符…

从海洋生物找灵感:造个机器人RoboPteropod,它能在水下干啥?

大家好&#xff01;在如今人类对水下环境探索不断深入的时代&#xff0c;从水下考古到珊瑚礁考察&#xff0c;各种任务都离不开水下机器人的助力。但传统水下机器人尺寸较大&#xff0c;在狭窄的水下空间施展不开。今天&#xff0c;我们就来认识一款受海洋小生物启发而设计的仿…

FastAPI系列16:从API文档到TypeScript 前端客户端(SDKs)

从API文档到TypeScript 前端客户端&#xff08;SDKs&#xff09; 快速入门生成一个TypeScript 客户端测试生成的TypeScript 客户端 API标签与客户端生成生成带有标签的 TypeScript 客户端 自定义Operation ID使用自定义Operation ID生成TypeScript客户端 在 FastAPI系列15&…

CS016-2-unity ecs

目录 【23】射击改进 【24】僵尸生成器 ​编辑【25】随机行走 【27】射击光效 【23】射击改进 a. 当距离目标太远的时候&#xff0c;要继续移动。而当距离目标到达攻击距离之后&#xff0c;则停止移动。 上图中的if&#xff1a;判断自身和目标的距离是否大于攻击距离&#…

CST软件对OPERACST软件联合仿真汽车无线充电站对人体的影响

上海又收紧了新能源车的免费上牌政策。所以年前一些伙伴和我探讨过买新能源汽车的问题&#xff0c;小伙伴们基本纠结的点是买插电还是纯电&#xff1f;我个人是很抗拒新能源车的&#xff0c;也开过坐过。个人有几个观点&#xff1a; 溢价过高&#xff0c;不保值。实际并不环保…

华为2024年报:鸿蒙生态正在取得历史性突破

华为于2025年03月31日发布2024年年度报告。报告显示&#xff0c;华为经营结果符合预期&#xff0c;实现全球销售收入 8,621 亿元人民币&#xff0c;净利润 626 亿元人民币。2024 年研发投入达到 1,797 亿元人民币&#xff0c;约占全年收入的 20.8%&#xff0c;近十年累计投入的…