前言:公司新項目使用了dubbo微服務(wù)+springboot的架構(gòu),中間注冊的時候需要把相關(guān)文件上傳到FTP服務(wù)器中,并且在審核的時候可以下載。
一、準備工作
1.搭建ftp服務(wù)器
公司測試服務(wù)器是window系統(tǒng)的,搭建ftp可以參考這篇文章http://www.itdecent.cn/p/ece21421e246。
2.相關(guān)類庫引用
在需要使用的模塊的pom文件中引用相關(guān)包
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
3.創(chuàng)建文件上傳與下載的工具類
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<File> fileList, String fileDirectory) throws IOException {
logger.info("開始連接ftp服務(wù)器");
boolean result = uploadFile(fileDirectory, fileList);
logger.info("開始連接ftp服務(wù)器,結(jié)束上傳,上傳結(jié)果:{}");
return result;
}
/**
* 上傳文件
*
* @param pathname ftp服務(wù)保存地址
* @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;
}
//創(chuàng)建多層目錄文件,如果有ftp服務(wù)器已存在該文件,則不創(chuàng)建,如果無,則創(chuàng)建
public boolean CreateDirecroty(String remote) throws IOException {
boolean success = true;
String directory = remote + "/";
// 如果遠程目錄不存在,則遞歸創(chuàng)建遠程服務(wù)器目錄
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("創(chuàng)建目錄[" + subDirectory + "]失敗");
changeWorkingDirectory(subDirectory);
}
} else {
changeWorkingDirectory(subDirectory);
}
paths = paths + "/" + subDirectory;
start = end + 1;
end = directory.indexOf("/", start);
// 檢查所有目錄是否創(chuàng)建完畢
if (end <= start) {
break;
}
}
}
return success;
}
//判斷ftp服務(wù)器文件是否存在
public boolean existFile(String path) throws IOException {
boolean flag = false;
FTPFile[] ftpFileArr = ftpClient.listFiles(path);
if (ftpFileArr.length > 0) {
flag = true;
}
return flag;
}
//創(chuàng)建目錄
public boolean makeDirectory(String dir) {
boolean flag = true;
try {
flag = ftpClient.makeDirectory(dir);
if (flag) {
System.out.println("創(chuàng)建文件夾" + dir + " 成功!");
} else {
System.out.println("創(chuàng)建文件夾" + 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 + " 失??!開始創(chuàng)建文件夾");
}
} catch (IOException ioe) {
ioe.printStackTrace();
}
return flag;
}
private boolean uploadFile(String remotePath, List<File> fileList) throws IOException {
boolean uploaded = true;
FileInputStream fis = null;
//連接FTP服務(wù)器
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;
}
// 轉(zhuǎn)移到FTP服務(wù)器目錄
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服務(wù)器下載文件
*
* @param remotePath FTP服務(wù)器上的相對路徑
* @param fileName 要下載的文件名
* @return 結(jié)果
*/
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服務(wù)器異常", 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.調(diào)用方法
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);
//文件已經(jīng)上傳成功
FTPUtil util = new FTPUtil(ip, port, username, password);
boolean success = util.uploadFile(Lists.newArrayList(targetFile), directory);
if (success) {
System.out.println("上傳成功");
}
//已經(jīng)上傳到ftp服務(wù)器上,刪除臨時文件
targetFile.delete();
}
這里是循環(huán)處理多個文件的方法。
5.注意事項
dubbo中不能夠傳遞multipartFile類型的數(shù)據(jù),所以,我這里處理上傳和下載都是在控制器中執(zhí)行的。查網(wǎng)上資料,有一種解決辦法,讓service實現(xiàn)hessian協(xié)議,這個協(xié)議是基于HTTP通訊協(xié)議,可以完成文件數(shù)據(jù)傳輸,但是我按照教程嘗試使用的時候,并沒有成功,暫時沒有解決問題。