java实现SSH协议连接linux

  • Post author:
  • Post category:java


初衷:

在每次部署项目的时候,每次都得打包,使用xshell连接linux服务器,每次在连接的时候都会很慢,还得杀死原先的进程id并删除之前的版本,很烦!!所以采用java代码的方式连接服务器实现自动上传换版本启动的过程。。


首先:

使用ssh协议的jar引进工程pom依赖:

        <dependency>
            <groupId>ch.ethz.ganymed</groupId>
            <artifactId>ganymed-ssh2</artifactId>
            <version>build210</version>
        </dependency>

可能本地中远程仓库中没有改依赖包,解决方法:首先去这个网站(

http://www.ganymed.ethz.ch/ssh2/

)去下载,然后呢把他添加到自己的本地仓库中,具体操作方法如下:

首先下载的是一个zip文件,解压文件,里面有一个jar包,然后把该jar包加入到本地仓库中:

mvn install:install-file -Dfile=D:\software\Maven\ganymed-ssh2-build210\ganymed-ssh2-build210.jar -DgroupId=ch.ethz.ganymed -DartifactId=ganymed-ssh2 -Dversion=build210 -Dpackaging=jar

然后在添加依赖就ojbk了。

下面就是代码实现:

代码实现:

1、实体类:

public class RemoteConnect {
    private String ip;
    private String userName;
    private String password;
//省略 set
get
|

2、业务代码:

import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.SCPClient;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;

public class RemoteSSH {

    private static final Logger logger = LoggerFactory.getLogger(RemoteSSH.class);
    private static String DEFAULTCHARTSET = "UTF-8";
    private static Connection conn;
    /**
     * 远程登录linux 服务器
     *
     * @param remoteConnect
     * @return
     */
    public static boolean login(RemoteConnect remoteConnect) {
        boolean flag = false;
        try {
            conn = new Connection(remoteConnect.getIp());
            conn.connect();//连接
            flag = conn.authenticateWithPassword(remoteConnect.getUserName(), remoteConnect.getPassword());
            if (flag) {
                logger.info("---认证成功-----");
            } else {
                logger.error("------认证失败-----");
                conn.close();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        return flag;
    }

    /**
     * @param remoteConnect
     * @param keyFile       一个文件对象指向一个文件,该文件包含OpenSSH密钥格式的用户的DSA或RSA私钥(PEM,不能丢失"
     *                      -----BEGIN DSA PRIVATE KEY-----" or "-----BEGIN RSA PRIVATE KEY-----"标签
     * @param keyfilePass   如果秘钥文件加密 需要用该参数解密,如果没有加密可以为null
     * @return Boolean
     * @throws
     * @Title: loginByKey
     * @Description: 秘钥方式  远程登录linux服务器
     */
    public static Boolean loginByFileKey(RemoteConnect remoteConnect, File keyFile, String keyfilePass) {
        boolean flag = false;
        // 输入密钥所在路径
        // File keyfile = new File("C:\\temp\\private");
        try {
            conn = new Connection(remoteConnect.getIp());
            conn.connect();
            // 登录认证
            flag = conn.authenticateWithPublicKey(remoteConnect.getUserName(), keyFile, keyfilePass);
            if (flag) {
                logger.info("认证成功!");
            } else {
                logger.info("认证失败!");
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * @param remoteConnect
     * @param keys          一个字符[],其中包含用户的DSA或RSA私钥(OpenSSH密匙格式,您不能丢失“
     *                      ----- begin DSA私钥-----”或“-----BEGIN RSA PRIVATE KEY-----“标签。char数组可以包含换行符/换行符。
     * @param keyPass       如果秘钥字符数组加密  需要用该字段解密  否则不需要可以为null
     * @return Boolean
     * @throws
     * @Title: loginByCharsKey
     * @Description: 秘钥方式  远程登录linux服务器
     */
    public static Boolean loginByCharsKey(RemoteConnect remoteConnect, char[] keys, String keyPass) {

        boolean flag = false;
        // 输入密钥所在路径
        // File keyfile = new File("C:\\temp\\private");
        try {
            conn = new Connection(remoteConnect.getIp());
            conn.connect();
            // 登录认证
            flag = conn.authenticateWithPublicKey(remoteConnect.getUserName(), keys, keyPass);
            if (flag) {
                logger.info("认证成功!");
            } else {
                logger.info("认证失败!");
                conn.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    public static String execute(String cmd) {
        String result = "";
        try {
            Session session = conn.openSession();// 打开一个会话
            session.execCommand(cmd);// 执行命令;
            result = processStdout(session.getStdout(), DEFAULTCHARTSET);
            // 如果为得到标准输出为空,说明脚本执行出错了 StringUtils.isBlank(result)
            if (result.equals("")) {
                result = processStdout(session.getStderr(), DEFAULTCHARTSET);
            }
//            conn.close();
//            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;

    }

    /**
     * @param in      输入流对象
     * @param charset 编码
     * @return String 以纯文本的格式返回
     * @throws
     * @Title: processStdout
     * @Description: 解析脚本执行的返回结果
     */
    public static String processStdout(InputStream in, String charset) {
        InputStream stdout = new StreamGobbler(in);
        StringBuffer buffer = new StringBuffer();
        try {
            BufferedReader br = new BufferedReader(new InputStreamReader(stdout, charset));
            String line = null;
            while ((line = br.readLine()) != null) {
                buffer.append(line + "\n");
            }
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return buffer.toString();
    }

    /**
     * @param cmd 脚本或者命令
     * @return String 命令执行成功后返回的结果值,如果命令执行失败,返回空字符串,不是null
     * @throws
     * @Title: executeSuccess
     * @Description: 远程执行shell脚本或者命令
     */
    public static String executeSuccess(String cmd) {
        String result = "";
        try {
            Session session = conn.openSession();// 打开一个会话
            session.execCommand(cmd);// 执行命令
            result = processStdout(session.getStdout(), DEFAULTCHARTSET);
            conn.close();
            session.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * @return String
     * @throws
     * @Title: ConnectLinux
     * @Description: 通过用户名和密码关联linux服务器
     */
    public static String connectLinux(String ip, String userName,
                                      String password, String commandStr) {

        logger.info("ConnectLinuxCommand  scpGet===" + "ip:" + ip + "  userName:" + userName + "  commandStr:"
                + commandStr);

        String returnStr = "";
//        boolean result = true;

        RemoteConnect remoteConnect = new RemoteConnect();
        remoteConnect.setIp(ip);
        remoteConnect.setUserName(userName);
        remoteConnect.setPassword(password);
        try {
            if (login(remoteConnect)) {
                returnStr = execute(commandStr);
                System.out.println(returnStr);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

//        if (returnStr != null && !returnStr.equals("")) {
//            result = false;
//        }
        return returnStr;
    }

    /**
     * @param ip         (其他服务器)
     * @param userName   用户名(其他服务器)
     * @param password   密码(其他服务器)
     * @param remoteFile 文件位置(其他服务器)
     * @param localDir   本服务器目录
     * @return void
     * @throws IOException
     * @throws
     * @Title: scpGet
     * @Description: 从其他服务器获取文件到本服务器指定目录
     */
    public static void scpGet(String ip, String userName,
                              String password, String remoteFile, String localDir)
            throws IOException {

        logger.info("ConnectLinuxCommand  scpGet===" + "ip:" + ip + "  userName:" + userName + "  remoteFile:"
                + remoteFile + "  localDir:" + localDir);
        RemoteConnect remoteConnect = new RemoteConnect();
        remoteConnect.setIp(ip);
        remoteConnect.setUserName(userName);
        remoteConnect.setPassword(password);

        if (login(remoteConnect)) {
            SCPClient client = new SCPClient(conn);
            client.get(remoteFile, localDir);
            conn.close();
        }
    }

    /**
     * @param ip
     * @param userName
     * @param password
     * @param localFile
     * @param remoteDir
     * @return void
     * @throws IOException
     * @throws
     * @Title: scpPut
     * @Description: 将文件复制到其他计算机中
     */
    public static void scpPut(String ip, String userName,
                              String password, String localFile, String remoteDir)
            throws IOException {
        logger.info("ConnectLinuxCommand  scpPut===" + "ip:" + ip + "  userName:" + userName + "  localFile:"
                + localFile + "  remoteDir:" + remoteDir);

        RemoteConnect remoteConnect = new RemoteConnect();
        remoteConnect.setIp(ip);
        remoteConnect.setUserName(userName);
        remoteConnect.setPassword(password);

        if (login(remoteConnect)) {
            //检测指定路径下的jar是否存在
            SCPClient client = new SCPClient(conn);
            client.put(localFile, remoteDir);
            System.out.println("aa");
            conn.close();
        }
    }

    //重新打包上传启动功能
    public static String allDeploy(String ip, String userName,
                                   String password) {
        RemoteConnect connect = new RemoteConnect(ip, userName, password);
        if (login(connect)) {
            String commandLine = "ps -ef|grep dailybuild-|grep -v grep|wc -l";
            String execute = execute(commandLine);
            if (execute.equals("1\n")) {
                String str = "ps -ef|grep dailybuild-|grep -v grep |awk '{print $2}' | xargs kill -9;";
                String result = execute(str);
//                String deleteStr = "cd /export;rm -rf dailybuild-0.0.1-SNAPSHOT.jar";
                String deleteStr = "find / -name dailybuild-0.0.1-SNAPSHOT.jar | xargs rm -rf ";
                execute(deleteStr);
                SCPClient client = new SCPClient(conn);
                try {
                    client.put("D:\\Project\\dailybuildV3_New\\target\\dailybuild-0.0.1-SNAPSHOT.jar", "/export");
                    logger.info("-----上传jar包成功----开始启动----");
                    execute("nohup java -jar /export/dailybuild-0.0.1-SNAPSHOT.jar > /export/dailybuild.log &");
                    String startLog = execute("tail -f /export/dailybuild.log");
                    if (startLog.contains("Started DailyBuildApplication"))
                        logger.info("-----完成启动----");
                    conn.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } else {
                String isExist = "find / -name dailybuild-0.0.1-SNAPSHOT.jar";
                String result = execute(isExist);
                if (result != "") execute("nohup java -jar " + result + ">/export/dailybuild.log &");
            }
        }
        return "完成";
    }

}

3、测试代码类:

public class RemoteTest {
    private static String ip = "10.85.153.27";
    private static String userName = "root";
    private static String password = "#TESTzdh27";

    public static void main(String[] args) throws IOException {
//        RemoteConnect connect = new RemoteConnect("10.85.153.27", "root", "#TESTzdh27");
//        boolean login = RemoteSSH.login(connect);
//        System.out.println(login);

//        String commandStr = "smtpnum = 'lsof -i:8091 | wc -l';print $smtpnum";
//        String result = RemoteSSH.connectLinux("10.85.153.27", "root", "#TESTzdh27", commandStr);
//        System.out.println(result);
        //下载
//        RemoteSSH.scpGet(ip, userName, password, "/home/shell/protect.sh", "D:\\java");
//        RemoteSSH.scpPut(ip,userName,password,"D:\\Project\\dailybuildV3_New\\target\\dailybuild-0.0.1-SNAPSHOT.jar","/home/shell");
        RemoteSSH.allDeploy(ip, userName, password);
    }
}

结论:测试没得问题,这种方法呢其实跟我们用xshell直接去连接服务器是一样的,只不过速度相对快一点,java中代码也是跟在客户端敲的代码是一样的,初步目标实现了。



版权声明:本文为geng2568原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。