Chia sẻ đoạn code Groovy sử dụng thao tác file trên ftpserver

Chia sẻ các bạn đoạn code groovy sử dụng thao tác file trên ftp. Thông tin tài khoản ftp đang đọc từ file config json, các bạn có thể sửa trực tiếp fix user/pw.

Các sử dụng:

@Autowired
FTPServer ftpServer

Cách sử dụng.

 ftpServer.createDirIfNotExist(path)

hoặc

 ftpServer.uploadFile(path + "/" + fileName, file.getBytes())

Source đây nhé.

package utils
import org.apache.commons.io.IOUtils
import org.apache.commons.net.ftp.FTP
import org.apache.commons.net.ftp.FTPClient
import org.apache.commons.net.ftp.FTPReply
import org.springframework.stereotype.Component
@Component
class FTPServer {
   private final int MAX_RETRY_ATTEMPTS = 3
   private final int BATCH_SIZE = 10
   private final int CONNECTION_TIMEOUT = 30000 // 30 seconds
   private final int DATA_TIMEOUT = 60000 // 60 seconds
   private final String FTP_UPLOAD = "FTP_UPLOAD"

   FTPClient getConnec(String server, String username, String password, String model = "P") {
       FTPClient ftpClient = new FTPClient()
       int port = 21
       // 2. CẤU HÌNH CONNECTION
       ftpClient.setConnectTimeout(CONNECTION_TIMEOUT)
       ftpClient.setDataTimeout(DATA_TIMEOUT)
       ftpClient.setBufferSize(1024 * 1024) // tăng tốc độ truyền
       ftpClient.setControlEncoding("UTF-8")
       // 3. KẾT NỐI SERVER
       System.out.println("Đang kết nối đến " + server + ":" + port + "...")
       try {
           ftpClient.connect(server, port)
       } catch (UnknownHostException e) {
           throw new Exception("Không tìm thấy server: " + server + "  " + e.getMessage())
       } catch (SocketException e) {
           throw new Exception("Lỗi kết nối socket: " + e.getMessage())
       } catch (IOException e) {
           throw new Exception("Lỗi I/O khi kết nối: " + e.getMessage())
       }
       // 4. KIỂM TRA REPLY CODE
       int replyCode = ftpClient.getReplyCode()
       if (!FTPReply.isPositiveCompletion(replyCode)) {
           throw new Exception("Server từ chối kết nối. Reply code: " + replyCode)
       }
       System.out.println("Kết nối thành công. Reply: " + ftpClient.getReplyString().trim())
       // 5. ĐĂNG NHẬP
       System.out.println("Đang đăng nhập với user: " + username + "...")
       boolean loginSuccess = ftpClient.login(username, password)
       if (!loginSuccess) {
           throw new Exception("Đăng nhập thất bại. Reply: " + ftpClient.getReplyString().trim())
       }
       System.out.println("Đăng nhập thành công")
       // 6. CẤU HÌNH PASSIVE MODE (QUAN TRỌNG!)
       if (model == "A") {
           ftpClient.enterLocalActiveMode()
           System.out.println("Đã bật Active Mode")
       } else {
           ftpClient.enterLocalPassiveMode()
           System.out.println("Đã bật PassiveMode")
       }
       // 7. CẤU HÌNH BINARY MODE
       ftpClient.setFileType(FTP.BINARY_FILE_TYPE)
       System.out.println("Đã đặt Binary Mode")
       return ftpClient
   }
   FTPUploadResult uploadFile(String ftpUrl, String fileBase64) {
       byte[] fileByte = fileBase64.decodeBase64()
       def stream = new ByteArrayInputStream(fileByte)
       def getAc = getAccFTP(FTP_UPLOAD)
       return uploadFileWithRetry(getAc.ip, getAc.user, getAc.pw, stream, ftpUrl)
   }
   FTPUploadResult uploadFileWithRetry(
           String server, String username, String password,
           InputStream localFilePath, String remoteFilePath) {
       for (int attempt = 1; attempt <= MAX_RETRY_ATTEMPTS; attempt++) {
           System.out.println("Thử upload lần " + attempt + "/" + MAX_RETRY_ATTEMPTS)
           FTPUploadResult result = uploadFileStream(server, username, password,
                   localFilePath, remoteFilePath)
           if (result.isSuccess()) {
               System.out.println("Upload thành công sau " + attempt + " lần thử")
               return result
           }
           System.err.println("Lần thử " + attempt + " thất bại: " + result.getErrorMessage())
           // Chờ trước khi thử lại (trừ lần cuối)
           if (attempt < MAX_RETRY_ATTEMPTS) {
               try {
                   Thread.sleep(2000 * attempt) // Tăng dần thời gian chờ
               } catch (InterruptedException e) {
                   Thread.currentThread().interrupt()
                   return new FTPUploadResult(false, "Upload bị ngắt", "INTERRUPTED")
               }
           }
       }
       return new FTPUploadResult(false,
               "Upload thất bại sau " + MAX_RETRY_ATTEMPTS + " lần thử", "MAX_RETRY_EXCEEDED")
   }
   FTPUploadResult uploadFileStream(
           String server, String username, String password,
           InputStream inputStream, String remoteFilePath) {
       FTPClient ftpClient = null
       int replyCode = 0
       try {
           ftpClient = getConnec(server, username, password)

           if (checkFileExists(ftpClient, remoteFilePath))
               ftpClient.deleteFile(remoteFilePath)
           // 10. UPLOAD FILE
           System.out.println("Bắt đầu upload: -> " + remoteFilePath)
           boolean uploaded = ftpClient.storeFile(remoteFilePath, inputStream)
           if (!uploaded) {
               replyCode = ftpClient.getReplyCode()
               String replyString = ftpClient.getReplyString()
               return new FTPUploadResult(false,
                       "Upload thất bại. Reply " + replyCode + ": " + replyString.trim(),
                       "UPLOAD_FAILED")
           }
           // 11. XÁC NHẬN UPLOAD THÀNH CÔNG
           System.out.println("Upload hoàn tất. Đang kiểm tra...")
           FTPUploadResult result = new FTPUploadResult(true, "Upload thành công", "SUCCESS")
           return result
       } catch (IOException e) {
           return new FTPUploadResult(false,
                   "Lỗi I/O trong quá trình upload: " + e.getMessage(), "IO_EXCEPTION")
       } catch (Exception e) {
           return new FTPUploadResult(false,
                   "Lỗi không xác định: " + e.getMessage(), "UNKNOWN_ERROR")
       } finally {
           // 12. CLEANUP
           if (inputStream != null) {
               try {
                   inputStream.close()
               } catch (IOException e) {
                   System.err.println("Lỗi khi đóng input stream: " + e.getMessage())
               }
           }
           if (ftpClient != null && ftpClient.isConnected()) {
               try {
                   ftpClient.logout()
                   ftpClient.disconnect()
                   System.out.println("Đã ngắt kết nối FTP")
               } catch (IOException e) {
                   System.err.println("Lỗi khi ngắt kết nối: " + e.getMessage())
               }
           }
       }
   }
   void createDirectoryTree(FTPClient ftpClient, String dirPath) throws IOException {
       String[] dirs = dirPath.split("[/\\\\]")
       String currentPath = ""
       for (String dir : dirs) {
           if (!dir.isEmpty()) {
               currentPath += "/" + dir
               try {
                   ftpClient.makeDirectory(currentPath)
                   System.out.println("Đã tạo thư mục: " + currentPath)
               } catch (IOException e) {
                   // Thư mục có thể đã tồn tại, bỏ qua lỗi
               }
           }
       }
   }
   FTPUploadResult uploadFile(String ftpUrl, byte[] fileByte) {
       def stream = new ByteArrayInputStream(fileByte)
       def getAc = getAccFTP(FTP_UPLOAD)
       return uploadFileWithRetry(getAc.ip, getAc.user, getAc.pw, stream, ftpUrl)
   }
   FTPUploadResult removeFile(String ftpUrl) {
       FTPClient ftpClient = null
       try {
           def getAc = getAccFTP(FTP_UPLOAD)
           ftpClient = getConnec(getAc.ip, getAc.user, getAc.pw)
           ftpClient.deleteFile(ftpUrl)
           ftpClient.logout()
           ftpClient.disconnect()
           return new FTPUploadResult(true, "", "SUCCESS")
       } catch (Exception e) {
           return new FTPUploadResult(false, e.getMessage(), "LOGIN_FAILED")
       } finally {
           // 12. CLEANUP
           if (ftpClient != null) {
               return new FTPUploadResult(false, "FTPClient NULL", "MOVE_FAILED")
           } else if (ftpClient.isConnected()) {
               try {
                   ftpClient.logout()
                   ftpClient.disconnect()
                   System.out.println("Đã ngắt kết nối FTP")
               } catch (IOException e) {
                   System.err.println("Lỗi khi ngắt kết nối: " + e.getMessage())
               }
           }
       }
   }
   boolean checkFileExists(FTPClient ftpClient, String filePath) throws IOException {
       def remoteFiles = ftpClient.listFiles(filePath)
       if (remoteFiles.length > 0) {
           println filePath + " DA TON TAI  "
           return true
       } else {
           println filePath + " CHUA CO  "
           return false
       }
   }

   FTPUploadResult createDirIfNotExist(String ftpDir) {
       FTPClient ftpClient = null
       try {
           def getAc = getAccFTP(FTP_UPLOAD)
           ftpClient = getConnec(getAc.ip, getAc.user, getAc.pw)
           createDirectoryTree(ftpClient, ftpDir)
       } catch (Exception e) {
           return new FTPUploadResult(false, e.getMessage(), "CREATE_DIR_FAILED")
       } finally {
           // 12. CLEANUP
           if (ftpClient != null) {
               return new FTPUploadResult(false, "FTPClient NULL", "LOGIN_FAILED")
           } else if (ftpClient.isConnected()) {
               try {
                   ftpClient.logout()
                   ftpClient.disconnect()
                   System.out.println("Đã ngắt kết nối FTP")
               } catch (IOException e) {
                   System.err.println("Lỗi khi ngắt kết nối: " + e.getMessage())
               }
           }
       }
   }

   Map<String, String> getAccFTP(String loai) {
       def configFTP = Config.getConfig("FTP")
       if (!configFTP)
           return [:]
       def entry = configFTP.data.find { it.loai == loai }
       if (!entry) return [:]
       return [
               ip  : entry.ip,
               user: entry.user,
               pw  : entry.pw
       ]
   }
   byte[] downloadFile(String ftpServer) {
       FTPClient ftpClient = null
       InputStream inputStream = null
       try {
           def getAc = getAccFTP(FTP_UPLOAD)
           ftpClient = getConnec(getAc.ip, getAc.user, getAc.pw)
           inputStream = ftpClient.retrieveFileStream(ftpServer)
           if (inputStream == null) throw new Exception("Lỗi không download file trên server FTP. Kiểm tra lại file trên đường dẫn " + ftpServer)
           byte[] sourceBytes = IOUtils.toByteArray(inputStream)
           return sourceBytes
       } catch (Exception e) {
           throw new Exception(e.getMessage())
       } finally {
           // 12. CLEANUP
           if (inputStream != null) {
               try {
                   inputStream.close()
               } catch (IOException e) {
                   System.err.println("Lỗi khi đóng input stream: " + e.getMessage())
               }
           }
           if (ftpClient != null && ftpClient.isConnected()) {
               try {
                   ftpClient.logout()
                   ftpClient.disconnect()
                   System.out.println("Đã ngắt kết nối FTP")
               } catch (IOException e) {
                   System.err.println("Lỗi khi ngắt kết nối: " + e.getMessage())
               }
           }
       }
   }
   void moveFile(String oldFile, String newFile) {
       FTPClient ftpClient = null
       try {
           def getAc = getAccFTP(FTP_UPLOAD)
           ftpClient = getConnec(getAc.ip, getAc.user, getAc.pw)
           def duLieu = downloadFile(oldFile)
           uploadFile(newFile, duLieu)
           ftpClient.deleteFile(oldFile)
           ftpClient.logout()
           ftpClient.disconnect()
       } catch (Exception e) {
           throw new Exception(e.getMessage())
       } finally {
           if (ftpClient != null && ftpClient.isConnected()) {
               try {
                   ftpClient.logout()
                   ftpClient.disconnect()
                   System.out.println("Đã ngắt kết nối FTP")
               } catch (IOException e) {
                   System.err.println("Lỗi khi ngắt kết nối: " + e.getMessage())
               }
           }
       }
   }
   String downloadFileBase64(String ftpServer) {
       def duLieu = downloadFile(ftpServer)
       return Base64.encoder.encodeToString(duLieu)
   }
   FTPUploadResult transferSingleFile(FTPClient srcFtp, FTPClient destFtp,
                                      String srcDir, String destDir, String fileName) throws IOException {
       String srcPath = srcDir
       String destPath = destDir + "/" + fileName
       int attempt = 0
       boolean success = false
       while (attempt < MAX_RETRY_ATTEMPTS && !success) {
           attempt++
           try (InputStream inputStream = srcFtp.retrieveFileStream(srcPath)) {
               if (inputStream == null) {
                   System.out.println(" Không đọc được file: " + srcPath)
                   srcFtp.completePendingCommand()
                   return new FTPUploadResult(false, " Không đọc được file: " + srcPath, "READ_FILE_FAILED")
               }
               System.out.printf("⬆️ [%d/%d] Đang chuyển: %s%n", attempt, MAX_RETRY_ATTEMPTS, fileName)
               success = destFtp.storeFile(destPath, inputStream)
               srcFtp.completePendingCommand()
               if (success) {
                   System.out.println(" Thành công: " + fileName)
                   return new FTPUploadResult(true, "Upload thành công ", "SUCCESS")
               } else {
                   System.out.println(" Upload lỗi, thử lại...")
                   Thread.sleep(1000)
               }
           } catch (Exception ex) {
               System.out.println("Lỗi khi chuyển file, thử lại...")
               ex.printStackTrace()
               try {
                   Thread.sleep(1000)
               } catch (InterruptedException ignored) {
               }
           }
       }
       if (!success) {
           System.out.println("Thất bại sau " + MAX_RETRY_ATTEMPTS + " lần: " + fileName)
           return new FTPUploadResult(false, "Thất bại sau " + MAX_RETRY_ATTEMPTS + " lần: " + fileName, "READ_FILE_FAILED")
       }
   } 
}
public class FTPUploadResult {
   private boolean success
   private String errorMessage
   private String errorCode
   private long uploadedBytes
   private long totalBytes
   public FTPUploadResult(boolean success, String errorMessage, String errorCode) {
       this.success = success
       this.errorMessage = errorMessage
       this.errorCode = errorCode
   }
   // Getters
   public boolean isSuccess() { return success }
   public String getErrorMessage() { return errorMessage }
   public String getErrorCode() { return errorCode }
   public long getUploadedBytes() { return uploadedBytes }
   public long getTotalBytes() { return totalBytes }
   // Setters
   public void setUploadedBytes(long uploadedBytes) { this.uploadedBytes = uploadedBytes }
   public void setTotalBytes(long totalBytes) { this.totalBytes = totalBytes }
   @Override
   public String toString() {
       if (success) {
           return String.format("Upload thành công: %d/%d bytes", uploadedBytes, totalBytes)
       } else {
           return String.format("Upload thất bại [%s]: %s", errorCode, errorMessage)
       }
   }
}

Link bài viết gốc đây nhé.
Chúc các bạn thành công !

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?