前言:公司新项目使用了dubbo
微服务+springboot
的架构,中间注册的时候需要把相关文件上传到FTP服务器中,并且在审核的时候可以下载。
一、准备工作
1.搭建ftp服务器
公司测试服务器是window系统的,搭建ftp可以参考这篇文章https://www.jianshu.com/p/ece21421e246。
2.相关类库引用
在需要使用的模块的pom
文件中引用相关包
commons-net
commons-net
3.6
3.创建文件上传与下载的工具类
package org.guoxn.base.api.util;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.List;
/**
* @author Created by YangFan.
* @date 2019/8/7
* 功能: ftp工具类
*/
@Component
@ConfigurationProperties(prefix = "ftp")
public class FTPUtil {
private static final Logger logger = LoggerFactory.getLogger(FTPUtil.class);
public FTPUtil() {
}
public FTPUtil(String ip, int port, String user, String pwd) {
this.ip = ip;
this.port = port;
this.username = user;
this.password = pwd;
}
public boolean uploadFile(List fileList, String fileDirectory) throws IOException {
logger.info("开始连接ftp服务器");
boolean result = uploadFile(fileDirectory, fileList);
logger.info("开始连接ftp服务器,结束上传,上传结果:{}");
return result;
}
/**
* 上传文件
*
* @param pathname ftp服务保存地址
* @param fileName 上传到ftp的文件名
* @param inputStream 输入文件流
* @return
*/
public boolean uploadFile(String pathname, String fileName, InputStream inputStream) {
boolean flag = false;
try {
System.out.println("开始上传文件");
if (connectServer(this.ip, this.port, this.username, this.password)) {
ftpClient.setFileType(ftpClient.BINARY_FILE_TYPE);
CreateDirecroty(pathname);
ftpClient.makeDirectory(pathname);
ftpClient.changeWorkingDirectory(pathname);
ftpClient.storeFile(fileName, inputStream);
inputStream.close();
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();
}
}
if (null != inputStream) {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
//创建多层目录文件,如果有ftp服务器已存在该文件,则不创建,如果无,则创建
public boolean CreateDirecroty(String remote) throws IOException {
boolean success = true;
String directory = remote + "/";
// 如果远程目录不存在,则递归创建远程服务器目录
if (!directory.equalsIgnoreCase("/") && !changeWorkingDirectory(new String(directory))) {
int start = 0;
int end = 0;
if (directory.startsWith("/")) {
start = 1;
} else {
start = 0;
}
end = directory.indexOf("/", start);
String path = "";
String paths = "";
while (true) {
String subDirectory = new String(remote.substring(start, end).getBytes("GBK"),
"iso-8859-1");
path = path + "/" + subDirectory;
if (!existFile(path)) {
if (makeDirectory(subDirectory)) {
changeWorkingDirectory(subDirectory);
} else {
System.out.println("创建目录[" + subDirectory + "]失败");
changeWorkingDirectory(subDirectory);
}
} else {
changeWorkingDirectory(subDirectory);
}
paths = paths + "/" + subDirectory;
start = end + 1;
end = directory.indexOf("/", start);
// 检查所有目录是否创建完毕
if (end <= start) {
break;
}
}
}
return success;
}
//判断ftp服务器文件是否存在
public boolean existFile(String path) throws IOException {
boolean flag = false;
FTPFile[] ftpFileArr = ftpClient.listFiles(path);
if (ftpFileArr.length > 0) {
flag = true;
}
return flag;
}
//创建目录
public boolean makeDirectory(String dir) {
boolean flag = true;
try {
flag = ftpClient.makeDirectory(dir);
if (flag) {
System.out.println("创建文件夹" + dir + " 成功!");
} else {
System.out.println("创建文件夹" + dir + " 失败!");
}
} catch (Exception e) {
e.printStackTrace();
}
return flag;
}
//改变目录路径
public boolean changeWorkingDirectory(String directory) {
boolean flag = true;
try {
flag = ftpClient.changeWorkingDirectory(directory);
if (flag) {
System.out.println("进入文件夹" + directory + " 成功!");
} else {
System.out.println("进入文件夹" + directory + " 失败!开始创建文件夹");
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
return flag;
}
private boolean uploadFile(String remotePath, List fileList) throws IOException {
boolean uploaded = true;
FileInputStream fis = null;
//连接FTP服务器
if (connectServer(this.ip, this.port, this.username, this.password)) {
try {
ftpClient.changeWorkingDirectory(remotePath);
ftpClient.setBufferSize(1024);
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.enterLocalPassiveMode();
for (File fileItem : fileList) {
fis = new FileInputStream(fileItem);
ftpClient.enterLocalPassiveMode();
String remote = new String(fileItem.getName().getBytes("GBK"), "iso-8859-1");
ftpClient.storeFile(remote, fis);
}
} catch (IOException e) {
logger.error("上传文件异常", e);
uploaded = false;
e.printStackTrace();
} finally {
fis.close();
ftpClient.disconnect();
}
}
return uploaded;
}
private InputStream downloadFile(String remotePath, String fileName) {
InputStream result = null;
if (connectServer(this.ip, this.port, this.username, this.password)) {
try {
int reply;
reply = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
ftpClient.disconnect();
return null;
}
// 转移到FTP服务器目录
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
ftpClient.changeWorkingDirectory(remotePath);
FTPFile[] fs = ftpClient.listFiles();
// 下载文件是否存在
boolean flag = false;
for (FTPFile ff : fs) {
byte[] bytes = ff.getName().getBytes("iso-8859-1");
String name = new String(bytes, "GBK");
if (name.equals(fileName)) {
result = ftpClient.retrieveFileStream(ff.getName());
flag = true;
}
}
if (!flag) {
logger.info("文件: " + fileName + "不存在 !");
} else {
logger.info("下载成功 !");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ftpClient.isConnected()) {
try {
ftpClient.disconnect();
} catch (IOException ioe) {
}
}
}
}
return result;
}
/**
* 从FTP服务器下载文件
*
* @param remotePath FTP服务器上的相对路径
* @param fileName 要下载的文件名
* @return 结果
*/
public InputStream downFile(String remotePath, String fileName) {
InputStream result = downloadFile(remotePath, fileName);
return result;
}
private boolean connectServer(String ip, int port, String user, String pwd) {
boolean isSuccess = false;
ftpClient = new FTPClient();
try {
ftpClient.connect(ip);
isSuccess = ftpClient.login(user, pwd);
} catch (IOException e) {
logger.error("连接FTP服务器异常", e);
}
return isSuccess;
}
private String ip;
private int port;
private String username;
private String password;
private FTPClient ftpClient;
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public FTPClient getFtpClient() {
return ftpClient;
}
public void setFtpClient(FTPClient ftpClient) {
this.ftpClient = ftpClient;
}
}
4.调用方法
for (MultipartFile file : files) {
String fileName = file.getOriginalFilename();
//扩展名
String fileExtensionName = fileName.substring(fileName.lastIndexOf(".") + 1);
String uploadFileName = System.currentTimeMillis() + fileExtensionName;
File fileDir = new File(path);
if (!fileDir.exists()) {
fileDir.setWritable(true);
boolean result = fileDir.mkdirs();
}
//上传文件到项目临时文件
File targetFile = new File(path, uploadFileName);
file.transferTo(targetFile);
//文件已经上传成功
FTPUtil util = new FTPUtil(ip, port, username, password);
boolean success = util.uploadFile(Lists.newArrayList(targetFile), directory);
if (success) {
System.out.println("上传成功");
}
//已经上传到ftp服务器上,删除临时文件
targetFile.delete();
}
这里是循环处理多个文件的方法。
5.注意事项
dubbo
中不能够传递multipartFile类型的数据,所以,我这里处理上传和下载都是在控制器中执行的。查网上资料,有一种解决办法,让service
实现hessian
协议,这个协议是基于HTTP
通讯协议,可以完成文件数据传输,但是我按照教程尝试使用的时候,并没有成功,暂时没有解决问题。