引言

最近有一个在集成系统上提供1G以上文件下载的功能,还要提供文件的展示功能和删除的操作,因为常规的文件流速度慢并且容易断掉因此我们采用FTP的方式,系统架构如下图所示,这里我们采用的ftp框架是apache的ftpserver

项目实现

配置ftpserver

首先是初始化ftpserver的配置,这里我们采用的是配置文件的方式,另外还可以使用注释掉的代码中的数据库方式


/*** 注意:被@Configuration标记的类会被加入ioc容器中,而且类中所有带 @Bean注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例。* ftp服务访问地址:*      ftp://localhost:3131/*/
@Configuration("MyFtp")
public class MyFtpServer {private static final Logger logger = LoggerFactory.getLogger(MyFtpServer.class);//    //springboot配置好数据源直接注入即可
//    @Autowired
//    private DataSource dataSource;protected FtpServer server;//我们这里利用spring加载@Configuration的特性来完成ftp server的初始化public MyFtpServer() {//this.dataSource = dataSource;try{initFtp();}catch (Exception e){e.printStackTrace();}logger.info("Apache ftp server is already instantiation complete!");}/*** ftp server init* @throws IOException*/public void initFtp() throws IOException {FtpServerFactory serverFactory = new FtpServerFactory();ListenerFactory listenerFactory = new ListenerFactory();//1、设置服务端口listenerFactory.setPort(UsersConst.port);//2、设置被动模式数据上传的接口范围,云服务器需要开放对应区间的端口给客户端DataConnectionConfigurationFactory dataConnectionConfFactory = new DataConnectionConfigurationFactory();dataConnectionConfFactory.setPassivePorts("10000-10500");listenerFactory.setDataConnectionConfiguration(dataConnectionConfFactory.createDataConnectionConfiguration());//3、增加SSL安全配置
//        SslConfigurationFactory ssl = new SslConfigurationFactory();
//        ssl.setKeystoreFile(new File("src/main/resources/ftpserver.jks"));
//        ssl.setKeystorePassword("password");//ssl.setSslProtocol("SSL");// set the SSL configuration for the listener
//        listenerFactory.setSslConfiguration(ssl.createSslConfiguration());
//        listenerFactory.setImplicitSsl(true);//4、替换默认的监听器Listener listener = listenerFactory.createListener();serverFactory.addListener("default", listener);//5、配置自定义用户事件Map<String, Ftplet> ftpLets = new HashMap();ftpLets.put("ftpService", new MyFtpPlet());serverFactory.setFtplets(ftpLets);//6、读取用户的配置信息//注意:配置文件位于resources目录下,如果项目使用内置容器打成jar包发布,FTPServer无法直接直接读取Jar包中的配置文件。//解决办法:将文件复制到指定目录(本文指定到根目录)下然后FTPServer才能读取到。PropertiesUserManagerFactory userManagerFactory = new PropertiesUserManagerFactory();String tempPath = System.getProperty("java.io.tmpdir") + System.currentTimeMillis() + ".properties";File tempConfig = new File(tempPath);ClassPathResource resource = new ClassPathResource("config/users.properties");IOUtils.copy(resource.getInputStream(), new FileOutputStream(tempConfig));userManagerFactory.setFile(tempConfig);userManagerFactory.setPasswordEncryptor(new ClearTextPasswordEncryptor());  //密码以明文的方式serverFactory.setUserManager(userManagerFactory.createUserManager());//6.2、基于数据库来存储用户实例
//        DbUserManagerFactory dbUserManagerFactory = new DbUserManagerFactory();
//        //todo....
//        dbUserManagerFactory.setDataSource(dataSource);
//        dbUserManagerFactory.setAdminName("admin");
//        dbUserManagerFactory.setSqlUserAdmin("SELECT userid FROM FTP_USER WHERE userid='{userid}' AND userid='admin'");
//        dbUserManagerFactory.setSqlUserInsert("INSERT INTO FTP_USER (userid, userpassword, homedirectory, " +
//                "enableflag, writepermission, idletime, uploadrate, downloadrate) VALUES " +
//                "('{userid}', '{userpassword}', '{homedirectory}', {enableflag}, " +
//                "{writepermission}, {idletime}, uploadrate}, {downloadrate})");
//        dbUserManagerFactory.setSqlUserDelete("DELETE FROM FTP_USER WHERE userid = '{userid}'");
//        dbUserManagerFactory.setSqlUserUpdate("UPDATE FTP_USER SET userpassword='{userpassword}',homedirectory='{homedirectory}',enableflag={enableflag},writepermission={writepermission},idletime={idletime},uploadrate={uploadrate},downloadrate={downloadrate},maxloginnumber={maxloginnumber}, maxloginperip={maxloginperip} WHERE userid='{userid}'");
//        dbUserManagerFactory.setSqlUserSelect("SELECT * FROM FTP_USER WHERE userid = '{userid}'");
//        dbUserManagerFactory.setSqlUserSelectAll("SELECT userid FROM FTP_USER ORDER BY userid");
//        dbUserManagerFactory.setSqlUserAuthenticate("SELECT userid, userpassword FROM FTP_USER WHERE userid='{userid}'");
//        dbUserManagerFactory.setPasswordEncryptor(new ClearTextPasswordEncryptor());
//        serverFactory.setUserManager(dbUserManagerFactory.createUserManager());//7、实例化FTP Serverserver = serverFactory.createServer();}/*** ftp server start*/public void start(){try {server.start();logger.info("Apache Ftp server is starting!");}catch(FtpException e) {e.printStackTrace();}}/*** ftp server stop*/public void stop() {server.stop();logger.info("Apache Ftp server is stoping!");}}

下面是用于与springboot一同启动和销毁的监听类

@WebListener
public class FtpServerListener implements ServletContextListener {private static final Logger logger = LoggerFactory.getLogger(FtpServerListener.class);private static final String SERVER_NAME="FTP-SERVER";//tomcat容器关闭时调用方法stop ftpServerpublic void contextDestroyed(ServletContextEvent sce) {WebApplicationContext ctx= WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());MyFtpServer server=(MyFtpServer)ctx.getServletContext().getAttribute(SERVER_NAME);server.stop();sce.getServletContext().removeAttribute(SERVER_NAME);}//spring 容器初始化调用方法startFtpServerpublic void contextInitialized(ServletContextEvent sce) {WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(sce.getServletContext());//spring boot 启动类中创建bean,命名为MyFtp()MyFtpServer server = (MyFtpServer) ctx.getBean("MyFtp");sce.getServletContext().setAttribute(SERVER_NAME, server);try {server.initFtp();server.start();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("FTP启动失败", e);}}}

springboot启动类,在启动时需要注册MyFtpServer的bean以及将监听器注册到ServletContext中

/*** @Classname Application* @Description 启动类* @Date 2020/8/25 2:39 下午* @Created by eatonsong*/
@SpringBootApplication
@ComponentScan(basePackages = "com.viewhigh.ftpserver")
@Configuration
public class Application implements ServletContextInitializer {public static void main(String[] args) {SpringApplication.run(Application.class,args);}@Overridepublic void onStartup(ServletContext servletContext) {servletContext.addListener(FtpServerListener.class);}@Beanpublic MyFtpServer MyFtp(){return  new MyFtpServer();}}

设置ftp的访问路径以及前缀

@Configuration
public abstract class FtpConfig implements WebMvcConfigurer {@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {//可以通过os来判断String os = System.getProperty("os.name");String homedirectory = UsersConst.homedirectory;//linux设置
//        registry.addResourceHandler("/ftp/**").addResourceLocations("file:/home/pic/");//windows设置//第一个方法设置访问路径前缀,第二个方法设置资源路径,既可以指定项目classpath路径,也可以指定其它非项目路径registry.addResourceHandler("/**").addResourceLocations("file:"+homedirectory);}}

users.properties用户配置

#admin用户密码和其他设置
ftpserver.user.admin.userpassword=admin
ftpserver.user.admin.homedirectory=C:\\myftp
#ftpserver.user.admin.homedirectory=/home/pic/
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
#匿名用户密码和其他设置(本处不设置匿名用户密码)
ftpserver.user.anonymous.userpassword=
#ftpserver.user.anonymous.homedirectory=C:\\myftp
ftpserver.user.anonymous.enableflag=true
ftpserver.user.anonymous.writepermission=true
ftpserver.user.anonymous.maxloginnumber=20
ftpserver.user.anonymous.maxloginperip=2
ftpserver.user.anonymous.idletime=300
ftpserver.user.anonymous.uploadrate=4800
ftpserver.user.anonymous.downloadrate=4800

这样我们的ftpserver就配置好了,启动springboot项目后访问ftp://127.0.0.1:3131可以看到我们的ftp服务界面

restApi

这里我们要为集成系统提供可以查询,删除的api
首先需要一个操作ftp的工具类

public class FtpClientUtil {// ftp服务器ip地址private static String FTP_ADDRESS = UsersConst.ipaddress;// 端口号private static int FTP_PORT = UsersConst.port;// 用户名private static String FTP_USERNAME = UsersConst.username;// 密码private static String FTP_PASSWORD = UsersConst.userpassword;// 相对路径private static String FTP_BASEPATH = "";private static FTPClient connect() throws IOException{int reply;FTPClient ftp = new FTPClient();ftp.setControlEncoding("UTF-8");ftp.connect(FTP_ADDRESS, FTP_PORT);// 连接FTP服务器ftp.login(FTP_USERNAME, FTP_PASSWORD);// 登录reply = ftp.getReplyCode();System.out.println("登录ftp服务返回状态码为:" + reply);if (!FTPReply.isPositiveCompletion(reply)) {ftp.disconnect();throw new RuntimeException("登录ftp服务返回状态码为:" + reply);}return ftp;}public static void disconnect(FTPClient ftp){if (ftp!=null&&ftp.isConnected()) {try {ftp.disconnect();} catch (IOException ioe) {}}}public static FTPFile[] listFile(String path) throws Exception{FTPClient ftp = null;try {ftp = connect();FTPFile []fileList = ftp.listFiles(path);ftp.logout();return fileList;}finally {disconnect(ftp);}}public static void uploadFile(String remoteFileName, InputStream input) throws Exception {FTPClient ftp = null;try {ftp = connect();ftp.setFileType(FTPClient.BINARY_FILE_TYPE);//设置为被动模式ftp.enterLocalPassiveMode();ftp.makeDirectory(FTP_BASEPATH);ftp.changeWorkingDirectory(FTP_BASEPATH);//originFilePath就是上传文件的文件名,建议使用生成的唯一命名,中文命名最好做转码boolean a = ftp.storeFile(remoteFileName, input);
//            boolean a = ftp.storeFile(new String(remoteFileName.getBytes(),"iso-8859-1"),input);System.out.println("要上传的原始文件名为:" + remoteFileName + ", 上传结果:" + a);input.close();ftp.logout();} finally {disconnect(ftp);}}public static void deleteFile(String filename) throws Exception{FTPClient ftp = null;try {ftp = connect();// 切换FTP目录ftp.changeWorkingDirectory(FTP_BASEPATH);ftp.dele(filename);ftp.logout();}finally {disconnect(ftp);}}public static void downloadFile(String filename, String localPath) throws Exception{FTPClient ftp = null;try {ftp = connect();// 切换FTP目录ftp.changeWorkingDirectory(FTP_BASEPATH);//此处为demo方法,正常应该到数据库中查询fileNameFTPFile[] ftpFiles = ftp.listFiles();for (FTPFile file : ftpFiles) {if (filename.equalsIgnoreCase(file.getName())) {File localFile = new File(localPath + "/" + file.getName());OutputStream os = new FileOutputStream(localFile);ftp.retrieveFile(file.getName(), os);os.close();}}ftp.logout();System.out.println("文件下载完成!!!");} finally {ftp.disconnect();}}
}

然后是api

@RestController
public class FtpController {@GetMapping("/hello")public String hello(){return "hello";}@GetMapping("/list")@ResponseBodypublic FTPFile[] getListByPath(String path) throws Exception{return FtpClientUtil.listFile(path);}@GetMapping("/delete")public boolean deleteFileByPathFileName(String fileName) throws Exception{FtpClientUtil.deleteFile(fileName);return true;}
}

结语

这样我们的功能就基本实现了,集成系统中就是普通的查询和api调用,项目源代码https://github.com/eatonsong/dataiftpserver.git 感谢star

搭建基于springboot的FTP服务器相关推荐

  1. 轻松搭建基于 SpringBoot Vue 的 Web 商城应用

    背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传.函数 ...

  2. Serverless 实战 —— 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用

    Serverless 实战 -- 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用 背景介绍 首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute ...

  3. 基于socket实现FTP服务器

    基于socket实现FTP服务器 前言 基于socket完成了一个FTP服务器,实现了其基本功能 环境 操作系统:Windows 10企业版 LTSC 开发语言:C++ 开发工具:Visual Stu ...

  4. win7连接sftp_Windows 7下 搭建 基于 ssh 的sftp 服务器

    Windows  xp 下 搭建 基于ssh 的sftp 服务器,服务器端可以用freesshd,F-secure server等,filezilla server不可用,之前傻乎乎的用filezil ...

  5. 基于CentOS的FTP服务器搭建

    目录 一,简介 1,Centos中的FTP 2,vsftpd 二,vsftpd的安装 1,安装vsftpd服务 2,开启服务 3,端口 4,关闭防火墙 三,vsftp匿名模式搭建 1,修改配置文件 2 ...

  6. ftp服务器搭建需要什么硬件,FTP 服务器搭建与配置

    简介 1.FTP是什么? FTP是文件传输协议(File Transfer Protocal)的简写,主要完成与远程计算机的文件传输. FTP存在服务器的概念,可以理解为文件服务器.也就存在权限的控制 ...

  7. 搭建windows下filezilla FTP服务器

    FTP服务器必不可少,鉴于serv-u越来越冗余繁多的设置,个人还是比较喜欢简单.干净,满足需求即可的东东,所以选择filezilla.更主要的原因是ta是开元免费使用的,虽然免费,功能却齐全,我发现 ...

  8. 搭建一个简单的FTP服务器

    本文介绍通过win7自带的IIS来搭建一个只能实现基本功能的FTP服务器,第一次装好WIN7后我愣是没整出来,后来查了一下网上资料经过试验后搭建成功,其实原理和步骤与windows前期的版本差不多,主 ...

  9. 快速搭建一个本地的FTP服务器

    如果需要开发FTP文件上传下载功能,那么需要在本机上搭建一个本地FTP服务器,方便调试. https://www.cnblogs.com/popfisher/p/7992036.html CMD 连接 ...

最新文章

  1. 华为机考HJ6求质因子C语言解法
  2. ActiveX(二)
  3. 如何在实际场景中使用异常检测?阿里云Prometheus智能检测算子来了
  4. mysql的实践小结的作文_MySql小结
  5. 从零学ELK系列(一):为什么要跟我学从零学ELK系列
  6. kubernetes视频教程笔记 (4)-服务发现-service和pod组建
  7. 数据库IO性能知识整理
  8. esayUI实践的一些体会
  9. 2020第十一届蓝桥杯省赛python真题详解
  10. [工具:iperf吞吐率测试工具 ]安装以及使用
  11. linux搭建WebSphere
  12. 所有的风只向她们吹 所有的日子都为她们破碎——査海生《四姐妹》
  13. 第十六期 CyanogenMod 小米3W刷机《手机就是开发板》
  14. LibreOJ 2060 食物链
  15. 国外设计博客小组收集
  16. 套接字的连接(服务器与客户端一对一的连接)
  17. 【TypeScript】TS与Vue
  18. SQL查找时间记录最近一条
  19. $(this)与this的区别
  20. 北京51cto线下活动--从香山到植物园记录的点点滴滴

热门文章

  1. 听说 Java 开发很赚钱?苦学两年却送起了外卖!
  2. jquery的$.alerts.alert怎么实现点击后跳转页面
  3. JAVA 字节码全解
  4. 基于ARM9-Linux平台的车载导航系统设计
  5. 中文事件抽取关键技术研究(谭红叶 博士毕业论文)
  6. MySQL使用GROUP_CONCAT()函数按ID分组将多条记录的某个字段以逗号或者指定分隔号隔开成一条记录
  7. 推荐几个比较好看的CSS颜色属性搭配
  8. linux 的pwd文件被删,恢复被删除的文件-linux篇
  9. linux打实时补丁以及实时性能测试
  10. 柚子壁纸为什么自动安装_一张壁纸能折射多少东西,侦探团成员壁纸信息大,灰原的最有意思...