场景

Apache Ftpserver

Apache FtpServer是100%纯Java FTP服务器。它被设计为基于当前可用的开放协议的完整且

可移植的FTP服务器引擎解决方案。FtpServer可以作为Windows服务或Unix / Linux守护程序独立运行,

也可以嵌入Java应用程序中。我们还提供对Spring应用程序内集成的支持,

并以OSGi捆绑软件的形式提供我们的发行版。默认的网络支持基于高性能异步IO库Apache MINA。

使用MINA,FtpServer可以扩展到大量并发用户。

特性

1、100%纯Java,免费的开源可恢复FTP服务器

2、多平台支持和多线程设计。

3、用户虚拟目录,写入权限,空闲超时和上传/下载带宽限制支持。

4、匿名登录支持。

5、上传和下载文件都是可恢复的。

6、处理ASCII和二进制数据传输。

7、支持IP限制以禁止IP。

8、数据库和文件可用于存储用户数据。

9、所有FTP消息都是可定制的。

10、隐式/显式SSL / TLS支持。

11、MDTM支持-您的用户可以更改文件的日期时间戳。

12、“模式Z”支持更快地上传/下载数据。

13、可以轻松添加自定义用户管理器,IP限制器,记录器。

14、可以添加用户事件通知(Ftplet)。

注:

博客:霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主

实现

Apache FtpServer在Windows上下载安装与使用

1、Apache Ftp Server下载

进入apache官网

Apache MINA — Apache MINA

 

点击FtpServer选项

 

选择自己需要下载的版本,比如这里选择1.1.1

然后再进入dist目录,选择zip点击下载

下载之后解压即可。

2、修改用户配置文件

找到res/conf下的users.properties

编辑该文件,是配置ftp用户相关信息的配置文件

# Password is "admin"

ftpserver.user.admin.userpassword=123456

ftpserver.user.admin.homedirectory=D:\\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

修改为上面示例配置,即配置admin账户的密码,文件路径等相关配置。

其他参数为0表示不进行限制,不然可以根据自己需要搜索或者官方源码api中说明进行配置。

3、修改ftpd全局配置文件

找到res/ftpd-typical.xml,并编辑如下两个地方

  

修改

取消密码加密

不然会提示

RECEIVED: PASS *****

导致登录失败。

 

 

再注释掉ssl认证

不然会提示

javax.net.ssl.SSLHandshakeException: SSL handshake failed.  at org.apache.mina.filter.ssl.SslFilter.messageReceived(SslFilter.java:519)

Caused by: javax.net.ssl.SSLHandshakeException: no cipher suites in common

 

 

3、启动ftpserver

 进入到bin目录下,打开cmd输入

.\ftpd.bat res/conf/ftpd-typical.xml

通过走配置文件的方式启动

 

启动成功之后浏览器访问本地ip的2121端口

  

输入上面配置的用户名admin,密码

登录成功之后如上所示。

Ftp 客户端FileZilla使用

FileZilla Ftp客户端工具

客户端 - FileZilla中文网

 

下载对应版本之后,解压即可用

 

进行文件传输测试可用。

SpringBoot中集成Apache FtpServer实现Ftp服务端

1、新建SpringBoot项目,添加所需依赖

       

       

            org.apache.ftpserver

            ftpserver-core

            1.1.1

       

2、新建FTP配置类

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;

/**

 * 配置类

 */

@Configuration

public class FtpConfig 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);

        DataConnectionConfigurationFactory dataConnectionConfigurationFactory=new DataConnectionConfigurationFactory();

        //设置多少时间后关闭一个闲置的链接,单位是秒,0代表不设置

        dataConnectionConfigurationFactory.setIdleTime(60*60*24);

        //设置主动模式端口

        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("users.properties");

            userManagerFactory.setUrl(classPathResource.getURL());

        }

        catch (Exception e){

            throw new RuntimeException("配置文件users.properties不存在");

        }

        userManagerFactory.setPasswordEncryptor(new ClearTextPasswordEncryptor());

        serverFactory.setUserManager(userManagerFactory.createUserManager());

        //配置自定义用户事件

        Map myFtplet = new HashMap();

        myFtplet.put("miaFtplet", new MyFtplet());

        serverFactory.setFtplets(myFtplet);

        //创建FtpServer

        FtpServer server = serverFactory.createServer();

        return server;

    }

}

2、这里的ftp连接端口、ftp主动模式端口、ftp被动模式端口范围从配置文件读取,所以在application.yml中添加配置

ftp:

  port: 200 #ftp连接端口

  activePort: 250 #ftp主动模式端口

  passivePorts: "50021-60021"  #被动连接数据传输端口

3、上面配置类中获取用户配置,读取resources下的文件,所以在resources下新建users.properties

#表示test的密码是123456 以下都是admin的参数设置,可以多个

ftpserver.user.test.userpassword=123456

ftpserver.user.test.homedirectory=C:\\ftpFile

ftpserver.user.test.enableflag=true

ftpserver.user.test.writepermission=true

ftpserver.user.test.maxloginnumber=0

ftpserver.user.test.maxloginperip=0

ftpserver.user.test.idletime=0

ftpserver.user.test.uploadrate=0

ftpserver.user.test.downloadrate=0

4、配置类中还对用户事件进行自定义

新建MyFtplet并继承DefaultFtplet,对会话连接、断连、登录、上传文件等事件进行自定义处理事件

import org.apache.ftpserver.ftplet.*;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import java.io.File;

import java.io.IOException;

import java.net.InetSocketAddress;

import java.util.UUID;

public class MyFtplet extends DefaultFtplet {

    public static final Logger log= LoggerFactory.getLogger(MyFtplet.class);

    @Override

    public FtpletResult onLogin(FtpSession session, FtpRequest request) throws FtpException, IOException {

        try {

            User user = session.getUser();

            String requestLine = request.getRequestLine();

            String name = user.getName();

            log.info("用户:'{}'登录成功,requestLine:'{}'", name, requestLine);

        }catch (Exception exception){

            log.error("用户:'{}'登录异常:{}", session.toString(),exception.toString());

        }

        return super.onLogin(session, request);

    }

    @Override

    public FtpletResult onConnect(FtpSession session) throws FtpException, IOException {

        try {

            UUID sessionId = session.getSessionId();

            InetSocketAddress clientAddress = session.getClientAddress();

            String hostString = clientAddress.getHostString();

            log.info("用户:'{}',hostString:'{}',建立连接", sessionId, hostString);

        }catch (Exception exception){

            log.error("用户:'{}',建立连接异常:{}", session.toString(),exception.toString());

        }

        return super.onConnect(session);

    }

    @Override

    public FtpletResult onDisconnect(FtpSession session) throws FtpException, IOException {

        try{

            String name = session.getUser().getName();

            String hostString = session.getClientAddress().getHostString();

            log.info("用户:'{}',hostString:'{}',断开连接", name, hostString);

        }catch (Exception exception){

            log.error("用户:'{}',断开连接异常:{}", session.toString(),exception.toString());

        }

        return super.onDisconnect(session);

    }

    /**

     *

     *  开始上传

     * Override this method to intercept uploads

     * @param session The current {@link FtpSession}

     * @param request The current {@link FtpRequest}

     * @return The action for the container to take

     * @throws FtpException

     * @throws IOException

     */

    @Override

    public FtpletResult onUploadStart(FtpSession session, FtpRequest request) throws FtpException, IOException {

        try {

            //获取上传文件的上传路径

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

        }catch (Exception exception){

            log.error("用户:'{}',上传文件异常:{}", session.toString(),exception.toString());

        }

        return super.onUploadStart(session, request);

    }

    /**

     *  上传完成

     * Override this method to handle uploads after completion

     * @param session The current {@link FtpSession}

     * @param request The current {@link FtpRequest}

     * @return The action for the container to take

     * @throws FtpException

     * @throws IOException

     */

    @Override

    public FtpletResult onUploadEnd(FtpSession session, FtpRequest request) throws FtpException, IOException {

        try {

            //获取上传文件的上传路径

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

        }catch (Exception exception){

            log.error("用户:'{}',上传文件结束异常:{}", session.toString(),exception.toString());

        }

        return super.onUploadEnd(session, request);

    }

}

5、启动应用,并连接和上传文件测试

连接并登录成功进入回调

 

文件上传成功进入回调

 

6、配置类相关配置含义可以查询官方源码以及demo等查看

官网下载源码版压缩包

 

 查看api说明

 

参考链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。