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

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

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

      SpringBoot 集成 FTP 與 SFTP

      FTP(File Transfer Protocol)和 SFTP(SSH File Transfer Protocol)雖同為文件傳輸協議,但在底層原理、安全性、傳輸方式等方面存在顯著差異,具體區別及各自優勢如下:

      核心區別

      1. 底層依賴與傳輸機制不同
        • FTP 基于TCP 協議獨立運行,使用兩個端口完成傳輸:21 端口用于控制指令(如連接、登錄),20 端口(主動模式)或動態端口(被動模式)用于實際數據傳輸,整個過程中控制流和數據流分離。
        • SFTP 是SSH 協議的子協議,依賴 SSH 的加密通道運行,僅通過 22 端口即可同時處理控制指令和數據傳輸,無需額外端口,傳輸過程中所有數據(包括指令和文件內容)都在 SSH 加密通道中完成。
      2. 安全性差異
        • FTP 是明文傳輸,用戶名、密碼及文件內容在網絡中均以未加密的形式發送,容易被監聽、竊取或篡改,安全性極低,僅適用于內網等完全可信的環境。
        • SFTP 基于 SSH 的加密機制(如對稱加密、非對稱加密),所有傳輸數據都會經過加密處理,且支持身份驗證(密碼或 SSH 密鑰),能有效防止數據泄露和篡改,安全性遠高于 FTP。
      3. 端口與防火墻適配性
        • FTP 的端口使用復雜(固定控制端口 + 動態數據端口),在防火墻或 NAT 環境下需額外配置端口映射,否則可能因端口封鎖導致連接失敗,適配性較差。
        • SFTP 僅使用 22 端口,端口單一且固定,防火墻規則配置簡單,在復雜網絡環境(如跨網傳輸、云服務器)中更易適配,無需額外開放多個端口。
      4. 兼容性與普及度
        • FTP 出現時間早(1971 年),是傳統文件傳輸的 “標準協議”,支持幾乎所有操作系統和設備,兼容性極強,老舊系統或簡易設備(如嵌入式設備)通常默認支持 FTP。
        • SFTP 是較新的協議(基于 SSH 發展而來),依賴 SSH 環境,部分老舊系統或設備可能未預裝 SSH 服務,兼容性略遜于 FTP,但隨著安全需求提升,主流系統(如 Linux、Windows 10+)已普遍支持。

      各自的優點與適用場景

      • SFTP 的核心優點
        1. 安全性碾壓:加密傳輸避免數據泄露,適合傳輸敏感文件(如用戶數據、財務報表等)。
        2. 端口簡化:僅需 22 端口,降低防火墻配置復雜度,尤其適合云服務器、跨網絡環境。
        3. 認證靈活:支持 SSH 密鑰認證,無需明文存儲密碼,進一步提升訪問安全性。
      • FTP 的核心優點
        1. 兼容性極強:適用于所有支持 TCP/IP 的設備,尤其在老舊系統或簡易嵌入式設備中更易部署。
        2. 傳輸效率略高:無加密開銷,在完全可信的內網環境中,純文件傳輸速度可能略快于 SFTP。

      FTP

      參考:https://bbs.huaweicloud.com/blogs/451602

      1. 在pom文件中添加這個
      <dependency>
          <groupId>commons-net</groupId>
          <artifactId>commons-net</artifactId>
          <version>3.9.0</version>
      </dependency>
      
      1. 增加配置信息

        ftp:
          host:
            ip: 你的ftp ip地址
          port: 21
          username: 你的賬號
          password: 你的密碼
          basePath: 要上傳的路徑(要有權限)
        
      @Data
      @Component
      @ConfigurationProperties(prefix = "ftp")
      public class FtpConfig {
          @Value("${ftp.host.ip}")
          private String host;
      
          @Value("${ftp.port}")
          private int port;
      
          @Value("${ftp.username}")
          private String username;
      
          @Value("${ftp.password}")
          private String password;
          
          @Value("${ftp.basePath}")
          private String basePath;
      }
      
      1. 編寫相關的工具類
      @Component
      public class FtpUtil {
      
          @Autowired
          private SFtpConfig ftpConfig;
      
          /**
           * 連接FTP服務器
           */
          private FTPClient connect() throws IOException {
              FTPClient ftpClient = new FTPClient();
              ftpClient.setControlEncoding("UTF-8");
              ftpClient.connect(ftpConfig.getHost(), ftpConfig.getPort());
              ftpClient.login(ftpConfig.getUsername(), ftpConfig.getPassword());
              ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
              ftpClient.enterLocalPassiveMode();
              ftpClient.setBufferSize(1024 * 1024); // 設置緩沖區大小
      
              // 檢查連接是否成功
              int replyCode = ftpClient.getReplyCode();
              if (!FTPReply.isPositiveCompletion(replyCode)) {
                  ftpClient.disconnect();
                  throw new IOException("FTP服務器拒絕連接");
              }
      
              return ftpClient;
          }
      
          /**
           * 上傳文件到FTP服務器
           * @param remotePath 遠程路徑
           * @param fileName 文件名
           * @param inputStream 輸入流
           * @return 是否上傳成功
           */
          public boolean uploadFile(String remotePath, String fileName, InputStream inputStream) {
              FTPClient ftpClient = null;
              try {
                  ftpClient = connect();
      
                  // 切換目錄
                  if (!ftpClient.changeWorkingDirectory(remotePath)) {
                      // 如果目錄不存在,則創建
                      String[] dirs = remotePath.split("/");
                      String tempPath = "";
                      for (String dir : dirs) {
                          if (dir.length() > 0) {
                              tempPath += "/" + dir;
                              if (!ftpClient.changeWorkingDirectory(tempPath)) {
                                  if (!ftpClient.makeDirectory(tempPath)) {
                                      return false;
                                  }
                              }
                          }
                      }
                  }
      
                  // 上傳文件
                  boolean success = ftpClient.storeFile(fileName, inputStream);
                  return success;
              } catch (IOException e) {
                  e.printStackTrace();
                  return false;
              } finally {
                  if (ftpClient != null && ftpClient.isConnected()) {
                      try {
                          ftpClient.logout();
                          ftpClient.disconnect();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      
          /**
           * 從FTP服務器下載文件
           * @param remotePath 遠程路徑
           * @param fileName 文件名
           * @param outputStream 輸出流
           * @return 是否下載成功
           */
          public boolean downloadFile(String remotePath, String fileName, OutputStream outputStream) {
              FTPClient ftpClient = null;
              try {
                  ftpClient = connect();
      
                  // 切換目錄
                  if (!ftpClient.changeWorkingDirectory(remotePath)) {
                      return false;
                  }
      
                  // 下載文件
                  boolean success = ftpClient.retrieveFile(fileName, outputStream);
                  return success;
              } catch (IOException e) {
                  e.printStackTrace();
                  return false;
              } finally {
                  if (ftpClient != null && ftpClient.isConnected()) {
                      try {
                          ftpClient.logout();
                          ftpClient.disconnect();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      
          /**
           * 刪除FTP服務器上的文件
           * @param remotePath 遠程路徑
           * @param fileName 文件名
           * @return 是否刪除成功
           */
          public boolean deleteFile(String remotePath, String fileName) {
              FTPClient ftpClient = null;
              try {
                  ftpClient = connect();
      
                  // 切換目錄
                  if (!ftpClient.changeWorkingDirectory(remotePath)) {
                      return false;
                  }
      
                  // 刪除文件
                  boolean success = ftpClient.deleteFile(fileName);
                  return success;
              } catch (IOException e) {
                  e.printStackTrace();
                  return false;
              } finally {
                  if (ftpClient != null && ftpClient.isConnected()) {
                      try {
                          ftpClient.logout();
                          ftpClient.disconnect();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      
          /**
           * 檢查文件是否存在
           * @param remotePath 遠程路徑
           * @param fileName 文件名
           * @return 文件是否存在
           */
          public boolean fileExists(String remotePath, String fileName) {
              FTPClient ftpClient = null;
              try {
                  ftpClient = connect();
      
                  // 切換目錄
                  if (!ftpClient.changeWorkingDirectory(remotePath)) {
                      return false;
                  }
      
                  FTPFile[] files = ftpClient.listFiles();
                  for (FTPFile file : files) {
                      if (file.getName().equals(fileName)) {
                          return true;
                      }
                  }
                  return false;
              } catch (IOException e) {
                  e.printStackTrace();
                  return false;
              } finally {
                  if (ftpClient != null && ftpClient.isConnected()) {
                      try {
                          ftpClient.logout();
                          ftpClient.disconnect();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      }
      
      

      寫在工具類中,后續可以直接調用

      SFTP

      參考: https://blog.csdn.net/qq_33204709/article/details/135974528

      配置類

      <!-- SFTP -->
      <dependency>
          <groupId>com.jcraft</groupId>
          <artifactId>jsch</artifactId>
          <version>0.1.55</version>
      </dependency>
      

      連接工具類

      @Data
      @Component
      @ConfigurationProperties(prefix = "ftp")
      public class SFtpConfig {
          @Value("${ftp.host.ip}")
          private String host;
      
          @Value("${ftp.port}")
          private int port;
      
          @Value("${ftp.username}")
          private String username;
      
          @Value("${ftp.password}")
          private String password;
      
          @Value("${ftp.basePath}")
          private String basePath;
      
          @Value("${ftp.timeOut}")
          private int timeOut;
      
          /*
          * sftp, 默認協議
           */
          private String protocol = "sftp";
      }
      

      接口(便于復用)

      public interface SFtpService {
          /**
           * 上傳文件
           * @param sftpPath SFTP目標路徑
           * @param file 要上傳的文件
           * @return 是否上傳成功(true:成功,false:失敗)
           */
          boolean upload(String sftpPath, MultipartFile file);
      
          /**
           * 下載文件
           * @param sftpPath SFTP文件路徑
           * @param response HTTP響應對象,用于輸出文件流
           * @return 是否下載成功(true:成功,false:失敗)
           */
          boolean download(String sftpPath, HttpServletResponse response);
      
          /**
           * 下載文件 全量加載到內存,僅適合小文件
           * @param sftpPath SFTP文件路徑
           * @return 文件字節數組
           */
      
          public byte[] download(String sftpPath);
          /**
           * 重命名文件(或移動文件)
           * @param oldPath 原文件路徑
           * @param newPath 新文件路徑
           * @return 是否重命名成功(true:成功,false:失敗)
           */
          boolean rename(String oldPath, String newPath);
      
          /**
           * 刪除文件(或目錄)
           * @param sftpPath 要刪除的文件或目錄路徑
           * @return 是否刪除成功(true:成功,false:失敗)
           */
          boolean delete(String sftpPath);
      }
      
      

      實現類

      @Service
      @Slf4j
      public class SFtpServiceImpl implements SFtpService {
          @Resource
          private SftpUtils sftpUtils;
          @Override
          public boolean upload(String sftpPath, MultipartFile file) {
              // 上傳文件
              ChannelSftp sftp = null;
              try (InputStream in = file.getInputStream()) {
                  // 開啟sftp連接
                  sftp = sftpUtils.createSftp();
      
                  // 進入sftp文件目錄
                  sftp.cd(sftpPath);
                  log.info("切換到目錄為:{}", sftpPath);
      
                  // 上傳文件
                  sftp.put(in, file.getOriginalFilename());
                  log.info("上傳文件成功,目標目錄:{}", sftpPath);
                  return true;
              } catch (SftpException | JSchException | IOException e) {
                  log.error("上傳文件失敗,原因:{}", e.getMessage(), e);
                  return false;
              } finally {
                  // 關閉sftp
                  sftpUtils.disconnect(sftp);
              }
          }
      
          @Override
          public boolean download(String sftpPath, HttpServletResponse response) {
              ChannelSftp sftp = null;
              try {
                  // 1. 建立SFTP連接
                  sftp = sftpUtils.createSftp();
      
                  // 2. 檢查文件是否存在(直接嘗試訪問文件)
                  try {
                      // 如果文件不存在,會拋出 SftpException
                      sftp.lstat(sftpPath);
                  } catch (SftpException e) {
                      log.error("文件不存在或無法訪問: {}", sftpPath);
                      return false;
                  }
      
                  // 3. 從路徑中提取文件名(如 "/upload/test.txt" -> "test.txt")
                  String fileName = sftpPath.substring(sftpPath.lastIndexOf("/") + 1);
      
                  // 4. 設置HTTP響應頭(支持中文文件名)
                  response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
                  response.setHeader(
                      HttpHeaders.CONTENT_DISPOSITION,
                      "attachment; filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())
                  );
      
                  // 5. 下載文件(直接使用完整路徑)
                  sftp.get(sftpPath, response.getOutputStream());
                  log.info("文件下載成功: {}", sftpPath);
                  return true;
      
              } catch (SftpException e) {
                  log.error("SFTP操作失敗: {}", e.getMessage(), e);
                  return false;
              } catch (IOException | JSchException e) {
                  log.error("系統異常: {}", e.getMessage(), e);
                  return false;
              } finally {
                  sftpUtils.disconnect(sftp);
              }
          }
      
          @Override
          public byte[] download(String sftpPath) {
              ChannelSftp sftp = null;
              try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {
                  // 1. 建立SFTP連接
                  sftp = sftpUtils.createSftp();
      
                  // 2. 檢查文件是否存在
                  try {
                      sftp.lstat(sftpPath);
                  } catch (SftpException e) {
                      log.error("文件不存在: {}", sftpPath);
                      return null;
                  }
      
                  // 3. 下載文件到內存
                  sftp.get(sftpPath, outputStream);
                  log.info("文件下載成功: {}", sftpPath);
                  return outputStream.toByteArray();
      
              } catch (SftpException | JSchException | IOException e) {
                  log.error("下載失敗: {}", e.getMessage(), e);
                  return null;
              } finally {
                  sftpUtils.disconnect(sftp);
              }
          }
      
          @Override
          public boolean rename(String oldPath, String newPath) {
              // 重命名文件(移動)
              ChannelSftp sftp = null;
              try {
                  // 開啟sftp連接
                  sftp = sftpUtils.createSftp();
      
                  // 修改sftp文件路徑
                  sftp.rename(oldPath, newPath);
                  log.info("sftp文件重命名成功,歷史路徑:{},新路徑:{}", oldPath, newPath);
                  return true;
              } catch (SftpException | JSchException e) {
                  log.error("sftp文件重命名失敗,原因:{}", e.getMessage(), e);
                  return false;
              } finally {
                  // 關閉sftp
                  sftpUtils.disconnect(sftp);
              }
          }
      
          @Override
          public boolean delete(String sftpPath) {
              // 刪除文件
              ChannelSftp sftp = null;
              try {
                  // 開啟sftp連接
                  sftp = sftpUtils.createSftp();
      
                  // 判斷sftp文件存在
                  boolean isExist = isFileExist(sftpPath, sftp);
                  if (!isExist) {
                      log.error("sftp文件刪除失敗,sftp文件不存在:" + sftpPath);
                      return false;
                  }
      
                  // 刪除文件
                  SftpATTRS sftpATTRS = sftp.lstat(sftpPath);
                  if (sftpATTRS.isDir()) {
                      sftp.rmdir(sftpPath);
                  } else {
                      sftp.rm(sftpPath);
                  }
                  log.info("sftp文件刪除成功,目標文件:{}.", sftpPath);
                  return true;
              } catch (SftpException | JSchException e) {
                  log.error("sftp文件刪除失敗,原因:{}", e.getMessage(), e);
                  return false;
              } finally {
                  // 關閉sftp
                  sftpUtils.disconnect(sftp);
              }
          }
      
      
      
          /**
           * 判斷目錄是否存在
           */
          private boolean isFileExist(String sftpPath, ChannelSftp sftp) {
              try {
                  // 獲取文件信息
                  SftpATTRS sftpATTRS = sftp.lstat(sftpPath);
                  return sftpATTRS != null;
              } catch (Exception e) {
                  log.error("判斷文件是否存在失敗,原因:{}", e.getMessage(), e);
                  return false;
              }
          }
      }
      

      control層調用

      @RestController
      @RequestMapping("/sftp")
      public class SFtpController {
      
          @Resource
          private SFtpService sftpService;
      
          /**
           * 上傳文件
           */
          @PostMapping("/upload")
          public R<Object> upload(@RequestParam String sftpPath, @RequestParam MultipartFile file) {
              sftpService.upload(sftpPath, file);
              return R.success();
          }
      
          /**
           * 下載文件
           */
          @GetMapping("/download")
          public void download(@RequestParam String sftpPath,  HttpServletResponse response) {
              sftpService.download(sftpPath, response);
          }
      
          /**
           * 重命名文件(移動)
           */
          @GetMapping("/rename")
          public R<Object> rename(@RequestParam String oldPath,  @RequestParam String newPath) {
              sftpService.rename(oldPath, newPath);
              return R.success();
          }
      
          /**
           * 刪除文件
           */
          @GetMapping("/delete")
          public R<Object> delete(@RequestParam String sftpPath) {
              sftpService.delete(sftpPath);
              return R.success();
          }
      }
      

      這里用SFTP容易有個坑,可能你寫的你能連接上,到了生產上連接不上。這個后續公眾號會發,或者詳細見我的csdn這篇文章https://blog.csdn.net/m0_58680378/article/details/147094033?spm=1011.2415.3001.5331

      posted @ 2025-07-10 19:01  叮咚~到賬一個億  閱讀(158)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 大伊香蕉在线精品视频75| 天堂亚洲免费视频| 亚洲另类欧美在线电影| 日本欧美一区二区三区在线播放| 亚洲国产日韩精品一区二区三区| 999精品色在线播放| 成人国产精品三上悠亚久久| 亚洲亚洲人成综合网络| 亚洲一区二区三区啪啪| 中文字幕无码免费不卡视频| 亚洲国产成人无码av在线影院| 国产成人一区二区三区免费| 亚洲AV无码秘?蜜桃蘑菇| 真人在线射美女视频在线观看| 日韩国产中文字幕精品| 好紧好爽好湿别拔出来视频男男| 国产精品女生自拍第一区| 午夜AAAAA级岛国福利在线| 欧美日韩一线| 亚洲中文字幕五月五月婷| 国产激情无码一区二区三区| 一级国产在线观看高清| 亚洲一区二区三区自拍偷拍 | 国产一区二区av天堂热| 狠狠色丁香婷婷综合尤物| 亚洲精品综合第一国产综合| 亚洲V天堂V手机在线| 最近日本免费观看高清视频| 亚洲无线码中文字幕在线| 亚洲国产午夜福利精品| 麻豆妓女爽爽一区二区三 | 思思热在线视频精品| 在线国产你懂的| 国产日韩av二区三区| 亚洲国产成人久久精品不卡| 国产在线98福利播放视频| 日韩亚av无码一区二区三区| 亚洲AV成人片不卡无码| 日韩人妻少妇一区二区三区 | 国产亚洲精品VA片在线播放| 蜜桃av无码免费看永久|