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

1、保存代码文件
✅ 目的:
将用户提交的源码以字符串形式写入磁盘,生成 .java 文件。📌 原因:
Java 是静态语言,必须先编译成 .class 文件才能运行。
需要物理文件路径来调用 javac 或使用 JavaCompiler API 编译。
可以通过隔离目录结构(如 UUID 子目录)实现用户代码之间的隔离。
实现步骤:
获取当前工作目录路径:
- 使用
System.getProperty("user.dir")
获取当前运行程序的工作目录路径。例如:/home/user/project
。构建全局代码存储目录的完整路径:
- 将工作目录路径与全局代码存储目录名称(假设是一个预定义的常量
GLOBAL_CODE_DIR_NAME
)拼接起来,形成全局代码存储目录的完整路径。例如:/home/user/project/codeTemp
。检查并创建全局代码存储目录:
- 使用工具类
FileUtil.exist(globalCodePathName)
判断全局代码存储目录是否存在。如果不存在,则调用FileUtil.mkdir(globalCodePathName)
创建该目录。生成用户专属目录:
- 通过
UUID.randomUUID()
生成一个唯一标识符,并将其作为当前用户的代码存放目录名,目的是为了避免多个用户提交代码时发生文件覆盖的问题。例如:/home/user/project/codeTemp/uuid-xxxxxx
。构造具体的Java文件路径:
- 在用户专属目录下创建一个固定名称的 Java 文件(假设使用的是
GLOBAL_JAVA_CLASS_NAME
作为文件名),例如:/home/user/project/codeTemp/uuid-xxxxxx/Main.java
。将用户代码写入到指定路径的文件中:
- 使用
FileUtil.writeString(code, userCodePath, StandardCharsets.UTF_8)
方法将用户传入的代码字符串以 UTF-8 编码格式写入到之前构造好的文件路径中。这个方法还会自动创建文件及其父目录(如果它们还不存在的话)。返回创建好的文件对象:
- 最后,返回刚刚创建好的
File
对象,供调用者用于后续的编译或执行操作。
/*** 1. 把用户的代码保存为文件** 这个方法的主要目的是将用户传入的字符串形式的 Java 源代码保存为一个临时文件,* 并返回该文件对象。为了隔离不同用户的代码,每次都会创建一个独立的目录来存放。** @param code 用户输入的 Java 源代码字符串* @return 返回保存后的 Java 文件对象(File),可用于后续编译或执行*/
public File saveCodeToFile(String code) {// 获取当前运行程序的工作目录路径(例如:/home/user/project)String userDir = System.getProperty("user.dir");// 构建全局代码存储目录的完整路径(userDir + 文件分隔符 + 全局目录名)// 例如:/home/user/project/codeTempString globalCodePathName = userDir + File.separator + GLOBAL_CODE_DIR_NAME;// 判断这个全局代码目录是否存在// 如果不存在,则使用工具类 FileUtil 创建该目录if (!FileUtil.exist(globalCodePathName)) {FileUtil.mkdir(globalCodePathName); // 创建目录}// 生成一个唯一标识符作为当前用户的代码目录名(UUID.randomUUID())// 目的是为了避免多个用户提交代码时发生文件覆盖的问题String userCodeParentPath = globalCodePathName + File.separator + UUID.randomUUID();// 构造具体的 Java 文件路径(在用户专属目录下创建一个固定名称的 Java 文件)// 例如:/home/user/project/codeTemp/uuid-xxxxxx/Main.javaString userCodePath = userCodeParentPath + File.separator + GLOBAL_JAVA_CLASS_NAME;// 使用 FileUtil 工具类将用户传入的代码字符串写入到指定路径的文件中// 编码方式为 UTF-8,确保中文等字符不会乱码// writeString 方法会自动创建文件及其父目录(如果不存在)File userCodeFile = FileUtil.writeString(code, userCodePath, StandardCharsets.UTF_8);// 返回创建好的文件对象,供调用者使用(如用于后续编译、执行操作)return userCodeFile;
}
2. 编译代码,得到 class 文件
✅ 目的:
将
.java
源文件编译为.class
字节码文件,供 JVM 执行。📌 原因:
- Java 程序不能直接执行
.java
文件,必须先经过编译。- 使用标准工具(如
javac
或 Java Compiler API)进行编译。- 如果编译失败,需要捕获错误信息并反馈给用户。
实现步骤:
构造编译命令:
- 使用
String.format()
方法构建用于编译 Java 源代码文件的命令字符串。这里使用了javac
命令,并通过-encoding utf-8
参数指定源文件的字符编码格式为 UTF-8,以确保支持中文等非ASCII字符集。- 获取用户代码文件的绝对路径(
userCodeFile.getAbsolutePath()
),将其拼接到命令字符串中。执行编译命令:
- 使用
Runtime.getRuntime().exec(compileCmd)
方法执行上述构造好的编译命令。这会启动一个子进程运行javac
编译器来编译用户的 Java 源代码文件。- 返回的
Process
对象表示正在运行的编译进程,可以通过它获取编译过程中的输入输出流以及控制进程的行为。处理编译过程和结果:
- 调用自定义工具类
ProcessUtils.runProcessAndGetMessage(compileProcess, "编译")
来处理编译进程。这个方法通常负责:
- 读取并收集编译过程中的标准输出和错误输出信息。
- 等待编译进程结束并获取其退出状态码。
- 将上述信息封装到一个
ExecuteMessage
对象中返回。检查编译是否成功:
- 根据
ExecuteMessage
对象中的退出值(exitValue
)判断编译是否成功。如果退出值不为0(即executeMessage.getExitValue() != 0
),则认为编译失败,并抛出一个RuntimeException
异常,附带消息“编译错误”。异常处理:
- 如果在执行编译命令或处理编译过程中发生任何异常(如 IO 异常、编译命令执行失败等),则捕获这些异常并在当前实现中直接抛出一个新的
RuntimeException
,将原始异常作为其原因。注意,这里的异常处理策略可以根据实际需要调整,例如可以返回一个包含错误信息的响应对象而不是直接抛出异常。返回编译结果:
- 如果编译成功(即退出值为0),则返回封装了编译过程信息的
ExecuteMessage
对象给调用者。该对象包含了编译的标准输出、错误输出及退出状态码,供后续逻辑使用。
/*** 进程执行信息*/
@Data
public class ExecuteMessage {private Integer exitValue;private String message;private String errorMessage;private Long time;private Long memory;
}
/*** 2. 编译代码** 此方法用于将用户保存的 Java 源代码文件(.java)进行编译,* 生成对应的字节码文件(.class)。如果编译失败,会记录错误信息。** @param userCodeFile 用户的 Java 源代码文件对象(已保存到磁盘)* @return 返回一个 ExecuteMessage 对象,包含编译过程的标准输出、错误输出和退出码*/
public ExecuteMessage compileFile(File userCodeFile) {// 构造编译命令:javac -encoding utf-8 [源文件路径]// -encoding utf-8 确保支持中文等字符集String compileCmd = String.format("javac -encoding utf-8 %s", userCodeFile.getAbsolutePath());try {// 使用 Runtime.getRuntime().exec() 执行系统命令 javac 进行编译// 返回一个 Process 对象,表示正在运行的编译进程Process compileProcess = Runtime.getRuntime().exec(compileCmd);// 调用工具类 ProcessUtils.runProcessAndGetMessage() 来运行并监听编译过程// 该方法会:// - 读取标准输出流(System.out)// - 读取错误输出流(System.err)// - 获取进程退出码(exit code)// 最终封装成一个 ExecuteMessage 对象返回ExecuteMessage executeMessage = ProcessUtils.runProcessAndGetMessage(compileProcess, "编译");// 判断编译是否成功:// - 如果 exitValue == 0,说明编译通过// - 如果 exitValue != 0,说明有语法错误或其他问题if (executeMessage.getExitValue() != 0) {// 抛出运行时异常,并提示“编译错误”// 实际项目中可以改为更具体的异常类型或封装错误信息返回throw new RuntimeException("编译错误");}// 如果编译成功,返回编译结果的信息对象return executeMessage;} catch (Exception e) {// 捕获所有异常,包括 IO 异常、执行命令失败、中断等// 可以选择记录日志或返回错误响应对象(如 getErrorResponse(e))// 当前直接抛出运行时异常// 注意:这里可以选择不抛出异常,而是返回 ExecuteMessage 错误对象// 示例:return getErrorResponse(e);throw new RuntimeException(e);}
}
3. 执行代码,得到输出结果
✅ 目的:
在受控环境下运行用户代码,并捕获其输出(包括标准输出和错误输出)。
📌 原因:
- 用户代码可能包含无限循环、异常抛出、资源占用等风险行为。
- 需要限制执行时间、内存使用,防止系统崩溃或被攻击。
- 需要重定向
System.out
和System.err
来获取输出内容。
实现步骤:
获取用户代码文件的父目录路径:
- 使用
userCodeFile.getParentFile().getAbsolutePath()
获取用户代码文件所在目录的绝对路径。因为编译后的.class
文件与.java
文件位于同一目录下,所以这个路径可以用来指定 Java 运行时的类路径(-cp
参数)。初始化执行结果列表:
- 创建一个
ArrayList<ExecuteMessage>
类型的列表executeMessageList
用于存储每次运行的结果信息。每个ExecuteMessage
对象包含一次执行的标准输出、错误输出以及退出状态码。遍历输入参数列表:
- 使用
for (String inputArgs : inputList)
循环遍历传入的inputList
,其中每个元素代表一组测试用例的输入参数。构造运行命令:
- 使用
String.format()
方法构建用于运行 Java 程序的命令字符串。该命令包括以下部分:
-Xmx256m
:设置 JVM 最大堆内存为 256MB,以防止程序占用过多内存。-Dfile.encoding=UTF-8
:设置文件编码格式为 UTF-8,确保支持多语言字符集。-cp %s
:指定类路径为当前用户的代码目录。Main
:要执行的主类名(假设是Main.class
)。%s
:本次循环的输入参数,作为main
方法的参数传入。执行命令并启动超时监控:
- 使用
Runtime.getRuntime().exec(runCmd)
执行上述构造好的命令,启动一个子进程来运行 Java 程序。- 启动一个新的线程,使用
Thread.sleep(TIME_OUT)
来实现超时控制。如果超过设定的时间限制,则调用runProcess.destroy()
强制终止该进程,避免长时间占用资源或死循环等情况。处理运行过程和结果:
- 调用
ProcessUtils.runProcessAndGetMessage(runProcess, "运行")
方法处理运行进程。此方法通常会读取并收集标准输出和错误输出信息,并等待进程结束获取其退出状态码。- 将收集到的信息封装成一个
ExecuteMessage
对象,并将其添加到executeMessageList
中。异常处理:
- 如果在执行命令或处理过程中发生任何异常(例如 IO 异常、命令执行失败等),则捕获这些异常并抛出一个新的
RuntimeException
,附带原始异常作为原因。返回执行结果列表:
- 当所有输入参数都被处理完毕后,返回包含所有执行结果的
executeMessageList
列表。
/*** 3. 执行文件,获得执行结果列表** 此方法用于执行用户编译后的 Java 字节码文件(.class),并传入多组输入参数,* 每次运行一个测试用例,并收集输出结果。** @param userCodeFile 编译生成的 .class 文件所在目录中的源代码文件(用来获取父路径)* @param inputList 用户提供的多个输入参数列表,代表多个测试用例* @return 返回一个 ExecuteMessage 列表,每个元素对应一次运行的标准输出、错误输出和退出码*/
public List<ExecuteMessage> runFile(File userCodeFile, List<String> inputList) {// 获取用户代码文件所在的父目录绝对路径(即存放 .class 文件的目录)String userCodeParentPath = userCodeFile.getParentFile().getAbsolutePath();// 创建一个列表,用于存储每次执行的结果信息对象List<ExecuteMessage> executeMessageList = new ArrayList<>();// 遍历输入参数列表,依次对每一组输入执行程序for (String inputArgs : inputList) {// 构造 Java 运行命令:// -Xmx256m: 设置 JVM 最大堆内存为 256MB,防止内存溢出// -Dfile.encoding=UTF-8: 强制使用 UTF-8 编码,避免中文乱码// -cp %s: 指定类路径为当前目录(即 userCodeParentPath)// Main: 要执行的主类名(假设是 Main.class)// %s: 本次循环的输入参数,作为 main 方法的 args 参数传入String runCmd = String.format("java -Xmx256m -Dfile.encoding=UTF-8 -cp %s Main %s", userCodeParentPath, inputArgs);try {// 使用 Runtime.getRuntime().exec() 执行构建好的 java 命令Process runProcess = Runtime.getRuntime().exec(runCmd);// 启动一个守护线程来监控执行时间,实现超时控制new Thread(() -> {try {// 等待预设的超时时间(TIME_OUT,单位毫秒)Thread.sleep(TIME_OUT);// 如果还未执行完成,则强制终止进程System.out.println("超时了,中断");runProcess.destroy();} catch (InterruptedException e) {throw new RuntimeException(e);}}).start();// 使用工具类 ProcessUtils 来运行并监听进程的执行过程// 该方法会读取标准输出流和错误输出流,并返回封装好的 ExecuteMessage 对象ExecuteMessage executeMessage = ProcessUtils.runProcessAndGetMessage(runProcess, "运行");// 将单次执行结果添加到结果列表中executeMessageList.add(executeMessage);} catch (Exception e) {// 如果执行过程中出现异常(如 IO 错误、命令执行失败等),// 则抛出运行时异常,并附带原始异常作为原因throw new RuntimeException("执行错误", e);}}// 返回所有测试用例执行后的结果列表return executeMessageList;
}
4. 收集整理输出结果
✅ 目的:
将程序执行的标准输出、错误输出、退出码等信息整合后返回给调用者。
📌 原因:
- 提供给用户清晰的运行结果反馈。
- 包括成功输出、异常堆栈、超时提示、内存溢出警告等。
- 用于后续判断是否通过测试用例。
实现步骤:
初始化响应对象:
- 创建一个
ExecuteCodeResponse
对象executeCodeResponse
,用于封装最终返回给用户的响应信息。- 初始化一个
List<String>
类型的列表outputList
,用于存储所有成功执行的结果输出。初始化最大执行时间:
- 定义一个
long
类型变量maxTime
并初始化为 0,用于记录所有测试用例中最大的执行时间(毫秒),以便于后续判断是否超时或评估性能。遍历执行消息列表:
- 使用
for (ExecuteMessage executeMessage : executeMessageList)
遍历传入的executeMessageList
,每个executeMessage
包含一次执行的标准输出、错误输出、退出码及执行时间等信息。检查并处理错误信息:
- 获取当前执行结果中的错误信息
errorMessage
。- 如果
errorMessage
不为空且非空白字符串(使用StrUtil.isNotBlank(errorMessage)
检查),则表示该次执行出现了错误。
- 将错误信息设置到
executeCodeResponse
的message
字段中。- 设置
executeCodeResponse
的状态码为 3(代表代码在运行过程中出现错误)。- 立即跳出循环,停止进一步处理其他执行结果,因为一旦有错误发生,通常意味着整个过程失败。
收集标准输出和更新最大执行时间:
- 如果没有错误信息,则将当前执行结果的标准输出内容添加到
outputList
中。- 获取当前执行结果的执行时间
time
(单位可能是毫秒),如果该值不为空,则更新maxTime
为当前已知的最大值。检查全部成功执行情况:
- 在循环结束后,比较
outputList.size()
和executeMessageList.size()
。如果两者相等,说明所有输入参数对应的执行均成功完成,此时设置executeCodeResponse
的状态码为 1(表示全部运行成功,无任何错误)。设置输出结果列表:
- 将收集到的所有标准输出内容
outputList
设置到executeCodeResponse
的outputList
字段中。构建判题信息:
- 创建一个新的
JudgeInfo
对象judgeInfo
,用于封装判题所需的信息(如执行时间和内存占用)。- 将之前计算得到的最大执行时间
maxTime
设置到judgeInfo
的time
字段中。- (注:关于内存占用的获取较为复杂,通常需要借助 JVM 工具或者操作系统命令行工具,在 Java 进程中精确获取用户代码使用的内存非常困难,因此此处不做具体实现)
设置判题信息:
- 将
judgeInfo
设置到executeCodeResponse
的judgeInfo
字段中。返回响应对象:
- 返回填充完毕的
executeCodeResponse
对象,供调用者使用。
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ExecuteCodeResponse {private List<String> outputList;/*** 接口信息*/private String message;/*** 执行状态*/private Integer status;/*** 判题信息*/private JudgeInfo judgeInfo;
}
/*** 4. 获取输出结果** 此方法根据代码执行过程中的多个执行结果(ExecuteMessage 列表),* 构建最终返回给用户的响应对象 ExecuteCodeResponse。* 主要功能包括:* - 提取所有运行成功的结果* - 检查是否有错误信息,并设置对应状态码* - 收集最大执行时间等判题信息** @param executeMessageList 执行过程中收集到的多个 ExecuteMessage 对象列表* @return 返回封装好的 ExecuteCodeResponse 对象,包含输出、状态、判题信息等*/
public ExecuteCodeResponse getOutputResponse(List<ExecuteMessage> executeMessageList) {// 创建一个最终要返回的响应对象ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();// 用于存储所有成功的标准输出内容List<String> outputList = new ArrayList<>();// 用于记录所有测试用例中最大的执行时间(毫秒),便于判断是否超时long maxTime = 0;// 遍历每个 ExecuteMessage(即每次输入参数对应的执行结果)for (ExecuteMessage executeMessage : executeMessageList) {// 获取当前执行结果的错误信息(如果有)String errorMessage = executeMessage.getErrorMessage();// 如果错误信息不为空或非空白字符串,说明该次执行出错if (StrUtil.isNotBlank(errorMessage)) {// 将错误信息设置到响应对象中executeCodeResponse.setMessage(errorMessage);// 设置状态码为 3:代表代码在运行过程中出现错误(如异常、编译未通过等)executeCodeResponse.setStatus(3);// 出现错误后直接跳出循环,不再处理后续结果break;}// 如果没有错误,则将本次运行的标准输出加入结果列表outputList.add(executeMessage.getMessage());// 获取本次运行的时间(单位可能是毫秒)Long time = executeMessage.getTime();// 如果时间有效,则更新最大时间if (time != null) {maxTime = Math.max(maxTime, time);}}// 如果所有测试用例都成功运行完毕(输出数量等于执行次数)if (outputList.size() == executeMessageList.size()) {// 设置状态码为 1:表示全部运行成功,无任何错误executeCodeResponse.setStatus(1);}// 将收集到的标准输出结果设置到响应对象中executeCodeResponse.setOutputList(outputList);// 创建并填充 JudgeInfo 判题信息对象(如时间和内存)JudgeInfo judgeInfo = new JudgeInfo();judgeInfo.setTime(maxTime); // 设置最大运行时间// 内存占用获取较为复杂,通常需要借助 JVM 工具或者操作系统命令行工具(如 ps、top 等)// 在 Java 进程中精确获取用户代码使用的内存非常困难,因此此处不做具体实现
// judgeInfo.setMemory();// 将判题信息设置到响应对象中executeCodeResponse.setJudgeInfo(judgeInfo);// 返回完整的响应对象return executeCodeResponse;
}
5. 文件清理,释放空间
✅ 目的:
删除临时生成的
.java
、.class
文件及目录,防止磁盘爆满。📌 原因:
- 沙箱频繁运行会导致大量临时文件堆积。
- 不及时清理会影响服务器性能与稳定性。
- 使用完即删是良好资源管理习惯。
实现步骤:
检查用户代码文件的父目录是否存在:
- 使用
if (userCodeFile.getParentFile() != null)
判断用户代码文件是否有父目录。如果该文件有父目录,说明它位于某个目录中,需要删除该目录及其所有内容;如果没有父目录,可能是根目录下的文件或其他特殊情况,直接认为删除成功。获取用户代码文件所在父目录的绝对路径:
- 使用
userCodeFile.getParentFile().getAbsolutePath()
获取用户代码文件所在父目录的绝对路径。这个路径指向包含.java
文件及其编译后生成的.class
文件的目录。递归删除整个目录及其内容:
- 调用
FileUtil.del(userCodeParentPath)
方法递归删除指定路径下的整个目录及其所有子目录和文件。FileUtil.del()
是一个工具方法,通常用于简化文件删除操作,并且支持递归删除。- 返回值
del
表示删除操作是否成功执行。打印删除操作的结果:
- 使用
System.out.println()
打印删除操作的结果,便于调试或记录日志。如果删除成功,输出“删除成功”;如果删除失败,输出“删除失败”。返回删除操作的结果:
- 根据删除操作的结果
del
,返回相应的布尔值。如果删除成功,返回true
;如果删除失败,返回false
。处理无父目录的情况:
- 如果用户代码文件没有父目录(即
userCodeFile.getParentFile()
返回null
),则默认认为删除成功,返回true
。这种情况较为罕见,但为了确保方法的健壮性,仍然需要处理。
/*** 5. 删除文件** 此方法用于删除用户代码文件及其所在的整个目录(包括编译生成的 .class 文件等),* 以释放磁盘空间并保持环境清洁。** @param userCodeFile 用户代码文件对象(通常为 .java 文件)* @return 如果成功删除则返回 true,否则返回 false*/
public boolean deleteFile(File userCodeFile) {// 检查用户代码文件的父目录是否存在if (userCodeFile.getParentFile() != null) {// 获取用户代码文件所在父目录的绝对路径String userCodeParentPath = userCodeFile.getParentFile().getAbsolutePath();// 使用 FileUtil.del() 方法递归删除整个目录及其内容// 返回值表示操作是否成功boolean del = FileUtil.del(userCodeParentPath);// 打印删除操作的结果(仅用于调试或日志记录)System.out.println("删除" + (del ? "成功" : "失败"));// 返回删除操作的结果return del;}// 如果用户代码文件没有父目录,则默认认为删除成功(这种情况很少见)return true;
}
6. 错误处理,提升程序健壮性
✅ 目的:
对所有可能出现的异常进行捕获和处理,避免沙箱自身崩溃。
📌 原因:
- 用户代码可能存在语法错误、死循环、异常抛出等问题。
- 外部命令执行(如
Runtime.exec()
)可能失败。- IO 操作、路径访问、权限控制等都可能引发异常。
- 需要统一的日志记录、错误码返回机制。
实现步骤:
- 创建响应对象:初始化一个新的
ExecuteCodeResponse
对象。- 设置输出列表:将输出列表设置为空列表,表示没有正常输出。
- 设置错误消息:从传入的异常对象中获取错误消息,并将其设置到响应对象中。
- 设置状态码:将状态码设置为2,表示发生了代码沙箱错误。
- 初始化判题信息:初始化一个
JudgeInfo
对象并设置到响应对象中。- 返回响应对象:返回构建好的
ExecuteCodeResponse
对象。
/*** 获取错误响应的方法** @param e 异常对象,包含错误信息* @return 包含错误信息的ExecuteCodeResponse对象*/
private ExecuteCodeResponse getErrorResponse(Throwable e) {// 创建一个新的ExecuteCodeResponse对象ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse();// 设置输出列表为空列表executeCodeResponse.setOutputList(new ArrayList<>());// 设置错误消息为异常对象的消息executeCodeResponse.setMessage(e.getMessage());// 设置状态码为2,表示代码沙箱错误executeCodeResponse.setStatus(2);// 初始化并设置JudgeInfo对象executeCodeResponse.setJudgeInfo(new JudgeInfo());// 返回构建好的ExecuteCodeResponse对象return executeCodeResponse;
}
至此,第一期的内容结束,不过我们可以发现一个问题,如果想要上线的话,安全么? 用户提交恶意代码,怎么办?
那针对这种情况,我们可以来提高程序安全性
这部分我放到下一期来讲!
相关文章:
Java 原生实现代码沙箱(OJ判题系统第1期)——设计思路、实现步骤、代码实现
设计思路: 1、保存代码文件 ✅ 目的: 将用户提交的源码以字符串形式写入磁盘,生成 .java 文件。 📌 原因: Java 是静态语言,必须先编译成 .class 文件才能运行。 需要物理文件路径来调用 javac 或使用 Java…...
课程设计。。。。
人脸考勤系统 需求分析 需求 1.实现企业日常人脸打卡需求 2.管理员要可以管理相关数据 3.可以移植到相关嵌入式设备 …..需求主要是这些,还可以让ai拓展一点 实现 1.介于可移植性这个需求,选用Qt框架,Qt框架跨平台性特比好࿰…...
gitlab相关面试题及答案
一、GitLab 基础 1. 什么是 GitLab?它与 GitHub 有什么区别? 答案: GitLab 是一个开源的 DevOps 平台,提供代码托管、CI/CD、问题跟踪等功能。与 GitHub 的主要区别: 开源与商业:GitLab 社区版开源&#x…...
『不废话』之Python 3.14 Beta版新特性
Python 3.14 的第一个Beta版已发布,有几个新特性可以提高我们的编码效率。 未来注释 在上一篇《『不废话』之Python高级特性技巧-CSDN博客》中提到3.7中新增了 “未来注释”,可以使用“from __future__ import annotations”或双引号包括的方式解决当类…...
AWS之数据分析类产品
以下是 Amazon Athena、Amazon QuickSight、AWS Lake Formation、AWS Glue、Amazon OpenSearch Service(原 Elasticsearch Service)、Amazon Kinesis Data Analytics 和 Amazon Redshift 的核心区别及典型使用场景的对比分析: 1. Amazon Athe…...
RabbitMQ消息的重复消费问题如何解决?
在RabbitMQ中,消息重复消费是一个常见问题,它通常发生在消费者处理消息时出现网络波动、节点故障或消费者自身处理逻辑异常,ACK 失败等情况,都会导致RabbitMQ 不能够正确感知消息已被成功处理,从而重新投递消息。以下是…...
5月9号.
v-for: v-bind: v-if&v-show: v-model: v-on: Ajax: Axios: async&await: Vue生命周期: Maven: Maven坐标:...
如何减少极狐GitLab 容器镜像库存储?
极狐GitLab 是 GitLab 在中国的发行版,关于中文参考文档和资料有: 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 减少容器镜像库存储 (BASIC ALL) 未清理的容器镜像库会随着时间的推移而变大。添加大量镜像或标签时: 获取可用标…...
怎么用idea打jar包
背景 前端使用vue开发,打包生成dist文件,需要打包成jar包 步骤 前端的dict文件放到后端的src\main\resources目录下dict文件夹改名为staticidea打开后端代码,依次点击右侧maven下的clean 、package最后会在项目的target目录下生成jar&…...
03 mysql 连接
安装 MySQL 后,我们就需要连接它。 使用命令行方式连接使用图形化工具连接一、使用命令行客户端连接 在上一节内容02 mysql 管理(Windows版)-CSDN博客 我们采用的就是这个连接方法,这种方法直接连接的是root用户,找到该命令行属性,打开可以看到里面的参数是root: 这种…...
Jenkins集成Maven
一、概述 Jenkins是一个开源的持续集成工具,用于自动化各种开发任务。Maven是一个项目管理和构建自动化工具,主要用于Java项目。通过将Jenkins和Maven集成,可以实现自动化构建、测试和部署,提高开发效率和代码质量。 二、前提条…...
Qwen智能体qwen_agent与Assistant功能初探
Qwen智能体qwen_agent与Assistant功能初探 一、Qwen智能体框架概述 Qwen(通义千问)智能体框架是阿里云推出的新一代AI智能体开发平台,其核心模块qwen_agent.agent提供了一套完整的智能体构建解决方案。该框架通过模块化设计,将L…...
Linux——MySQL基础
基础知识 连接服务器 mysql -h 127.0.0.1 -P 3306 -u root -p -h 指明登录部署了myqsl服务的主机 -P 指明访问的端口号 -u 指明用户 -p 指明登录密码(可以不填写) 什么是数据库 首先,数据库是分为服务端和客户端的: mysql是客户…...
k8s监控方案实践(二):集成Alertmanager告警与钉钉Webhook通知
k8s监控方案实践(二): 集成Alertmanager告警与钉钉Webhook通知 文章目录 k8s监控方案实践(二): 集成Alertmanager告警与钉钉Webhook通知一、Alertmanager简介1. 什么是Alertmanager?2. Promethe…...
学习threejs,使用Physijs物理引擎
👨⚕️ 主页: gis分享者 👨⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨⚕️ 收录于专栏:threejs gis工程师 文章目录 一、🍀前言1.1 ☘️Physijs 物理引擎1.1.1 ☘️…...
UG471 之 SelectIO 逻辑资源
背景 《ug471》介绍了Xilinx 7 系列 SelectIO 的输入/输出特性及逻辑资源的相关内容。 第 1 章《SelectIO Resources》介绍了输出驱动器和输入接收器的电气特性,并通过大量实例解析了各类标准接口的实现。 第 2 章《SelectIO Logic Resources》介绍了输入输出数据…...
基于HISI3519dv500的yolov8-obb车位检测
1. 数据标注 标注软件:roLabelImg 安装方式:见 https://github.com/cgvict/roLabelImg.git 操作指南: 标注后的数据格式如下: <annotation verified"no"><folder>4800</folder><filename>fr…...
Prometheus生产实战全流程详解(存储/负载/调度篇)
一、存储架构实战(TSDB深度优化) 1. 存储拓扑设计 2. 关键参数调优 4. 性能压测对照表 二、负载治理实战(百万级Series管控) 三、调度优化实战(精准采集控制) 2. 优先级调度配置 3. 自适应抓取调整 4…...
Mac电脑远程连接window系统服务器
1.下载 首先需要下载Microsoft Remote Desktop软件,下载链接如下: https://go.microsoft.com/fwlink/?linkid868963 2、软件下载成功后,可按照引导程序进行安装,成功后进入软件,可看到如下界面:...
【Qt】编译 Qt 5.15.x For Windows 基础教程 Visual Studio 2019 MSVC142 x64
【Qt】编译 Qt 5.15.x For Windows 基础教程 Visual Studio 2019 MSVC142 x64 目录 【Qt】编译 Qt 5.15.x For Windows 基础教程 Visual Studio 2019 MSVC142 x64准备工作:(必须)第一步:第二步:第三步: 建议…...
【Qt】之【Bug】点击按钮(ui->pushButton)触发非本类设置的槽函数
解决 先说解决办法,按钮在ui为默认命名ui->pushButton,后面改了下按钮名为该按钮的功能相关,就不会随意触发其他槽函数了。 没想到是这个原因。。。 可能是之前默认的objectName与旧的槽函数自动连接了 记录一下,找了好久其他的原因。 以…...
buck和boost总结
目录 1. 基本概念与原理 2. 工作模式 3. 典型应用场景 4. Buck-Boost电路:升降压结合 5. 核心区别与选择 1. 基本概念与原理 Buck电路(降压电路) 通过开关器件(如MOSFET)周期性地导通和关断,控制电感充…...
rtsp,。。。。
下面是基于 FFmpeg H.264 RTSP GStreamer 的低延时视频传输方案的详细搭建指南。此方案可将延迟控制在 <100ms,适合远程驾驶、监控等实时性要求较高的应用场景。 📦 方案架构 摄像头(OpenCV)→ FFmpeg(H.264编码…...
微信小程序地图缩放scale隐性bug
bug1 在真机环境下通过this.mapCtx.getScale获取当前地图的缩放等级带小数, 当设置scale带小数时,地图会先执行到缩放到带小数的缩放等级,然后会再次缩放取整的缩放等级(具体向上取整还是向下取整未知,两种情况都观察…...
Java中关于多态的总结
多态是面向对象编程的三大特性之一(封装、继承、多态),它允许不同类的对象对同一消息做出不同的响应。 多态的基本概念 1、定义 多态(Polymorphism)指同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果…...
突破跨界传输瓶颈:Zynq OCM与DDR核间数据共享性能深度调优
一、当硬件加速遇上内存墙:Zynq数据共享的终极挑战 在某军工雷达信号处理项目中,工程师小王遇到了棘手难题——通过Zynq的ARM核与FPGA协同处理雷达回波数据时,系统吞吐量始终无法突破200MB/s的瓶颈。经过三天三夜的排查,发现问题的根源竟是OCM与DDR之间的数据传输效率不足…...
基于 Ubuntu 24.04 部署 WebDAV
无域名,HTTP 1. 简介 WebDAV(Web Distributed Authoring and Versioning)是一种基于 HTTP 的协议,允许用户通过网络直接编辑和管理服务器上的文件。本教程介绍如何在 Ubuntu 24.04 上使用 Apache2 搭建 WebDAV 服务,无…...
JVM、JRE、JDK的区别
JVM JVM全称Java虚拟机(Java Virtual Machine, JVM),它是运行java字节码的虚拟机,JVM针对不同的系统有不同的实现,目的运行相同的字节码有同样的结果,JVM是“一次编译,到处运行”实现的关键。如下不同的编程语言编译生成字节码文…...
解密火星文:LeetCode 269 题详解与 Swift 实现
文章目录 摘要描述题解答案题解代码分析构建图(Graph)拓扑排序(Topological Sort) 示例测试及结果时间复杂度空间复杂度实际场景类比总结 摘要 这篇文章我们来聊聊 LeetCode 269 题:火星词典(Alien Dictio…...
系统思考:短期困境与长期收益
最近在项目中,一直有学员会提到一个议题,如何平衡当前困境和长期收益? 我的思考是在商业和人生的路上,我们常常听到“鱼和熊掌不可兼得”的说法,似乎短期利益和长期目标注定是对立的。但事实上,鱼与熊掌是…...
K8S - Harbor 镜像仓库部署与 GitLab CI 集成实战
引言 在 Kubernetes 环境中,容器镜像的存储与管理至关重要。企业级镜像仓库(如 Harbor)为团队提供了安全、稳定、可扩展的镜像管理解决方案。 一、Harbor 安装与配置 Harbor 是由 VMware 开源的企业级云原生镜像仓库,它不仅支持…...
2025-05-10-FFmepg库裁切有水印的视频
裁后 代码 import subprocess# 文件路径 input_video_path "bg_video.mp4" output_video_path "output_video_cropped.mp4"# 裁剪视频下方的水印 def crop_video(input_video_path, output_video_path, crop_height):# 获取视频的分辨率def get_video…...
通信协议选型篇:如何根据项目需求选择合适的通信协议?
🧭 本文为《嵌入式通信协议全解析》第七篇,面向系统架构师、嵌入式开发者与技术决策者,提供一套实用的通信协议选型方法论,结合性能对比表、使用案例与决策树,助你在“带宽、功耗、距离、可靠性、生态”之间做出最优权衡。 🔍 一、为什么通信协议的选型很关键? 在嵌入…...
Altera系列FPGA纯verilog视频图像去雾,基于暗通道先验算法实现,提供4套Quartus工程源码和技术支持
目录 1、前言工程概述免责声明 2、相关方案推荐我已有的所有工程源码总目录----方便你快速找到自己喜欢的项目Altera系列FPGA相关方案推荐本博主已有的图像处理方案 3、设计思路框架工程设计原理框图输入Sensor之-->OV7725摄像头输入Sensor之-->OV5640摄像头输入Sensor之…...
大模型的实践应用39-Qwen3(72B)+langchain框架+MCP(大模型上下文协议)+RAG+传统算法等研发数学教学管理与成绩提升系统
大家好,我是微学AI,今天给大家介绍一下大模型的实践应用39-Qwen3(72B)+langchain框架+MCP(大模型上下文协议)+RAG+传统算法等研发数学教学管理与成绩提升系统。 在2025年AI技术快速发展的背景下,大模型已展现出在教育领域的巨大潜力。通义千问Qwen3作为阿里云推出的最新一代…...
【强化学习】动态规划(Dynamic Programming, DP)算法
1、动态规划算法解题 LeetCode 931. 下降路径最小和 给你一个 n x n 的 方形 整数数组 matrix ,请你找出并返回通过 matrix 的下降路径 的 最小和 。 下降路径 可以从第一行中的任何元素开始,并从每一行中选择一个元素。在下一行选择的元素和当前行所选…...
【Linux】深入拆解Ext文件系统:从磁盘物理结构到Linux文件管理
目录 1、理解硬件 (1)磁盘 (2)磁盘的物理结构 (3)磁盘的存储结构 (4)磁盘的逻辑结构 (5)CHS && LBA地址 2、引入文件系统 (1&…...
linux ptrace 图文详解(八) gdb跟踪被调试程序的子线程、子进程
目录 一、gdb跟踪被调试程序的fork、pthread_create操作 二、实现原理 三、代码实现 四、总结 (代码:linux 6.3.1,架构:arm64) One look is worth a thousand words. —— Tess Flanders 相关链接: …...
【列表类型】
1、按索引取值 索引可正向存取,也可反向存取 l [111, paipai, cat] # 正向取值 print(l[1]) # 方向取值 print(l[-1]) # 通过索引给列表重新赋值,前提:索引存在 l[0] ccat print(l) # 索引不存在的情况下,取值or重新赋值的情况下都会报错 …...
MySQL 8.0 OCP 英文题库解析(二)
Oracle 为庆祝 MySQL 30 周年,截止到2025.07.31 之前。所有人均可以免费考取 原价245美元的MySQL OCP 认证。 从今天开始,将英文题库免费公布出来,并进行解析,帮助大家在一个月之内轻松通过OCP认证。 本期公布试题6~15。 试题6: …...
数据分析与逻辑思维:六步解决业务难题;参考书籍《数据分析原理:6步解决业务分析难题 (周文全, 黄怡媛, 马炯雄)》
文章目录 一、懂业务:业务背景与逻辑前提1.1 明确业务目标与问题定义1.2 培养批判性思维与高于业务视角 二、定指标:构建科学的指标体系2.1 指标拆解与维度分析2.2 典型指标体系案例:用户与业务视角 三、选方法:匹配业务需求的分析…...
人力资源管理系统如何有效提高招聘效率?
在传统招聘模式下,企业招聘常常陷入 “泥潭”。HR 每天需要花费大量时间在海量简历中 “大海捞针”,手动筛选、电话沟通、安排面试,流程繁琐且效率低下。好不容易邀约到候选人,却因面试安排冲突、信息传递不及时等问题,…...
FAISS 与机器学习、NLP 的关系
FAISS(Facebook AI Similarity Search)是一个用于高效相似性搜索和密集向量聚类的开源库,由 Facebook AI Research 开发。它在机器学习(特别是自然语言处理,NLP)领域中扮演着重要角色,主要解决大…...
文件包含2
远程文件包含与本地文件包含的区别 对比 对比项本地文件包含(LFI)远程文件包含(RFI)定义攻击者包含服务器本地的文件攻击者包含远程服务器(如HTTP/FTP)上的文件依赖条件不需要特殊配置需要allow_url_incl…...
嵌入式系统架构验证工具:AADL Inspector v1.10 全新升级
软件架构建模与早期验证是嵌入式应用的关键环节。架构分析与设计语言(AADL)是专为应用软件及执行平台架构模型设计的语言,兼具文本与图形化的双重特性。AADL Inspector是一款轻量级的独立工具: 核心处理能力包括 √ 支持处理AA…...
软考高级系统架构设计师备考分享:操作系统核心知识点整理
在备战软考高级系统架构设计师的过程中,操作系统作为核心考点之一,需要系统性地掌握其核心原理。本文将从操作系统分类、进程状态模型、同步互斥机制、死锁问题及存储管理五大模块展开梳理,结合考试高频考点和实际案例进行解析。 一、操作系统…...
22、城堡防御工事——React 19 错误边界与监控
一、魔法护盾:错误边界机制 1. 城墙结界(Error Boundary) // 客户端错误边界use client function useErrorBoundary() {const [error, setError] useState(null);const handleError useCallback((error, errorInfo) > {setError(erro…...
有关SOA和SpringCloud的区别
目录 1. 定义 2. 架构风格 3. 技术栈 4. 服务交互 5. 适用场景 前言 面向服务架构(SOA)是一种软件设计风格,它将应用程序的功能划分为一系列松散耦合的服务。这些服务可以通过标准的通信协议进行交互,通常是HTTP或其他消息传…...
大数据——Mac环境DataSpell集成Jupyter
1、设置 2、添加新的解释器 3、解释器类型选择Conda 4、进入选中全部,然后重启 5、dataspell右下角会显示当前项目的运行环境 6、创建Jupyter Notebook文件 7、测试 8、查看当前配置 (1)本地模式安装使用 (2)…...
解锁健康养生新境界
在追求高品质生活的当下,健康养生早已超越 “治未病” 的传统认知,成为贯穿全生命周期的生活艺术。它如同精密的交响乐,需饮食、运动、心理与生活习惯多维度协奏,方能奏响生命的强音。 饮食养生讲究 “顺时、适性”。遵循二十四节…...