Java操作FTP實現上傳下載功能

FTP簡介

文件傳輸協議(File Transfer Protocol,FTP)是用於在網絡上進行文件傳輸的一套標準協議,它工作在 OSI 模型的第七層,TCP 模型的第四層, 即應用層, 使用 TCP 傳輸而不是 UDP, 客戶在和服務器建立連接前要經過一個“三次握手”的過程, 保證客戶與服務器之間的連接是可靠的, 而且是面向連接, 為數據傳輸提供可靠保證。

FTP也是一個應用程序,基於不同的操作系統有不同的FTP應用程序,而所有這些應用程序都遵守同一種協議以傳輸文件。可以使用FTP進行下載和上傳。

文件傳送協議FTP(File Transfer Protocol)是Internet上使用比較廣泛的文件傳送協議。FTP提供交互式的訪問,允許客戶指明文件的類型與格式,並允許文件具有存取權限。FTP屏蔽瞭各種計算機系統的細節,因此適用於在異構網絡中任意計算機之間傳送文件。它的基本應用就是將文件從一臺計算機復制到另一臺計算機中。它要存取一個文件,就必須先獲得一個本地文件的副本,如果修改文件,也隻能對文件的副本進行修改,然後再將修改後的文件副本傳回到原節點。

您隻要記住幾個關鍵詞:交互式、存取權限和副本。

簡單文件傳送協議TFTP(Trivial File Transfer Protocol)是一個小而易於實現的文件傳送協議。TFTP是基於UDP數據報,需要有自己的差錯改正措施。TFTP隻支持文件傳輸,不支持交互,沒有龐大的命令集。也沒有目錄列表功能,以及不能對用戶進行身份鑒別。但它的代碼所占內存較小,不需要硬盤就可以固化TFTP代碼,很適合較小的計算機和特殊用途的設備。

您會發現TFTP和FTP一個主要的區別就是它沒有交互式,且不進行身份驗證。

FTP的客戶可以是任意平臺

FTP標準端口:

  • 20 數據接口
  • 21 指令接口

FTP架構

FTP監聽於TCP的21號端口,是一種C/S架構的應用程序。在Linux中常用的服務端軟件和客戶端軟件一般如下表所示:

FTP數據連接模式

FTP有2種數據連接模式:命令連接和數據連接

  • 命令連接:是指文件管理類命令,始終在線的持久性連接,直到用戶退出登錄為止(可以簡單的理解為建立連接)
  • 數據連接:是指數據傳輸,按需創建及關閉的連接(可以簡單的理解為傳輸數據)

數據連接需要關註的點有:

1.數據傳輸格式

  • 文件傳輸
  • 二進制傳輸

2.數據傳輸模式

  • 主動模式:由服務器端創建數據連接
  • 被動模式:由客戶端創建數據連接

兩種數據傳輸模式的建立過程:

1.主動模式

命令連接(建立連接通道)

Client端以一個1024以上的隨機端口(端口號大於1023小於65535)來連接Server端的21號端口

數據連接(傳輸數據)

Server端以20號端口去連接Client創建命令連接時使用的隨機端口+1的端口

示例:

命令連接:Client(9527)–> Server(21),數據連接:Server(20/tcp) –> Client(9527+1)

2.被動模式

命令連接

Client以一個1024以上的隨機端口號(端口號大於1023小於65535)來連接Server端的21號端口,命令連接建立完畢後,Server端會告知Client端用於創建數據連接的隨機端口號(端口號大於1023小於65535)

數據連接

Client以創建命令連接時使用的隨機端口號+1去連服務器端通過命令連接告知自己的一個隨機端口號來創建數據連接

示例:

命令連接:Client(9527) –> Server(21),數據連接:Client(9527+1) –> Server(隨機端口)

註意:

主動模式存在弊端,因為客戶端的端口是隨機的,客戶端如果開瞭防火墻,則服務器端去連客戶端創建數據連接時可能會被拒絕

用戶認證

Ftp的用戶認證主要有三種:

1.虛擬用戶:僅用於訪問某特定服務中的資源

虛擬用戶通過ftp訪問的資源位置為給虛擬用戶指定的映射成為的系統用戶的傢目錄

2.系統用戶:可以登錄系統的真實用戶(出於對安全性的考慮,這種認證很少使用)

系統用戶通過ftp訪問的資源位置為用戶的傢目錄

3.匿名用戶

匿名用戶(映射為ftp用戶)的共享資源位置是/var/ftp

服務端

  • /etc/pam.d/vsftpd #vsftpd用戶認證配置文件
  • /etc/vsftpd/ #配置文件目錄
  • /etc/vsftpd/vsftpd.conf #主配置文件
  • vsftpd常見的配置參數

客戶端

lftp工具 支持指定用戶名和密碼登錄

Vsftp安裝與配置

在linux環境下,使用最多的FTP服務端軟件就是Vsftpd!

安裝Vsftpd,運行一下命令需要在root用戶下進行!

yum install vsftpd 安裝
yum remove vsftpd 卸載

啟動服務

啟動服務 service vsftpd start 或者 systemctl start vsftpd.service  

重啟服務 systemctl restart vsftpd.service 

停止服務 systemctl stop vsftpd.service 

設置開機自啟動  systemctl enable vsftpd.service    

配置文件說明

/etc/vsftpd/vsftpd.conf 這個文件是vsftpd服務的核心配置文件!

我們在修改配置文件的時候,最好先備份一份!

cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak

/etc/vsftpd/ftpusers這個文件是禁止使用vsftpd的用戶列表文件。記錄不允許訪問FTP服務器的用戶名單,管理員可以把一些對系統安全有威脅的用戶賬號記錄在此文件中,以免用戶從FTP登錄後獲得大於上傳下載操作的權利,而對系統造成損壞。

/etc/vsftpd/user_list這個文件禁止或允許使用vsftpd的用戶列表文件。這個文件中指定的用戶缺省情況(即在/etc/vsftpd/vsftpd.conf中設置userlist_deny=YES)下也不能訪問FTP服務器,在設置瞭userlist_deny=NO時,僅允許user_list中指定的用戶訪問FTP服務器。

註意配置文件中的值一定不要有空格

# Example config file /etc/vsftpd/vsftpd.conf
#
#
# 禁止匿名登錄
anonymous_enable=NO
# 是否允許本地用戶(即linux系統中的用戶帳號)登錄FTP服務器,默認設置為YES允許
# 本地用戶登錄後會進入用戶主目錄,而匿名用戶登錄後進入匿名用戶的下載目錄/var/ftp/pub
# 若隻允許匿名用戶訪問,前面加上 #註釋掉即可阻止本地用戶訪問FTP服務器
local_enable=YES
#
# 是否允許本地用戶對FTP服務器文件具有寫權限,默認設置為YES允許
write_enable=YES
#
# 掩碼,本地用戶默認掩碼為077
# 你可以設置本地用戶的文件掩碼為缺省022,也可根據個人喜好將其設置為其他值
local_umask=022
#
# 是否允許匿名用戶上傳文件,須將全局的write_enable=YES。默認為YES
#anon_upload_enable=YES
#
#是否允許匿名用戶創建新文件夾
#anon_mkdir_write_enable=YES

# 是否激活目錄歡迎信息功能
# 當用戶用CMD模式首次訪問服務器上某個目錄時,FTP服務器將顯示歡迎信息
# 默認情況下,歡迎信息是通過該目錄下的.message文件獲得的
# 此文件保存自定義的歡迎信息,由用戶自己建立
dirmessage_enable=YES
#
# 是否讓系統自動維護上傳和下載的日志文件
# 默認情況該日志文件為/var/log/vsftpd.log,也可以通過下面的xferlog_file選項對其進行設定
# 默認值為NO
xferlog_enable=YES
#
# 是否設定FTP服務器將啟用FTP數據端口的連接請求
# ftp-data數據傳輸,21為連接控制端口
connect_from_port_20=YES
#
# 設定是否允許改變上傳文件的屬主,與下面一個設定項配合使用
# 註意,不推薦使用root用戶上傳文件
#chown_uploads=YES
# 設置想要改變的上傳文件的屬主,如果需要,則輸入一個系統用戶名
# 可以把上傳的文件都改成root屬主。whoever:任何人
#chown_username=whoever
#
# 設定系統維護記錄FTP服務器上傳和下載情況的日志文件
#xferlog_file=/var/log/xferlog
#
#如果你想,你可以有一個標準的ftpd xferlog格式的日志文件。
#註意默認的日志文件位置是/var/log/xferlog。
xferlog_std_format=YES
#
#您可以更改默認值,以使空閑會話超時。
#idle_session_timeout=600
#
# #您可以更改數據連接超時的默認值。
#data_connection_timeout=120
#
#運行vsftpd需要的非特權系統用戶,缺省是nobody
#nopriv_user=ftpsecure
#
# 是否識別異步ABOR請求。
# 如果FTP client會下達“async ABOR”這個指令時,這個設定才需要啟用
# 而一般此設定並不安全,所以通常將其取消
#async_abor_enable=YES
#
# 是否以ASCII方式傳輸數據。默認情況下,服務器會忽略ASCII方式的請求。
# 啟用此選項將允許服務器以ASCII方式傳輸數據
# 不過,這樣可能會導致由"SIZE /big/file"方式引起的DoS攻擊
#ascii_upload_enable=YES
#ascii_download_enable=YES

# 登錄FTP服務器時顯示的歡迎信息
# 如有需要,可在更改目錄歡迎信息的目錄下創建名為.message的文件,並寫入歡迎信息保存後
#ftpd_banner=Welcome to blah FTP service.

# 黑名單設置。如果很討厭某些email address,就可以使用此設定來取消他的登錄權限
# 可以將某些特殊的email address抵擋住。
#deny_email_enable=YES

# 當上面的deny_email_enable=YES時,可以利用這個設定項來規定哪些郵件地址不可登錄vsftpd服務器
# 此文件需用戶自己創建,一行一個email address即可
#banned_email_file=/etc/vsftpd/banned_emails

# You may specify an explicit list of local users to chroot() to their home
# directory. If chroot_local_user is YES, then this list becomes a list of
# users to NOT chroot().
# (Warning! chroot'ing can be very dangerous. If using chroot, make sure that
# the user does not have write access to the top level directory within the
# chroot)
chroot_local_user=YES

#  允許 chroot 用戶具備寫權限
allow_writeable_chroot=YES
#當chroot_list_enable=YES,chroot_local_user=YES時,在/etc/vsftpd.chroot_list文件中列出的用戶,可以切換到其他目錄;未在文件中列出的用戶,不能切換到其他目錄。
#當chroot_list_enable=YES,chroot_local_user=NO時,在/etc/vsftpd.chroot_list文件中列出的用戶,不能切換到其他目錄;未在文件中列出的用戶,可以切換到其他目錄。
#當chroot_list_enable=NO,chroot_local_user=YES時,所有的用戶均不能切換到其他目錄。
#當chroot_list_enable=NO,chroot_local_user=NO時,所有的用戶均可以切換到其他目錄。
chroot_list_enable=YES

# 被列入此文件的用戶,在登錄後將不能切換到自己目錄以外的其他目錄
# 從而有利於FTP服務器的安全管理和隱私保護。此文件需自己建立
#chroot_list_file=/etc/vsftpd/chroot_list
#
# 是否允許遞歸查詢。默認為關閉,以防止遠程用戶造成過量的I/O
#ls_recurse_enable=YES
#
# 是否允許監聽。
# 如果設置為YES,則vsftpd將以獨立模式運行,由vsftpd自己監聽和處理IPv4端口的連接請求
listen=YES
#
# 設定是否支持IPV6。如要同時監聽IPv4和IPv6端口,
# 則必須運行兩套vsftpd,采用兩套配置文件
# 同時確保其中有一個監聽選項是被註釋掉的
# listen_ipv6=NO

# 設置是否阻扯user_list文件中的用戶登錄FTP服務器,默認為YES
#userlist_deny=YES/NO

# 設置PAM外掛模塊提供的認證服務所使用的配置文件名,即/etc/pam.d/vsftpd文件
# 此文件中file=/etc/vsftpd/ftpusers字段,說明瞭PAM模塊能抵擋的帳號內容來自文件/etc/vsftpd/ftpusers中
pam_service_name=vsftpd

# 是否允許ftpusers文件中的用戶登錄FTP服務器,默認為NO
# 若此項設為YES,則user_list文件中的用戶允許登錄FTP服務器
# 而如果同時設置瞭userlist_deny=YES,則user_list文件中的用戶將不允許登錄FTP服務器,甚至連輸入密碼提示信息都沒有
userlist_enable=YES
# 是否使用tcp_wrappers作為主機訪問控制方式。
# tcp_wrappers可以實現linux系統中網絡服務的基於主機地址的訪問控制
# 在/etc目錄中的hosts.allow和hosts.deny兩個文件用於設置tcp_wrappers的訪問控制
# 前者設置允許訪問記錄,後者設置拒絕訪問記錄。
# 如想限制某些主機對FTP服務器192.168.57.2的匿名訪問,編緝/etc/hosts.allow文件,如在下面增加兩行命令:
# vsftpd:192.168.57.1:DENY 和vsftpd:192.168.57.9:DENY
# 表明限制IP為192.168.57.1/192.168.57.9主機訪問IP為192.168.57.2的FTP服務器
# 此時FTP服務器雖可以PING通,但無法連接
tcp_wrappers=YES

#開啟被動模式
pasv_enable=YES
# 傳輸文件的端口范圍,如果是雲服務器記得開放端口,linux服務器本身也要開放端口
pasv_min_port=9000
pasv_max_port=9005

傳輸模式配置

開啟被動模式:

connect_from_port_20=NO(默認為YES) #設置是否允許主動模式
pasv_enable=YES(默認為YES) #設置是否允許被動模式
pasv_min_port=50000(default:0(use any port))
pasv_max_port=60000(default:0(use any port))

開啟主動模式:

connect_from_port_20=YES
pasv_enable=NO

系統用戶配置

linux創建用戶:

useradd -d /home/ftp/compass -s /sbin/nologin  compass
passwd compass

為虛擬用戶創建傢目錄

mkdir -p /home/ftp/compass

設置權限

chown -R compass:compass /home/ftp/compass

配置selinux允許ftp訪問home和外網訪問

[root@master ~]# setsebool -P allow_ftpd_full_access on
[root@master ~]# setsebool -P tftp_home_dir on

重啟vsftpd服務

[root@master ~]# systemctl restart vsftpd

無法登錄的情況 在/etc/vsftpd/vsftpd.conf配置文件中添加瞭以下兩句

    chroot_local_user=YES  #原本就有,取掉註釋就好
    allow_writeable_chroot=YES   #添加
    chown compass:compass -R /home/ftp/compass

java操作ftp文件服務器

有時候,我們需要接收用戶上傳的文件存儲到服務器,然後保存起來,下次用戶可以直接下載,或者是保存為檔案,我這裡提供三個方法,一個是上傳文件到ftp,還有就是從ftp下載文件,還有就是刪除ftp服務器刪的文件

1.引入依賴

       <!--    ftp上傳下載-->
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.7</version>
        </dependency>

2.提供接口

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;

/**
 * ftp文件服務器操作接口
 *
 * @author compass
 * @date 2022/10/19 15:00
 * @since 1.0.0
 **/
public interface FtpService {

    /**
     * 上傳文件到ftp
     *
     * @param inputStream 輸入流
     * @param fileName    新的文件名,包含拓展名
     * @param filePath    保存路徑
     * @return
     * @author compass
     */
    Boolean uploadFile(InputStream inputStream, String fileName, String filePath);

    /**
     * 下載ftp文件,直接轉到輸出流
     * @author compass
     * @param ftpFilePath
     * @author compass
     */
    byte[] downloadFileBytes(String ftpFilePath, HttpServletResponse response);

    /**
     * 刪除ftp文件
     * @author compass
     * @param ftpFilePath ftp下文件路徑,根目錄開始
     * @return
     */
    Boolean deleteFile(String ftpFilePath);
}

3.對提供操作ftp接口進行實現

/**
 * @author compass
 * @date 2022-10-19
 * @since 1.0
 **/

import java.io.*;

import compass.token.pocket.com.common.AjaxResult;
import compass.token.pocket.com.entity.FtpInstanceEntity;
import compass.token.pocket.com.service.FtpService;
import compass.token.pocket.com.utils.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
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.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;

@Slf4j
@Service
public class FtpServiceImpl implements FtpService {

    @Resource
    FtpInstanceEntity ftpInstanceEntity;

    /**
     * 上傳文件到ftp
     *
     * @param inputStream 輸入流
     * @param fileName    新的文件名,包含拓展名
     * @param filePath    保存路徑
     * @return
     * @author compass
     */
    @Override
    public Boolean uploadFile(InputStream inputStream, String fileName, String filePath) {
        // 定義保存結果
        boolean isSuccess = false;
        // 初始化連接
        FTPClient ftp = connectFtpServer();
        if (ftp != null) {
            try {
                // 設置文件傳輸模式為二進制,可以保證傳輸的內容不會被改變
                ftp.setFileType(FTP.BINARY_FILE_TYPE);
                //註:上傳文件都為0字節,設置為被動模式即可
                ftp.enterLocalPassiveMode();
                // 跳轉到指定路徑,逐級跳轉,不存在的話就創建再進入
                toPathOrCreateDir(ftp, filePath);
                // 上傳文件 參數:上傳後的文件名,輸入流,,返回Boolean類型,上傳成功返回true
                isSuccess = ftp.storeFile(fileName, inputStream);
                // 關閉輸入流
                inputStream.close();
                // 退出ftp
                ftp.logout();
            } catch (IOException e) {
                log.error(e.toString());
            } finally {
                if (ftp.isConnected()) {
                    try {
                        // 斷開ftp的連接
                        ftp.disconnect();
                    } catch (IOException ioe) {
                        log.error(ioe.toString());
                    }
                }
            }
        }
        return isSuccess;
    }

    /**
     * 下載ftp文件,直接轉到輸出流
     *
     * @param ftpFilePath
     * @author compass
     */
    @Override
    public byte[] downloadFileBytes(String ftpFilePath , HttpServletResponse response) {
        FTPClient ftp = connectFtpServer();
        try {
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftp.enterLocalPassiveMode();
            boolean retrieveFile = ftp.retrieveFile(ftpFilePath, stream);
            if (!retrieveFile){
                throw new RuntimeException("FTP文件下載失敗");
            }
            ftp.logout();
            return stream.toByteArray();
        } catch (Exception e) {
            log.error("FTP文件下載失敗!" + e.toString());
            ResponseUtil.response(response,AjaxResult.businessError(e.getMessage(), "-1"));
            throw new RuntimeException(e.getMessage());
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                    log.error(ioe.toString());
                }
            }

        }
    }

    /**
     * 刪除ftp文件
     * @param ftpFilePath 文件路徑
     * @return java.lang.Boolean
     * @author compass
     * @date 2022/10/19 18:35
     * @since 1.0.0
     **/
    @Override
    public Boolean deleteFile(String ftpFilePath ) {
        FTPClient ftp = connectFtpServer();
        boolean result = false;
        try {
            result = ftp.deleteFile(ftpFilePath);
            ftp.logout();
            return result;
        } catch (Exception e) {
            log.error("FTP文件刪除失敗!" + e.toString());
        } finally {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException ioe) {
                    log.error(ioe.toString());
                }
            }
        }
        return result;
    }

    /**
     * 創建FTPClient對象
     *
     * @return org.apache.commons.net.ftp.FTPClient
     * @author compass
     * @date 2022/10/19 18:35
     * @since 1.0.0
     **/
    private FTPClient connectFtpServer() {
        // 創建FTPClient對象(對於連接ftp服務器,以及上傳和上傳都必須要用到一個對象)
        FTPClient ftpClient = new FTPClient();
        // 設置連接超時時間
        ftpClient.setConnectTimeout(1000 * 10);
        // 設置ftp字符集
        ftpClient.setControlEncoding("utf-8");
        // 設置被動模式,文件傳輸端口設置,否則文件上傳不成功,也不報錯
        ftpClient.enterLocalPassiveMode();
        try {
            // 定義返回的狀態碼
            int replyCode;
            // 連接ftp(當前項目所部署的服務器和ftp服務器之間可以相互通訊,表示連接成功)
            ftpClient.connect(ftpInstanceEntity.getHost());
            // 輸入賬號和密碼進行登錄
            ftpClient.login(ftpInstanceEntity.getUsername(), ftpInstanceEntity.getPassword());
            // 接受狀態碼(如果成功,返回230,如果失敗返回503)
            replyCode = ftpClient.getReplyCode();
            // 根據狀態碼檢測ftp的連接,調用isPositiveCompletion(reply)-->如果連接成功返回true,否則返回false
            if (!FTPReply.isPositiveCompletion(replyCode)) {
                log.info("connect ftp {} failed", ftpInstanceEntity.getHost());
                // 說明連接失敗,需要斷開連接
                ftpClient.disconnect();
                throw new RuntimeException(String.format("connect ftp %s failed", ftpInstanceEntity.getHost()));
            }
            log.info("連接狀態碼:" + replyCode);
        } catch (IOException e) {
            log.error("connect fail:" + e.toString());
            throw new RuntimeException(String.format("connect ftp %s error", ftpInstanceEntity.getHost()));
        }
        return ftpClient;
    }

    /**
     * 跳轉到指定路徑 不存在就創建
     *
     * @param ftp      操作ftp對象
     * @param filePath 文件路徑
     * @return void
     * @author compass
     * @date 2022/10/19 15:05
     * @since 1.0.0
     **/
    private void toPathOrCreateDir(FTPClient ftp, String filePath) throws IOException {
        String[] dirs = filePath.split("/");
        for (String dir : dirs) {
            if (StringUtils.isEmpty(dir)) {
                continue;
            }
            if (!ftp.changeWorkingDirectory(dir)) {
                ftp.makeDirectory(dir);
                ftp.changeWorkingDirectory(dir);
            }
        }
    }

}

4.配置ftp相關參數

在配置文件中配置連接ftp服務器的配置

ftp:
  #ftp服務器的地址
  host: 127.0.0.1
  #ftp服務器的端口號(連接端口號)
  port: 21
  #ftp的用戶名
  username: compass
  #ftp的密碼
  password: 6317738ef8324199a24602308f3a9a18
  #ftp上傳的根目錄
  basePath: /home/ftp/compass
  #回顯地址
  httpPath: ftp://127.0.0.1

然後將配置文件的內容讀取到一個bean裡面

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "ftp")
public class FtpInstanceEntity {
    /**
     * ftp服務器的地址
     */
    private String host;
    /**
     * ftp服務器的端口號(連接端口號)
     */
    private String port;
    /**
     * ftp的用戶名
     */
    private String username;
    /**
     * ftp的密碼
     */
    private String password;
    /**
     * ftp上傳的根目錄
     */
    private String basePath;
    /**
     * 回顯地址
     */
    private String httpPath;

}

5.寫測試controller

package compass.token.pocket.com.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import compass.token.pocket.com.common.AjaxResult;
import compass.token.pocket.com.entity.FtpInstanceEntity;
import compass.token.pocket.com.service.FtpService;
import compass.token.pocket.com.utils.FileUtils;
import compass.token.pocket.com.utils.ResponseUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 文件測試控制器
 * @author compass
 * @date 2022/10/27 22:41
 * @since 1.0.0
 **/
@Slf4j
@RestController
@RequestMapping("/fileTestController")
public class FileTestController {

    @Resource
    private FtpService ftpService;

    @Resource
    FtpInstanceEntity ftpInstanceEntity;


    /**
     * ftp服務器文件上傳
     * @param file 需要上傳的文件
     * @return compass.token.pocket.com.common.AjaxResult<java.lang.String>
     * @author compass
     * @date 2022/10/19 14:51
     * @since 1.0.0
     **/
    @PostMapping(value = "/pdfUpload")
    public AjaxResult<String> pdfUpload(@RequestParam("file") MultipartFile file) {
        try {
            String fileDir = DateUtil.format(new Date(), "yyyy-MM-dd");
            boolean upload = ftpService.uploadFile(file.getInputStream(), file.getOriginalFilename(), fileDir);
            if (upload) {
                String savePath = ftpInstanceEntity.getBasePath() + "/" + fileDir + "/" + file.getOriginalFilename();
                return AjaxResult.success("上傳成功", savePath);
            } else {
                return new AjaxResult<>("file upload error");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new AjaxResult<>("file upload error");
    }

    /**
     * ftp服務器文件下載
     * @param ftpPath 需要下載的文件路徑
     * @return compass.token.pocket.com.common.AjaxResult<java.lang.String>
     * @author compass
     * @date 2022/10/19 14:51
     * @since 1.0.0
     **/
    @GetMapping(value = "/pdfDownload", produces = "application/octet-stream")
    public void downloadFile(@RequestParam("ftpPath") String ftpPath, HttpServletRequest request, HttpServletResponse response) {
        String userAgent = request.getHeader("User-Agent");
        String fileName = ftpPath.substring(ftpPath.lastIndexOf('/') + 1);
        try {
            if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
                //IE瀏覽器處理
                fileName = URLEncoder.encode(fileName, "UTF-8");
            } else {
                // 非IE瀏覽器的處理:
                fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
            }
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
            response.setContentType("application/octet-stream; charset=UTF-8");
            byte[] bytes = ftpService.downloadFileBytes( ftpPath,response);
            ServletOutputStream outputStream = response.getOutputStream();
            outputStream.write(bytes);
            outputStream.flush();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * ftp服務器文件刪除
     * @param ftpPath 需要刪除的文件路徑
     * @return compass.token.pocket.com.common.AjaxResult<java.lang.Boolean>
     * @author compass
     * @date 2022/10/19 14:51
     * @since 1.0.0
     **/
    @PostMapping("ftpDeleteFile")
    public AjaxResult<Boolean> ftpDeleteFile(@RequestParam("ftpPath") String ftpPath){
        Boolean isSuccess = ftpService.deleteFile(ftpPath);
        if (isSuccess){
             return  AjaxResult.success("刪除成功", true);
        }else {
            return  AjaxResult.businessError("刪除失敗", false);
        }

    }

}

到這裡操作ftp文件服務器的基本操作差不多結束瞭,講的不是特別詳細,但是基本來說,夠用,如果遇到不能解決的問題請自行百度。

以上就是Java操作FTP實現上傳下載功能的詳細內容,更多關於Java FTP上傳下載的資料請關註WalkonNet其它相關文章!

推薦閱讀: