SpringBoot使用hutool操作FTP的詳細(xì)過程
項(xiàng)目場(chǎng)景:
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>實(shí)現(xiàn)步驟:
1、引入依賴
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.9.0</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.15</version>
</dependency>2、yml配置
ftp: # 服務(wù)器地址 host: 127.0.0.1 # 端口號(hào) port: 21 # 用戶名 userName: test # 密碼 password: test
3、Config配置類
我這里用的是static修飾的變量,方便工具類調(diào)用。
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* ftp配置
*/
@Configuration
public class FtpConfig {
/**
* 服務(wù)器地址
*/
private static String host;
/**
* 端口
*/
private static Integer port;
/**
* 用戶名
*/
private static String userName;
/**
* 密碼
*/
private static String password;
@Value("${ftp.host}")
public void setHost(String host) {
FtpConfig.host = host;
}
public static String getHost() {
return host;
}
@Value("${ftp.port}")
public void setPort(Integer port) {
FtpConfig.port = port;
}
public static Integer getPort() {
return port;
}
@Value("${ftp.userName}")
public void setUserName(String userName) {
FtpConfig.userName = userName;
}
public static String getUserName() {
return userName;
}
@Value("${ftp.password}")
public void setPassword(String password) {
FtpConfig.password = password;
}
public static String getPassword() {
return password;
}
}4、 FtpUtil工具類
import cn.hutool.core.io.FileUtil;
import cn.hutool.extra.ftp.Ftp;
import cn.hutool.extra.ftp.FtpMode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.net.ftp.FTPFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* FTP服務(wù)工具類
*/
@Slf4j
public class FtpUtil {
/**
* 獲取 FTPClient對(duì)象
*/
private static Ftp getFTPClient() {
try {
if(StringUtils.isBlank(FtpConfig.getHost()) || FtpConfig.getPort() == null
|| StringUtils.isBlank(FtpConfig.getUserName()) || StringUtils.isBlank(FtpConfig.getPassword())) {
throw new RuntimeException("ftp配置信息不能為空");
}
Ftp ftp = new Ftp(FtpConfig.getHost(),FtpConfig.getPort(),FtpConfig.getUserName(),FtpConfig.getPassword());
//設(shè)置為被動(dòng)模式,防止防火墻攔截
ftp.setMode(FtpMode.Passive);
return ftp;
} catch (Exception e) {
e.printStackTrace();
log.error("獲取ftp客戶端異常",e);
throw new RuntimeException("獲取ftp客戶端異常:"+e.getMessage());
}
}
/**
* 下載ftp服務(wù)器上的文件到本地
* @param remoteFile ftp上的文件路徑
* @param localFile 輸出的目錄,使用服務(wù)端的文件名
*/
public static void download(String remoteFile, String localPath) {
if(StringUtils.isBlank(remoteFile) || StringUtils.isBlank(localPath)) {
return;
}
Ftp ftp = getFTPClient();
try {
if(!FileUtil.exist(localPath)){
FileUtil.mkdir(localPath);
}
File lFile = FileUtil.file(localPath);
ftp.download(remoteFile, lFile);
} catch (Exception e) {
e.printStackTrace();
log.error("FTP文件下載異常",e);
} finally {
//關(guān)閉連接
try {
if(ftp != null) ftp.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* 本地文件上傳到ftp服務(wù)器上
* @param remoteDir 上傳的ftp目錄
* @param remoteFileName 保存到ftp服務(wù)器上的名稱
* @param localFile 本地文件全名稱
*/
public static boolean upload(String remoteDir, String remoteFileName, String localFile) {
if(StringUtils.isBlank(remoteDir) || StringUtils.isBlank(remoteFileName) || StringUtils.isBlank(localFile)) {
return false;
}
Ftp ftp = getFTPClient();
try {
File lFile = FileUtil.file(localFile);
if(!lFile.exists()) {
log.error("本地文件不存在");
return false;
}
if(StringUtils.isBlank(remoteFileName)) {
return ftp.upload(remoteDir, lFile);
} else {
return ftp.upload(remoteDir, remoteFileName, lFile);
}
} catch (Exception e) {
e.printStackTrace();
log.error("文件上傳FTP異常",e);
return false;
} finally {
//關(guān)閉連接
try {
if(ftp != null) ftp.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* 刪除FTP服務(wù)器中的文件
* @param remoteFile ftp上的文件路徑
*/
public static boolean delFile(String remoteFile) {
if(StringUtils.isBlank(remoteFile)) {
return false;
}
Ftp ftp = getFTPClient();
try {
return ftp.delFile(remoteFile);
} catch (Exception e) {
e.printStackTrace();
log.error("刪除FTP服務(wù)器中的文件異常",e);
return false;
} finally {
//關(guān)閉連接
try {
if(ftp != null) ftp.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/**
* 遍歷某個(gè)目錄下所有文件,不會(huì)遞歸遍歷
* @param path 目錄
*/
public static List<String> listFile(String path) {
List<String> listFile = new ArrayList<>();
Ftp ftp = getFTPClient();
try {
FTPFile[] ftpFiles = ftp.lsFiles(path);
for (int i = 0; i < ftpFiles.length; i++) {
FTPFile ftpFile = ftpFiles[i];
if(ftpFile.isFile()){
listFile.add(ftpFile.getName());
}
}
return listFile;
} catch (Exception e) {
e.printStackTrace();
log.error("遍歷某個(gè)目錄下所有文件異常",e);
return null;
} finally {
//關(guān)閉連接
try {
if(ftp != null) ftp.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
}5、測(cè)試
@RestController
@RequestMapping("/test")
public class TestController {
@RequestMapping(value = "ftpTest", method = RequestMethod.GET)
public void ftpTest() {
//上傳文件到ftp
FtpUtil.upload("opt/upload","APP_RELATION.sql", "F:/APP_RELATION.sql");
//下載遠(yuǎn)程文件
FtpUtil.download("opt/upload/APP_RELATION.sql", "D:/");
//刪除遠(yuǎn)程文件
FtpUtil.delFile("opt/upload/APP_RELATION.sql");
}
}總結(jié):
上傳的時(shí)候碰到一個(gè)問題,就是本地開啟防火墻時(shí),上傳的文件大小是0kb,必須要關(guān)了防火墻才正常,后來FTP模式設(shè)置為“被動(dòng)模式”解決。
//設(shè)置為被動(dòng)模式,防止防火墻攔截 ftp.setMode(FtpMode.Passive);
主動(dòng)模式(Active Mode):
- 工作原理:客戶端在本地打開一個(gè)非特權(quán)端口(通常大于1023),并通過這個(gè)端口發(fā)送PORT命令給服務(wù)器,告訴服務(wù)器客戶端用于數(shù)據(jù)傳輸?shù)亩丝谔?hào)。然后,服務(wù)器使用其20端口(數(shù)據(jù)端口)主動(dòng)連接到客戶端指定的端口進(jìn)行數(shù)據(jù)傳輸。
- 安全性:由于服務(wù)器需要主動(dòng)連接到客戶端的端口,這可能引發(fā)一些安全問題,特別是當(dāng)客戶端位于防火墻或NAT設(shè)備后面時(shí)。
- 適用場(chǎng)景:適用于客戶端位于可以接受入站連接的網(wǎng)絡(luò)環(huán)境,且沒有防火墻或NAT設(shè)備限制的場(chǎng)景。
被動(dòng)模式(Passive Mode):
- 工作原理:客戶端發(fā)送PASV命令給服務(wù)器,服務(wù)器在本地打開一個(gè)端口(通常是高位的非特權(quán)端口),并通過PASV命令的響應(yīng)告訴客戶端這個(gè)端口號(hào)。然后,客戶端主動(dòng)連接到服務(wù)器指定的這個(gè)端口進(jìn)行數(shù)據(jù)傳輸。
- 安全性:由于客戶端主動(dòng)連接到服務(wù)器,這種模式更適合于客戶端位于防火墻或NAT設(shè)備后面的場(chǎng)景,因?yàn)檫@些設(shè)備通常允許出站連接但限制入站連接。
- 適用場(chǎng)景: 特別適用于網(wǎng)絡(luò)環(huán)境不穩(wěn)定、存在防火墻或NAT設(shè)備的場(chǎng)景。
到此這篇關(guān)于SpringBoot使用hutool操作FTP的文章就介紹到這了,更多相關(guān)SpringBoot使用hutool內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的示例代碼
這篇文章主要介紹了Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01
mybatis學(xué)習(xí)之路mysql批量新增數(shù)據(jù)的方法
這篇文章主要介紹了mybatis學(xué)習(xí)之路mysql批量新增數(shù)據(jù)的方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02
Java 利用binarySearch實(shí)現(xiàn)抽獎(jiǎng)計(jì)算邏輯
這篇文章主要介紹了Java 利用binarySearch實(shí)現(xiàn)抽獎(jiǎng)計(jì)算邏輯,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-12-12
struts2實(shí)現(xiàn)簡(jiǎn)單文件下載功能
這篇文章主要為大家詳細(xì)介紹了struts2實(shí)現(xiàn)簡(jiǎn)單文件下載功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
JMeter連接Mysql數(shù)據(jù)庫(kù)的實(shí)現(xiàn)步驟
本文主要介紹了JMeter操作Mysql數(shù)據(jù)庫(kù),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12

