天天看點

2,分布式檔案存儲FastDFS1,簡介2,上傳流程3,檔案存儲微服務4,檔案上傳

代碼實作過程:

1.引入依賴,表示是FastDFS的用戶端

2.配置FastDFS配置檔案資訊,裡面包含了FastDFS的路徑、端口、連接配接逾時時間等(注意這個我并沒有加載,在使用的時候在工具類中加載這個檔案的,進而擷取Tracker對象)

3.SpringBoot配置檔案application.yml配置multipart設定上傳檔案大小

4.啟動類加入@SpringBootApplication(exclude={DataSourceAutoConfiguration.class}):排除資料庫自動加載

5.已經搭建完成了

6.前端請求上傳,controller層使用Multipart接收,檔案的資訊封裝在裡面。

7.建立一個實體類FastDFSFile,使用者封裝Multipart中的資訊,例如檔案的名字、内容、字尾名等。然後然後調用工具類發方法把這個實體類傳入到工具類中,使用工具類上傳到伺服器中。傳回

8.工具類首先要加載fdfs_client.conf配置檔案,然後通過獲得實體類FastDFSFile中的資訊發送給服務。

9.工具類執行檔案上傳,會傳回字元串集合,然後傳回給controller層。

10.controller層再通過工具類擷取tracker 的ip和端口的資訊,然後和字元串拼接成完整的URL傳回給前端

1,簡介

簡單來說就是部署在伺服器中,然後把檔案上傳到改伺服器中的技術。是一個分布式系統。

需要安裝到docker上的。

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,上傳流程

兩個元件:Tracker負責檔案管理負載均衡操作,控制中心(注冊中心)

​ Storage 檔案上傳、檔案下載下傳、檔案删除、檔案修改等…

2,分布式檔案存儲FastDFS1,簡介2,上傳流程3,檔案存儲微服務4,檔案上傳
2,分布式檔案存儲FastDFS1,簡介2,上傳流程3,檔案存儲微服務4,檔案上傳

storage Sever定時向Tracker Server注冊(Tracker Server更多是排程的作用)。

使用者請求上傳檔案請求Tracker,Tracker調用Storage查找可用的storage,tracker把查找到的storage傳回給用戶端(storage的IP和端口,作用就可以準确找到哪一個Storage Server),用戶端就根據IP和端口找到storage,用戶端上傳檔案的時候就會到這個Storager中,并且會在storage會建立升恒file_id并把上傳檔案内容寫入磁盤(伺服器中)。storage傳回資訊給用戶端,用戶端可以吧這些路徑資訊存到資料庫中。這樣我們就可以從資料庫中擷取路徑進而找到storage伺服器中檔案

注意,storage是以組的方式叢集

項目中的流程:檔案上傳到我們的項目,項目從tracker擷取storage傳回給項目,然後項目就把檔案上傳到storage就可以了。

用戶端上傳檔案後存儲伺服器将檔案 ID 傳回給用戶端,此檔案 ID 用于以後通路該檔案的索引資訊。檔案索引資訊包括:組名,虛拟磁盤路徑,資料兩級目錄,檔案名。

2,分布式檔案存儲FastDFS1,簡介2,上傳流程3,檔案存儲微服務4,檔案上傳

組名:檔案上傳後所在的 storage 組名稱,在檔案上傳成功後有storage 伺服器傳回,需要用戶端自行儲存。

虛拟磁盤路徑:storage 配置的虛拟路徑,與磁盤選項store_path*對應。如果配置了

store_path0 則是 M00,如果配置了 store_path1 則是 M01,以此類推。

資料兩級目錄:storage 伺服器在每個虛拟磁盤路徑下建立的兩級目錄,用于存儲資料

檔案。

檔案名:與檔案上傳時不同。是由存儲伺服器根據特定資訊生成,檔案名包含:源存儲

伺服器 IP 位址、檔案建立時間戳、檔案大小、随機數和檔案拓展名等資訊。

通路伺服器中的檔案是,是通過Nginx通路的。

3,檔案存儲微服務

預設FastDFS已經安裝好。

建立檔案管理微服務changgou-service-file,該工程主要用于實作檔案上傳以及檔案删除等功能。

3.1 依賴

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>changgou-service</artifactId>
        <groupId>com.changgou</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>changgou-service-file</artifactId>
    <description>檔案上傳工程</description>

    <!--依賴包-->
    <dependencies>
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27.0.0</version>
        </dependency>
        <dependency>
            <groupId>com.changgou</groupId>
            <artifactId>changgou-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>
           

3.2 FastDFS配置

搭建上傳服務需要的配置檔案,其中端口和路徑是stacker的路徑,因為要先通過stacker才能擷取到storage

在resources檔案夾下建立fasfDFS的配置檔案fdfs_client.conf

connect_timeout=60
network_timeout=60
charset=UTF-8
http.tracker_http_port=8080
tracker_server=192.168.211.132:22122
           

connect_timeout:連接配接逾時時間,機關為秒。

network_timeout:通信逾時時間,機關為秒。發送或接收資料時。假設在逾時時間後還不能發送或接收資料,則本次網絡通信失敗

charset: 字元集

http.tracker_http_port :.tracker的http端口

tracker_server: tracker伺服器IP和端口設定

注意這裡是tracker的路徑,因為要先通過找到tracker才能擷取到storage

3.2 SpringBoot配置檔案

spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  application:
    name: file
server:
  port: 18082
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:7001/eureka
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true
           

max-file-size是單個檔案大小,max-request-size是設定總上傳的資料大小

3.3 啟動類

建立com.changgou包,建立啟動類FileApplication

// 排除資料庫自動加載 	 
@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})
@EnableEurekaClient
public class FileApplication {

    public static void main(String[] args) {
        SpringApplication.run(FileApplication.class);
    }
}
           

上傳檔案服務的啟動類需要加入@SpringBootApplication(exclude={DataSourceAutoConfiguration.class})

排除資料庫主動加載,因為該服務引用了changgou-common(裡面有加載資料庫的依賴)。如果不排除主動加載會報錯。

4,檔案上傳

操作過程:

前端點選上傳檔案背景是使用MultipartFile來接受,從MultipartFile中擷取裡面的資訊(包括檔案名等),把這些資訊封裝到FastDFSFile對象中,然後使用上傳工具類發檔案發送到伺服器中。把這些封裝資訊的對象傳入到工具類中就能可以實作上傳了,因為上傳的時候需要的就這這些資訊(檔案名,位元組類型,字尾名)。最後傳回URL給前端顯示。

4.1 檔案資訊封裝

檔案上傳一般都有檔案的名字、檔案的内容、檔案的擴充名、檔案的md5值、檔案的作者等相關屬性,我們可以建立一個對象封裝這些屬性,錄入上傳一張圖檔就需要這些資訊

代碼如下:

建立

com.changgou.file.FastDFSFile

代碼如下:

public class FastDFSFile implements Serializable {

    //檔案名字
    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 md5, String author) {
        this.name = name;
        this.content = content;
        this.ext = ext;
        this.md5 = md5;
        this.author = author;
    }

    public FastDFSFile(String name, byte[] content, String ext) {
        this.name = name;
        this.content = content;
        this.ext = ext;
    }

    public FastDFSFile() {
    }

    //..get..set..toString
}
           

4.2 controller檔案上傳

MultipartFile接受檔案上傳

建立一個FileController,在該控制器中實作檔案上傳操作,代碼如下:

@RestController
@CrossOrigin
public class FileController {

    /***
     * 檔案上傳
     * @return
     */
    @PostMapping(value = "/upload")
    public String upload(@RequestParam("file")MultipartFile file) throws Exception {
        //封裝一個FastDFSFile
        FastDFSFile fastDFSFile = new FastDFSFile(
                file.getOriginalFilename(), //檔案名字
                file.getBytes(),            //檔案位元組數組
                StringUtils.getFilenameExtension(file.getOriginalFilename()));//檔案擴充名

        //檔案上傳
        String[] uploads = FastDFSClient.upload(fastDFSFile);
        // 拼接通路位址
        String url =  FastDFSClient.getTrackerUrl()+"/"+uploads[0]+"/"+uploads[1];
        //組裝檔案上傳位址	
        return new Result(true, StatusCode.OK, url);
    }
}
           

4.2 檔案操作工具類

(1)初始化Tracker資訊

com.changgou.util.FastDFSClient

類中初始化Tracker資訊,在類中添加如下靜态塊:

就是要加載這個配置檔案

/***
 * 初始化tracker資訊
 */
static {
    try {
        //擷取tracker的配置檔案fdfs_client.conf的位置
        String filePath = new ClassPathResource("fdfs_client.conf").getPath();
        //加載tracker配置資訊
        ClientGlobal.init(filePath);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
           

(2)操作檔案

方法中都會涉及到擷取TrackerServer或者StorageClient,我們可以把它們單獨抽取出去,分别在類中添加如下2個方法:

/***
 * 擷取TrackerServer
 */
public static TrackerServer getTrackerServer() throws Exception{
    //建立一個Tracker通路的用戶端對象TrackerClien
    TrackerClient trackerClient = new TrackerClient();
    //通過TrackerClient通路TrackerServer服務,擷取裡連接配接資訊
    TrackerServer trackerServer = trackerClient.getConnection();
    return trackerServer;
}

/***
 * 擷取StorageClient
 * @return
 * @throws Exception
 */
public static StorageClient getStorageClient() throws Exception{
    //擷取TrackerServer
    TrackerServer trackerServer = getTrackerServer();
    //通過TrackerServer建立StorageClient
    StorageClient storageClient = new StorageClient(trackerServer,null);
    return storageClient;
}
           

修改其他方法,在需要使用TrackerServer和StorageClient的時候,直接調用上面的方法,完整代碼如下:

public class FastDFSClient {

    /***
     * 初始化tracker資訊
     */
    static {
        try {
            //擷取tracker的配置檔案fdfs_client.conf的位置
            String filePath = new ClassPathResource("fdfs_client.conf").getPath();
            //加載tracker配置資訊
            ClientGlobal.init(filePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /****
     * 檔案上傳
     * @param file : 要上傳的檔案資訊封裝->FastDFSFile
     * @return String[]
     *          1:檔案上傳所存儲的組名
     *          2:檔案存儲路徑
     */
    public static String[] upload(FastDFSFile file){
        //擷取檔案作者
        NameValuePair[] meta_list = new NameValuePair[1];
        meta_list[0] =new NameValuePair(file.getAuthor());

        /***
         * 檔案上傳後的傳回值
         * uploadResults[0]:檔案上傳所存儲的組名,例如:group1
         * uploadResults[1]:檔案存儲路徑,例如:M00/00/00/wKjThF0DBzaAP23MAAXz2mMp9oM26.jpeg
         */
        String[] uploadResults = null;
        try {
            //擷取StorageClient對象
            StorageClient storageClient = getStorageClient();
            /**執行檔案上傳
             *1 上傳檔案位元組數組
             *2 檔案的字尾名
             * 3 附加參數 例如拍攝場地:廣州
             其中file.getExt在controller層就把字尾名加到FastDFSFile中了
            */
            uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return uploadResults;
    }


    /***
     * 擷取檔案資訊
     * @param groupName:組名
     * @param remoteFileName:檔案存儲完整名
     */
    public static FileInfo getFile(String groupName,String remoteFileName){
        try {
            //擷取StorageClient對象
            StorageClient storageClient = getStorageClient();
            //擷取檔案資訊
            return storageClient.get_file_info(groupName,remoteFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 檔案下載下傳
     * @param groupName:組名
     * @param remoteFileName:檔案存儲完整名
     * @return
     */
    public static InputStream downFile(String groupName,String remoteFileName){
        try {
            //擷取StorageClient
            StorageClient storageClient = getStorageClient();
            //通過StorageClient下載下傳檔案
            byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
            //将位元組數組轉換成位元組輸入流
            return new ByteArrayInputStream(fileByte);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 檔案删除實作
     * @param groupName:組名
     * @param remoteFileName:檔案存儲完整名
     */
    public static void deleteFile(String groupName,String remoteFileName){
        try {
            //擷取StorageClient
            StorageClient storageClient = getStorageClient();
            //通過StorageClient删除檔案
            storageClient.delete_file(groupName,remoteFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /***
     * 擷取組資訊
     * @param groupName :組名
     */
    public static StorageServer getStorages(String groupName){
        try {
            //建立TrackerClient對象
            TrackerClient trackerClient = new TrackerClient();
            //通過TrackerClient擷取TrackerServer對象
            TrackerServer trackerServer = trackerClient.getConnection();
            //通過trackerClient擷取Storage組資訊
            return trackerClient.getStoreStorage(trackerServer,groupName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 根據檔案組名和檔案存儲路徑擷取Storage服務的IP、端口資訊
     * @param groupName :組名
     * @param remoteFileName :檔案存儲完整名
     */
    public static ServerInfo[] getServerInfo(String groupName, String remoteFileName){
        try {
            //建立TrackerClient對象
            TrackerClient trackerClient = new TrackerClient();
            //通過TrackerClient擷取TrackerServer對象
            TrackerServer trackerServer = trackerClient.getConnection();
            //擷取服務資訊
            return trackerClient.getFetchStorages(trackerServer,groupName,remoteFileName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 擷取Tracker服務位址
     */
    public static String getTrackerUrl(){
        try {
            //建立TrackerClient對象
            TrackerClient trackerClient = new TrackerClient();
            //通過TrackerClient擷取TrackerServer對象
            TrackerServer trackerServer = trackerClient.getConnection();
            //擷取Tracker位址
            return "http://"+trackerServer.getInetSocketAddress().getHostString()+":"+ClientGlobal.getG_tracker_http_port();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /***
     * 擷取TrackerServer
     */
    public static TrackerServer getTrackerServer() throws Exception{
        //建立TrackerClient對象
        TrackerClient trackerClient = new TrackerClient();
        //通過TrackerClient擷取TrackerServer對象
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerServer;
    }

    /***
     * 擷取StorageClient
     * @return
     * @throws Exception
     */
    public static StorageClient getStorageClient() throws Exception{
        //擷取TrackerServer
        TrackerServer trackerServer = getTrackerServer();
        //通過TrackerServer建立StorageClient
        StorageClient storageClient = new StorageClient(trackerServer,null);
        return storageClient;
    }
}
           

[外鍊圖檔轉存失敗,源站可能有防盜鍊機制,建議将圖檔儲存下來直接上傳(img-Bv6fN8Ak-1596182843330)(C:\Users\MT\AppData\Local\Temp\1596182789950.png)]

etConnection();

return trackerServer;

}

/***
 * 擷取StorageClient
 * @return
 * @throws Exception
 */
public static StorageClient getStorageClient() throws Exception{
    //擷取TrackerServer
    TrackerServer trackerServer = getTrackerServer();
    //通過TrackerServer建立StorageClient
    StorageClient storageClient = new StorageClient(trackerServer,null);
    return storageClient;
}
           

}

![\[外鍊圖檔轉存中...(img-Bv6fN8Ak-1596182843330)\]](https://img-blog.csdnimg.cn/20200731171810188.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1ODUwODcy,size_16,color_FFFFFF,t_70)