最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot集成FTP上傳文件功能實現(xiàn)

 更新時間:2025年08月22日 10:06:07   作者:齊 飛  
文章介紹了FTP和SFTP的區(qū)別,強調(diào)SFTP基于SSH加密更安全,且使用單一端口,同時說明Spring Boot集成FTP上傳需配置依賴、文件類、對象池及懶加載機制,以實現(xiàn)高效文件傳輸與資源管理,本文重點給大家介紹SpringBoot集成FTP上傳文件功能實現(xiàn),感興趣的朋友一起看看吧

FTP是什么?

文件傳輸協(xié)議(英語:File Transfer Protocol,縮寫:FTP)是一個用于在計算機網(wǎng)絡(luò)上在客戶端和服務(wù)器之間進行文件傳輸?shù)膽?yīng)用層協(xié)議。

SFTP 和 FTP 的區(qū)別

SFTP 和 FTP 是兩種不同的文件傳輸協(xié)議,它們在安全性、連接方式和功能上有顯著差異。

FTP(File Transfer Protocol)

  • 使用明文傳輸數(shù)據(jù),包括用戶名和密碼。
  • 需要兩個端口:控制端口(21)和數(shù)據(jù)端口(20)。
  • 不支持加密,容易被中間人攻擊。
  • 支持匿名登錄和主動/被動模式。

SFTP(SSH File Transfer Protocol)

  • 基于 SSH 協(xié)議,所有數(shù)據(jù)傳輸均加密。
  • 僅使用單一端口(默認 22),簡化防火墻配置。
  • 支持文件操作(如重命名、刪除)和目錄列表。
  • 無需額外配置,依賴 SSH 服務(wù)即可使用。

SpringBoot集成FTP上傳文件

pom依賴

        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.6</version>
        </dependency>

配置文件

ftp:
  host: host.test
  port: 21
  username: ftptest01
  password: xxxxxx
  path: /var/ftp/test/
  outlink: https://host.test
  filePath: /test/
  encoding: utf-8
  maxActive: 100
  minIdel: 2
  maxIdel: 5
  maxWaitMillis: 3000
  passivemode: true

配置類

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
 * @author qf
 * @version 1.0
 * @data 2025/7/20 18:28
 */
@Data
@Component
@ConfigurationProperties(prefix = "ftp")
public class FTPConfig {
    private String host;
    private Integer port;
    private String username;
    private String password;
    private String encoding;
    private Integer maxActive;
    private Integer minIdel;
    private Integer maxIdel;
    private Integer maxWaitMillis;
    private Boolean passivemode;
    private String outlink;
    private String filePath;
    private String path;
}

對象池的創(chuàng)建與管理

import lombok.extern.log4j.Log4j2;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
 * @author qf
 * @version 1.0
 * @data 2025/7/20 18:34
 */
@Log4j2
@Component
public class FtpClientFactory implements PooledObjectFactory<FTPClient> {
    @Autowired
    private FTPConfig ftpConfig;
    /**
     * 創(chuàng)建連接放入池中
     *
     * @return
     * @throws Exception
     */
    @Override
    public PooledObject<FTPClient> makeObject() throws Exception {
        FTPClient ftpClient = new FTPClient();
        //ftpClient.setControlEncoding(ftpConfig.getEncoding());
        ftpClient.setConnectTimeout(ftpConfig.getMaxWaitMillis());
        try {
            ftpClient.connect(ftpConfig.getHost(), ftpConfig.getPort());
            int replyCode = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                ftpClient.disconnect();
                log.warn("FTP服務(wù)拒絕鏈接");
                return null;
            }
            boolean login = ftpClient.login(ftpConfig.getUsername(), ftpConfig.getPassword());
            if (!login) {
                log.warn("ftpClient登入失敗,username:{" + ftpConfig.getUsername() + "},password:{" + ftpConfig.getPassword() + "}");
                throw new RuntimeException("ftpClient登入失敗,username:{" + ftpConfig.getUsername() + "},password:{" + ftpConfig.getPassword() + "}");
            }
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.setBufferSize(1024);
            if (ftpConfig.getPassivemode()) {
                ftpClient.enterLocalPassiveMode();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        log.info("添加一個FtpClient進入連接池");
        return new DefaultPooledObject<>(ftpClient);
    }
    @Override
    public void destroyObject(PooledObject<FTPClient> pooledObject) throws Exception {
        FTPClient ftpClient = pooledObject.getObject();
        try {
            if (ftpClient != null && ftpClient.isConnected()) {
                ftpClient.logout();
            }
        } catch (IOException e) {
            throw new RuntimeException("沒有獲取到FtpClient或已斷開連接:", e);
        } finally {
            try {
                ftpClient.disconnect();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 連接狀態(tài)檢查
     *
     * @param pooledObject
     * @return
     */
    @Override
    public boolean validateObject(PooledObject<FTPClient> pooledObject) {
        FTPClient ftpClient = pooledObject.getObject();
        try {
            return ftpClient.sendNoOp();
        } catch (IOException e) {
            log.info("無法驗證FtpClient {}", e.getMessage());
            return false;
        }
    }
    @Override
    public void activateObject(PooledObject<FTPClient> pooledObject) throws Exception {
    }
    @Override
    public void passivateObject(PooledObject<FTPClient> pooledObject) throws Exception {
    }
    public FTPConfig getConfig() {
        return this.ftpConfig;
    }
}

PooledObjectFactory 是 Apache Commons Pool 2 庫中的一個核心接口,它定義了用于創(chuàng)建和管理池化對象(即那些可以被多個客戶端重復(fù)使用的對象)生命周期的方法。通過實現(xiàn)這個接口,可以定制化對象的創(chuàng)建、激活、驗證和銷毀等過程,從而更好地控制對象池的行為。
其中:

  • PooledObject makeObject() throws Exception
  • 創(chuàng)建一個新的實例,并將其包裝在一個 PooledObject 實例中返回。這是用來生成新的池對象的方法。
  • void destroyObject(PooledObject p) throws Exception
  • 銷毀指定的池對象。當(dāng)對象池決定不再需要某個對象時,會調(diào)用此方法來清理資源。
  • boolean validateObject(PooledObject p)
  • 驗證池中的某個對象是否仍然有效。如果返回 true,則認為該對象可以繼續(xù)使用;否則,可能需要重新創(chuàng)建或銷毀該對象。
  • void activateObject(PooledObject p) throws Exception
  • 當(dāng)從池中借用對象之前調(diào)用,用于“激活”對象,比如重置狀態(tài)等操作。
  • void passivateObject(PooledObject p) throws Exception

當(dāng)對象歸還到池后調(diào)用,用于將對象置于“鈍化”狀態(tài),通常涉及清理工作以準備下次使用。

FTP連接池初始化

import lombok.extern.log4j.Log4j2;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
 * @author qf
 * @version 1.0
 * @data 2025/7/20 18:47
 */
@Lazy
@Log4j2
@Component
public class FtpClientPool {
    private FtpClientFactory factory;
    private final GenericObjectPool<FTPClient> internalPool;
    /**
     * 初始化連接池
     */
    public FtpClientPool(@Autowired FtpClientFactory factory) {
        log.info("**********************初始化Ftp連接池*********************");
        this.factory = factory;
        FTPConfig config = factory.getConfig();
        GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
        poolConfig.setMaxTotal(config.getMaxActive());
        poolConfig.setMinIdle(config.getMinIdel());
        poolConfig.setMaxIdle(config.getMaxIdel());
        poolConfig.setMaxWaitMillis(config.getMaxWaitMillis());
        this.internalPool = new GenericObjectPool<FTPClient>(factory, poolConfig);
        this.internalPool.setTestOnBorrow(true);
        log.info("連接池配置:{}", config.toString());
        log.info("*********************初始化Ftp連接池完畢*******************");
    }
    /**
     * 獲取FTPClient
     * @return
     */
    public FTPClient getFTPClient(){
        try {
            log.info("從連接池中獲取FtpClient");
            return internalPool.borrowObject();
        } catch (Exception e) {
            log.error("從連接池獲取FTPClient失敗!");
            return null;
        }
    }
    /**
     * 歸還連接
     * @param ftpClient
     */
    public void returnFTPClient(FTPClient ftpClient) {
        try {
            ftpClient.getStatus();
            log.info("歸還FtpClient:" + ftpClient);
            internalPool.returnObject(ftpClient);
        } catch (IOException e) {
            log.info("移除過期ftpClient {}", e.getMessage());
            try {
                internalPool.invalidateObject(ftpClient);
            } catch (Exception ex) {
                log.info("移除過期ftpClient失敗 {}", e.getMessage());
            }
        }
    }
    /**
     * 銷毀連接池
     */
    public void destory() {
        log.info("*********************close FtpPool**********************");
        internalPool.close();
    }
}

FTP工具類

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
/**
 * @author qf
 * @version 1.0
 * @data 2025/7/20 18:47
 */
@Lazy
@Slf4j
@Component
public class FTPClientUtil {
    @Autowired
    private FtpClientPool pool;
    /**
     * 上傳文件
     *
     * @param file
     * @param path
     * @return
     * @throws IOException
     */
    public Boolean upload(MultipartFile file, String path) throws IOException {
        FTPClient ftpClient = pool.getFTPClient();
        InputStream inputStream = null;
        Boolean result = false;
        try {
            inputStream = file.getInputStream();
            createDir(ftpClient, path);
            result = ftpClient.storeFile(path, inputStream);
            log.info("文件{},服務(wù)器路徑{},上傳結(jié)果result:{}", file.getOriginalFilename(), path, result);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            inputStream.close();
            pool.returnFTPClient(ftpClient);
        }
        return result;
    }
    /**
     * 創(chuàng)建文件夾
     *
     * @param ftpClient
     * @param path
     * @return
     * @throws IOException
     */
    private Boolean createDir(FTPClient ftpClient, String path) throws IOException {
        Boolean flag = false;
        String substring = path.substring(path.indexOf("/") + 1, path.lastIndexOf("/"));
        ftpClient.changeWorkingDirectory("/");
        //boolean b = ftpClient.changeWorkingDirectory(substring);
        String[] split = substring.split("/");
        for (String s : split) {
            flag = ftpClient.makeDirectory(s);
            boolean changeFlag=ftpClient.changeWorkingDirectory(s);
            log.info("目錄:{},創(chuàng)建目錄結(jié)果:{},切換目錄結(jié)果:{}",s,flag,changeFlag);
        }
        ftpClient.changeWorkingDirectory("/");
        return flag;
    }
}

這里因為項目部署在多個服務(wù)器中,而有一些環(huán)境不使用ftp,因此使用懶加載的方式。
示例:

     @Lazy
     @Autowired
     private FTPClientUtil ftpClientUtil;

Controller

import com.qf.util.ftp.FTPClientUtil;
import com.qf.util.ftp.FTPConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.UUID;
/**
 * @author qf
 * @version 1.0
 * @data 2025/7/20 19:36
 */
@Slf4j
@RestController
@RequestMapping("api")
public class TestController {
    @Autowired
    private FTPConfig ftpConfig;
    @Autowired
    private FTPClientUtil ftpClientUtil;
    @PostMapping(value = "/uploadExcelFile",headers = "content-type=multipart/form-data")
    public Boolean uploadImgFile(@RequestParam("file") MultipartFile file) throws IOException {
        String path = ftpConfig.getPath();
        String originalFilename = file.getOriginalFilename();
        String fileSuffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        String fileId = UUID.randomUUID().toString().replace("-", "");
        String newFileName = fileId + fileSuffix;
        String filePath = path + newFileName;
        Boolean flag = ftpClientUtil.upload(file, filePath);
        return flag;
    }
}

到此這篇關(guān)于SpringBoot集成FTP上傳文件功能實現(xiàn)的文章就介紹到這了,更多相關(guān)springboot ftp上傳文件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JAVA程序內(nèi)存溢出問題原因分析

    JAVA程序內(nèi)存溢出問題原因分析

    這篇文章主要介紹了JAVA程序內(nèi)存溢出問題原因,較為詳細的分析java導(dǎo)致程序內(nèi)存溢出的原因與解決方法,需要的朋友可以參考下
    2015-06-06
  • 使用Java構(gòu)造和解析Json數(shù)據(jù)的兩種方法(詳解一)

    使用Java構(gòu)造和解析Json數(shù)據(jù)的兩種方法(詳解一)

    JSON(JavaScript Object Notation) 是一種輕量級的數(shù)據(jù)交換格式,采用完全獨立于語言的文本格式,是理想的數(shù)據(jù)交換格式。接下來通過本文給大家介紹使用Java構(gòu)造和解析Json數(shù)據(jù)的兩種方法,需要的朋友參考下吧
    2016-03-03
  • mybatis動態(tài)拼接實現(xiàn)有條件的插入

    mybatis動態(tài)拼接實現(xiàn)有條件的插入

    這篇文章主要介紹了mybatis動態(tài)拼接實現(xiàn)有條件的插入,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • JAVA各種加密與解密方式總結(jié)大全

    JAVA各種加密與解密方式總結(jié)大全

    這篇文章主要給大家介紹了關(guān)于JAVA各種加密與解密方式總結(jié)的相關(guān)資料,加密是指對原來為明文的文件或數(shù)據(jù)按某種算法進行處理,使其成為不可讀的一段代碼,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-07-07
  • IDEA配置Maven教程的超詳細講解版

    IDEA配置Maven教程的超詳細講解版

    IntelliJ IDEA是當(dāng)前最流行的Java IDE(集成開發(fā)環(huán)境)之一,也是業(yè)界公認最好用的Java開發(fā)工具之一,這篇文章主要給大家介紹了關(guān)于IDEA配置Maven教程的超詳細講解版,需要的朋友可以參考下
    2023-11-11
  • Java實現(xiàn)Base64圖片轉(zhuǎn)URL的完整方案

    Java實現(xiàn)Base64圖片轉(zhuǎn)URL的完整方案

    這篇文章主要介紹了如何使用Java實現(xiàn)Base64格式圖片轉(zhuǎn)換為可訪問的URL鏈接的過程,包括數(shù)據(jù)有效性校驗、圖片壓縮、方向信息校正以及阿里云OSS存儲對接,核心實現(xiàn)代碼涵蓋了從獲取Base64圖片數(shù)據(jù)到上傳OSS的完整流程,需要的朋友可以參考下
    2025-11-11
  • IDEA maven依賴錯誤中包下面紅色波浪線

    IDEA maven依賴錯誤中包下面紅色波浪線

    這篇文章主要介紹了IDEA maven依賴錯誤中包下面紅色波浪線,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 解決SpringBoot請求返回字符串中文亂碼的問題

    解決SpringBoot請求返回字符串中文亂碼的問題

    這篇文章主要介紹了解決SpringBoot請求返回字符串中文亂碼的問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • Feign 使用HttpClient和OkHttp方式

    Feign 使用HttpClient和OkHttp方式

    這篇文章主要介紹了Feign 使用HttpClient和OkHttp方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • Spring Boot 3.5.3新特性解析及JDK21集成實戰(zhàn)應(yīng)用

    Spring Boot 3.5.3新特性解析及JDK21集成實戰(zhàn)應(yīng)用

    Spring Boot 3.5.3作為關(guān)鍵補丁版本,不僅修復(fù)了此前版本中的棘手回歸問題,更深度整合JDK21特性,為高并發(fā)與云原生應(yīng)用帶來突破性提升,本文將深入解析其核心技術(shù)亮點及實戰(zhàn)應(yīng)用,感興趣的朋友跟隨小編一起看看吧
    2025-08-08

最新評論

综艺| 太谷县| 石楼县| 恩施市| 乐安县| 南澳县| 苍梧县| 应城市| 富裕县| 南涧| 鄂尔多斯市| 防城港市| 平顶山市| 土默特左旗| 左云县| 云龙县| 新兴县| 许昌市| 精河县| 当涂县| 乌拉特前旗| 客服| 剑阁县| 承德县| 个旧市| 临朐县| 灵石县| 聊城市| 佛坪县| 宁海县| 舟曲县| 湖州市| 荣成市| 大足县| 布尔津县| 尤溪县| 昭平县| 区。| 巨鹿县| 南乐县| 万年县|