java 整合jsch使用 远程交互服务器

java 整合jsch使用 远程交互服务器

java 通过jsch 远程执行命令 jsch 主要是类似Xshell 只不过是代码级别使用
而 Xshell使用界面化

jsch可以执行任何shell 脚本 但是弊端是执行一次必须要关闭当前会话 每次都要cd当前目录
在执行相关命令 都是操作 channle 同时写了一个cmd执行方法为的是执行linux命令
execCommandByJSch (…) 这个方法是比较重要的 session就是维护你当前会话和服务器进行交流的

channle相当于管道流 数据交互用的

依赖

  <!-- sftp的依赖-->
        <dependency>
            <groupId>com.jcraft</groupId>
            <artifactId>jsch</artifactId>
            <version>0.1.55</version>
        </dependency>

这里是以前某个项目的一部分代码

package com.ubix.infinite.business.maintain.util;


import com.alibaba.fastjson.JSON;
import com.jcraft.jsch.*;

import com.ubix.infinite.business.maintain.constants.MaintainConstants;
import com.ubix.infinite.business.maintain.pojo.MaiFtpServer;
import com.ubix.infinite.business.maintain.pojo.MaiServerAndPath;
import com.ubix.infinite.business.maintain.pojo.MaiServerSoftware;
import com.ubix.infinite.business.maintain.task.recoder.SoftwareDbUtils;
import com.ubix.infinite.common.core.contexts.SecurityContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.*;
import java.util.*;

@Slf4j
public class Ftp {

    private static final String ENCODE_UTF_8 = "UTF-8";
    private Date lastPushDate = null;
    private static final String HISTORY_FOLDER = "history_server";

    private Session sshSession;

    private ChannelSftp channel;


    public Ftp(String host, int port, String username, String password) throws Exception {
        connection(host, port, username, password);
    }


    public Ftp(MaiFtpServer maiFtpServer) throws Exception {
        String username = maiFtpServer.getUsername();
        String password = maiFtpServer.getPassword();
        String host = maiFtpServer.getHost();
        int port = maiFtpServer.getPort();
        connection(host, port, username, password);
    }

    /**
     * 链接服务器
     * @param host
     * @param port
     * @param username
     * @param password
     * @throws Exception
     */
    public void connection(String host, int port, String username, String password) throws Exception {
        JSch jsch = new JSch();
        jsch.getSession(username, host, port);
        //根据用户名,密码,端口号获取session
        sshSession = jsch.getSession(username, host, port);
        sshSession.setPassword(password);
        //修改服务器/etc/ssh/sshd_config 中 GSSAPIAuthentication的值yes为no,解决用户不能远程登录
        sshSession.setConfig("userauth.gssapi-with-mic", "no");

        //为session对象设置properties,第一次访问服务器时不用输入yes
        sshSession.setConfig("StrictHostKeyChecking", "no");
        sshSession.connect();
        //获取sftp通道
        channel = (ChannelSftp) sshSession.openChannel("sftp");
        channel.connect();
        log.info("连接ftp成功!");
    }


    /**
     * 关闭通道
     */
    public void closeChannel() {
        if (null != channel) {
            try {
                channel.disconnect();
            } catch (Exception e) {
                log.error("关闭SFTP通道发生异常:", e);
            }
        }
        if (null != sshSession) {
            try {
                sshSession.disconnect();
            } catch (Exception e) {
                log.error("SFTP关闭 session异常:", e);
            }
        }
    }

    /**
     * @param directory  上传ftp的目录
     * @param uploadFile 本地文件目录
     * @param isDel      是否删除原文件
     */
    public Hashtable<String, Object> upload(String directory, String uploadFile, boolean isDel, MaiFtpServer maiFtpServer) {
        Hashtable<String, Object> collectionResult = new Hashtable<>();

        try {
            cdDirectory(directory);
            collectionResult = toUpload(directory, uploadFile, isDel, maiFtpServer);
        } catch (Exception e) {
            log.info("上传失败");

        }

        return collectionResult;

    }

    /**
     * 根据当前路径获取目录文件
     * @param directory
     * @return
     */
    public String getSonDirectory(String directory) {

        String dir = directory.substring(0, directory.lastIndexOf("/") + 1);

        try {
            channel.cd(dir);
        } catch (SftpException e) {
          log.error(e.getMessage());
        }

        return "true";
    }


    /**
     * 获取文件夹下的文件
     *
     * @param directory 路径
     */
    public Vector<?> listFiles(String directory) {
        try {
            if (isDirExist(directory)) {
                Vector<?> vector = channel.ls(directory);
                //移除上级目录和根目录:"." ".."
                vector.remove(0);
                vector.remove(0);
                return vector;
            }
        } catch (SftpException e) {
            log.error("获取文件夹信息异常!", e);
        }
        return null;
    }


    /**
     * 判断目录是否存在
     *
     * @param directory 路径
     */
    public boolean isDirExist(String directory) {
        boolean isDirExistFlag = false;
        try {
            SftpATTRS sftpATTRS = channel.lstat(directory);
            isDirExistFlag = true;
            return sftpATTRS.isDir();
        } catch (Exception e) {
            if ("no such file".equals(e.getMessage())) {
                isDirExistFlag = false;
            }
        }
        return isDirExistFlag;
    }

    /**
     * 进入该路径
     * @param directory
     * @throws SftpException
     */
    public void cdDirectory(String directory) throws SftpException {

        String[] directories = directory.split("/");

        for (int i = 0; i < directories.length; i++) {
            String d = directories[i];
            if (StringUtils.isBlank(d)) {
                continue;
            }

            try {
                if (i == 1) {
                    channel.cd("/" + d);
                    continue;
                }

                channel.cd(d);

            } catch (Exception e) {

                channel.mkdir(d);
                channel.cd(d);
            }
        }

    }

    /**
     * 遍历该路径的shell脚本并启动或停止
     * @param directory
     * @param maiFtpServer
     * @param operator
     * @return
     */
    public Hashtable<String, Object> queryShAndOperator(String directory, MaiFtpServer maiFtpServer, String operator) {
        Hashtable<String, Object> hashtable = new Hashtable<>();
        Vector ls = null;
        try {
            ls = channel.ls(directory);

        } catch (SftpException e) {
            log.error(e.getMessage());
        }
        Iterator iterator = ls.iterator();

        String result = "空";
        while (iterator.hasNext()) {
            ChannelSftp.LsEntry next = (ChannelSftp.LsEntry) iterator.next();
            String filename = next.getFilename();

            if (filename.contains(".sh")) {

                hashtable = startUpSh(directory, filename, maiFtpServer, operator, "");

                log.info(" the {} ,the result: {}", filename, result);

            }

        }

        return hashtable;
    }

    /**
     * 上传文件,解压,遍历并且启动
     * @param directory
     * @param uploadFile
     * @param isDel
     * @param maiFtpServer
     * @return
     */
    public Hashtable<String, Object> toUpload(String directory, String uploadFile, boolean isDel, MaiFtpServer maiFtpServer) {
        Set<String> fileNames = new HashSet<>();
        Hashtable<String, Object> resultHashTable = new Hashtable<>();

        //上传文件
        try {
            List<File> files = getFiles(uploadFile, new ArrayList<>());
            for (int i = 0; i < files.size(); i++) {
                File file = files.get(i);
                InputStream input = new BufferedInputStream(new FileInputStream(file));
                channel.put(input, file.getName());
                fileNames.add(file.getName());
                try {
                        input.close();

                } catch (Exception e) {
                    log.error(e.getMessage());
                    log.error("{} close the file is error {}", file.getName(), e.getMessage());
                }
                if (file.exists() && isDel) {
                    boolean b = file.delete();
                    log.info("{} the file is upload success! {}", file.getName(), b);
                }
            }

            for (File file : files) {
                String fileName = file.getName();

                //zip解压
                if (fileName.contains(".zip")) {
                    cdAndExecCmd(directory, fileName, "unzip " + fileName);
                }

                if (!fileName.contains(".sh")) {
                    continue;
                }

                log.info("尝试启动 {} 脚本", fileName);

                // 如果上传文件集合里面包含.sh为后缀的文件  尝试启动它
                Hashtable<String, Object> hashtable = startUpSh(directory, fileName, maiFtpServer, "start", uploadFile);
                resultHashTable.put(hashtable.get(MaintainConstants.FILE_NAME).toString(), hashtable.get(MaintainConstants.LOG).toString());

            }

            if (directory.contains("gcc")||directory.contains("redis")||directory.contains("mysql")||directory.contains("nacos")){
                return resultHashTable;
            }
            //获取解压后的所有启动文件以及所在路径
            Set<String> unZipSonDirectorySet = lsDirectory(directory);
            Map<String, String> startUpMap = cdUnKnownDirectory(unZipSonDirectorySet, directory);

            //启动这些服务
            Hashtable<String, Object> hashtable = startServerMap(startUpMap, maiFtpServer);
            if (StringUtils.isNotBlank(maiFtpServer.getHost())){
                hashtable.put(MaintainConstants.HOST, maiFtpServer.getHost());
            }
            resultHashTable.putAll(hashtable);


        } catch (Exception e) {

            log.info("upload the files is error!!", e);
        }

        return resultHashTable;
    }

    /**
     *  遍历map集合的文件并且启动
     * @param startUpMap
     * @param maiFtpServer
     * @return
     */
    private Hashtable<String, Object> startServerMap(Map<String, String> startUpMap, MaiFtpServer maiFtpServer) {

        Hashtable<String, Object> hashtable = new Hashtable<>();
        Hashtable<String, Object> h;

        if (startUpMap.isEmpty()) {
            return null;
        }

        for (String s : startUpMap.keySet()) {
            try {

                h = startUpServer(s, maiFtpServer);
                hashtable.putAll(h);

            } catch (IOException e) {
                log.error("start the {} is error!!", startUpMap.get(s));
            }
        }
        return hashtable;
    }

    /**
     * 查找当前路径下所有.sh的文件以及所在路径
     *
     * @param directorySet
     * @param basePath
     */
    Map<String, String> cdUnKnownDirectory(Set<String> directorySet, String basePath) {

        Map<String, String> map = new HashMap<>();
        for (String directory : directorySet) {
            String path = basePath + directory + "/";
            try {

                channel.cd(path);
            } catch (SftpException e) {
                log.error("{} is not directory!! ", directory);
                if (directory.contains(".sh")) {
                    log.info("try start up the {}", directory);
                    map.put(basePath, directory);
                    continue;
                }

            }

            //历史版本不启动
            if (directory.contains(HISTORY_FOLDER)) {
                continue;
            }

            Set<String> set = lsDirectory(path);
            if (CollectionUtils.isEmpty(set)) {
                continue;
            }
            map.putAll(cdUnKnownDirectory(set, path));

        }

        return map;
    }


    /**
     * 列出本目录所有的文件和子目录
     *
     * @param directory
     * @return Set<String>
     */
    public Set<String> lsDirectory(String directory) {

        Set<String> set = new HashSet<>();

        Vector ls = null;
        try {
            ls = channel.ls(directory);
        } catch (SftpException e) {
            log.error("the {} is not directory!!", directory);
        }

        if (ls == null) {
            return null;
        }


        Iterator iterator = ls.iterator();

        while (iterator.hasNext()) {
            ChannelSftp.LsEntry next = (ChannelSftp.LsEntry) iterator.next();
            String filename = next.getFilename();

            if (filename.startsWith(".")) {
                continue;
            }
            set.add(filename);

        }

        return set;
    }

    /**
     * 对某个文件执行命令
     * @param directory
     * @param fileName
     * @param cmd
     * @return
     *
     */
    public String cdAndExecCmd(String directory, String fileName, String cmd) {

        String tryStartUpShCmd = "cd " + directory + " && " + cmd;
        String execute = execCommandByJSch(tryStartUpShCmd);
        log.info("startup " + fileName + " result:" + execute);

        return execute;
    }

    /**
     * 运行shell脚本
     * @param directory
     * @param fileName
     * @param maiFtpServer
     * @param operator
     * @param uploadFile
     * @return
     */
    public Hashtable<String, Object> startUpSh(String directory, String fileName, MaiFtpServer maiFtpServer, String operator, String uploadFile) {

        Hashtable<String, Object> hashtable = new Hashtable<>();
        String tryStartUpShCmd = "cd " + directory + "&& sed -i 's/\\r//' " + fileName;
        execCommandByJSch(tryStartUpShCmd);
        String execute ;

        String tryStartUpShCmd2 = "cd " + directory + " && sh " + fileName + " " + operator;
        execute = execCommandByJSch(tryStartUpShCmd2);

        MaiServerSoftware maiServerSoftware = new MaiServerSoftware();
        maiServerSoftware.setIp(maiFtpServer.getHost());
        maiServerSoftware.setTargetPath(directory);
        maiServerSoftware.setCreateBy(SecurityContext.getUsername());
        maiServerSoftware.setOperate(operator);
        execute = execute.replaceAll("\r\n|\n", "");

        if (execute.length() < 70) {
            maiServerSoftware.setLog(execute);
        } else {
            maiServerSoftware.setLog(execute.substring(0, 50));
        }
        log.info(" the result:" + execute);
        maiServerSoftware.setServerId(maiFtpServer.getHost());
        maiServerSoftware.setServiceName(fileName);
        maiServerSoftware.setSrcPath(uploadFile);

        if (execute.contains(MaintainConstants.SUCCESS)) {
            maiServerSoftware.setStatus(true);
        }

        SoftwareDbUtils ftpOperate = new SoftwareDbUtils();
        //保存操作记录
        if (ftpOperate.save(maiServerSoftware)) {
            log.info("save the {} is success!!", JSON.toJSON(maiServerSoftware));
        } else {
            log.error("save the {} is error!!", JSON.toJSON(maiServerSoftware));
        }

        log.info("startup " + fileName + " result:" + execute);

        hashtable.put(MaintainConstants.FILE_NAME, maiServerSoftware.getServiceName());
        hashtable.put(MaintainConstants.LOG, execute);
        return hashtable;
    }


    /**
     * 获取本地某路径下文件
     * @param realpath
     * @param files
     * @return
     */
    public List<File> getFiles(String realpath, List<File> files) {
        File realFile = new File(realpath);
        if (realFile.isDirectory()) {
            File[] subfields = realFile.listFiles(new FileFilter() {
                @Override
                public boolean accept(File file) {
                    if (null == lastPushDate) {
                        return true;
                    } else {
                        long modifyDate = file.lastModified();
                        return modifyDate > lastPushDate.getTime();
                    }
                }
            });

            if (subfields.length==0){
                return files;
            }

            for (File file : subfields) {
                if (file.isDirectory()) {
                    getFiles(file.getAbsolutePath(), files);
                } else {
                    files.add(file);
                }

            }
        } else {
            files.add(realFile);
        }
        return files;
    }

    /**
     * 查询该路径下的shell并开启服务
     * @param directory
     * @param maiFtpServer
     * @return
     */
    public Hashtable<String, Object> startUpServerToFtp(String directory, MaiFtpServer maiFtpServer) {

        Hashtable<String, Object> startServerResult = new Hashtable<>();
        //先停止服务
        try {
            startServerResult = startUpServer(directory, maiFtpServer);
        } catch (IOException e) {
            log.error(e.getMessage());
        }

        return startServerResult;
    }


    /**
     * 查找历史文件
     * @param directory
     */
    public void mkdirHistory(String directory) {

        // 查找历史文件名  查找出来进行备份
        String getFilesCmd = "cd " + directory + "; mkdir history_server";
        execCommandByJSch(getFilesCmd);

    }

    /**
     * 移动文件
     * @param directory
     * @param targetPath
     * @param fileNamePrefix
     */
    public void mv(String directory, String targetPath, String fileNamePrefix) {
        if (!StringUtils.isBlank(fileNamePrefix)) {
            fileNamePrefix = "./" + fileNamePrefix + "*";
        } else {
            fileNamePrefix = "*";
        }
        // 查找历史文件名  查找出来进行备份
        String getFilesCmd = "cd " + directory + "&& mv  " + fileNamePrefix + " " + targetPath;
        execCommandByJSch(getFilesCmd);

    }

    /**
     * 删除文件
     */
    public void deleteFile(String directory) {

        String tryStartUpShCmd2 = "rm -rf  " + directory;
        execCommandByJSch(tryStartUpShCmd2);
    }

    /**
     * 移动文件到历史文件夹里面
     * @param maiServerAndPath
     */
    public void moveFileToHistory(MaiServerAndPath maiServerAndPath)  {

        String directory = maiServerAndPath.getDirectory();

        mkdirHistory(directory);

        mv(directory, HISTORY_FOLDER, null);

    }

    /**
     * exec 执行ssh命令
     * @param command
     * @return
     */
    public String execCommandByJSch(String command) {

        //1.默认方式,执行单句命令
        InputStream in;
        String result = null;
        try {
            ChannelExec channelExec = (ChannelExec) sshSession.openChannel("exec");
            in = channelExec.getInputStream();
            channelExec.setCommand(command);
            channelExec.setErrStream(System.err);
            channelExec.connect();
            result = IOUtils.toString(in, ENCODE_UTF_8);

            channelExec.disconnect();

        } catch (Exception e) {
            log.error(e.getMessage());
        }

        return result;

    }

    /**
     * 启动服务
     * @param directory
     * @param maiFtpServer
     * @return
     * @throws IOException
     */
    private Hashtable<String, Object> startUpServer(String directory, MaiFtpServer maiFtpServer) throws IOException {

        return queryShAndOperator(directory, maiFtpServer, "start");

    }


    /**
     * 停止服务
     * @param maiServerAndPath
     * @return
     */
    public Hashtable<String, Object> stopServer(MaiServerAndPath maiServerAndPath) {

        Hashtable<String, Object> executeResult = queryShAndOperator(maiServerAndPath.getDirectory(), maiServerAndPath.getMaiFtpServer(), "stop");

        return executeResult;

    }

    /**
     * 移动history_server某个文件到当前
     * @param directory
     * @param fileName
     */
    public void mvToCurrent(String directory, String fileName) {
        mv(directory, HISTORY_FOLDER, null);
        mv(directory + "/" + HISTORY_FOLDER, "../", fileName);

    }


}


posted @ 2022-01-20 16:00  怀念脱发的日子  阅读(2152)  评论(0)    收藏  举报