Apache FtpServer在Windows上使用以及SpringBoot中集成apache ftpserver实现Ftp 服务端搭建

news2024/11/15 8:37:46

场景

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,并编辑如下两个地方

  

修改

<file-user-manager file="./res/conf/users.properties" encrypt-passwords="clear"/>

取消密码加密

不然会提示

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项目,添加所需依赖

​
        <!-- https://mvnrepository.com/artifact/org.apache.ftpserver/ftpserver-core -->
        <dependency>
            <groupId>org.apache.ftpserver</groupId>
            <artifactId>ftpserver-core</artifactId>
            <version>1.1.1</version>
        </dependency>

​

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<String, Ftplet> myFtplet = new HashMap<String, Ftplet>();
        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说明

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/505641.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【图】邻接表

目录 无向图的邻接表 链表&#xff08;存相邻顶点下标&#xff09;的类 数组里放的顶点 邻接表&#xff08;操作&#xff09; 构造和析构&#xff08;创建销毁邻接表&#xff09; 插入顶点 插入边 获取下标 插v1、v2之间的边 删除顶点 删除边 输出&#xff1a; 其他…

多种采购方式下,数智化招采系统解决方案(实例)

广发证券成立于1991年&#xff0c;是国内首批综合类证券公司&#xff0c;先后于2010年和2015年在深圳证券交易所及香港联合交易所主板上市。 多年来&#xff0c;广发证券在竞争激烈、复杂多变的行业环境中努力开拓、锐意进取&#xff0c;以卓越的经营业绩、持续完善的全面风险…

Node.js对ES6 及更高版本的支持

目录 1、简介 2、默认情况下什么特性随着 Node.js 一起发布&#xff1f; 3、有哪些特性在开发中&#xff1f; 4、移除这个标记&#xff08;--harmony&#xff09;吗 5、Node.js 对应 V8 引擎 1、简介 Node.js 是针对 V8 引擎构建的。通过与此引擎的最新版本保持同步&…

PMP课堂模拟题目及解析(第5期)

41. 项目的混凝土供应商通知项目经理&#xff0c;材料将比预定时间晚三个星期交付。项目经理更新了进度计划并通知项目团队。在这种情况下&#xff0c;哪种合同类型承担的风 险最小&#xff1f; A. 总价加激励费用合同。 B. 总价加经济价格调整合同。 C. 工料合同。 D. 固…

matlab学习笔记

一、序言 1. 图像的输入输出和显示 fimread("test.png"); frgb2gray(f);%rgb图像转化为灰度图像 imshow(f); imwrite(f,"result.jpg","quality",50);%50代表jpg形式压缩质量0-1002. matlab支持的四种图像类别 灰度级图像(Gray-scale images) …

类和对象【C++】【中篇】

目录 一、类的6个默认成员函数 1、构造函数 2、析构函数 3、拷贝构造函数 4、赋值重载函数 二、赋值运算符重载 一、类的6个默认成员函数 注意&#xff1a;默认成员函数不能在类外面定义成全局函数。因为类里没有的话会自动生成&#xff0c;就会产生冲突。 1、构造函数…

k8s采用ansible安装

一、准备工作 测试服务器 服务器配置进程功能备注192.168.0.189CPU:4核 内存32Gansibleansible一键安装k8s192.168.0.141CPU&#xff1a;12核 内存&#xff1a;10Gdocker&#xff0c;kube-apiserver&#xff0c;etcd&#xff0c;kube-scheduler&#xff0c;kube-controller-m…

产品经理 - 原型图设计软件

原型图设计软件哪个好用&#xff1f;6款好用软件推荐&#xff01; - 知乎 摩客, 墨刀 2014 即时设计是一款支持在线协作的专业级 UI 设计工具&#xff0c;用户数已突破230万&#xff1b; 2021年 5,000万(美元) 国外 axure 老牌 如果有进一步模拟的必要&#xff0c;再换用Ad…

JetPack之lifecycle原理分析

Lifecycle是什么 Lifecycle可以有效的避免内存泄漏和解决android生命周期的常见难题Livecycle 是一个表示android生命周期及状态的对象LivecycleOwner 用于连接有生命周期的对象&#xff0c;如activity,fragmentLivecycleObserver 用于观察查LifecycleOwnerLifecycle框架使用观…

关于SSL证书有效期缩短,看这一篇就够了

在TLS/SSL证书有效期不断被缩短的大趋势下&#xff0c;我们在前文和大家聊了聊企业面临的困境、应对策略及证书自动化管理&#xff0c;今天想和大家继续探讨的是TLS/SSL证书自动化管理切实可行的解决方案。 01 自动化证书管理的重要性 TLS/SSL证书是保障网络连接安全的重要手…

图片位深度以及转换办法

位图文件的格式&#xff1a; ① 位图文件头&#xff0c;所用结构体&#xff1a;BITMAPFILEHEADER&#xff0c;占14个字节 ② 位图信息头&#xff0c;所用结构体&#xff1a;BITMAPINFOHEADER&#xff0c;占40个字节 ③ 颜色表项&#xff0c;所用结构体&#xff1a;RGBQUAD&…

Qt5.14版本通用环境配置安装——最详细教学(看不懂,你怪我)

✨✨✨大家好&#xff0c;我是会飞的鱼-blog&#xff0c;今天我来给大家介绍一下Qt5.14.1安装&#xff0c;有不足之处&#xff0c;请大家多多指教。感谢大家支持&#xff01;&#xff01;&#xff01; 目录 前言 安装文件下载&#xff1a; 安装&#xff1a; 设置 QtCreator…

测试相关记录

1、提测计划、需求拆分、颗粒度 2、线上bug回顾 3、提测流水线 4、测试业绩合同指定

6.2.4图的基本操作 6.3.1图的广度优先遍历 6.3.2图的深度优先遍历

6.2.4图的基本操作 考研里面只考邻接矩阵和邻接表的存储结构 思想较为简单见video 重点理解时间复杂度的遍历原理 6.3.1图的广度优先遍历&#xff08;BFS&#xff09;&#xff08;Breadth first traversal&#xff09; 我们从树的广度优先遍历入手去看图的广度优先遍历的思想 …

【Python入门知识】NumPy 中的随机数及ufuncs函数

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 什么是随机数&#xff1f; 随机数并不意味着每次都有不同的数字。随机意味着无法在逻辑上预测的事物。 伪随机和真随机 计算机在程序上工作&#xff0c;程序是权威的指令集。 因此&#xff0c;这意味着必须有某种算法来…

2路 QSFP,40G 光纤的数据实时采集(5GByte/s 带宽)板卡设计原理图 -PCIE732

板卡概述 PCIE732 是一款基于 PCIE 总线架构的高性能数据传输卡&#xff0c;板卡具有 1 个 PCIex8 主机接口、2 个 QSFP40G 光纤接口&#xff0c;可以实现 2 路 QSFP 40G 光纤的数据实时采集、传输。板卡采用 Xilinx 的高性 能 Kintex UltraScale 系列 FPGA 作为实时处理器…

【鲁棒优化、无功优化】两阶段鲁棒优化的主动配电网动态无功优化【IEEE33节点】(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

网曝快手在离职证明上写:如需背调,只能通过公司指定邮箱,其他渠道均不认可!如何捍卫自己的权益?...

许多公司都喜欢用离职证明拿捏打工人&#xff0c;最近有网友曝光快手在离职证明上做文章&#xff0c;在离职证明上写&#xff1a;如需背调&#xff0c;只能通过公司指定邮箱xxxxkuaishou.com&#xff0c;其他渠道均不认可&#xff01; 楼主问&#xff1a;这种情况如何捍卫自己的…

camunda脚本如何使用

一、camunda脚本有什么用途 在Camunda中&#xff0c;脚本是一种灵活的方式&#xff0c;可以用于在流程定义和表单中编写自定义逻辑。使用脚本&#xff0c;您可以编写JavaScript、Groovy、Python、Ruby等脚本语言中的代码&#xff0c;以实现各种功能。 以下是Camunda脚本的一些…

Shell脚本快速入门

Shell脚本快速入门 1 Hello World2 Shell 变量3 Shell 传递参数4 Shell 基本运算符5 Shell echo命令5 Shell printf 命令6 Shell test 命令7 Shell 流程控制8 Shell 函数9 Shell 输入/输出重定向10 Shell 文件包含参考 1 Hello World 编写脚本文件 test.sh #!/bin/bash echo …