FastDFS + SpringBoot + RestFul 簡單的完成文件上傳(簡單)

一個簡單的FastDFS + SpringBoot + RestFul 上傳文件的案例

前言:FastDFS是一個新接觸的技術,SpringBoot和RestFul在本文中就不做介紹了,閱讀本文需要有SpringBoot和RestFul的基礎

FastDFS

什麼是 FastDFS
FastDFS 是⼀個開源的輕量級分佈式⽂件系統,它解決了⼤數據量存儲和負載均衡等問題,特別適合以中⼩ ⽂件(建議範圍:4 KB < file_size < 500 MB)爲載體的在線服務,如相冊⽹站、視頻⽹站等。在 UC 基於 FastDFS 開發向⽤戶提供了⽹盤、社區、⼴告和應⽤下載等業務的存儲服務。

FastDFS 由 C 語⾔開發,⽀持 Linux、FreeBSD 等 UNIX 系統類 Google FS,不是通⽤的⽂件系統,只能通 過專有 API 訪問,⽬前提供了 C、Java 和 PHP API,爲互聯⽹應⽤量身定做,解決了⼤容量⽂件存儲問 題,追求⾼性能和⾼擴展性,FastDFS 可以看做是基於⽂件的 Key Value Pair 存儲系統,稱作分佈式⽂件存 儲服務會更合適。

FastDFS 特性
⽂件不分塊存儲,上傳的⽂件和 OS ⽂件系統中的⽂件⼀⼀對應 ⽀持相同內容的⽂件只保存⼀份,節約磁盤空間 下載⽂件⽀持 HTTP 協議,可以使⽤內置 Web Server,也可以和其他 Web Server 配合使⽤ ⽀持在線擴容 ⽀持主從⽂件 存儲服務器上可以保存⽂件屬性(meta-data)V2.0 ⽹絡通信採⽤ libevent,⽀持⼤併發訪問,整體性 能更好

FastDFS 相關概念
FastDFS 服務端有三個⻆角⾊:跟蹤服務器(Tracker Server)、存儲服務器(Storage Server)和客戶端 (Client)。
Tracker Server:跟蹤服務器,主要做調度⼯作,起負載均衡的作⽤。在內存記錄集羣中所有存儲組和 存儲服務器的狀態信息,是客戶端和數據服務器交互的樞紐。相⽐ GFS 中的 Master 更爲精簡,不記錄 ⽂件索引信息,佔⽤的內存量很少。 Storage Server:存儲服務器(⼜稱存儲節點或數據服務器),⽂件和⽂件屬性(Meta Data)都保存 到存儲服務器上。Storage Server 直接利⽤ OS 的⽂件系統調⽤管理⽂件。 Client:客戶端,作爲業務請求的發起⽅,通過專有接⼝,使⽤ TCP/IP 協議與跟蹤器服務器或存儲節 點進⾏數據交互。FastDFS 向使⽤者提供基本⽂件訪問接⼝,如 upload、download、append、delete 等,以客戶端庫的⽅式提供給⽤戶使⽤。

上傳機制

首先客戶端請求 Tracker 服務獲取到存儲服務器的 IP 地址和端口,然後客戶端根據返回的 IP 地址和端口號請求上傳文件,存儲服務器接收到請求後生產文件,並且將文件內容寫入磁盤並返回給客戶端 file_id、路徑信息、文件名等信息,客戶端保存相關信息上傳完畢。

圖示

在這裏插入圖片描述

項目結構

在這裏插入圖片描述

fastdfs包

FastDFSFile:改類是上傳的工具類,封裝FastDFSFile。主要包括文件的基礎信息 [文件名,內容,文件的類型,作者]

代碼

package com.jimmy.fastdfs;

/**
 * @Author Jimmy
 * @Date 2019/8/22 9:25 PM
 * @Desc
 *
 * 上傳工具類:
 * 封裝 FastDFSFile,文件基礎信息包括文件名、內容、文件類型、作者等
 */

public class FastDFSFile {
    //文件名
    private String name;
    //文件內容
    private byte[] content;
    //文件類型
    private String ext;
    //作者 (上傳者)
    private String author;

    public FastDFSFile() {
    }


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

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public byte[] getContent() {
        return content;
    }

    public void setContent(byte[] content) {
        this.content = content;
    }

    public String getExt() {
        return ext;
    }

    public void setExt(String ext) {
        this.ext = ext;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

FastDFSClient:該類客戶端 提供上傳文件

代碼

package com.jimmy.fastdfs;

import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.core.io.ClassPathResource;


import java.io.IOException;

/**
 * @Author Jimmy
 * @Date 2019/8/22 9:29 PM
 * @Desc
 *
 * FastDFSClient:客戶端 提供上傳文件
 */

public class FastDFSClient {


    //TODO 1.類加載時讀取配置信息,並進行初始化
    static {
        try {
            String path = new ClassPathResource("FastDFS.conf").getFile().getAbsolutePath();
            //FastDFS客戶端初始化方法
            ClientGlobal.init(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //TODO 2.上傳文件
    public static String[] upload(FastDFSFile file){

        //打印查看文件的信息 文件名和文件的字節長度
        System.out.println("FileName:" + file.getName() + " FileContent:" + file.getContent().length);


        //文件屬性
        //NameValuePair,主要存儲文件的一些基礎屬性,如作者信息、創建時間等
        NameValuePair[] nameValuePair = new NameValuePair[1];
        nameValuePair[0] = new NameValuePair("author",file.getAuthor());


        //上傳結果
        String[] uploadResults = null;

        //存儲客戶端
        StorageClient storageClient = null;

        try {
            //獲取客戶端實例
            storageClient = getStorageClient();
            //封裝最終上傳結果
            uploadResults = storageClient.upload_file(file.getContent(),file.getExt(),nameValuePair);
        } catch (Exception e) {
            e.printStackTrace();
        }

        //驗證上傳結果
        if (uploadResults == null && storageClient != null) {
            //這裏直接打印上傳文件失敗 不做其他操作
            System.out.println("上傳文件失敗");
        }
        System.out.println("上傳文件成功");
        return uploadResults;
    }


    /**
     * 首先獲取 TrackerServer [追蹤服務器] 信息,
     * 使用 TrackerServer 構建出每次操作的客戶端實例 StorageClient
     * @return
     */
    private static StorageClient getStorageClient() throws IOException {
        //獲取TrackerServer
        TrackerServer trackerServer = getTrackerServer();
        StorageClient client = new StorageClient(trackerServer, null);
        return client;
    }

    /**
     * 獲取TrackerServer的方法
     * @return
     */
    private static TrackerServer getTrackerServer() throws IOException {

            TrackerClient trackerClient = new TrackerClient();
            //客戶端獲得追蹤服務器的連接
            TrackerServer server = trackerClient.getConnection();
            return server;
    }

    /**
     * TODO 上傳文件返回的URL
     * @return
     * @throws IOException
     */
    public static String getTrackerUrl() throws IOException {
        return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ClientGlobal.getG_tracker_http_port()+"/";
    }
}

controller包

UploadFileController:處理文件上傳的controller

代碼

package com.jimmy.controller;

import com.jimmy.fastdfs.FastDFSClient;
import com.jimmy.fastdfs.FastDFSFile;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

/**
 * @Author Jimmy
 * @Date 2019/8/22 10:15 PM
 * @Desc 處理文件上傳的controller
 */

@RestController
@RequestMapping("/fastdfs")
public class UploadFileController {

    /**
     * TODO 上傳文件的接口
     * @param file
     * @return
     */

    @PostMapping("/upload")
    public ResponseEntity<String> upload(MultipartFile file) throws IOException {
        if (file.isEmpty()) {
            return new ResponseEntity<>("文件爲不能爲空",HttpStatus.INTERNAL_SERVER_ERROR);
        }
        String path = saveFile(file);
        return new ResponseEntity<>(path,HttpStatus.CREATED);
    }



    public String saveFile(MultipartFile file) throws IOException {
        //文件信息
        String[] fileInformation = {};
        //文件的名稱
        String fileName = file.getOriginalFilename();
        //通過文件的名稱獲取文件的類型
        String fileType = fileName.substring(fileName.lastIndexOf(".") + 1);

        //儲存文件內容的字節數組
        byte[] fileContent = null;

        InputStream inputStream = file.getInputStream();
        //一下操作是將文件讀取到字節數組
        if (inputStream != null) {
            int length = inputStream.available();
            fileContent = new byte[length];
            inputStream.read(fileContent);
        }
        //關閉流
        inputStream.close();
        FastDFSFile fastDFSFile = new FastDFSFile(fileName, fileContent, fileType);

        fileInformation = FastDFSClient.upload(fastDFSFile);

        String path = FastDFSClient.getTrackerUrl() + fileInformation[0] + "/" + fileInformation[1];
        return path;
    }
}

UploadFile.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上傳</title>
    <script type="text/javascript" src="js/jquery.min.js"></script>
</head>
<body>

    <script>
        $(function () {
            $("#button").click(function () {

                var data = new FormData;
                var file = $("#file").prop("files");
                data.append("file",file[0]);

                $.ajax({
                    type: "POST",
                    url: "/fastdfs/upload",
                    data: data,
                    cache: false,
                    processData: false,
                    contentType: false,
                    statusCode: {
                        201: function (data) {
                            alert("上傳成功!文件的路徑爲:"+data)
                            window.location.href = data;
                        },
                        500: function (data) {
                            console.log(data.toString())
                            alert("文件上傳失敗")
                        }
                    }
                });
            })
        })
    </script>

    <div>
        <form>
            <input type="file" id="file"/>
            <input type="button" id="button" value="上傳"/>
        </form>
    </div>
</body>
</html>

application.properties

### 最大上傳文件大小
spring.servlet.multipart.max-file-size=10MB
### 總上傳的文件大小
spring.servlet.multipart.max-request-size=10MB

配置文件 FastDFS.conf

connect_timeout = 60
network_timeout = 60
charset = UTF-8
http.tracker_http_port = 追蹤服務器端口號
http.anti_steal_token = no
http.secret_key = 123456

tracker_server = 服務器IP:22122

pom.xml 文件

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.jimmy</groupId>
    <artifactId>springboot_fastdfs</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot_fastdfs</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.csource</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

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