java方法实现远程登录Linux系统并执行相关命令

项目环境说明

1.本地环境:Windows10、jdk1.8、Maven 3.6.0
2.远程环境:CentOS7
3.开发工具:IntelliJ IDEA

远程系统的准备工作的

确保系统能Ping的通外网。

利用了SSH2技术来实现远程登录Linux系统,并执行的相关后续的Linux命令

相关 Maven的jar包如下:

        <dependency>
            <groupId>ch.ethz.ganymed</groupId>
            <artifactId>ganymed-ssh2</artifactId>
            <version>build210</version>
        </dependency>
         <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.4</version>
        </dependency>

具体实现方法如下几步:

  • 方法中的全部变量:
   private static String DEFAULTCHART = "UTF-8";
   private String ip;//远程登录的ip
   private Connection conn;
   private String userName;//远程系统上的用户名
   private String userPwd;//密码
  • 登录方法
   /**
    * 远程登录linux主机
    *
    * @return 登录成功返回true,否则返回false
    * @throws Exception
    * @since V0.1
    */
   public Boolean login() throws Exception {
       boolean flg = false;
       try {
           conn = new Connection(ip, 22);//22是默认端口号,如端口号改变的可以在这里更改
           // 连接
           conn.connect();
           // 认证
           flg = conn.authenticateWithPassword(userName, userPwd);
       } catch (IOException e) {
           throw new Exception("远程连接服务器失败", e);
       }
       return flg;
   }
  • 远程执行shll脚本或者命令
    /**
     * 远程执行shll脚本或者命令
     *
     * @param cmd 即将执行的命令
     * @return 命令执行完后返回的结果值
     * @throws Exception
     * @since V0.1
     */
    public String execute(String cmd) throws Exception {
        String result = "";
        Session session = null;
        try {
            if (login()) {
                // 打开一个会话
                session = conn.openSession();
                // 执行命令
                session.execCommand(cmd);
                // processStdout(会话后续结果信息,编码状态);  自定义解析方法
                result = processStdout(session.getStdout(), DEFAULTCHART);
                // 如果为输出为空,说明脚本执行出错了
                if (StringUtils.isBlank(result)) {
                    result = processStdout(session.getStderr(), DEFAULTCHART);
                }
                session.close();
            }
        } catch (IOException e) {
            throw new Exception("命令执行失败", e);
        } finally {
            if (session != null) {
                session.close();
            }
        }
        return result;
    }
  • 解析脚本或命令执行返回的结果集
    /**
     * 解析脚本执行返回的结果集
     *
     * @param in      输入流对象
     * @param charset 编码
     * @return 以纯文本的格式返回
     * @throws Exception
     * @since V0.1
     */
    private String processStdout(InputStream in, String charset) throws Exception {
    //  InputStream 字节输入流
    //StreamGobbler的作用是把session的标准输出包装成InputStream
        InputStream stdout = new StreamGobbler(in);
        StringBuffer buffer = new StringBuffer();
        // InputStreamReader  处理字符流的抽象类
        InputStreamReader isr = null; 
        BufferedReader br = null;
        try {
            isr = new InputStreamReader(stdout, charset);//设置信息的编码格式
            br = new BufferedReader(isr);
            String line = null;
            //BufferedReader的readLine()方法是阻塞式的, 如果到达流末尾, 就返回null, 
            while ((line = br.readLine()) != null) {
                buffer.append(line + "\n");
            }
        } catch (UnsupportedEncodingException e) {
            throw new Exception("不支持的编码字符集异常", e);
        } catch (IOException e) {
            throw new Exception("读取指令失败", e);
        } finally {
            br.close();
            isr.close();
            stdout.close();
        }
        return buffer.toString();
    }
  • 退出登录
/**
     * 方法说明:  退出登录
     * @date: 2019/8/21 14:51
     */
    @Override
    public void close() {
        if (conn != null) {
            conn.close();
        }
    }
  • 上传文件
    /**
     * 上传文件
     * 登录的用户权限不足会出错,将文件夹传给文件时会出错
     *
     * @param remoteFilePath 远程的文件地址
     * @param localFilePath  本地的文件地址
     * @return
     */
    public boolean sftpDownload(String remoteFilePath, String localFilePath) throws Exception {
        File file = new File(localFilePath);
        boolean flag = false;
        SCPClient scp = null;
        //执行Linux命令查看系统中的Linux文件是否存在
        if (!execute("find " + remoteFilePath).equals(remoteFilePath + "\n")) {
            execute("cd /;mkdir " + remoteFilePath);//上传时远程的文件地址不存在就创建
        }
        //上传时本地的文件地址存在执行上传操作
        if (file.exists()) {
            try {
                if (login()) {
                    scp = conn.createSCPClient();
                    //将本地文件上传
                    scp.put(localFilePath, remoteFilePath);
                    flag = true;
                }
            } catch (IOException e) {
                flag = false;
                throw new Exception("文件地址错误!", e);
            } finally {
                if (conn != null) {
                    conn.close();
                }
            }
        }
        return flag;
    }
  • 下载文件
   /**
    * 下载文件
    * 登录的用户权限不足会出错,将文件夹传给文件时会出错
    *
    * @param remoteFilePath 远程文件地址
    * @param localFilePath  本地文件地址
    * @return
    */
   public boolean uoloadFile(String remoteFilePath, String localFilePath) throws Exception {
       File file = new File(localFilePath);
       boolean flag = false;
       SCPClient scp = null;
       //判断本地中的地址是否存在
       if (!file.exists() && !file.isDirectory()) {
           file.mkdir();//下载时如果本地文件地址不存在,就创建
       }
       //如果远程文件地址存在刚执行文件传输
       if (execute("find " + remoteFilePath).equals(remoteFilePath + "\n")) {
           log.debug("远程文件地址:  " + execute("find " + remoteFilePath));
           try {
               if (login()) {
                   scp = conn.createSCPClient();
                   scp.get(remoteFilePath, localFilePath);
                   flag = true;
               }
           } catch (IOException e) {
               flag = false;
               throw new Exception("文件地址错误!", e);
           } finally {
               if (conn != null) {
                   conn.close();
               }
           }
       }
       return flag;
   }
  • 安装jdk
    /**
     * 安装jdk
     * @param localFilePath  本地的jdk路径
     * @param remoteFilePath 远程jdk地址
     * @return 
     */
	public boolean installationJDK(String remoteFilePath, String localFilePath) throws Exception {
        boolean flag ;
        File file = new File(localFilePath);
        String name = file.getName();//获取上传jdk压缩包的名字,方便解压操作
        String absolutePath = file.getParent();//获取的本地jdk压缩包的路径
        //将文件上传
        flag = sftpDownload(remoteFilePath, localFilePath);
        if (flag) {
        //上传成功后,将文件解压并删除jdk压缩包;多条命令执行以  ;  隔开
            execute("cd " + remoteFilePath + ";tar -zxvf " + name + ";rm -rf " + name);
            //jdkName存放Linux系统下的jdk的绝对地址
            String jdkName = execute("find " + remoteFilePath + " -maxdepth 1 -name \"jdk*\"");
            //jdkName是返回字符串后面会带\n 
            jdkName = jdkName.replaceAll("\n", "");
            flag = uoloadFile("/etc/profile", absolutePath);
            //如果上传成功
            if (flag) {
            //将下载下来配置文件地址给absolutePath 
                absolutePath = absolutePath + "\\profile";
                List<String> fileContent = new ArrayList<>();
                fileContent.add("export JAVA_HOME=" + jdkName);
                fileContent.add("\nexport JRE_HOME=${JAVA_HOME}/jre");
                fileContent.add("\nexport CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib");
                fileContent.add("\nexport PATH=${JAVA_HOME}/bin:$PATH");
                //writeFile为自定义方法
                flag = writeFile(absolutePath, fileContent);
                if (flag) {
                    flag = sftpDownload("/etc/", absolutePath);
                    if (flag) {
                        //设置将jdk设置为系统默认
                        execute("rm -rf /usr/bin/java;rm -rf /usr/bin/javac;rm -rf /etc/alternatives");
                        execute("cd /usr/bin;ln -sf "+jdkName+"/bin/java /usr/bin/java");
                        execute("ln -sf "+jdkName+"/bin/java  /usr/bin/javac");
                        execute("source /etc/profile");
                        if(!execute("java -version").contains("java version")){
                            flag=false;
                        }
                    }
                }
            }
        }
        return flag;
    }
  • 写入文件
    /**
     * 写入文件
     * @param localFilePath 本地文件地址
     * @param fileContent   写入文件的内容
     * @return
     */
    public boolean writeFile(String localFilePath, List<String> fileContent) throws IOException {
        File file = new File(localFilePath);
        //如果本地文件不存在将不执行
        if (!file.exists()) {
            return false;
        }
        OutputStream fileOut = null;
        PrintWriter pw = null;
        try {
            fileOut = new FileOutputStream(localFilePath, true);//true是对文件进行追加
            pw = new PrintWriter(fileOut);
            for (String conten : fileContent) {
                pw.print(conten);
            }
            pw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            pw.close();
            fileOut.close();
        }
        return true;
    }

直接使用java方法执行Linux查看jdk版本号命令出错误,Linux的默认Jdk执行地址的问题,所以要修改默认的执行路径

注意事项和流程

在一次会话结束后必须有关闭,多次未关闭会报通道异常;正确执行流程如下:调用longin方法进行登录,执行相关的方法,退出时调用close方法。
如图所示:
在这里插入图片描述

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值