jfinal-4.2 调用commons-exec 执行命令

[背景]

项目部署到客户的服务器,运行过程重出了点小问题,需要我上去看看,然后各种远程,

显示vpn,然后是堡垒机,然后远程桌面1个windows,windows使用xshell连接服务器,

我仅仅是想执行几条调试的命令,为什么要花费这么大的代价

[解决办法]

整合commons-exec,通过http发送命令执行

pom.xml中添加依赖

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

编写工具类

package com.litong.utils.exec;

import java.io.ByteArrayOutputStream;

import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteWatchdog;
import org.apache.commons.exec.PumpStreamHandler;

/**
 * @author bill robot
 * @date 2020年8月17日_下午1:59:09 
 * @version 1.0 
 * @desc
 */

public class ExecUtil {
  /**
   * 带返回结果的命令执行
   * @return
   */
  public static String execCmd(String command) {
    try {
      // 接收正常结果流
      ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
      // 接收异常结果流
      ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
      // 解析命令
      CommandLine commandline = CommandLine.parse(command);
      // 获取命令执行器
      DefaultExecutor exec = new DefaultExecutor();
      exec.setExitValues(null);
      // 设置一分钟超时
      ExecuteWatchdog watchdog = new ExecuteWatchdog(60 * 1000);
      exec.setWatchdog(watchdog);
      //数据泵流处理器
      PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream, errorStream);
      exec.setStreamHandler(streamHandler);
      //执行命令
      exec.execute(commandline);
      // 不同操作系统注意编码,否则结果乱码
      String out = outputStream.toString("GBK");
      String error = errorStream.toString("GBK");
      return out + error;
    } catch (Exception e) {
      e.printStackTrace();
      return e.getMessage();
    }
  }

  public static void main(String[] args) {
    String command = "ping 192.168.0.10";
    String result = ExecUtil.execCmd(command);
    System.out.println(result);
  }
}

编写controller

package com.litong.jfinal.controler;

import com.jfinal.core.Controller;
import com.litong.utils.exec.ExecUtil;

/**
 * @author bill robot
 * @date 2020年8月17日_下午1:58:45   
 * @version 1.0 
 * @desc
 */
public class ConsoleController extends Controller {
  public void index(String cmd) {
    String execCmd = ExecUtil.execCmd(cmd);
    renderText(execCmd);
    return;
  }
}

测试命令

image.png

image.png

image.png

image.png

完成

评论区

hb963724769

2020-08-18 10:11

卧槽,你这功能用完不删,那就是往服务器上放了个原子弹啊

李通

2020-08-18 10:18

用户先登录,登录之后判断角色是否为超级管理员,如果是允许执行,毕竟人生苦短,vpn,堡垒机,跳板机,实际访问速度,让我的心力憔悴

JFinal

2020-08-18 11:15

@李通 在页面弄一个输入框,在输入框里面输入命令,这样用起来体验会更好,毕竟浏览器地址栏里面对空格、中文之类的字符有转换,体验不好

JFinal

2020-08-18 11:22

类似的用法我很早就是下面这么玩的:

后台管理专门弄了一个 function action

public class FunctionController extends BaseController {

// 在这里放一些功能性的 action,例如清缓存之类的
// 有时候会手动改数据库内容,清缓存功能
public void clearCache(String cacheName, String cacheKey) {
if (cacheKey != null) {
CacheKit.remove(cacheName, cacheKey);
} else {
CacheKit.removeAll(cacheName);
}

renderText("OK");
}

// 执行 linux 命令
public void execCmd(String cmd) {
....
renderText(ret);
}
}

同样的,只有超级管理员才能使用,通过配置权限即可

类似于 clearCache 这种实用小功能,想起来需要啥就顺手加一个,连 UI 都不需要

hjk0205

2020-08-18 11:26

@hb963724769 看起来确实挺恐怖的,尤其是对外的服务

hb963724769

2020-08-18 11:45

@李通 生死全在前员工身上,另外不管是不是管理员,现在大家对系统通常都是保存账号密码的。虽然有权限,但是真不知道是不是管理员干的。

haojay

2020-08-18 19:26

安全面前无小事,这东西,测试机器搞搞还行,生产机上打死都不能放啊,出了事情,这锅背不起的