SpringBoot使用hutool操作FTP的详细过程

 更新时间:2024年09月25日 09:33:21   作者:涛哥是个大帅比  
在使用SpringBoot结合hutool操作FTP时,遇到防火墙导致上传文件大小为0kb的问题,通过设置FTP为被动模式解决,本文详细解析了FTP的主动模式和被动模式的工作原理、安全性及适用场景,帮助理解FTP的连接方式和解决网络限制问题

项目场景:

<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>

实现步骤:

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:
  # 服务器地址
  host: 127.0.0.1
  # 端口号
  port: 21
  # 用户名
  userName: test
  # 密码
  password: test

3、Config配置类

 我这里用的是static修饰的变量,方便工具类调用。

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
 * ftp配置
 */
@Configuration
public class FtpConfig {
    /**
     * 服务器地址
     */
    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服务工具类
 */
@Slf4j
public class FtpUtil {
    /**
     * 获取 FTPClient对象
     */
    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());
            //设置为被动模式,防止防火墙拦截
            ftp.setMode(FtpMode.Passive);
            return ftp;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("获取ftp客户端异常",e);
            throw new RuntimeException("获取ftp客户端异常:"+e.getMessage());
        }
    }
    /**
     * 下载ftp服务器上的文件到本地
     * @param remoteFile    ftp上的文件路径
     * @param localFile     输出的目录,使用服务端的文件名
     */
    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 {
            //关闭连接
            try {
                if(ftp != null)  ftp.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
    /**
     * 本地文件上传到ftp服务器上
     * @param remoteDir 上传的ftp目录
     * @param remoteFileName  保存到ftp服务器上的名称
     * @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 {
            //关闭连接
            try {
                if(ftp != null)  ftp.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
    /**
     * 删除FTP服务器中的文件
     * @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服务器中的文件异常",e);
            return false;
        } finally {
            //关闭连接
            try {
                if(ftp != null)  ftp.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
    /**
     * 遍历某个目录下所有文件,不会递归遍历
     * @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("遍历某个目录下所有文件异常",e);
            return null;
        } finally {
            //关闭连接
            try {
                if(ftp != null)  ftp.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

5、测试 

@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");
		//下载远程文件
		FtpUtil.download("opt/upload/APP_RELATION.sql", "D:/");
		//删除远程文件
		FtpUtil.delFile("opt/upload/APP_RELATION.sql");
	}
}

总结:

上传的时候碰到一个问题,就是本地开启防火墙时,上传的文件大小是0kb,必须要关了防火墙才正常,后来FTP模式设置为“被动模式”解决。

//设置为被动模式,防止防火墙拦截
ftp.setMode(FtpMode.Passive);

主动模式(Active Mode):

  • 工作原理:客户端在本地打开一个非特权端口(通常大于1023),并通过这个端口发送PORT命令给服务器,告诉服务器客户端用于数据传输的端口号。然后,服务器使用其20端口(数据端口)主动连接到客户端指定的端口进行数据传输。
  • 安全性:由于服务器需要主动连接到客户端的端口,这可能引发一些安全问题,特别是当客户端位于防火墙或NAT设备后面时。
  • 适用场景:适用于客户端位于可以接受入站连接的网络环境,且没有防火墙或NAT设备限制的场景。

被动模式(Passive Mode): 

  • 工作原理:客户端发送PASV命令给服务器,服务器在本地打开一个端口(通常是高位的非特权端口),并通过PASV命令的响应告诉客户端这个端口号。然后,客户端主动连接到服务器指定的这个端口进行数据传输。
  • 安全性:由于客户端主动连接到服务器,这种模式更适合于客户端位于防火墙或NAT设备后面的场景,因为这些设备通常允许出站连接但限制入站连接。
  • 适用场景: 特别适用于网络环境不稳定、存在防火墙或NAT设备的场景。

到此这篇关于SpringBoot使用hutool操作FTP的文章就介绍到这了,更多相关SpringBoot使用hutool内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot之整合MyBatis实现CRUD方式

    SpringBoot之整合MyBatis实现CRUD方式

    这篇文章主要介绍了SpringBoot之整合MyBatis实现CRUD方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • java web请求和响应中出现中文乱码问题的解析

    java web请求和响应中出现中文乱码问题的解析

    这篇文章主要为大家解析了java web请求和响应中出现中文乱码问题,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-10-10
  • Java使用Apache compress实现文件夹压缩成Zip包

    Java使用Apache compress实现文件夹压缩成Zip包

    Apache common提供了很多实用的工具包,这篇文章主要来和大家介绍一下Java如何使用Apache compress包实现文件夹压缩成Zip包,希望对大家有所帮助
    2024-01-01
  • SpringBoot整合Redis之编写RedisConfig

    SpringBoot整合Redis之编写RedisConfig

    RedisConfig需要对redis提供的两个Template的序列化配置,所以本文为大家详细介绍了SpringBoot整合Redis如何编写RedisConfig,需要的可以参考下
    2022-06-06
  • SSH框架网上商城项目第6战之基于DataGrid的数据显示

    SSH框架网上商城项目第6战之基于DataGrid的数据显示

    SSH框架网上商城项目第6战之基于DataGrid的数据显示,提供了丰富的选择、排序、分组和编辑数据的功能支持,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • SpringBoot 对象存储 MinIO的详细过程

    SpringBoot 对象存储 MinIO的详细过程

    MinIO 是一个基于 Go 实现的高性能、兼容 S3 协议的对象存储,它适合存储海量的非结构化的数据,这篇文章主要介绍了SpringBoot 对象存储 MinIO,需要的朋友可以参考下
    2023-07-07
  • 关于Java中的 JSP 详解

    关于Java中的 JSP 详解

    JSP 代表 Java 服务器页面。它是一种在应用服务器端使用的编程工具。JSP 基本上用于支持平台–独立和动态的方法来构建 Web 依赖的应用程序。JSP 页面类似于 ASP 页面,因为它们是在服务器上编译的,而不是在用户的 Web 浏览器上进行编译。下面来看看文章的详细介绍内容
    2021-11-11
  • 浅谈基于Token的WEB后台认证机制

    浅谈基于Token的WEB后台认证机制

    这篇文章主要介绍了浅谈基于Token的WEB后台认证机制,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-12-12
  • Java如何连接数据库图文教程

    Java如何连接数据库图文教程

    关于java数据库的文章早已是非常多了,本文是对我个人过往学习java数据库,理解及应用java数据库的一个总结,下面这篇文章主要给大家介绍了关于Java如何连接数据库的相关资料,需要的朋友可以参考下
    2023-04-04
  • Java项目中如何引入Hutool工具类并正确使用它

    Java项目中如何引入Hutool工具类并正确使用它

    Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,这篇文章主要给大家介绍了关于Java项目中如何引入Hutool工具类并正确使用它的相关资料,需要的朋友可以参考下
    2024-01-01

最新评论