代码
添加依赖:
<dependency>
<groupId>org.apache.ftpserver</groupId>
<artifactId>ftpserver-core</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.ftpserver</groupId>
<artifactId>ftplet-api</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.0.16</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.21</version>
</dependency>
新建类
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.setting.Setting;
import org.apache.ftpserver.DataConnectionConfigurationFactory;
import org.apache.ftpserver.FtpServer;
import org.apache.ftpserver.FtpServerFactory;
import org.apache.ftpserver.ftplet.Authority;
import org.apache.ftpserver.ftplet.FtpException;
import org.apache.ftpserver.ftplet.Ftplet;
import org.apache.ftpserver.listener.Listener;
import org.apache.ftpserver.listener.ListenerFactory;
import org.apache.ftpserver.usermanager.impl.BaseUser;
import org.apache.ftpserver.usermanager.impl.WritePermission;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author :
* @date : 2023/5/10
*/
/**
* 正式服务
* 注意:被@Configuration标记的类会被加入ioc容器中,而且类中所有带 @Bean注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例。
* ftp服务访问地址:
* ftp://localhost:3131/
* 端口号3131等配置信息写在ftpserver.setting文件中
*/
@Component
public class LekangFtpServer {
private static final Log log = LogFactory.get();
private static FtpServer server;
//我们这里利用spring加载@Configuration的特性来完成ftp server的初始化
public LekangFtpServer() throws FtpException {
initFtp();
// log.info("Apache ftp server is already instantiation complete!");
}
/**
* ftp server init
*/
public static void initFtp() throws FtpException {
//使用hutool读取FTP默认配置
Setting ftpinfo = new Setting("ftpserver.setting");
//获取端口
Integer port = ftpinfo.getStr("port")!=null?Integer.valueOf(ftpinfo.getStr("port")):null;
//被动模式端口
String passivePorts = ftpinfo.getStr("passivePorts");
//用户名称
String username = ftpinfo.getStr("username");
//用户密码
String password = ftpinfo.getStr("password");
//空闲时间
Integer idleTime =ftpinfo.getStr("idleTime")!=null?Integer.valueOf(ftpinfo.getStr("idleTime")):null;
//上传速率限制
Integer uploadrate =ftpinfo.getStr("uploadrate")!=null?Integer.valueOf(ftpinfo.getStr("uploadrate")):null;
//上传路径
String basedir = ftpinfo.getStr("basedir");
//ftpserver配置
FtpServerFactory serverFactory = new FtpServerFactory();
ListenerFactory listenerFactory = new ListenerFactory();
//设置服务端口
listenerFactory.setPort(port);
//设置被动模式数据上传的接口范围,云服务器需要开放对应区间的端口给客户端
DataConnectionConfigurationFactory dataConnectionConfFactory = new DataConnectionConfigurationFactory();
dataConnectionConfFactory.setPassivePorts(passivePorts);
listenerFactory.setDataConnectionConfiguration(dataConnectionConfFactory.createDataConnectionConfiguration());
//增加SSL安全配置 --暂时不需要
//4、替换默认的监听器
Listener listener = listenerFactory.createListener();
serverFactory.addListener("default", listener);
//配置自定义用户事件
Map<String, Ftplet> ftpLets = new HashMap();
ftpLets.put("ftpService", new MyFtpPlet());
serverFactory.setFtplets(ftpLets);
//配置自定义用户
BaseUser lekang = new BaseUser();
lekang.setName(username);
lekang.setPassword(password);
lekang.setHomeDirectory(basedir);
lekang.setMaxIdleTime(idleTime);
//设置用户权限
List<Authority> authorities = new ArrayList<Authority>();
authorities.add(new WritePermission());
lekang.setAuthorities(authorities);
serverFactory.getUserManager().save(lekang);
//实例化FTP Server
server = serverFactory.createServer();
}
/**
* ftp server start
* @PostConstruct 跟随容器启动执行
*/
@PostConstruct
public static void start(){
try {
server.start();
log.info("FTP开启!");
}catch(FtpException e) {
e.printStackTrace();
}
}
/**
* ftp server stop
* @PreDestroy 跟随容器关闭执行
*/
@PreDestroy
public static void stop() {
server.stop();
log.info("FTP关闭!");
}
}
import cn.hutool.extra.spring.SpringUtil;
import com.xsj.xsj1800wstz.mapper.QueryByProvinceMapper;
import com.xsj.xsj1800wstz.tools.StringProcessingTool;
import com.xsj.xsj1800wstz.tools.TimeStampTool;
import org.apache.ftpserver.ftplet.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
/**
* @author :
* @date : 2023/5/10
*/
@Component
public class MyFtpPlet extends DefaultFtplet {
public QueryByProvinceServiceImpl queryByProvinceServiceImpl = SpringUtil.getBean(QueryByProvinceServiceImpl.class);
private static final Logger logger = LoggerFactory.getLogger(MyFtpPlet.class);
@Override
public FtpletResult onUploadStart(FtpSession session, FtpRequest request)
throws FtpException, IOException {
//获取上传文件的上传路径
String path = session.getUser().getHomeDirectory();
//获取上传用户
String name = session.getUser().getName();
//获取上传文件名
String filename = request.getArgument();
logger.info("用户:'{}',上传文件到目录:'{}',文件名称为:'{}',状态:开始上传~", name, path, filename);
return super.onUploadStart(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();
logger.info("用户:'{}',上传文件到目录:'{}',文件名称为:'{},状态:成功!'", name, path, filename);
//自己可以在这加一些逻辑 (比如通过图片大小判断是否传输完毕,然后把图片路径等存入数据库)
return super.onUploadEnd(session, request);
}
@Override
public FtpletResult onDownloadStart(FtpSession session, FtpRequest request) throws FtpException, IOException {
//todo servies...
return super.onDownloadStart(session, request);
}
@Override
public FtpletResult onDownloadEnd(FtpSession session, FtpRequest request) throws FtpException, IOException {
//todo servies...
return super.onDownloadEnd(session, request);
}
}
ftpserver.setting 文件(放在resources文件夹下)
注意事项,如果部署到云服务器,需要外网访问的话,则需要开放port为3131的端口号,并且还要开放用于被动模式连接的passivePorts为10000-10002的端口号。外网访问要走被动模式这一路线。
idleTime是以秒为单位的保持连接时长,下面代码中的300就是5分钟
port=3131
passivePorts=10000-10002
username=test
password=123456
basedir=D:\
idleTime=300
Xftp访问ftpserver方式
1.主机要写云服务器地址或者本地localhost ,协议选ftp
端口号写ftpserver.setting中的port
用户名密码也是写ftpserver.setting的用户名密码
如果是ftpserver在云服务器中,要勾选下面红框的使用被动模式!
个人小思考
如何判断文件是否通过ftpserver传输完毕(因为不论传输多少,传输目标路径都会显示传输文件夹),个人认为可以通过文件大小来判断是否传输完毕,可以把文件大小写在文件名中,然后传过来之后在MyFtpPlet 类的onUploadEnd方法中的相应位置(我已注明位置)获取文件大小与文件名中的大小进行比较