FastDFS之文件上傳/下載/刪除

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);
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章