1、依赖引入

hm-manage/pom.xml

<!-- ftpclient 文件上传服务器的依赖-->
<dependency>
    <groupId>commons-net</groupId>
    <artifactId>commons-net</artifactId>
    <version>3.1</version>
</dependency>
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.55</version>
</dependency>

2、工具类

hm-manage/src/main/java/com/hm/manage/utils/SSHRemoteCall.java

package com.hm.manage.utils;

import java.io.*;
import java.util.Vector;
import java.util.Properties;

import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;

/**
 * @author : hm
 * @description : 工具类
 * @create :2021-11-03 09:17:00
 */
public class SSHRemoteCall {
    // 私有的对象
    private static SSHRemoteCall sshRemoteCall;

    /**
     * 私有的构造方法
     */
    private SSHRemoteCall() {
    }

    // 懒汉式,线程不安全,适合单线程
    public static SSHRemoteCall getInstance() {
        if (sshRemoteCall == null) {
            sshRemoteCall = new SSHRemoteCall();
        }
        return sshRemoteCall;
    }

    // 懒汉式,线程安全,适合多线程
    public static synchronized SSHRemoteCall getInstance2() {
        if (sshRemoteCall == null) {
            sshRemoteCall = new SSHRemoteCall();
        }
        return sshRemoteCall;
    }
    // 默认端口号
    private static final int DEFAULT_PORT = 55555;
    private int port;// 端口号
    // ip地址
    private static String ipAddress = "172.18.16.170";
    // 账号
    private static String userName = "hik";
    // 密码
    private static String password = "wujin320@2019";
    // JSCH session
    private Session session;
    // 是否登陆5
    private boolean logined = false;

    /**
     * 构造方法,可以直接使用DEFAULT_PORT
     *
     * @param ipAddress
     * @param userName
     * @param password
     */
    public SSHRemoteCall(String ipAddress, String userName, String password) {
        this(ipAddress, DEFAULT_PORT, userName, password);
    }

    /**
     * 构造方法,方便直接传入ipAddress,userName,password进行调用
     *
     * @param ipAddress
     * @param port
     * @param userName
     * @param password
     */
    public SSHRemoteCall(String ipAddress, int port, String userName, String password) {
        super();
        this.ipAddress = ipAddress;
        this.userName = userName;
        this.password = password;
        this.port = port;
    }

    /**
     * 远程登陆
     *
     * @throws Exception
     */
    public void sshRemoteCallLogin(String ipAddress, int port, String userName, String password) throws Exception {
        // 如果登陆就直接返回
        if (logined) {
            return;
        }
        // 创建jSch对象
        JSch jSch = new JSch();
        try {
            // 获取到jSch的session, 根据用户名、主机ip、端口号获取一个Session对象
            session = jSch.getSession(userName, ipAddress, port);
            // 设置密码
            session.setPassword(password);

            // 方式一,通过Session建立连接
            // session.setConfig("StrictHostKeyChecking", "no");
            // session.connect();

            // 方式二,通过Session建立连接
            // java.util.Properties;
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);// 为Session对象设置properties
            // session.setTimeout(3000);// 设置超时
            session.connect(); //通过Session建立连接

                    // 设置登陆状态
                    logined = true;
        } catch (JSchException e) {
            // 设置登陆状态为false
            logined = false;
            throw new Exception(
                    "主机登录失败, IP = " + ipAddress + ", USERNAME = " + userName + ", Exception:" + e.getMessage());
        }
    }

    /**
     * 关闭连接
     */
    public void closeSession() {
        // 调用session的关闭连接的方法
        if (session != null) {
            // 如果session不为空,调用session的关闭连接的方法
            session.disconnect();
        }

    }
       /**
       * 关闭连接
       */
      public void closeLogin(){
          if (logined) {
              logined = false;
          }
      }

    /**
     * 执行相关的命令
     *
     * @param command
     * @throws IOException
     */
    public String execCommand(String command) throws IOException {
        InputStream in = null;// 输入流(读)
        Channel channel = null;// 定义channel变量
        try {
            // 如果命令command不等于null
            if (command != null) {
                // 打开channel
                //说明:exec用于执行命令;sftp用于文件处理
                channel = session.openChannel("exec");
                // 设置command
                ((ChannelExec) channel).setCommand(command);
                System.out.println("相关命令:"+command);
                // channel进行连接
                channel.connect();
                // 获取到输入流
                in = channel.getInputStream();
                // 执行相关的命令
                String processDataStream = processDataStream(in);
                // 打印相关的命令

                System.out.println("1、打印相关返回的命令: " + processDataStream);
                return processDataStream;
            }
        } catch (JSchException e) {
            return "JSchException: " + e.getMessage();
        } catch (IOException e) {
            System.err.println("IOException occurred: " + e.getMessage());
            throw e; // 重新抛出 IOException,保持接口一致性
        } catch (Exception e) {
            System.err.println("Unexpected exception occurred: " + e.getMessage());
            return "Error: " + e.getMessage();
        } finally {
            if (in != null) {
                in.close();
            }
            if (channel != null) {
                channel.disconnect();
            }

        }
        return null;
    }

    /**
     * 执行相关的命令
     *
     * @param command 待执行的命令
     * @return 命令执行结果或错误信息
     * @throws IOException 如果发生 I/O 错误
     */
    public String execCommand2(String command) throws IOException {
        // 校验命令是否为空
        if (command == null || command.trim().isEmpty()) {
            return "Error: Command is null or empty.";
        }

        // 防止命令注入攻击,简单校验命令内容
        if (!command.matches("[a-zA-Z0-9\\s.\\-/]+")) {
            return "Error: Invalid command format.";
        }

        Channel channel = null;
        try  { // 使用 try-with-resources 管理资源
            InputStream in = new ByteArrayInputStream(new byte[0]);
            // 打开 channel
            channel = session.openChannel("exec");
            if (channel == null) {
                return "Error: Failed to open channel.";
            }

            // 设置命令
            ((ChannelExec) channel).setCommand(command);
            System.out.println("Executing command: " + command);

            // 连接 channel
            channel.connect();
            if (!channel.isConnected()) {
                return "Error: Channel connection failed.";
            }

            // 获取输入流
            in = channel.getInputStream();

            // 处理数据流
            String processDataStream = processDataStream(in);
            System.out.println("Command executed successfully. Result: " + processDataStream);

            return processDataStream;
        } catch (JSchException e) {
            System.err.println("JSchException occurred: " + e.getMessage());
            return "JSchException: " + e.getMessage();
        } catch (IOException e) {
            System.err.println("IOException occurred: " + e.getMessage());
            throw e; // 重新抛出 IOException,保持接口一致性
        } catch (Exception e) {
            System.err.println("Unexpected exception occurred: " + e.getMessage());
            return "Error: " + e.getMessage();
        } finally {
            if (channel != null && channel.isConnected()) {
                channel.disconnect(); // 确保 channel 正常断开
            }
        }
    }


    /**
     * 对将要执行的linux的命令进行遍历
     *
     * @param in
     * @return
     * @throws Exception
     */
    public String processDataStream(InputStream in) throws Exception {
        StringBuffer sb = new StringBuffer();
        BufferedReader br = new BufferedReader(new InputStreamReader(in));
        String result = "";
        try {
            while ((result = br.readLine()) != null) {
                sb.append(result);
                // System.out.println(sb.toString());
            }
        } catch (Exception e) {
            throw new Exception("获取数据流失败: " + e);
        } finally {
            br.close();
        }
        return sb.toString();
    }

    /**
     * 上传文件 可参考:https://www.cnblogs.com/longyg/archive/2012/06/25/2556576.html
     *
     * @param directory  上传文件的目录
     * @param uploadFile 将要上传的文件
     */
    public void uploadFile(String directory, String uploadFile) {
        try {
            // 打开channelSftp
            ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
            // 远程连接
            channelSftp.connect();
            // 创建一个文件名称问uploadFile的文件
            File file = new File(uploadFile);
            // 将文件进行上传(sftp协议)
            // 将本地文件名为src的文件上传到目标服务器,目标文件名为dst,若dst为目录,则目标文件名将与src文件名相同.
            // 采用默认的传输模式:OVERWRITE
            channelSftp.put(new FileInputStream(file), directory, ChannelSftp.OVERWRITE);
            // 切断远程连接
            channelSftp.exit();
            System.out.println("2、" + file.getName() + " 文件上传成功.....");
        } catch (JSchException e) {
            e.printStackTrace();
        } catch (SftpException e) {
            e.printStackTrace();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * 下载文件 采用默认的传输模式:OVERWRITE
     *
     * @param src linux服务器文件地址
     * @param dst 本地存放地址
     * @throws JSchException
     * @throws SftpException
     */
    public void fileDownload(String src, String dst) throws JSchException, SftpException {
        // src 是linux服务器文件地址,dst 本地存放地址
        ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
        // 远程连接
        channelSftp.connect();
        // 下载文件,多个重载方法
        channelSftp.get(src, dst);
        // 切断远程连接,quit()等同于exit(),都是调用disconnect()
        channelSftp.quit();
        // channelSftp.disconnect();
        System.out.println("3、" + src + " ,下载文件成功.....");
    }

    /**
     * 删除文件
     *
     * @param
     * @param
     * @param
     * @throws SftpException
     * @throws JSchException
     */
    public void deleteFile(String directoryFile) throws SftpException, JSchException {
        // 打开openChannel的sftp
        ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
        // 远程连接
        channelSftp.connect();
        // 删除文件
        channelSftp.rm(directoryFile);
        // 切断远程连接
        channelSftp.exit();
        System.out.println("4、" + directoryFile + " 删除的文件.....");
    }

    /**
     * * 列出目录下的文件
     *
     * @param directory 要列出的目录
     * @param
     * @return
     * @throws SftpException
     * @throws JSchException
     */
    public Vector listFiles(String directory) throws JSchException, SftpException {
        ChannelSftp channelSftp = (ChannelSftp) session.openChannel("sftp");
        // 远程连接
        channelSftp.connect();
        // 显示目录信息
        Vector ls = channelSftp.ls(directory);
        System.out.println("5、" + ls);
        // 切断连接
        channelSftp.exit();
        return ls;
    }


}

3、调用

3.1、执行命令并返回

@Override
public String getServerInfo(Long id) {
    Hardserver hardserver = hardserverMapper.selectHardserverById(id);
    log.info("--------------------hardserver = {}",hardserver);
    String result = "无结果";
    if(hardserver!=null){
        try {
            // 1、远程ssh
            SSHRemoteCall.getInstance().sshRemoteCallLogin(hardserver.getServerIp(), Integer.parseInt(hardserver.getServerPort()), hardserver.getUsername(), hardserver.getUPassword());
            // 2、 执行命令
            String command = "du -sh";
            // 3、执行命令
            result = SSHRemoteCall.getInstance().execCommand("cd " + hardserver.getFilePath() + "\n"+command);
            log.info("---------execCommand2 = {}",result);
            //SSHRemoteCall.getInstance().closeSession();
            // 关闭登陆状态就行。把session释放了再创建会获取不到。
            SSHRemoteCall.getInstance().closeLogin();
        } catch (Exception e) {
            // 打印报错
            log.info("---------连接失败-----------sshRemoteCallLogin = {}",e.getMessage());
            throw new RuntimeException(e);
        }
    }
    return result;
}

3.2、上传下载文件

public static void main(String[] args) {
314         // 连接到指定的服务器
315         try {
316             // 1、首先远程连接ssh
317             SSHRemoteCall.getInstance().sshRemoteCallLogin(ipAddress, userName, password);
318             // 打印信息
319             System.out.println("0、连接192.168.110.130,ip地址: " + ipAddress + ",账号: " + userName + ",连接成功.....");
320 
321             // 2、执行相关的命令
322             // 查看目录信息
323             // String command = "ls /home/hadoop/package ";
324             // 查看文件信息
325             // String command = "cat /home/hadoop/package/test ";
326             // 查看磁盘空间大小
327             // String command = "df -lh ";
328             // 查看cpu的使用情况
329             // String command = "top -bn 1 -i -c ";
330             // 查看内存的使用情况
331             String command = "free ";
332             SSHRemoteCall.getInstance().execCommand(command);
333 
334             // 3、上传文件
335             String directory = "/home/hadoop/package/poi.xlsx";// 目标文件名
336             String uploadFile = "E:\\poi.xlsx";// 本地文件名
337             SSHRemoteCall.getInstance().uploadFile(directory, uploadFile);
338 
339             // 4、下载文件
340             // src 是linux服务器文件地址,dst 本地存放地址,采用默认的传输模式:OVERWRITE
341             //test为文件名称哈
342             String src = "/home/hadoop/package/test";
343             String dst = "E:\\";
344             SSHRemoteCall.getInstance().fileDownload(src, dst);
345 
346             // 5、刪除文件
347             String deleteDirectoryFile = "/home/hadoop/package/test";
348             SSHRemoteCall.getInstance().deleteFile(deleteDirectoryFile);
349 
350             // 6、展示目录下的文件信息
351             String lsDirectory = "/home/hadoop/package";
352             SSHRemoteCall.getInstance().listFiles(lsDirectory);
353 
354             // 7、关闭连接
355             SSHRemoteCall.getInstance().closeSession();
356         } catch (Exception e) {
357             // 打印错误信息
358             System.err.println("远程连接失败......");
359             e.printStackTrace();
360         }
361     }