You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot服务端如何调用运行同仓库脚本并解决文件找不到问题

Spring Boot调用项目内Shell脚本找不到文件的解决方案

问题核心原因

你当前直接将前端传入的脚本名传入ProcessBuilder启动进程,进程默认会从JVM启动时的工作目录查找对应文件,没有指定脚本的实际存放路径,也没有做路径合法性校验,因此触发文件找不到报错。

分步修复方案

1. 统一脚本存放规则

把所有可执行脚本统一放到项目src/main/resources/scripts目录下,同时在application.properties/application.yml中配置脚本路径,实现本地和AWS环境适配:

# 本地调试配置
app.scripts.path=src/main/resources/scripts
# AWS环境部署时改成对应服务器路径,比如EC2上的/opt/your_app/scripts
# app.scripts.path=/opt/your_app/scripts

2. 新增安全校验逻辑

必须做路径合法性校验,避免路径穿越漏洞,比如用户传入../rm -rf /*这类恶意脚本名会直接威胁服务安全,建议只允许执行白名单内的脚本,同时校验脚本路径是否落在允许的目录范围内。

3. 修复控制器代码

import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.FileCopyUtils;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;

@RestController
public class ScriptController {

    @Value("${app.scripts.path}")
    private String scriptsBasePath;

    // 白名单:只允许执行列表内的脚本,按需修改
    private static final List<String> ALLOWED_SCRIPTS = List.of("test1.sh", "backup.sh", "sync_data.sh");

    @PostMapping
    public ResponseEntity<SampleRest> runScript(@Valid @RequestBody ScriptsDetailsRequestModel scriptDetails) throws IOException {
        String scriptName = scriptDetails.getScriptName();
        // 1. 校验脚本是否在白名单内
        if (!ALLOWED_SCRIPTS.contains(scriptName)) {
            return new ResponseEntity<>(HttpStatus.FORBIDDEN);
        }
        // 2. 拼接脚本完整路径,校验路径合法性
        Path scriptPath = Paths.get(scriptsBasePath, scriptName).normalize();
        if (!scriptPath.startsWith(Paths.get(scriptsBasePath).normalize())) {
            // 路径穿越攻击,直接拒绝
            return new ResponseEntity<>(HttpStatus.FORBIDDEN);
        }
        if (!Files.exists(scriptPath)) {
            return new ResponseEntity<>(HttpStatus.NOT_FOUND);
        }
        // 3. 构造执行命令,指定bash解释器,避免执行权限问题
        String[] cmd = new String[]{"/bin/bash", scriptPath.toAbsolutePath().toString()};
        ProcessBuilder pb = new ProcessBuilder(cmd);
        // 可选:配置工作目录、环境变量
        pb.directory(Paths.get(scriptsBasePath).toFile());
        // 4. 启动进程,必须读取进程输出流和错误流,否则进程会卡住
        Process p = pb.start();
        // 异步读取输出,避免阻塞
        new Thread(() -> {
            try {
                // 读取标准输出
                FileCopyUtils.copy(p.getInputStream(), System.out);
                // 读取错误输出
                FileCopyUtils.copy(p.getErrorStream(), System.err);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }).start();
        // 可选:等待脚本执行完成,或者直接返回
        // int exitCode = p.waitFor();
        SampleRest returnValue = new SampleRest();
        returnValue.setMsg("脚本执行触发成功");
        return new ResponseEntity<>(returnValue, HttpStatus.OK);
    }
}

环境适配注意事项

本地调试

  • 给脚本目录下的所有sh文件加执行权限:chmod +x src/main/resources/scripts/*.sh
  • 确认IDEA启动项目的工作目录是项目根目录,和配置的app.scripts.path匹配

AWS环境适配

  • 如果部署到EC2/ECS:部署时将scripts目录同步到配置的app.scripts.path对应路径,同时保留脚本的执行权限
  • 如果部署到Lambda:Lambda只允许读写/tmp目录,启动时需要把类路径下的脚本复制到/tmp目录再执行,修改脚本基础路径配置为/tmp/scripts即可

内容的提问来源于stack exchange,提问作者Helpthisamatuerprogrammer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 04:27:01