• springboot快速搭建ftpserver服务端


    前言

    基于springboot,使用ftpserver快速搭建一个FTP服务端。

    搭建过程很简单,我们把过程分成4个步骤,一分钟内快速完成构建。

    实现功能

    1. 使用ftpserver快速搭建一个FTP服务端
    2. 支持多个用户多个目录上传目录
    3. 支持FTP主动模式(单个端口)和被动模式(范围随机端口)
    4. 监听ftpserver状态,方便进行更细粒度权限控制等定制功能

    依赖项

    gradle方式:

     implementation 'org.apache.ftpserver:ftpserver-core:1.2.0'
    

    maven方式

    <dependency>
        <groupId>org.apache.ftpservergroupId>
        <artifactId>ftpserver-coreartifactId>
        <version>1.2.0version>
    dependency>
    

    配置文件

    首先,在springboot项目中增加两个配置,创建ftpserver.properties配置和在application.properties基础上增加ftp配置。配置如下:

    1、ftpserver.properties配置

    #表示admin的密码是12345,以下都是admin的参数设置,可以设置多个用户
    ftpserver.user.admin.userpassword=eguid
    ftpserver.user.admin.homedirectory=C://ftp
    ftpserver.user.admin.enableflag=true
    ftpserver.user.admin.writepermission=true
    ftpserver.user.admin.maxloginnumber=0
    ftpserver.user.admin.maxloginperip=0
    ftpserver.user.admin.idletime=0
    ftpserver.user.admin.uploadrate=0
    ftpserver.user.admin.downloadrate=0
    #用户名是eguid的用户配置
    ftpserver.user.eguid.userpassword=eguid
    ftpserver.user.eguid.homedirectory=C://ftp/eguid
    ftpserver.user.eguid.enableflag=true
    ftpserver.user.eguid.writepermission=true
    ftpserver.user.eguid.maxloginnumber=0
    ftpserver.user.eguid.maxloginperip=0
    ftpserver.user.eguid.idletime=0
    ftpserver.user.eguid.uploadrate=0
    ftpserver.user.eguid.downloadrate=0
    

    2、application.properties配置

    在原有application.properties基础上增加以下配置

    ##FTP内嵌服务器
    #ftp连接端口
    ftp.port=8021
    # ftp主动模式端口
    ftp.activePort=8022
    #ftp被动模式数据传输端口
    ftp.passivePorts=50021-60021
    

    初始化FTP服务

    该类继承自ApplicationRunner类,会在springboot服务启动后自动启动。
    由于没有考虑到springboot重启的情况,所以ftp服务会出现无法释放端口的问题,解决该问题请参考博主另一篇文章《springboot内嵌ftpserver服务端在服务重启后报错端口被占用解决办法》,就可以解决跟随springboot重启ftp服务的问题。

    import org.apache.ftpserver.FtpServer;
    import org.apache.ftpserver.ftplet.FtpException;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import org.springframework.stereotype.Component;
    
    /**
     * 初始化ftp服务器
     * @author 汤姆猫不是猫
     */
    @Component
    public class InitFtpServer implements ApplicationRunner {
    
        public static final Logger log = LoggerFactory.getLogger(InitFtpServer.class);
    
        @Autowired
        private FtpServer server;
    
        @Override
        public void run(ApplicationArguments args) throws Exception {
            try {
                server.start();
                log.info("汤姆猫不是猫: ftp server start success ");
            } catch (FtpException e) {
                e.printStackTrace();
                log.error("汤姆猫不是猫: ftp server start error {}", e);
    
            }
        }
    }
    

    ftpserver服务主动模式和被动模式参数配置

    
    import org.apache.ftpserver.DataConnectionConfigurationFactory;
    import org.apache.ftpserver.FtpServer;
    import org.apache.ftpserver.FtpServerFactory;
    import org.apache.ftpserver.ftplet.Ftplet;
    import org.apache.ftpserver.listener.ListenerFactory;
    import org.apache.ftpserver.usermanager.ClearTextPasswordEncryptor;
    import org.apache.ftpserver.usermanager.PropertiesUserManagerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cache.annotation.CachingConfigurerSupport;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.core.io.ClassPathResource;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * ftpserver配置,含主动模式和被动模式
     * @author 汤姆猫不是猫
     */
    @Configuration
    public class FtpServerConfig extends CachingConfigurerSupport {
    
        @Value("${ftp.port}")
        private Integer ftpPort;
    
        @Value("${ftp.activePort}")
        private Integer ftpActivePort;
    
        @Value("${ftp.passivePorts}")
        private String ftpPassivePorts;
        
        @Bean
        public FtpServer createFtpServer() {
            FtpServerFactory serverFactory = new FtpServerFactory();
    
            ListenerFactory factory = new ListenerFactory();
            //这个只是控制端口,还有主动模式端口和被动模式下的某个范围端口
            factory.setPort(ftpPort);
            factory.setIdleTimeout(10);
            //被动模式
            DataConnectionConfigurationFactory dataConnectionConfigurationFactory = new DataConnectionConfigurationFactory();
            dataConnectionConfigurationFactory.setIdleTime(30);
            dataConnectionConfigurationFactory.setActiveLocalPort(ftpActivePort);//主动模式端口
            dataConnectionConfigurationFactory.setPassiveIpCheck(true);
            dataConnectionConfigurationFactory.setPassivePorts(ftpPassivePorts);被动模式使用的端口范围
    
            factory.setDataConnectionConfiguration(dataConnectionConfigurationFactory.createDataConnectionConfiguration());
            // 替换默认的监听器
            serverFactory.addListener("default", factory.createListener());
    
            PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();
            try {
                ClassPathResource classPathResource = new ClassPathResource("ftpserver.properties");
                userManagerFactory.setUrl(classPathResource.getURL());
            } catch (Exception e) {
                throw new RuntimeException("汤姆猫不是猫:配置文件ftpserver.properties不存在");
            }
    
            userManagerFactory.setPasswordEncryptor(new ClearTextPasswordEncryptor());
            serverFactory.setUserManager(userManagerFactory.createUserManager());
    
            Map<String, Ftplet> m = new HashMap<String, Ftplet>();
            m.put("miaFtplet", new FtpServerListener());
    
            serverFactory.setFtplets(m);
            // 创建ftpserver
            FtpServer server = serverFactory.createServer();
            return server;
        }
    }
    
    

    监听ftp服务运行状态

    import org.apache.ftpserver.ftplet.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.UUID;
    
    /**
     * 监听ftpserver服务上传和下载情况
     * @author 汤姆猫不是猫
     */
    public class FtpServerListener extends DefaultFtplet {
    
        public static final Logger log = LoggerFactory.getLogger(FtpServerListener.class);
    
        /**
         * 开始连接
         */
        @Override
        public FtpletResult onConnect(FtpSession session) throws FtpException,
                IOException {
            UUID sessionId = session.getSessionId();
            if(sessionId!=null) {
                log.info("{}尝试登录ftpserver", sessionId.toString());
            }
            User user = session.getUser();
            if(user!=null&&user.getName()!=null){
                log.info("{}尝试使用用户名:{},密码:{}登录ftpserver.", sessionId.toString(), user.getName(), user.getPassword());
            }
            return super.onConnect(session);
        }
    
        /**
         * 关闭连接
         */
        @Override
        public FtpletResult onDisconnect(FtpSession session) throws FtpException,
                IOException {
            UUID sessionId = session.getSessionId();
            if(sessionId!=null) {
                log.info("{}关闭ftpserver连接", sessionId.toString());
            }
            User user = session.getUser();
            if(user!=null&&user.getName()!=null){
                log.info("{}用户名:{}关闭ftpserver连接.",  sessionId.toString(), user.getName());
            }
            return super.onDisconnect(session);
        }
    
        /**
         * 开始上传
         */
        @Override
        public FtpletResult onUploadStart(FtpSession session, FtpRequest request)
                throws FtpException, IOException {
            //获取上传文件的上传路径
            String path = session.getUser().getHomeDirectory();
            //自动创建上传路径
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            //获取上传用户
            String name = session.getUser().getName();
            //获取上传文件名
            String filename = request.getArgument();
    
            log.info("用户:'{}',上传文件到目录:'{}',文件名称为:'{}',状态:开始上传~", name, path, filename);
            return super.onUploadEnd(session, request);
        }
    
        /**
         * 上传完成
         */
        @Override
        public FtpletResult onUploadEnd(FtpSession session, FtpRequest request)
                throws FtpException, IOException {
            //获取上传文件的上传路径
            String path = session.getUser().getHomeDirectory();
            //获取上传用户
            String name = session.getUser().getName();
            //获取上传文件名
            String filename = request.getArgument();
    
            File file = new File(path + "/" + filename);
            if (file.exists()) {
                System.out.println(file);
            }
    
            log.info("用户:'{}',上传文件到目录:'{}',文件名称为:'{},状态:成功!'", name, path, filename);
            return super.onUploadStart(session, request);
        }
    
        @Override
        public FtpletResult onDownloadStart(FtpSession session, FtpRequest request) throws FtpException, IOException {
            return super.onDownloadStart(session, request);
        }
    
        @Override
        public FtpletResult onDownloadEnd(FtpSession session, FtpRequest request) throws FtpException, IOException {
            return super.onDownloadEnd(session, request);
        }
    
    }
    

    以上步骤完成后,启动springboot。使用ftpclient工具尝试连接配置文件里的8021控制端口,如以下图所示,可以看到已经连接成功。
    ftp服务连接成功
    end


    以上就是全部搭建过程,是不是很简单。如果觉得博主写得还不错,欢迎“关注、点赞、收藏”一键三连!


  • 相关阅读:
    Windows10下Vmware开机蓝屏解决办法,亲测有效
    一个基于.Net+Vue开发的开源权限工作流系统
    springboot+旅游管理系统 毕业设计-附源码261117
    【数据结构】P1 线性表+顺序表
    Linux --必备指令集
    经典算法题12-贪心算法
    【Vue组件间通信】 全局事件总线、订阅与发布
    观察者模式:包工头的救赎
    git上传项目的基本步骤与一些问题
    docker基础命令
  • 原文地址:https://blog.csdn.net/eguid/article/details/127125088