
controller,对外接口
package org.example.xxxxxx.processRestart.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.example.xxxx.processRestart.service.ProcessRestartService;
import org.example.xxxx.processRestart.vo.ProcessRestartReqVo;
import org.example.xxxx.util.ProcessOperationUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 供远程调用
*/
@RestController
@RequestMapping("restartApi")
@RequiredArgsConstructor
@Log4j2
public class ProcessRestartController {
private final ProcessRestartService service;
/**
* 远程重启程序接口
* @return
*/
@PostMapping("/executeRrestart")
public ResponseEntity<Map<String, Object>> restartProcess(@RequestBody ProcessRestartReqVo model) {
log.info("【远程重启程序】:{}", model);
Map<String, Object> stringObjectMap = service.restartProcess(model);
Map<String,Object> resMap = new HashMap<>();
resMap.put("data",stringObjectMap);
return ResponseEntity.ok(resMap);
}
public static void main(String[] args) {
try {
ProcessOperationUtil.killProcessByPort(20099);
Thread.sleep(3000);
ProcessOperationUtil.startExistingProcess("D:\\testexe\\testf1.exe");
//ProcessOperationUtil.startExistingProcess("D:\\myProjectDemo\\nacos\\bin\\startup.cmd");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
ProcessRestartService
public interface ProcessRestartService {
public Map<String, Object> restartProcess(@RequestBody ProcessRestartReqVo model);
}
ProcessRestartServiceImpl ,实现类
package org.example.xxxxx.processRestart.service.impl;
import lombok.extern.java.Log;
import lombok.extern.log4j.Log4j2;
import org.example.xxxx.processRestart.service.ProcessRestartService;
import org.example.xxxx.processRestart.vo.ProcessRestartReqVo;
import org.example.xxxx.util.ProcessOperationUtil;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 远程重启务实现类
*/
@Service
@Log4j2
public class ProcessRestartServiceImpl implements ProcessRestartService {
@Override
public Map<String, Object> restartProcess(ProcessRestartReqVo model) {
Map<String,Object> result = new HashMap<>();
try {
// 1. 获取配置信息
if (model.getPort() == null || model.getStartProgramPath()==null || model.getStartProgramPath()=="") {
result.put("code", 400);
result.put("msg", "无效的程序名称:" + model.getProcessName() + ",支持的端口或路径为空");
return result;
}
// 2. 执行杀进程+重启操作
ProcessOperationUtil.killProcessByPort(model.getPort());
ProcessOperationUtil.startExistingProcess(model.getStartProgramPath());
log.info("重启「" + model.getProcessName() + "」程序执行完成");
// 3. 返回成功结果
result.put("code", 200);
result.put("msg", "成功:「" + model.getProcessName() + "」程序执行完成");
return result;
} catch (Exception e) {
// 4. 返回异常结果
result.put("code", 500);
result.put("msg", "失败:「" + model.getProcessName() + "」重启异常,原因:" + e.getMessage());
return result;
}
}
}
ProcessOperationUtil ,主要核心代码启用和杀死程序
package org.example.xxxxxx.util;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.TimeUnit;
/**
* Windows进程操作工具类
*/
@Slf4j
@Component
public class ProcessOperationUtil {
// 定义静态常量
private static final File WINDOWS_NULL_DEVICE = new File("NUL");
/**
* Windows系统:根据端口号杀死占用进程(含子进程)
* @param port 目标端口
* @throws IOException 命令执行异常
*/
public static void killProcessByPort(int port){
try {
// 查找占用端口的所有进程PID(包括非LISTENING状态,避免遗漏)
String findPidCmd = String.format("netstat -ano | findstr \":%d\" | findstr \"LISTENING\"", port);
String cmdResult = executeWindowsCommand(findPidCmd,5);
log.info("停止服务-----{}",cmdResult);
if (!cmdResult.isEmpty()) {
String[] lines = cmdResult.split("\n");
for (String line : lines) {
line = line.trim();
if (line.isEmpty()) {
continue;
}
String[] parts = line.split("\\s+");
if (parts.length >= 5) {
String pid = parts[4];
if (pid != null && !pid.trim().isEmpty() && !pid.equals("0")) {
// 杀死进程及其子进程(/T参数:终止进程和子进程;/F:强制终止)
String killCmd = String.format("taskkill /F /T /PID %s", pid.trim());
executeWindowsCommand(killCmd,5);
log.info("【杀进程】:端口{},PID={} 及其子进程已强制终止", port, pid);
}
}
}
} else {
log.info("【杀进程】:端口{} 未被占用,无需终止进程", port);
}
} catch (Exception e) {
log.error("【杀进程】:端口{} 终止进程失败,原因:{}", port, e.getMessage());
}
}
/**
* 启动程序
* @param programPath 现有程序完整路径
*/
public static void startExistingProcess(String programPath) throws IOException {
ProcessBuilder pb = new ProcessBuilder();
String wrappedPath = "\"" + programPath + "\"";
if (programPath.endsWith(".bat") || programPath.endsWith(".cmd")) {
pb.command("cmd.exe", "/c", "start", "\"\"", wrappedPath);
} else {
pb.command("cmd.exe", "/c", "start", "/B", "/MIN", "\"\"", wrappedPath);
}
pb.redirectInput(WINDOWS_NULL_DEVICE);
pb.redirectOutput(WINDOWS_NULL_DEVICE);
pb.redirectError(WINDOWS_NULL_DEVICE);
File workDir = new File(programPath).getParentFile();
if (workDir != null && workDir.exists()) {
pb.directory(workDir);
}
Process process = pb.start();
new Thread(() -> {
try {
process.getInputStream().close();
process.getOutputStream().close();
process.getErrorStream().close();
process.waitFor(3, TimeUnit.SECONDS);
int exitCode = process.waitFor();
log.info("【启动程序】:启动命令执行完成,退出码:{}(0为成功)", exitCode);
} catch (Exception ignored) {}
process.destroy();
}).start();
log.info("【启动程序】{} 已后台执行", programPath);
}
public static void start(ProcessBuilder processBuilder) throws IOException{
// 启动进程(非阻塞,不影响主进程)
Process process = processBuilder.start();
// 异步等待命令执行完成,不阻塞主线程,执行后释放句柄
new Thread(() -> {
try {
// 显式关闭流
process.getInputStream().close();
process.getOutputStream().close();
process.getErrorStream().close();
int exitCode = process.waitFor();
log.info("【启动程序】:启动命令执行完成,退出码:{}(0为成功)", exitCode);
} catch (IOException | InterruptedException e) {
Thread.currentThread().interrupt();
log.error("【启动程序】:命令执行中断 -> {}", e.getMessage());
} finally {
// 释放Process句柄,彻底解除与子进程的关联
process.destroy();
}
}).start();
}
/**
* 执行Windows系统命令并返回结果
* @param cmd 命令内容
* @return 命令执行结果
* @throws IOException 执行异常
*/
private static String executeWindowsCommand(String cmd, int timeoutSeconds) {
StringBuilder result = new StringBuilder();
try {
Process process = new ProcessBuilder("cmd.exe", "/c", cmd)
.redirectErrorStream(true)
.start();
// 异步读流,防止缓冲区满导致阻塞
new Thread(() -> {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream(), "GBK"))) {
String line;
while ((line = reader.readLine()) != null) {
result.append(line).append("\n");
}
} catch (IOException ignored) {}
}).start();
// 超时控制,最多等 timeoutSeconds 秒,强制结束
boolean finished = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
if (!finished) {
process.destroy();
log.warn("【命令超时】{} 已强制终止", cmd);
}
} catch (Exception e) {
log.error("【命令执行失败】{}", cmd, e);
}
return result.toString().trim();
}
}

982

被折叠的 条评论
为什么被折叠?



