目录
- 一、问题
- 二、工具介绍
- 三、解决方法
一、问题
场景:Ruoyi架构,bat文件上传到了服务器的文件夹upload下,如何通过在前端点击“执行”,后端Java去操控对应的bat文件执行呢?
解决方案:Java可以通过Process类的Runtime.getRuntime().exec调用外部的脚本或者是操作系统命令。
二、工具介绍
Runtime.getRuntime().exec()
这段代码就像是在你的Java程序里创建一个子进程打开一个命令提示符窗口,可以让你直接运行电脑上的命令或程序,同时还能够管理和获取这个外部程序的运行情况,并返回进程对应的Process对象实例
Process process = Runtime.getRuntime().exec( "notepad.exe ");
//用于等待子进程完成再往下执行。
process.waitfor();
Process中有以下方法:
// 等待当前线程等待,直到进程终止。
int waitFor()
// 杀掉子进程,如果已终止该子进程,此方法立即返回。
// 如果没有终止该子进程,调用的线程将被阻塞,直到退出子进程,0 表示正常终止。
void destroy()
// 返回子进程的出口值,值 0 表示正常终止
int exitValue()
// 获取子进程的错误流
InputStream getErrorStream()
// 获取子进程的输入流
InputStream getInputStream()
// 获取子进程的输出流
OutputStream getOutputStream()
如果执行Runtime.getRuntime().exec("notepad.exe")
相当于打开记事本效果:
cmd /c start
命令可以打开一个新的命令提示符窗口,并在其中执行指定的命令或程序,但打开新窗口的根路径在当前目录,可以在命令中使用 cd
命令来切换路径
参数 /c
表示这个cmd一旦被调用,程序不用等待cmd后面的内容执行完毕,就返回到调用start的环境里,这样可以避免如果cmd后面的内容运行过长而导致程序处于等待而呈现假死的现象,下面cmd /c start 测试脚本程序.bat
相当于打开一个新窗口执行bat程序,但不会中断原先的窗口:
/K
表示在命令执行完毕后不关闭窗口,cd 命令用于切换路径,下面命令可以打开一个新的命令提示符窗口,并将其根路径设置为 C:\path\to\directory:
cmd /c start cmd.exe /K "cd C:\path\to\directory"
三、解决方法
首先我们创建一个脚本测试程序
将其通过前端上传到服务器上
由于Ruoyi默认上传文件时,会以后端地址+profile+年/月/日/标识符
的方式放入对应文件夹,也就是http很长这一段
我们可以看到文件目录,原始文件名称也被修改了
我们需要找到文件目录和文件名,先设置common获取目录
filePath = filePath.substring(filePath.indexOf("profile"));
//处理filePath,将profile替换为RuoYiConfig.getProfile()
filePath = filePath.replace("profile", RuoYiConfig.getProfile());
//处理filePath,将/替换为\
filePath = filePath.replace("/", "\\");
//设置common为filePath目录最后一个\之前的部分
String common = filePath.substring(0, filePath.lastIndexOf("\\"));
获取到文件目录后,设置需要执行的命令
//进入common目录后,执行filePath
File file = new File(filePath);
String cmd = "cmd /c start cmd.exe /K \"cd /d " + common + " && " + file.getAbsolutePath() + "\"";
Process process = Runtime.getRuntime().exec(cmd);
String cmd 这个命令会打开一个新的命令提示符窗口,然后进入common目录,也就是E:\ftpTest\upload\2023\07\27
并执行运行文件命令。如果文件路径中包含空格或其他特殊字符,需要使用引号将其括起来:
String cmd = "cmd /c start cmd.exe /K \"cd /d " + common + " && \"" + file.getAbsolutePath() + "\"\"";
但执行命令可不行,还要判断命令是否执行完成,在Java中,可以使用Process类来执行命令,并通过waitFor()方法等待命令执行完成。waitFor()方法返回一个整数值,表示命令的执行结果,返回0表示命令执行成功,返回非0值表示命令执行失败。可以使用以下代码示例来实现该功能:
Process process = Runtime.getRuntime().exec(cmd);
int exitCode = process.waitFor();
if (exitCode == 0) {
return "执行成功";
} else {
return "执行失败";
}
完整代码示例如下,具体的fileUploadService服务这一块需要根据项目自定义:
public static final String executeBat(String filePath) {
try {
filePath = filePath.substring(filePath.indexOf("profile"));
filePath = filePath.replace("profile", RuoYiConfig.getProfile());
filePath = filePath.replace("/", "\\");
String common = filePath.substring(0, filePath.lastIndexOf("\\"));
File file = new File(filePath);
String cmd = "cmd /c start cmd.exe /K \"cd /d " + common + " && " + file.getAbsolutePath() + "\"";
Process process = Runtime.getRuntime().exec(cmd);
int exitCode = process.waitFor();
if (exitCode == 0) {
return "执行成功";
} else {
return "执行失败";
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return filePath;
}
public AjaxResult bat(@PathVariable("id")Integer id) {
if(!fileUploadService.selectFileUploadById(id).getUrl().endsWith(".bat")){
return AjaxResult.error("文件格式错误");
}
String path = fileUploadService.selectFileUploadById(id).getUrl();
String result = FileUploadUtils.executeBat(path);
return AjaxResult.success(result);
}
import java.io.IOException;
public class CommandExecutor {
public static void main(String[] args) {
try {
Process process = Runtime.getRuntime().exec("cmd /c start cmd.exe");
int exitCode = process.waitFor();
if (exitCode == 0) {
System.out.println("Command executed successfully.");
} else {
System.out.println("Command execution failed.");
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
之后,前端点击执行调用后端接口后,服务器端将运行对应的bat文件