前端控制后台springboot项目停止,启动,重启

1. windows 端口号被占用 强制删除
netstat -ano|findstr "8080"
taskkill /F /PID 708
2. 思路

模拟容器平台前端控制后台springboot项目停止,启动,重启。
后台需要两个,一个专门负责管理脚本 vue-back-bat.jar,通过脚本控制另一个后台,一个是具体服务 vue-back-manage.jar 都解压后放在D盘
启动
cmd /c start /b javaw -Dfile.encoding=utf-8 -cp . org.springframework.boot.loader.JarLauncher

3. vue-back-bat后台 设置端口9002

使用commons-exec执行bat脚本

<dependency>
     <groupId>org.apache.commons</groupId>
     <artifactId>commons-exec</artifactId>
     <version>1.3</version>
 </dependency>

yml 配置异步请求接口超时时间

spring:
  mvc:
    async:
      # 超时设置15s
      request-timeout: 15000

封装CommandUtil

/**
 * 采用 commons-exec 处理bat,shell脚本或者命令行
 *
 * @author bestm
 */
@Slf4j
@Component
public class CommandUtil {
    /**
     * 设置超时时间 10s
     */
    private static final long TIMEOUT = 10 * 1000L;

    /**
     * 新线程以阻塞方式执行子进程,来处理命令行或者脚本
     *
     * @param command 命令行或者脚本  ipconfig /all, D:/my.bat 111 222
     * @return 返回状态码
     * @throws IOException
     * @throws ExecuteException
     */
    public String execCommand(String command) {
        CommandLine cmdLine = CommandLine.parse(command);
        DefaultExecutor executor = new DefaultExecutor();

        // 设置命令执行退出值为0,如果命令成功执行并且没有错误,则返回0
        executor.setExitValue(0);
        // 输出结果
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        PumpStreamHandler streamHandler = new PumpStreamHandler(baos, baos);
        executor.setStreamHandler(streamHandler);

        ExecuteWatchdog watchdog = new ExecuteWatchdog(TIMEOUT);
        executor.setWatchdog(watchdog);

        try {
            int exitValue = executor.execute(cmdLine);
            if (exitValue == 0) {
                log.info(baos.toString("GBK"));
                return exitValue + "";
            }
        } catch (IOException e) {
            return null;
        }
        return null;
    }

    /**
     * 异步执行
     *
     * @param command  注意如果是 cmd /c start /b java -cp  后台运行子进程,不能杀死
     */
    public String execCommandAsync(String command) {
        CommandLine commandLine = CommandLine.parse(command);
        DefaultExecutor executor = new DefaultExecutor();

        // 输出结果
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        //接收异常结果流
        ByteArrayOutputStream errStream = new ByteArrayOutputStream();

        //10s超时
        ExecuteWatchdog watchdog = new ExecuteWatchdog(10 * 1000);
        executor.setWatchdog(watchdog);

        PumpStreamHandler streamHandler = new PumpStreamHandler(baos, baos);
        executor.setStreamHandler(streamHandler);

        try {
            int code = executor.execute(commandLine);
            System.out.println("result code: " + code);
            // 不同操作系统注意编码,否则结果乱码
            String suc = baos.toString("GBK");
            String err = errStream.toString("GBK");
            log.info(err);
            return suc;
        } catch (Exception e) {
            watchdog.killedProcess();
        }
        return "";
    }
}

Controller

@Slf4j
@RestController
@RequestMapping("/cmd")
public class CmdController {
    @Autowired
    private SyConfigFileUtil syConfigFileUtil;
    @Autowired
    private CommandUtil commandUtil;

    private static final String RESTART_CMD = "restart.cmd";
    private static final String STOP_CMD = "stop.cmd";

    /**
     * 重启项目vue-back-manage
     *
     * @return  无法获取脚本执行结果,因为是后台子进程执行,子进程挂起
     */
    @PostMapping("/restart")
    public Callable<String> restart() {
      return () -> {
          try {
              String command = "cmd /c start /b " + syConfigFileUtil.getClassPath() + "/" + RESTART_CMD;
              log.info(command);
              return commandUtil.execCommandAsync(command);
          } catch (Exception exception) {
              log.info("超时返回");
              return "0";
          }
      };
    }

    /**
     * 停止项目vue-back-manage
     *
     * @return
     */
    @PostMapping("/stop")
    public String stop() {
        String command = "cmd /c start /b " + syConfigFileUtil.getClassPath() + "/" + STOP_CMD;
        log.info(command);
        String code = commandUtil.execCommand(command);
        log.info("退出码:{}", code);
        return code;
    }
}

stop.bat

set num=9001
for /f "tokens=5" %%a in ('netstat /ano ^| findstr %num%') do (
	if %%a neq 0 (
		echo 端口号9001的pid为%%a
        taskkill /F /pid %%a
        goto _break
	) else (
		echo 端口号9001未被占用
	)
)

rem 结束for循环
:_break

```
restart.bat
```bat
set num=9001
for /f "tokens=5" %%a in ('netstat /ano ^| findstr %num%') do (
	if %%a neq 0 (
		echo 端口号9001的pid为%%a
        taskkill /F /pid %%a
        goto _break
	) else (
		echo 端口号9001未被占用
	)
)

rem 结束for循环
:_break

rem 切换盘符
D:
rem 这里切换到项目目录内,否则会导致application.pid无法生成
cd D:/vue-back-manage

rem 后台执行 启动springboot项目 cmd /c start /b
java -Dfile.encoding=utf-8 -cp . org.springframework.boot.loader.JarLauncher
```
#### 4. vue-back-manage后台 设置端口9001
获取项目路径工具类SyConfigFileUtil
```java
/**
 * 系统配置文件读取
 *
 * @author liuxb
 * @date 2022/5/22 11:47
 **/
@Slf4j
@Component
public class SyConfigFileUtil {
    @Value("classpath:restart.cmd")
    private Resource resource;

    /**
     * 获取类路径
     *
     * @return
     */
    public String getClassPath() {
        try {
            return resource.getFile().getParentFile().getAbsolutePath();
        } catch (IOException e) {
            return "";
        }
    }

    /**
     * 读取文件内容
     *
     * @param filePath 相对项目的文件路径
     * @return
     */
    public String getFileContent(String filePath) {
        File file = new File(getClassPath(), filePath);
        log.info("路径:{}", file.getPath());
        String content = null;
        try (InputStream inputStream = new FileInputStream(file)) {
            content = IOUtils.toString(inputStream);
        } catch (IOException e) {
            throw new BizException("读取文件失败");
        }
        return content;
    }

    /**
     * 修改文件内容
     *
     * @param filePath 相对项目的文件路径
     * @param content  文件内容
     * @return
     */
    public boolean updateFile(String filePath, String content) {
        File file = new File(getClassPath(), filePath);
        log.info("路径:{}", file.getPath());
        try (OutputStream out = new FileOutputStream(file)) {
            IOUtils.write(content, out, StandardCharsets.UTF_8);
        } catch (IOException e) {
            throw new BizException("写入文件失败");
        }
        return true;
    }
}
```
读取pidController
```java
 @Autowired
 private SyConfigFileUtil syConfigFileUtil;
 private static final String APPLICATION_PID = "../../application.pid";
    @PostMapping("/getPID")
    public String getPID() {
        return syConfigFileUtil.getFileContent(APPLICATION_PID);
    }
```

读取ymlController
```java
@Slf4j
@Validated
@RestController
@RequestMapping("/yml")
public class YmlController {
    @Autowired
    private SyConfigFileUtil syConfigFileUtil;

    private static final String CONFIG_FILE = "application.yml";

    /**
     * 读取application.yml内容
     *
     * @return
     */
    @PostMapping("/getApplication")
    public String getApplication() {
        return syConfigFileUtil.getFileContent(CONFIG_FILE);
    }

    /**
     * 修改application.yml内容
     *
     * @param content application.yml内容
     * @return
     */
    @PostMapping("/updateApplication")
    public boolean updateApplication(@RequestSingleBody @NotBlank(message = "内容不能为空") String content) {
        return syConfigFileUtil.updateFile(CONFIG_FILE, content);
    }

}
```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值