基于ssh

根据业务需求有的项目中可能会需要java执行linux命令
用springboot整合一下

maven依赖

  1. <dependency>
  2. <groupId>ch.ethz.ganymed</groupId>
  3. <artifactId>ganymed-ssh2</artifactId>
  4. <version>build210</version>
  5. </dependency>

yml配置文件

在配置文件中自定义服务器的ip,账号,密码,方便修改

ssh:
  ip: 192.168.12.103
  user: root
  pass: 1234

配置类

先要连接获取connection对象

@Configuration
@Slf4j
public class SshConfig {

    @Value("${ssh.ip}")
    private String ip;

    @Value("${ssh.user}")
    private String user;

    @Value("${ssh.pass}")
    private String pass;

    @Bean
    public Connection getConnection() {
        Connection conn = new Connection(ip);
        try {
            conn.connect();
            //账号,密码验证
            boolean isAuthenticated = conn.authenticateWithPassword(user, pass);
            if (!isAuthenticated) {
                throw new IOException("密码不正确!");
            }
        } catch (
                IOException e) {
            log.error("连接异常====>{}", e.getMessage());
        }
        return conn;
    }

}

执行命令

封装一个方法,执行命令并返回执行结果,execCommand方法来执行命令
一个session对象只能执行一次execCommand方法

    /**
     * 执行命令并返回执行结果
     *
     * @param command 命令
     * @return java.lang.String
     * @author YangYudi
     * @date 2021/1/8 9:04
     */
    public String execCommand(String command) {
        StringBuilder result = new StringBuilder();
        try {
            Session session = connection.openSession();
            session.execCommand(command);

            //获取返回信息
            InputStream stdout = new StreamGobbler(session.getStdout());
            BufferedReader stdoutReader = new BufferedReader(new InputStreamReader(stdout));

            InputStream stderr = new StreamGobbler(session.getStderr());
            BufferedReader stderrReader = new BufferedReader(new InputStreamReader(stderr));
            //一直读到流结束 逐行读取
            String line;
            //标准输出
            while ((line = stdoutReader.readLine()) != null) {
                result.append(line).append("\n");
            }
            //标准错误输出
            while ((line = stderrReader.readLine()) != null) {
                result.append(line).append("\n");
            }
            //等待收到远程进程的退出码
            session.waitForCondition(ChannelCondition.EXIT_STATUS, 10000);
            stdoutReader.close();
            stderrReader.close();
            session.close();
        } catch (IOException e) {
            log.error("ssh执行出错:{}", e.getMessage());
        }
        return result.toString();
    }

测试方法

     @Test
    void saltTestMinion() {
        //执行minion节点上的脚本
        String result = sshCommandUtils.execCommand("salt '*' --out=json cmd.run_all 'cat /usr/local/hello.txt'");
        System.out.println(result);
    }

需要考虑的问题

这里把connection作为单例对象使用,在多线程情况下,可能不太适用
多线程情况下执行命令connection最好不要用单例

在本机执行命令

根据项目所在的计算机执行命令就不需要借助ssh了

maven依赖

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

api使用

封装一个方法,根据传入的命令返回执行结果

    public static String execCommand(String command) {
        CommandLine cmd = CommandLine.parse(command);
        OutputStream outputStream = new ByteArrayOutputStream();
        DefaultExecutor executor = new DefaultExecutor();
        PumpStreamHandler streamHandler = new PumpStreamHandler(outputStream);
        ShutdownHookProcessDestroyer processDestroyer = new ShutdownHookProcessDestroyer();
        executor.setStreamHandler(streamHandler);
        executor.setProcessDestroyer(processDestroyer);
        try {
            executor.execute(cmd);
        } catch (Exception e) {
            log.error("{}", e);
        }
        return outputStream.toString();
    }