Maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 自定义starter都应该继承自该依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starters</artifactId>
<version>2.1.6.RELEASE</version>
</parent>
<groupId>com.cch</groupId>
<artifactId>ftp-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>ftp-starter</name>
<description>ftp client project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-net/commons-net -->
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/log4j-over-slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>1.7.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置类
package com.cch.ftpstarter.config;
/*
* @ClassName:FtpAutoConfiguration
* @Description TODO
* @Time 2019-07-08 12:16
*/
import com.cch.ftpstarter.properties.FTPProperties;
import com.cch.ftpstarter.util.FtpClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
@Configuration
@EnableConfigurationProperties(FTPProperties.class)
@ConditionalOnClass(FtpClient.class)
public class FtpAutoConfiguration {
@Autowired
private FTPProperties properties;
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@ConditionalOnMissingBean(FtpClient.class)// 当容器中没有指定Bean的情况下,自动配置FtpClient类
public FtpClient ftpClient(){
FtpClient ftpClient = new FtpClient(properties);
return ftpClient;
}
}
在resources下创建META-INF目录
在META-INF目录下创建spring.factories文件
在spring.factories文件中输入
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.cch.ftpstarter.config.FtpAutoConfiguration
属性类
package com.cch.ftpstarter.properties;
/*
* @ClassName:FTPConfig
* @Description TODO
* @Time 2019-07-05 14:14
*/
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "ftp") // 自动获取配置文件中前缀为ftp的属性,把值传入对象参数
public class FTPProperties {
private String server = "localhost";
private Integer port = 21;
private String user = "";
private String password = "";
public String getServer() {
return server;
}
public void setServer(String server) {
this.server = server;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
FTP操作类(spring bean)
package com.cch.ftpstarter.util;
/*
* @ClassName:FtpClient
* @Description ftp客户端操作类
* @Time 2019-07-04 18:46
*/
import com.cch.ftpstarter.properties.FTPProperties;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.log4j.Logger;
import java.io.*;
import java.net.MalformedURLException;
import java.util.ArrayList;
import java.util.List;
public class FtpClient {
private static final Logger LOGGER = Logger.getLogger(FtpClient.class);
//实际操作FTP服务的客户端类
private FTPClient ftpClient = null;
//构造 初始化
public FtpClient(FTPProperties ftpProperties) {
String ftpServer = ftpProperties.getServer();
Integer port = ftpProperties.getPort();
String user = ftpProperties.getUser();
String pwd = ftpProperties.getPassword();
ftpClient = new FTPClient();
ftpClient.setControlEncoding("utf-8");
try {
ftpClient.connect(ftpServer, port); //连接ftp服务器
ftpClient.login(user, pwd); //登录ftp服务器
int replyCode = ftpClient.getReplyCode(); //是否成功登录服务器
if (!FTPReply.isPositiveCompletion(replyCode)) {
LOGGER.error("未能成功连接FTP服务器[" + ftpServer + ":" + port + "]");
throw new IOException("不能连接FTP服务器 :" + ftpServer);
}
LOGGER.info("成功连接FTP服务器[" + ftpServer + ":" + port + "]");
// set data transfer mode.
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// Use passive mode to pass firewalls.
ftpClient.enterLocalPassiveMode();
} catch (MalformedURLException e) {
LOGGER.error("FTP服务器地址错误:" + ftpServer);
} catch (IOException e) {
LOGGER.error("登录FTP服务器[" + ftpServer + ":" + port + "]出现错误" + e);
}
}
//构造 初始化
public FtpClient(String ftpServer,Integer port,String user,String pwd) {
ftpClient = new FTPClient();
ftpClient.setControlEncoding("utf-8");
try {
ftpClient.connect(ftpServer, port); //连接ftp服务器
ftpClient.login(user, pwd); //登录ftp服务器
int replyCode = ftpClient.getReplyCode(); //是否成功登录服务器
if (!FTPReply.isPositiveCompletion(replyCode)) {
LOGGER.error("未能成功连接FTP服务器[" + ftpServer + ":" + port + "]");
throw new IOException("不能连接FTP服务器 :" + ftpServer);
}
LOGGER.info("成功连接FTP服务器[" + ftpServer + ":" + port + "]");
// set data transfer mode.
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
// Use passive mode to pass firewalls.
ftpClient.enterLocalPassiveMode();
} catch (MalformedURLException e) {
LOGGER.error("FTP服务器地址错误:" + ftpServer);
} catch (IOException e) {
LOGGER.error("登录FTP服务器[" + ftpServer + ":" + port + "]出现错误" + e);
}
}
//设置超时时间
public void setTimeout(int defaultTimeout, int connectTimeout, int dataTimeout) {
ftpClient.setDefaultTimeout(defaultTimeout);
ftpClient.setConnectTimeout(connectTimeout);
ftpClient.setDataTimeout(dataTimeout);
}
/**
* 方法描述 上传文件
* @method upload
* @param localFile 本地文件对象
* @param ftpFileName FTP服务器文件地址
*/
private void upload(File localFile, String ftpFileName) throws IOException {
if (!localFile.exists()) {
throw new IOException("Can't upload '" + localFile.getAbsolutePath() + "'. This file doesn't exist.");
}
InputStream in = null;
try {
in = new BufferedInputStream(new FileInputStream(localFile));
if (!ftpClient.storeFile(ftpFileName, in)) {
throw new IOException("Can't upload file '" + ftpFileName + "' to FTP server. Check FTP permissions and path.");
}
LOGGER.info("文件" + ftpFileName + "上传成功");
} catch (IOException e) {
e.printStackTrace();
} finally {
in.close();
}
}
/**
* 方法描述 上传文件
* @method upload
* @param localFilePath 本地文件路径
* @param ftpFileName FTP服务器文件地址
*/
public void upload(String localFilePath, String ftpFileName) throws IOException {
File file = new File(localFilePath);
upload(file, ftpFileName);
}
/**
* 方法描述 上次文件到FTP服务器的指定目录
* @method upload2Dir
* @param localFilePath 本地文件路径
* @param remoteDir FTP服务器中的目录路径
*/
public void upload2Dir(String localFilePath, String remoteDir) throws IOException {
createDir(remoteDir);
File localFile = new File(localFilePath);
upload(localFile, remoteDir + "/" + localFile.getName());
}
/**
* 方法描述 上次文件到FTP服务器的指定目录
* @method upload2Dir
* @param localFilePath 本地文件路径
* @param remoteDir FTP服务器中的目录路径
* @param remoteFileName FTP服务器中的文件名
*/
public void upload2Dir(String localFilePath, String remoteDir, String remoteFileName) throws IOException {
createDir(remoteDir);
File localFile = new File(localFilePath);
upload(localFile, remoteDir + "/" + remoteFileName);
}
/**
* 方法描述 创建FTP目录
* @method createDir
* @param remoteDir FTP服务器中目录字符串
*/
private void createDir(String remoteDir) throws IOException {
if (!ftpClient.changeWorkingDirectory(remoteDir)) {
String[] paths = remoteDir.split("/");
StringBuffer dirBuffer = new StringBuffer();
for (int index = 1; index < paths.length; index++) {
dirBuffer.append("/");
dirBuffer.append(paths[index]);
String dirName = dirBuffer.toString();
if (ftpClient.changeWorkingDirectory(dirName)) {
continue;
} else {
ftpClient.makeDirectory(dirName);
LOGGER.info("创建目录" + dirName + "成功");
ftpClient.changeWorkingDirectory(dirName);
}
}
}
}
/**
* 方法描述 上次目录到FTP服务器
* @method uploadDir
* @param localPath 本地文件路径
* @param remotePath FTP服务器目录路径
*/
public void uploadDir(String localPath, String remotePath) throws IOException {
localPath = localPath.replace("\\\\", "/");
File file = new File(localPath);
if (file.exists()) {
if (!ftpClient.changeWorkingDirectory(remotePath)) {
if (ftpClient.makeDirectory(remotePath)) {
LOGGER.info("创建目录" + remotePath + "成功");
}
ftpClient.changeWorkingDirectory(remotePath);
}
File[] files = file.listFiles();
if (null != files) {
for (File f : files) {
if (f.isDirectory() && !f.getName().equals(".") && !f.getName().equals("..")) {
uploadDir(f.getPath(), remotePath + "/" + f.getName());
} else if (f.isFile()) {
upload(f, remotePath + "/" + f.getName());
}
}
}
}
}
/**
* 方法描述
* @method 下载文件
* @param ftpFileName FTP服务器中的文件路径
* @param localFilePath 本地文件保存路径
*/
public void download(String ftpFileName, String localFilePath) throws IOException {
OutputStream out = null;
File localFile = new File(localFilePath);
try {
FTPFile[] fileInfoArray = ftpClient.listFiles(ftpFileName);
if (fileInfoArray == null || fileInfoArray.length == 0) {
throw new FileNotFoundException("File " + ftpFileName + " was not found on FTP server.");
}
FTPFile fileInfo = fileInfoArray[0];
if (fileInfo.getSize() > Integer.MAX_VALUE) {
throw new IOException("File " + ftpFileName + " is too large.");
}
out = new BufferedOutputStream(new FileOutputStream(localFile));
if (!ftpClient.retrieveFile(ftpFileName, out)) {
throw new IOException("Error loading file " + ftpFileName + " from FTP server. Check FTP permissions and path.");
}
out.flush();
LOGGER.info("文件" + ftpFileName + "下载成功:" + localFilePath);
} catch (IOException e) {
LOGGER.error("文件下载出现错误" + e);
} finally {
out.close();
}
}
/**
* 方法描述
* @method 下载FTP服务器中的指定目录
* @param remotePath FTP服务器中的被下载目录路径
* @param localPath 本地保存目录的路径
*/
public void downloadDir(String remotePath, String localPath) throws IOException {
localPath = localPath.replace("\\\\", "/");
File file = new File(localPath);
if (!file.exists()) {
file.mkdirs();
}
FTPFile[] ftpFiles = ftpClient.listFiles(remotePath);
for (int i = 0; ftpFiles != null && i < ftpFiles.length; i++) {
FTPFile ftpFile = ftpFiles[i];
if (ftpFile.isDirectory() && !ftpFile.getName().equals(".") && !ftpFile.getName().equals("..")) {
downloadDir(remotePath + "/" + ftpFile.getName(), localPath + "/" + ftpFile.getName());
} else {
download(remotePath + "/" + ftpFile.getName(), localPath + "/" + ftpFile.getName());
}
}
}
/**
* 方法描述 删除FTP服务器中的指定的目录
* @method deleteDir
* @param remoteDir 被删除目录的路径
*/
public void deleteDir(String remoteDir) throws IOException {
FTPFile[] ftpFiles = ftpClient.listFiles(remoteDir);
if (ftpFiles.length > 0) {
for (int i = 0; i < ftpFiles.length; i++) {
FTPFile ftpFile = ftpFiles[i];
String name = ftpFile.getName();
if (ftpFile.isDirectory()) {
deleteDir(remoteDir + "/" + ftpFile.getName());
} else {
deleteFile(remoteDir + "/" + name);
}
}
deleteDir(remoteDir);
} else {
if (!ftpClient.removeDirectory(remoteDir)) {
throw new IOException("Can't remove folder '" + remoteDir + "' from FTP server.");
}
LOGGER.info("删除目录" + remoteDir + "成功");
}
}
/**
* 方法描述 删除FTP服务器中指定的文件
* @method deleteFile
* @param ftpFileName 被删除文件的路径
*/
public void deleteFile(String ftpFileName) throws IOException {
if (!ftpClient.deleteFile(ftpFileName)) {
throw new IOException("Can't remove file '" + ftpFileName + "' from FTP server.");
}
LOGGER.info("删除文件" + ftpFileName + "成功");
}
/**
* 方法描述 获取ftp服务器指定目录中的文件名称列表
* @method list
* @param remotePath 远程目录
* @return List<String> 文件名称列表
*/
public List<String> list(String remotePath) throws IOException {
ftpClient.changeWorkingDirectory(remotePath);
List<String> fileNames = new ArrayList<String>();
FTPFile[] ftpFiles = ftpClient.listFiles();
for (FTPFile ftpFile : ftpFiles) {
String fileName = ftpFile.getName();
fileNames.add(fileName);
}
return fileNames;
}
/**
* 方法描述 断开FTP服务器连接
* @method disconnect
*/
public void disconnect() {
if (null != ftpClient && ftpClient.isConnected()) {
try {
ftpClient.logout();
ftpClient.disconnect();
LOGGER.info("FTP服务器连接关闭");
} catch (IOException ex) {
LOGGER.error("关闭FTP服务器错误");
}
}
}
}
引用Starter
使用 maven install 将项目打包到maven仓库或maven远程中心仓库
然后直接使用dependency 引用FTP Starter的groupId和artifactId即可。