环境为springboot项目:
Maven依赖:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/>
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
application.yml配置文件:
#ftp配置
ftp:
userName: //账号
password: //密码
host: //192.168.1.000//地址
outPost: 192.168.1.000//地址
port: 21//端口
pathPrefix: transportation/ //上传文件路径
FtpUtils工具:
package com.knd.common.utils;
import com.knd.enums.FileTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.SocketException;
import java.util.*;
/**
* @Description: ftp工具类
*/
@Slf4j
@Component
@ConfigurationProperties(prefix = "ftp")//读取配置文件的值
public class FtpUtils {
public static String userName;
public static String password;
public static String host;
public static String outPost;
public static int port;
public static String pathPrefix;
public void setOutPost(String outPost) {
FtpUtils.outPost = outPost;
}
public void setUserName(String userName) {
FtpUtils.userName = userName;
}
public void setPassword(String password) {
FtpUtils.password = password;
}
public void setHost(String host) {
FtpUtils.host = host;
}
public void setPort(int port) {
FtpUtils.port = port;
}
public void setPathPrefix(String pathPrefix) {
FtpUtils.pathPrefix = pathPrefix;
}
/**
* 获取FTPClient对象
*
* @return
*/
public static FTPClient getFTPClient() {
FTPClient ftpClient = new FTPClient();
try {
ftpClient = new FTPClient();
ftpClient.connect(host, port);// 连接FTP服务器
ftpClient.login(userName, password);// 登陆FTP服务器
if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
log.error("未连接到FTP,,请正确配置。");
ftpClient.disconnect();
} else {
log.info("FTP连接成功。");
}
} catch (SocketException e) {
e.printStackTrace();
log.error("FTP的IP地址可能错误,请正确配置。错误明细:" + e.getMessage());
} catch (IOException e) {
e.printStackTrace();
log.error("FTP的端口错误,请正确配置。错误明细:" + e.getMessage());
}
return ftpClient;
}
/**
* 从FTP服务器下载文件
*
* @param ftpPath FTP服务器中文件所在路径 格式: ftptest/aa
* @param localPath 下载到本地的位置 格式:H:/download
* @param fileName 文件名称
*/
public static void downloadFtpFile(String ftpPath, String localPath, String fileName) {
FTPClient ftpClient = null;
try {
ftpClient = getFTPClient();
ftpClient.setControlEncoding("UTF-8"); // 中文支持
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
ftpClient.changeWorkingDirectory(ftpPath);
File localFile = new File(localPath + File.separatorChar + fileName);
OutputStream os = new FileOutputStream(localFile);
ftpClient.retrieveFile(fileName, os);
os.close();
ftpClient.logout();
} catch (FileNotFoundException e) {
System.out.println("没有找到" + ftpPath + "文件");
e.printStackTrace();
} catch (SocketException e) {
System.out.println("连接FTP失败.");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件读取错误。");
e.printStackTrace();
}
}
/**
* 下载文件
*
* @param ftpPath 文件路径
* @param fileName 文件名
* @return
* @date 2019/3/14 13:13
*/
public static void downloadFtpFile(String ftpPath, String fileName, OutputStream out) {
FTPClient ftpClient = null;
try {
ftpClient = getFTPClient();
ftpClient.setControlEncoding("UTF-8"); // 中文支持
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
ftpClient.changeWorkingDirectory(ftpPath);
ftpClient.retrieveFile(fileName, out);
ftpClient.logout();
} catch (FileNotFoundException e) {
System.out.println("没有找到" + ftpPath + "文件");
e.printStackTrace();
} catch (SocketException e) {
System.out.println("连接FTP失败.");
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
System.out.println("文件读取错误。");
e.printStackTrace();
}
}
/**
* 把ftp上的文件copy到指定目录文件下
*
* @param getDirPath //源文件路径
* @param path //FTP服务器中文件所在路径
* @param fileName //文件全名(加上后缀)
* @date 2020/3/13 9:37
*/
public static String retrieveFile(String getDirPath, String path, String fileName) {
OutputStream out = null;
InputStream inputStream = null;
try {
out = new ByteArrayOutputStream();
downloadFtpFile(getDirPath, out);
inputStream = new ByteArrayInputStream(((ByteArrayOutputStream) out).toByteArray());
return uploadFile(path, fileName, inputStream);
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
try {
out.close();
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 文件下载
*
* @param ftpPathAndFileName 文件路径+文件名 即上传文件成功后返回的路径
* @param out
*/
public static void downloadFtpFile(String ftpPathAndFileName, OutputStream out) {
Map<String, String> map = extractFtpPathAndFileName(ftpPathAndFileName);
downloadFtpFile(map.get("ftpPath"), map.get("FileName"), out);
}
/**
* Description: 向FTP服务器上传文件
*
* @param ftpPath FTP服务器中文件所在路径 格式: ftptest/aa
* @param fileName ftp文件名称
* @param input 文件流
* @return 成功返回路径加文件名, 失败返回null
*/
public static String uploadFile(String ftpPath,
String fileName, InputStream input) {
if (StringUtils.isBlank(ftpPath) || StringUtils.isBlank(fileName) || input == null) {
return null;
}
if (ftpPath.charAt(ftpPath.length() - 1) != '/') {
ftpPath += "/";
}
ftpPath = pathPrefix + ftpPath;
FTPClient ftpClient = null;
try {
int reply;
ftpClient = getFTPClient();
reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
return null;
}
BufferedInputStream bufferedInputStream = new BufferedInputStream(input);
ftpClient.setBufferSize(1024 * 1024);
ftpClient.setControlEncoding("UTF-8"); // 中文支持
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
createDir(ftpPath);
ftpClient.changeWorkingDirectory(ftpPath);
ftpClient.storeFile(fileName, bufferedInputStream);
input.close();
ftpClient.logout();
return ftpPath + fileName;
} catch (IOException e) {
// e.printStackTrace();
log.error("ftp文件上传异常----->" + e.getMessage(), e);
return null;
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException ioe) {
log.error("ftp流关闭异常----->" + ioe.getMessage(), ioe);
}
}
}
}
/**
* 上传文件
*
* @param ftpPath
* @param file
* @return 返回ftpPath和文件名拼接的路径
*/
public static String uploadFile(String ftpPath,
MultipartFile file) throws IOException {
if (StringUtils.isBlank(ftpPath) || file == null || file.isEmpty()) {
return null;
}
String fileName = UUID.randomUUID() + file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
String b = uploadFile(ftpPath, fileName, file.getInputStream());
if (b != null) {
return b;
}
return null;
}
/**
* 转换文件路径
*
* @param fileTypeEnum 文件类型
* @return
*/
public static String getFilePathStr(FileTypeEnum fileTypeEnum) {
//定义日期
Date date = new Date();
Calendar c = Calendar.getInstance();
c.setTime(date);
String day = c.get(Calendar.YEAR) + "-" + c.get(Calendar.MONTH) + "-" + c.get(Calendar.DATE);
String fileType = fileTypeEnum.getMsg();
String filePathStr = day + "/" + fileType;
return filePathStr;
}
/**
* 创建目录(有则切换目录,没有则创建目录)
*
* @param dir
* @return
*/
public static boolean createDir(String dir) {
FTPClient ftpClient = getFTPClient();
if (!StringUtils.isNotBlank(dir)) {
return true;
}
String d;
try {
//目录编码,解决中文路径问题
d = new String(dir.toString().getBytes("GBK"), "iso-8859-1");
//尝试切入目录
if (ftpClient.changeWorkingDirectory(d)) {
return true;
}
String[] arr = dir.split("/");
StringBuffer sbfDir = new StringBuffer();
//循环生成子目录
for (String s : arr) {
sbfDir.append("/");
sbfDir.append(s);
//目录编码,解决中文路径问题
d = new String(sbfDir.toString().getBytes("GBK"), "iso-8859-1");
//尝试切入目录
if (ftpClient.changeWorkingDirectory(d)) {
continue;
}
if (!ftpClient.makeDirectory(d)) {
// System.out.println("[失败]ftp创建目录:" + sbfDir.toString());
log.error("[失败]ftp创建目录:" + sbfDir.toString());
return false;
}
System.out.println("[成功]创建ftp目录:" + sbfDir.toString());
}
//将目录切换至指定路径
return ftpClient.changeWorkingDirectory(d);
} catch (Exception e) {
e.printStackTrace();
log.error("文件目录切换/创建异常----->" + e.getMessage(), e);
return false;
}
}
/**
* * 删除文件 *
*
* @param pathName FTP服务器保存目录
* @param fileName 要删除的文件名称
* @return
*/
public static boolean deleteFile(String pathName, String fileName) {
FTPClient ftpClient = getFTPClient();
boolean flag = false;
try {
System.out.println("开始删除文件");
// 切换FTP目录
ftpClient.changeWorkingDirectory(pathName);
ftpClient.dele(fileName);
ftpClient.logout();
flag = true;
System.out.println("删除文件成功");
} catch (Exception e) {
System.out.println("删除文件失败");
e.printStackTrace();
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return flag;
}
/**
* 删除文件
*
* @param ftpPathAndFileName 文件路径+文件名 即上传文件成功后返回的路径
* @return
*/
public static boolean deleteFile(String ftpPathAndFileName) {
Map<String, String> map = extractFtpPathAndFileName(ftpPathAndFileName);
return deleteFile(map.get("ftpPath"), map.get("FileName"));
}
/**
* 通过路径获取ftp路径和文件名
*
* @param ftpPathAndFileName
* @return
*/
public static Map<String, String> extractFtpPathAndFileName(String ftpPathAndFileName) {
if (StringUtils.isBlank(ftpPathAndFileName)
|| ftpPathAndFileName.lastIndexOf("/") <= 0
|| ftpPathAndFileName.charAt(ftpPathAndFileName.length() - 1) == '/'
) {
throw new IllegalArgumentException("ftpPathAndFileName参数错误,该参数为文件路径+文件名");
}
Map<String, String> ret = new HashMap<>();
String ftpPath = ftpPathAndFileName.substring(0, ftpPathAndFileName.lastIndexOf("/") + 1);
String FileName = ftpPathAndFileName.substring(ftpPathAndFileName.lastIndexOf("/") + 1);
ret.put("ftpPath", ftpPath);
ret.put("FileName", FileName);
return ret;
}
}
FileTypeEnum枚举:
@Getter
@Slf4j
public enum FileTypeEnum {
IDCARDZ(1, "xx", "xxImg"),
IDCARDF(2, "yyy", "yyyImg"),
FileTypeEnum(Integer code, String msg, String path) {
this.code = code;
this.path = path;
this.msg = msg;
}
private Integer code;
private String msg;
private String path;
public static String getPath(Integer code) {
if (code == null) {
throw new BDException("未知文件类型");
}
Optional<FileTypeEnum> optional = stream(FileTypeEnum.values()).filter(x -> Objects.equals(x.code, code)).findFirst();
if (optional.isPresent()) {
return optional.get().path;
}
throw new BDException("未知文件类型");
}
public static FileTypeEnum getEnum(Integer code) {
if (code == null) {
return null;
}
return stream(FileTypeEnum.values()).filter(x -> Objects.equals(x.code, code)).findFirst().orElse(null);
}
}