1、FastDFS簡介
FastDFS是一個開源的輕量級分布式檔案系統,它對檔案進行管理,功能包括:檔案存儲、檔案同步、檔案通路(檔案上傳、檔案下載下傳)等,解決了大容量存儲和負載均衡的問題。特别适合以檔案為載體的線上服務,如相冊網站、視訊網站等等。
FastDFS為網際網路量身定制,充分考慮了備援備份、負載均衡、線性擴容等機制,并注重高可用、高性能等名額,使用FastDFS很容易搭建一套高性能的檔案伺服器叢集提供檔案上傳、下載下傳等服務。
FastDFS 架構包括 Tracker server 和 Storage server。用戶端請求 Tracker server 進行檔案上傳、下載下傳,通過Tracker server 排程最終由 Storage server 完成檔案上傳和下載下傳。Tracker server 作用是負載均衡和排程,通過 Tracker server 在檔案上傳時可以根據一些政策找到Storage server 提供檔案上傳服務。可以将 tracker 稱為追蹤伺服器或排程伺服器。Storage server 作用是檔案存儲,用戶端上傳的檔案最終存儲在 Storage 伺服器上,Storageserver 沒有實作自己的檔案系統而是利用作業系統的檔案系統來管理檔案。可以将storage稱為存儲伺服器
2、檔案上傳流程
用戶端上傳檔案後存儲伺服器将檔案 ID 傳回給用戶端,此檔案 ID 用于以後通路該檔案的索引資訊。檔案索引資訊包括:組名,虛拟磁盤路徑,資料兩級目錄,檔案名
組名:檔案上傳後所在的 storage 組名稱,在檔案上傳成功後有storage 伺服器傳回,需要用戶端自行儲存。
虛拟磁盤路徑:storage 配置的虛拟路徑,與磁盤選項store_path*對應。如果配置了store_path0 則是 M00,如果配置了 store_path1 則是 M01,以此類推。
資料兩級目錄:storage 伺服器在每個虛拟磁盤路徑下建立的兩級目錄,用于存儲資料檔案。
檔案名:與檔案上傳時不同。是由存儲伺服器根據特定資訊生成,檔案名包含:源存儲伺服器 IP 位址、檔案建立時間戳、檔案大小、随機數和檔案拓展名等資訊。
3、搭建檔案存儲微服務
建立檔案管理微服務 service_file,該工程主要用于實作檔案上傳以及檔案删除等功能。
3.1 修改pom.xml,引入依賴
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐web</artifactId>
</dependency>
<dependency>
<groupId>net.oschina.zcx7878</groupId>
<artifactId>fastdfs‐client‐java</artifactId>
<version>1.27.0.0</version>
</dependency>
</dependencies>
3.2 在resources檔案夾下建立fasfDFS的配置檔案fdfs_client.conf
# 連接配接逾時時間,機關為秒。
connect_timeout=60
# 通信逾時時間,機關為秒
network_timeout=60
# 字元集
charset=utf-8
# tracker的http端口:浏覽器通路
http.tracker_http_port=8080
# Tracker伺服器與外界通信的IP和端口:Java程式通路
tracker_server=192.168.33.133:22122
3.3 在resources檔案夾下建立application.yml
server:
port: 18082
spring:
application:
name: file
servlet:
multipart:
max‐file‐size: 10MB
max‐request‐size: 10MB
main:
allow‐bean‐definition‐overriding: true # 當遇到同樣名字的時候,是否允許覆寫注冊
eureka:
client:
service‐url:
defaultZone: http://127.0.0.1:7001/eureka
instance:
prefer‐ip‐address: true
- max-file-size是單個檔案大小
- max-request-size是設定總上傳的資料大小
3.4 建立啟動類
@SpringBootApplication
@EnableEurekaClient
public class FileApplication {
public static void main(String[] args) {
SpringApplication.run(FileApplication.class);
}
}
4、檔案上傳示例代碼
4.1 檔案資訊封裝
檔案上傳一般都有檔案的名字、檔案的内容、檔案的擴充名、檔案的md5值、檔案的作者等相關屬性,我們可以建立一個對象封裝這些屬性。
@Getter
@Setter
public class FastDFSFile {
// 檔案名字
private String name;
// 檔案内容
private byte[] content;
// 檔案擴充名
private String ext;
// 檔案MD5摘要值
private String md5;
// 檔案建立作者
private String author;
public FastDFSFile(String name, byte[] content, String ext, String
height,String width, String author) {
this.name = name;
this.content = content;
this.ext = ext;
this.author = author;
}
public FastDFSFile(String name, byte[] content, String ext) {
super();
this.name = name;
this.content = content;
this.ext = ext;
}
}
4.2、檔案操作工具類
@Slf4j
public class FastDFSUtils {
static {
try{
// 獲得配置檔案路徑
String file = new ClassPathResource("fsdf_client.conf").getPath();
// 加載tracker配置資訊
ClientGlobal.init(file);
} catch(Exception e){
e.printStackTrace();
}
}
/**
* 檔案上傳方法
* @param file
* @return
*/
public static String[] upload(FastDFSFile file) {
// 擷取檔案的作者
NameValuePair[] meta_list = new NameValuePair[1];
meta_list[0] = new NameValuePair("author", file.getAuthor());
// 接收傳回資料
String[] uploadResults = null;
StorageClient storageClient = null;
try {
// 建立StorageClient用戶端對象
storageClient = getStorageClient();
/**
* 1)檔案位元組數組
* 2)檔案擴充名
* 3)檔案作者
*/
uploadResults = storageClient.upload_file(file.getContent(),file.getExt(),meta_list);
} catch (Exception e){
log.error("Exception when uploadind the file:" +
file.getName(), e);
}
if (uploadResults == null && storageClient!=null) {
log.error("upload file fail, error code:" +
storageClient.getErrorCode());
}
// 擷取組名
String groupName = uploadResults[0];
// 擷取檔案存儲路徑
String remoteFileName = uploadResults[1];
return uploadResults;
}
/**
* 檔案下載下傳
* @param groupName 檔案所在組名:group1
* @param remoteFileName 檔案的存儲路徑名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
* @return
*/
public static InputStream downloadFile(String groupName,String remoteFileName) throws Exception {
// 1. 獲得Storage用戶端
StorageClient storageClient = getStorageClient();
// 2. 下載下傳檔案
byte[] buf = storageClient.download_file(groupName, remoteFileName);
// 3. 将位元組數組轉換為輸入流
return new ByteArrayInputStream(buf);
}
/** 檔案删除
* @param groupName 檔案所在組名:group1
* @param remoteFileName 檔案的存儲路徑名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
*/
public static void deleteFile(String groupName,String remoteFileName) throws Exception{
getStorageClient().delete_file(groupName, remoteFileName);
}
/**
* 擷取檔案資訊
* @param groupName 檔案所在組名:group1
* @param remoteFileName 檔案的存儲路徑名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
* @return
*/
public static FileInfo getFileInfo(String groupName, String remoteFileName) throws Exception {
return getStorageClient().get_file_info(groupName, remoteFileName);
}
/**
* 擷取Tracker的資訊
* @throws Exception
*/
public static String getTrackerInfo() throws IOException{
// 擷取TrackerServer對象
TrackerServer trackerServer = getTrackerServer();
// 獲得Tracker的IP和端口
String ip = trackerServer.getInetSocketAddress().getHostString();
int port = ClientGlobal.getG_tracker_http_port();
return "http://"+ip+":"+port+"/";
}
/**
* * 擷取Storage用戶端
*/
private static StorageClient getStorageClient() throws IOException {
TrackerServer trackerServer = getTrackerServer();
StorageClient storageClient = new StorageClient(trackerServer,
null);
return storageClient;
}
/*
**
* 擷取Tracker伺服器
*/
private static TrackerServer getTrackerServer() throws IOException {
TrackerClient trackerClient = new TrackerClient();
TrackerServer trackerServer = trackerClient.getConnection();
return trackerServer;
}
}
4.3、檔案上傳控制器
@RestController
@CrossOrigin
public class FileController {
@PostMapping("/upload")
public Result uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
// 建立FastDFSFile對象:封裝檔案資料
FastDFSFile fastDFSFile = new FastDFSFile(
file.getOriginalFilename(),
file.getBytes(),
StringUtils.getFilenameExtension(file.getOriginalFilename()));
// 調用工具類方法執行上傳
String[] uploadResults = FastDFSUtils.upload(fastDFSFile);
// 擷取組名
String groupName = uploadResults[0];
// 擷取檔案存儲路徑
String remoteFileName = uploadResults[1];
// 拼接通路位址
String url = FastDFSUtils.getTrackerInfo() +groupName+"/"+remoteFileName;
return new Result(true, StatusCode.OK, "上傳成功",url);
}
}