<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      SpringBoot使用JSch操作Linux

      • 推薦使用Hutool的Jsch工具包(它用的連接池的技術)

      一、SSH遠程連接服務器

      1、SSH(Secure Shell)主要有兩大功能

      1、遠程命令執行:SSH允許用戶在遠程主機上執行命令。用戶可以通過SSH連接到遠程主機,然后在命令行界面輸入命令,就像直接在遠程主機的控制臺上操作一樣。這是SSH最常用的功能,它使得用戶可以方便地管理和維護遠程主機。

      2、安全的文件傳輸:SSH提供了SFTP(SSH File Transfer Protocol)和SCP(Secure Copy)兩種文件傳輸協議,用于在本地主機和遠程主機之間安全地傳輸文件。這兩種協議都使用SSH的安全機制,可以保護文件在傳輸過程中的安全性和完整性。

      3、除了這兩大功能,SSH還有一些其他的功能,例如端口轉發和動態端口轉發(也稱為SOCKS代理),它們可以用來建立安全的網絡連接,或者繞過網絡限制。

      二、JNA、Process和JSch

      • JNA

      JNA主要用于在Java程序中調用本地庫的函數,而不是用于遠程連接到其他系統。如果你的Java程序正在Linux系統上運行,你可以使用JNA來調用Linux的本地庫函數,包括那些可以獲取文件和文件夾路徑的函數。然而,如果你的Java程序正在一個系統(如Windows)上運行,你不能使用JNA來連接到另一個系統(如Linux)。

      • JSch

      如果你需要從一個運行在Windows上的Java程序連接到一個Linux系統,你可能需要使用其他的工具或庫。例如,你可以使用SSH(安全殼層)來遠程連接到Linux系統,然后執行命令來獲取文件和文件夾的路徑。在Java中,有一些庫可以幫助你使用SSH,如JSch和Apache MINA SSHD。

      簡單理解JNA、Process和JSch

      • JNA(Java Native Access)和Process類都是Java中與本地系統交互的工具。JNA允許Java代碼直接調用本地(C/C++)庫的函數,而Process類則允許Java代碼啟動和控制操作系統的進程,例如執行shell命令。(JNA和Process是Java調用系統(Windows、Linux等)的本地函數,或者三方程序)

      • JSch是一個Java庫,它提供了SSH(Secure Shell)的Java實現,允許Java程序通過SSH協議連接到遠程系統(如Linux)。一旦連接成功,你可以通過JSch執行遠程命令,上傳和下載文件,就像直接在遠程系統上操作一樣。(JSch則是Java連接系統(Windows、Linux等)的工具,比如連接上Linux后,相當于直接操作Linux一樣)

      三、Java使用SSH的包

      3.1、JSch和Apache MINA SSHD


      JSch和Apache MINA SSHD都是優秀的SSH庫,它們各有優點,選擇哪一個主要取決于你的具體需求。

      JSch是一個成熟且廣泛使用的庫,它提供了SSH2的完整實現,包括SFTP,SCP,端口轉發等功能。JSch的API相對簡單,易于使用,而且JSch的社區活躍,有大量的教程和示例代碼可供參考。

      Apache MINA SSHD則是一個更現代的庫,它基于Apache MINA,一個高性能的網絡應用框架。MINA SSHD提供了SSH2的完整實現,包括SFTP,SCP,端口轉發等功能。MINA SSHD的API設計更現代,更符合Java的編程習慣,而且MINA SSHD支持異步非阻塞IO,對于需要處理大量并發連接的應用來說,可能會有更好的性能。

      總的來說,如果你需要一個簡單易用,社區支持好的SSH庫,JSch可能是一個不錯的選擇。如果你需要一個設計現代,支持異步非阻塞IO的SSH庫,或者你已經在使用Apache MINA,那么MINA SSHD可能更適合你。


      3.2、JSch的四種認證機制:

      1. 密碼(本文使用:這是最常見的身份驗證方式,用戶需要提供用戶名和密碼來進行身份驗證。

      2. 公鑰:在這種方式中,用戶需要提供一個私鑰,JSch會使用這個私鑰來進行身份驗證。這種方式通常比基于密碼的身份驗證更安全,因為私鑰通常比密碼更難被猜測或者破解。

      3. 鍵盤交互:這種方式允許服務器發送一個或多個提問給客戶端,客戶端需要回答這些問題來進行身份驗證。這種方式可以用來實現一些復雜的身份驗證流程,例如一次性密碼,或者多因素身份驗證。

      4. GSSAPI:GSSAPI是一種用于安全通信的API,它支持各種不同的身份驗證機制,例如Kerberos。JSch可以使用GSSAPI來進行身份驗證,但這需要額外的庫支持。

      四、JSch實現登錄Linux,遠程命令執行、SFTP下載和上傳文件

      4.1、導包Jsch

      • 官方的包上次更新18年(本文使用)
          // jsch包
          implementation 'com.jcraft:jsch:0.1.55'
      

      image

      4.2、Jsch工具類

      package com.cc.jschdemo.utils;
      
      import com.jcraft.jsch.*;
      import lombok.Data;
      import org.apache.commons.lang3.StringUtils;
      import org.springframework.http.HttpHeaders;
      import org.springframework.stereotype.Component;
      
      import javax.annotation.PreDestroy;
      import javax.servlet.ServletOutputStream;
      import javax.servlet.http.HttpServletResponse;
      import java.io.*;
      import java.net.URLEncoder;
      import java.nio.charset.StandardCharsets;
      import java.util.*;
      
      /**
       * <p>JSch工具類</p>
       * <li>交給spring管理:每個使用的地方都是單例,都是單獨的這個類。(new 也可以)</li>
       *
       * <li>所有方法都沒有關閉(連接、會話),需要使用方自己關閉</li>
       *
       * @author CC
       * @since 2023/11/8
       */
      @Data
      @Component
      public class JSchUtil {
      
          //緩存session會話
          private Session session;
      
          //通道:執行命令
          private ChannelExec channelExec;
          //通道:SFTP
          private ChannelSftp channelSftp;
          //通道:執行復雜Shell命令
          private ChannelShell channelShell;
      
      
          //登陸Linux服務器
          public void loginLinux(String username, String password, String host, Integer port) {
              try {
                  //每次都會重新初始化session
                  if (Objects.isNull(session) || !session.isConnected()) {
                      JSch jsch = new JSch();
                      session = jsch.getSession(username, host, port);
                      session.setPassword(password);
      
                      // 配置Session參數
                      Properties config = new Properties();
                      // 不進行公鑰的檢查
                      config.put("StrictHostKeyChecking", "no");
                      session.setConfig(config);
                      // 設置連接超時時間(s/秒)
                      session.setTimeout(300);
                  }
                  if (!session.isConnected()) {
                      // 連接到遠程服務器
                      session.connect();
                  }
              }catch(Exception e){
                  throw new RuntimeException("連接Linux失敗:" + e.getMessage());
              }
          }
      
          //執行命令:可以多次執行,然后必須調用關閉接口
          public String executeCommand(String command) {
              StringBuilder result = new StringBuilder();
              BufferedReader buf = null;
              try {
                  //每次執行都創建新的通道
                  channelExec = (ChannelExec) session.openChannel("exec");
                  channelExec.setCommand(command);
      
                  //正確的流中沒有數據就走錯誤流中去拿。
                  InputStream in = channelExec.getInputStream();
                  InputStream errStream = channelExec.getErrStream();
                  channelExec.connect();
      
                  buf = new BufferedReader(new InputStreamReader(in));
                  String msg;
                  while ((msg = buf.readLine()) != null) {
                      result.append(msg);
                  }
      
                  if (StringUtils.isBlank(result.toString())) {
                      buf = new BufferedReader(new InputStreamReader(errStream));
                      String msgErr;
                      while ((msgErr = buf.readLine()) != null) {
                          result.append(msgErr);
                      }
                  }
              }catch(Exception e){
                  throw new RuntimeException("關閉連接失敗(執行命令):" + e.getMessage());
              }finally {
                  if (Objects.nonNull(buf)) {
                      try {
                          buf.close();
                      }catch(Exception e){
                          e.printStackTrace();
                      }
                  }
              }
              return result.toString();
          }
      
          /**
           * 執行復雜shell命令
           *
           * @param cmds 多條命令
           * @return 執行結果
           * @throws Exception 連接異常
           */
          public String execCmdByShell(List<String> cmds) {
      
              String result = "";
              try {
                  channelShell = (ChannelShell) session.openChannel("shell");
      
                  InputStream inputStream = channelShell.getInputStream();
                  channelShell.setPty(true);
                  channelShell.connect();
                  OutputStream outputStream = channelShell.getOutputStream();
                  PrintWriter printWriter = new PrintWriter(outputStream);
                  for (String cmd : cmds) {
                      printWriter.println(cmd);
                  }
                  printWriter.flush();
                  byte[] tmp = new byte[1024];
                  while (true) {
                      while (inputStream.available() > 0) {
                          int i = inputStream.read(tmp, 0, 1024);
                          if (i < 0) {
                              break;
                          }
                          String s = new String(tmp, 0, i);
                          if (s.contains("--More--")) {
                              outputStream.write((" ").getBytes());
                              outputStream.flush();
                          }
                          System.out.println(s);
                      }
                      if (channelShell.isClosed()) {
                          System.out.println("exit-status:" + channelShell.getExitStatus());
                          break;
                      }
                      //間隔1s后再執行
                      try {
                          Thread.sleep(1000);
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
                  outputStream.close();
                  inputStream.close();
              }catch(Exception e){
                  e.printStackTrace();
              }
      
              return result;
          }
      
          //下載除了云服務器的文件(你自己的服務器):因為云服務器,像阿里云服務器下載文件好像是一段一段給你的,不是一起給你。
          public void downloadOtherFile(String remoteFileAbsolutePath, String fileName, HttpServletResponse response) {
              try {
                  channelSftp = (ChannelSftp) session.openChannel("sftp");
                  channelSftp.connect();
      
                  //獲取輸入流
                  InputStream inputStream = channelSftp.get(remoteFileAbsolutePath);
                  //直接下載到本地文件
      //            channelSftp.get(remoteFileAbsolutePath, "D:\\Develop\\Test\\studio-3t-x64.zip");
      
                  response.setCharacterEncoding(StandardCharsets.UTF_8.name());
                  response.setContentType("application/octet-stream;charset=".concat(StandardCharsets.UTF_8.name()));
                  response.setHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, HttpHeaders.CONTENT_DISPOSITION);
                  response.setHeader(HttpHeaders.CONTENT_DISPOSITION,
                          "attachment; filename=".concat(
                                  URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
                          ));
                  ServletOutputStream out = response.getOutputStream();
      
                  // 從InputStream輸入流讀取數據 并寫入到ServletOutputStream輸出流
                  byte[] buffer = new byte[4096];
                  int bytesRead;
                  while ((bytesRead = inputStream.read(buffer)) != -1) {
                      out.write(buffer, 0, bytesRead);
                  }
                  out.flush();
                  out.close();
              }catch(Exception e){
                  throw new RuntimeException("關閉連接失敗(下載文件):" + e.getMessage());
              }
          }
      
          //下載云服務器的文件(因為云服務器傳文件是一段一段的,所以不能直接像操作我們的服務器一樣直接下載)(阿里云為例)
          public void downloadCloudServerFile(String remoteFileAbsolutePath, String fileName, HttpServletResponse response) {
              try {
                  channelSftp = (ChannelSftp) session.openChannel("sftp");
                  channelSftp.connect();
      
                  //獲取輸入流
                  InputStream inputStream = channelSftp.get(remoteFileAbsolutePath);
      
                  //阿里云應該是斷點續傳,后面研究……
      
              }catch(Exception e){
                  throw new RuntimeException("關閉連接失敗(下載文件):" + e.getMessage());
              }
          }
      
          //ls命令:獲取文件夾的信息
          public String ls(String path){
              StringBuilder sb = new StringBuilder();
              try {
                  channelSftp = (ChannelSftp) session.openChannel("sftp");
                  channelSftp.connect();
      
                  Vector ls = channelSftp.ls(path);
                  Iterator iterator = ls.iterator();
                  while (iterator.hasNext()) {
                      Object next = iterator.next();
                      System.out.println(next);
                      sb.append(next);
                  }
              } catch (Exception e){
                  throw new RuntimeException(e.getMessage());
              }
              return sb.toString();
          }
      
          //關閉通道:釋放資源
          private void closeChannel(){
              //不為空,且已經連接:關閉
              if (Objects.nonNull(channelExec)) {
                  channelExec.disconnect();
              }
              if (Objects.nonNull(channelSftp)) {
                  channelSftp.disconnect();
              }
              if (Objects.nonNull(channelShell)) {
                  channelShell.disconnect();
              }
          }
      
          /** 關閉通道、關閉會話:釋放資源
           * spring銷毀前,關閉 所有會話 及 所有通道
           */
          @PreDestroy
          public void closeAll(){
              System.out.println("我被銷毀了。。。。。。。。。。。。。。。。。。。。。。");
      
              this.closeChannel();
      
              if (Objects.nonNull(session) && session.isConnected()) {
                  session.disconnect();
              }
          }
      
      }
      
      

      4.2、使用Jsch工具類:執行命令

      4.2.1、執行簡單命令

      package com.cc.jschdemo.web.controller;
      
      import com.cc.jschdemo.utils.JSchUtil;
      import com.jcraft.jsch.ChannelExec;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RequestParam;
      import org.springframework.web.bind.annotation.RestController;
      
      import javax.annotation.Resource;
      import java.io.InputStream;
      import java.util.Arrays;
      
      /**
       * <p></p>
       *
       * @author CC
       * @since 2023/11/8
       */
      @RestController
      @RequestMapping("/jsch")
      public class JSchController {
      
          @Resource
          private JSchUtil jSchUtil;
      
          /** <p>執行命令<p>
           **/
          @GetMapping
          public String executeCommand() {
              //登陸(默認只連接5分鐘,5分鐘后銷毀)
              jSchUtil.loginLinux("服務器賬號", "服務器密碼", "服務器IP", 服務器端口);
              //一、執行命令
              String mkdir = jSchUtil.executeCommand("mkdir ccc");
              String docker = jSchUtil.executeCommand("docker");
              String dockerPs = jSchUtil.executeCommand("docker ps");
      
              System.out.println(mkdir);
              System.out.println(docker);
              System.out.println(dockerPs);
      
              //執行完,關閉連接
              jSchUtil.closeAll();
      
              return docker;
          }
      }
      
      • 結果:
      • 多了一個文件夾
        image

      4.2.1、執行復雜的shell命令

         /** <p>執行命令<p>
           **/
          @PostMapping
          public String execCmdByShell() {
              //登陸(默認只連接5分鐘,5分鐘后銷毀)
              jSchUtil.loginLinux("服務器賬號", "服務器密碼", "服務器IP", 服務器端口);
              //二、執行shell腳本(可以改造成傳入的shell腳步)
              jSchUtil.execCmdByShell(Arrays.asList("cd /", "ll" , "cd cc/", "mkdir ccccc222", "ll"));
              //執行完,關閉連接
              jSchUtil.closeAll();
      
              return "docker";
          }
      
      • 結果

      image

      4.3、使用Jsch工具類:下載文件

      4.3.1、普通服務器下載

          //下載普通服務器的文件
          @PutMapping
          public void downloadOtherFile(HttpServletResponse response) {
              //登陸(默認只連接5分鐘,5分鐘后銷毀)
               jSchUtil.loginLinux("服務器賬號", "服務器密碼", "服務器IP", 服務器端口);
              //下載文件
              jSchUtil.downloadOtherFile(
                      "/dev/libbb/studio-3t-x64.zip",
                      "studio-3t-x64.zip",
                      response
              );
              //執行完,關閉連接
              jSchUtil.closeAll();
          }
      

      4.3.2、阿里云服務器下載

      • 博主很懶,沒留下什么……

      五、Hutool工具封裝的JSch(推薦)

      • Hutool使用的是JSch連接池,推薦使用……
      • 博主比較懶,還沒實現……

      六、總結

      參考:

      https://www.jb51.net/article/264152.htm

      https://www.jb51.net/article/264148.htm

      posted on 2023-11-29 10:45  C_C_菜園  閱讀(2367)  評論(1)    收藏  舉報

      導航

      主站蜘蛛池模板: 日本高清在线观看WWW色| 国产偷自视频区视频| 熟女系列丰满熟妇AV| 日本三级香港三级三级人妇久| 国产高清在线精品一区APP| 内射囯产旡码丰满少妇| 国产精品乱码人妻一区二区三区 | 日韩激情无码av一区二区| 亚洲男人的天堂av手机在线观看| 久久一日本道色综合久久| 永修县| 中文国产人精品久久蜜桃| 亚洲精品国产中文字幕| 亚洲人成电影网站 久久影视| 国产精品黄色片| 国内精品视频一区二区三区八戒| 国产私拍福利精品视频| 久久久国产精品VA麻豆| 毛片亚洲AV无码精品国产午夜| 无码人妻熟妇av又粗又大| 日本黄色一区二区三区四区| 国产精品中文第一字幕| 国产精品亚洲第一区在线| 国产成人亚洲欧美二区综合| 国偷自产一区二区三区在线视频| 国产黄色一区二区三区四区| 久久精品中文字幕少妇| 国产精品七七在线播放| 奇米777四色在线精品| 国产欧美日韩亚洲一区二区三区| 野花韩国高清电影| 亚洲熟女乱色一区二区三区| 日韩人妻少妇一区二区三区| 国内精品免费久久久久电影院97| 在线高清免费不卡全码| 蜜臀av日韩精品一区二区| 建德市| 亚洲精品成人片在线观看精品字幕| 亚洲一区二区三区丝袜| 爱啪啪av导航| 亚洲精品中文字幕尤物综合|