【分布式专题】-FastDFS搭建高可用分布式文件存储系统 集成springboot调用

目录

 

1.什么是FastDFS?

1.1简介

1.2FastDFS的存储策略

1.3FastDFS的上传过程

1.4FastDFS的文件同步

1.5FastDFS的文件下载

2.FastDFS搭建

2.1环境介绍

2.2依赖库安装

2.2.1下载安装libfastcommon

2.3安装FastDFS

2.4 配置FastDFS

2.4.1配置跟踪器Tracker

2.4.2配置存储Storage

2.4.3 文件上传测试

3.FastDFS集成Nginx 模块

3.1Nginx安装

4.集成Springboot

4.1环境

4.2依赖包

4.3配置

4.4编写核心代码

4.4.1创建FastDFSFile实体类

4.4.2创建FastDFSClient类

4.4.3封装文件上传工具类:

4.4.4编写文件上传的controller

4.4.5编写文件上传的页面index.html

4.5 测试


1.什么是FastDFS?

关于FastDFS的更多参考资料可以访问下面几个地址:

余庆大佬的Github:https://github.com/happyfish100  遗憾的是wiki不全,要上手的话还是得先找别的资料学习一下.

FastDFS的设计原理:http://blog.chinaunix.net/uid-20196318-id-4058561.html 推荐,可以帮助更好的理解FastDFS.

个人封装的Springboot+FastDFS实现图片的上传和获取Demo:https://github.com/laohanjianshen/springboot-fdfs 建议在fdfs搭好之后再来看.

本篇原理部分参考这篇:https://www.cnblogs.com/chiangchou/p/fastdfs.html#_label0_0  搭建不建议参考这篇,有坑.但无论如何感谢作者.

1.1简介

FastDFS 是一个开源的高性能分布式文件系统(DFS)。 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡。是由淘宝的架构师余庆写的,虽然存在一些缺陷,现已被淘宝弃用,但由于其开源和免费以及好用,对一些中小型公司仍是不错的选择.比较适合小文件的海量存储(建议范围:4KB < file_size <500MB),如果文件比较大的话,可以考虑用HDFS.

FastDFS主要有三个角色:跟踪服务TrackerServer,存储服务StorageServer,客户端Client.

Tracker Server:跟踪服务器,主要做调度工作,起到均衡的作用;负责管理所有的 storage server和 group,每个 storage 在启动后会连接 Tracker,告知自己所属 group 等信息,并保持周期性心跳。

Storage Server:存储服务器,主要提供容量和备份服务;以 group 为单位,每个 group 内可以有多台 storage server,数据互为备份。

Client:客户端,上传下载数据的服务器,也就是我们自己的项目所部署在的服务器。

1.2FastDFS的存储策略

为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用。

在卷中增加服务器时,同步已有的文件由系统自动完成,同步完成后,系统自动将新增服务器切换到线上提供服务。当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就扩大了存储系统的容量。

1.3FastDFS的上传过程

FastDFS向使用者提供基本文件访问接口,比如upload、download、append、delete等,以客户端库的方式提供给用户使用。

Storage Server会定期的向Tracker Server发送自己的存储信息。当Tracker Server Cluster中的Tracker Server不止一个时,各个Tracker之间的关系是对等的,所以客户端上传时可以选择任意一个Tracker。

当Tracker收到客户端上传文件的请求时,会为该文件分配一个可以存储文件的group,当选定了group后就要决定给客户端分配group中的哪一个storage server。当分配好storage server后,客户端向storage发送写文件请求,storage将会为文件分配一个数据存储目录。然后为文件分配一个fileid,最后根据以上的信息生成文件名存储文件。

1.4FastDFS的文件同步

写文件时,客户端将文件写至group内一个storage server即认为写文件成功,storage server写完文件后,会由后台线程将文件同步至同group内其他的storage server。

每个storage写文件后,同时会写一份binlog,binlog里不包含文件数据,只包含文件名等元信息,这份binlog用于后台同步,storage会记录向group内其他storage同步的进度,以便重启后能接上次的进度继续同步;进度以时间戳的方式进行记录,所以最好能保证集群内所有server的时钟保持同步。

storage的同步进度会作为元数据的一部分汇报到tracker上,tracke在选择读storage的时候会以同步进度作为参考。

1.5FastDFS的文件下载

客户端uploadfile成功后,会拿到一个storage生成的文件名,接下来客户端根据这个文件名即可访问到该文件。

跟upload file一样,在downloadfile时客户端可以选择任意tracker server。tracker发送download请求给某个tracker,必须带上文件名信息,tracke从文件名中解析出文件的group、大小、创建时间等信息,然后为该请求选择一个storage用来服务读请求。

在理清了上面这些FastDFS的原理和流程之后,下面开始正式搭建,在正式搭建前一定要理解上面的原理,否则你会很困惑.


2.FastDFS搭建

2.1环境介绍

环境:CentOS7.3 64位操作系统

FastDFS版本:V5.05

跟网上众多教程一样,本文也仅演示单机版的,原因主要是因为比较容易理解,在写这篇我搭了一个6个节点的分布式FastDFS,但如果搭建过程都贴上来的话,不仅重复的内容多,而且极难理解,建议初学者先按本篇搭建一个单机版的,搭建完之后你会有一个更深入的理解,在此基础上再考虑进行分布式演进,同时可以加深印象,不必急于求成直接就搭一个N节点的系统,我一开始也这么想的,但现在回头发现这么做其实很蠢,就好比走都没学会就想飞是一样的. 为了避免浪费不必要的时间,建议安装的依赖库,版本,以及操作顺序都按本篇走,因为我亲自踩过一遍坑,确保本篇是100%走的通的.

如果你确实想一步登天,我也给你个传送门:https://www.jianshu.com/p/88ccae4cbd82 可以参考这篇的架构,比较合理,节点数也适中,前提你得有6台服务器或者你的电脑内存16G及以上,开6个虚拟机.

2.2依赖库安装

2.2.1下载安装libfastcommon

#下载
wget https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz

#解压
# tar -zxvf V1.0.7.tar.gz
# cd libfastcommon-1.0.7

#安装
./make.sh
./make.sh install

创建软链接:

#libfastcommon.so 安装到了/usr/lib64/libfastcommon.so,但是FastDFS主程序设置的lib目录是/usr/local/lib,所以需要创建软链接

ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so
ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so 

2.3安装FastDFS

#下载
wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz

#解压 
tar -zxvf V5.05.tar.gz
cd fastdfs-5.05

#安装
./make.sh
./make.sh install

创建软链接:

#由于FastDFS 服务脚本设置的 bin 目录是 /usr/local/bin, 但实际命令安装在 /usr/bin/ 下,所以需要创建软链接

ln -s /usr/bin/fdfs_trackerd   /usr/local/bin
ln -s /usr/bin/fdfs_storaged   /usr/local/bin
ln -s /usr/bin/stop.sh         /usr/local/bin
ln -s /usr/bin/restart.sh      /usr/local/bin

2.4 配置FastDFS

配置文件的详细参考文档可以看这篇:FastDFS配置文件参考

2.4.1配置跟踪器Tracker

① 进入/etc/fdfs,复制FastDFS跟踪器样例配置文件 tracker.conf.sample,并重命名为tracker.conf

cd /etc/fdfs
cp tracker.conf.sample tracker.conf
vim tracker.conf

②编辑tracker.conf,只需要改我下面提到的即可,其他保持默认.

# 配置文件是否不生效,false 为生效
disabled=false

# Tracker 数据和日志目录地址(根目录必须存在,子目录会自动创建),为了尽量少的改动,我这里在余庆老师给的默认地址上加个tracker文件夹即可
base_path=/home/yuqing/fastdfs/tracker

# HTTP 服务端口 当然你保持8080也没毛病,只要不冲突.
http.server_port=80 

③创建tracker基础数据目录,即base_path对于的目录

mkdir -p /home/yuqing/fastdfs/tracker

 ④关闭防火墙或打开跟踪端口(默认22122)

vim /etc/sysconfig/iptables

添加如下端口行:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT

重启防火墙:
service iptables restart


或者用下面这种方式也行,我个人一直用这种方式:

/sbin/iptables -I INPUT -p tcp --dport 22122 -j ACCEPT

iptalbes-save

⑤启动Tracker

初次成功启动tracker后,它会自动在我们配置的目录(/home/yuqing/fastdfs/tracker)下创建data和log两个目录.

/etc/init.d/fdfs_trackerd start

启动后,可以通过下面的命令查看是否启动成功: 

netstat -unltp|grep fdfs

如果看到22122端口处于LISTEN状态,说明Tracker已经成功启动.

关闭Tracker命令:

service fdfs_trackerd stop

⑥ 设置Tracker开机启动

chkconfig fdfs_trackerd on
或者:
vim /etc/rc.d/rc.local
加入配置:
/etc/init.d/fdfs_trackerd start 

至此,tracker server就配置OK了,接下来的storage的配置步骤也几乎如出一辙.

2.4.2配置存储Storage

① 进入 /etc/fdfs 目录,复制 FastDFS 存储器样例配置文件 storage.conf.sample,并重命名为 storage.conf

cd /etc/fdfs
cp storage.conf.sample storage.conf
vim storage.conf

② 编辑storage.conf

下面提到的需要修改,其它的默认即可

# 配置文件是否不生效,false 为生效
disabled=false 


# Storage 数据和日志目录地址(根目录必须存在,子目录会自动生成)
base_path=/home/yuqing/fastdfs/storage

# 存放文件时 storage server 支持多个路径。这里配置存放文件的基路径数目,通常只配一个目录。
store_path_count=1


# 逐一配置 store_path_count 个路径,索引号基于 0。
# 如果不配置 store_path0,那它就和 base_path 对应的路径一样。
store_path0=/home/yuqing/fastdfs/file


# tracker_server 的列表 ,会主动连接 tracker_server
# 有多个 tracker server 时,每个 tracker server 写一行
#填写你刚刚启动的trackerServer的ip和端口号
tracker_server=192.168.174.128:22122

# 访问端口
http.server_port=80
 

③ 创建Storage基础数据目录,对应base_path目录

mkdir -p /home/yuqing/fastdfs/storage

# 这是配置的store_path0路径
mkdir -p /home/yuqing/fastdfs/file

④ 防火墙中打开存储器端口(默认的 23000) 

vim /etc/sysconfig/iptables

添加如下端口行:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 23000 -j ACCEPT

重启防火墙:
service iptables restart

⑤ 启动 Storage

启动Storage前确保Tracker是启动的。初次启动成功,会在 /home/yuqing/fastdfs/storage 目录下创建 data、 logs 两个目录。

可以用这种方式启动
# /etc/init.d/fdfs_storaged start

也可以用这种方式,后面都用这种
# service fdfs_storaged start

查看 Storage 是否成功启动,23000 端口正在被监听,就算 Storage 启动成功。

netstat -unltp|grep fdfs

关闭Storage命令:

service fdfs_storaged stop

查看Storage和Tracker是否在通信:

/usr/bin/fdfs_monitor /etc/fdfs/storage.conf

⑥ 设置 Storage 开机启动

chkconfig fdfs_storaged on

#或者:
vim /etc/rc.d/rc.local
#加入配置:
/etc/init.d/fdfs_storaged start
 

⑦ Storage 目录

同 Tracker,Storage 启动成功后,在base_path 下创建了data、logs目录,记录着 Storage Server 的信息。

在 store_path0 目录下,创建了N*N个子目录:

2.4.3 文件上传测试

① 修改 Tracker 服务器中的客户端配置文件 

cd /etc/fdfs
cp client.conf.sample client.conf
vim client.conf

修改如下配置即可,其它默认。

# Client 的数据和日志目录
base_path=/home/yuqing/fastdfs/client
# Tracker端口
tracker_server=192.168.174.128:22122
 

②上传测试

 在linux内部执行如下命令上传 root目录下的某张图片(当然你可以上传其他目录下的图片都OK,我这里正好root下有一张)

# /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /root/a.png

上传成功后返回文件ID号:group1/M00/00/00/wKiugFxQeEuAXSoXAABPKl4woFc369.png

返回的文件ID由group、存储目录、两级子目录、fileid、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。

3.FastDFS集成Nginx 模块

3.1Nginx安装

Nginx的安装本不想在这里赘述的,已经写过很多篇了,这里就简单演示下,如果不会可以翻我之前的博客.

演示中的Nginx的版本:1.12.2

在安装Nginx前,请先确定你的服务器上已安装相应的库,比如:gcc,PCRE,pcre-devel,zlib,OpenSSL等依赖,若无请自行用yum安装.

①:下载Nginx和FastDFS的Nginx模块:

wget -c https://nginx.org/download/nginx-1.12.2.tar.gz
wget https://github.com/happyfish100/fastdfs-nginx-module/archive/master.zip

 ②分别解压之:

tar  -zxvf nginx-1.12.2.tar.gz
unzip master.zip

③编译和安装:

#进入Nginx解压后的目录,执行下面这条命令添加fdfs-nginx模块:
./configure --add-module=../fastdfs-nginx-module-master/src/ 

#编译和安装
make && make install

安装完成后确认下是否成功:

/usr/local/nginx/sbin/nginx -V

如果看到红框中的就成功了:

如果出现下图这种错误,请检查你的Nginx版本及fdfs-nginx版本,可能存在不兼容问题.

④配置fdfs-nginx模块:

 #复制 fastdfs-nginx-module 源码中的配置文件到/etc/fdfs 目录,并修改:
cd /softpackages/fastdfs-nginx-module-master/src

cp mod_fastdfs.conf /etc/fdfs/

vi /etc/fdfs/mod_fastdfs.conf

修改如下配置,其它的保持默认: 

# 连接超时时间
connect_timeout=10

# Tracker Server
tracker_server=192.168.174.128:22122

# StorageServer 默认端口
storage_server_port=23000

# 如果文件ID的uri中包含/group**,则要设置为true
url_have_group_name = true

# Storage 配置的store_path0路径,必须和storage.conf中的一致
store_path0=/home/yuqing/fastdfs/file

⑤复制 FastDFS 的部分配置文件到/etc/fdfs 目录,这步不可少:

cd /softpackages/fastdfs-5.05/conf/

cp anti-steal.jpg http.conf mime.types /etc/fdfs/
 

⑥配置nginx,修改nginx.conf.

vim /usr/local/nginx/conf/nginx.conf
#在80端口下添加fastdfs-nginx模块,其它配置保持默认

location ~/group([0-9])/M00 {
    ngx_fastdfs_module;
}

为了防止有些人配错,我直接贴一份我的配置,以供复制:

worker_processes  1;
events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       80;
        server_name  localhost;
        location / {
            root   html;
            index  index.html index.htm;
        }
        error_page 500 502 503 504 /50x.html;
        location = /50x.html{
                root html;
        }

        location ~/group([0-9])/M00{
             ngx_fastdfs_module;
        }
    }
}

注意:

listen 80 端口值是要与 /etc/fdfs/storage.conf 中的 http.server_port=80 (前面改成80了)相对应。如果改成其它端口,则需要统一,同时在防火墙中打开该端口。

location 的配置,如果有多个group则配置location ~/group([0-9])/M00 ,没有则不用配group。

⑦ 在/home/yuqing/fastdfsfile 文件存储目录下创建软连接,将其链接到实际存放数据的目录,这一步可以省略:

ln -s /home/yuqing/fastdfs/file/data/ /home/yuqing/fastdfs/file/data/M00 

⑧ 启动nginx

/usr/local/nginx/sbin/nginx

打印出如下就算配置成功:

⑨测试图片访问

在浏览器中能访问到即算成功。注意和第三点中直接使用nginx路由访问不同的是,这里配置 fastdfs-nginx-module 模块,可以重定向文件链接到源服务器取文件。

http://192.168.174.128/group1/M00/00/00/wKiugFxQeEuAXSoXAABPKl4woFc369.png

效果如图:我上传的图比较小,将就着看吧...

 至此,FastDFS+NGINX搭建的文件服务器就完成了,通过亲自搭建,你对整个FastDFS的流程应该有所深入理解,其过程大致如下图所示:

当然这不是最终的服务架构,最终要架构成什么样子,还是要看你公司的服务器量和要设计的存储量级等,一个高可用的企业级FastDFS架构至少需要6个节点,其架构大致如下(盗的图):

每个模块都有2个节点,以确保一个挂了还有另外一个,最终通过Keepalived向外暴露一个虚拟的访问ip.有条件搭6节点的可以在本篇往上翻,我已经给了这篇的URL了,可以进一步深入研究.

4.集成Springboot

上面已经搭好了一个"分布式"的文件系统,最终对我们这些后端码农来说,还是要回到文件的上传和下载,至于为啥选springboot就不再解释了2019年了毕竟...

4.1环境

Jdk:1.8

springboot:2.1.2 RELEASE

fastdfs-client-java:1.27.0.0 这里不要选用余大佬github上推荐的版本,可能是还未发布,加入pom后依赖下载不下来,坑了我好久.

4.2依赖包

贴一份我项目的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 http://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.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.xpc</groupId>
    <artifactId>fdfs</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>fdfs</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-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27.0.0</version>
        </dependency>
    </dependencies>

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

</project>

4.3配置

在resources目录下创建:fdfs_client.conf文件,并加入以下配置:

connect_timeout = 60
network_timeout = 60
charset = UTF-8
http.tracker_http_port = 80
http.anti_steal_token = false
tracker_server = 192.168.174.128:22122

为了简单,我把防盗链关了,如果是生产环境下,建议开启.

4.4编写核心代码

4.4.1创建FastDFSFile实体类

@Data
public class FastDFSFile {
    private String name;
    private byte[] content;
    private String ext;//扩展名
    private String md5;
    private String author;

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

4.4.2创建FastDFSClient类

@Data
public class FastDFSClient {
    private static final Logger logger = LoggerFactory.getLogger(FastDFSClient.class);
    private static TrackerClient trackerClient;
    private static TrackerServer trackerServer;
    private static StorageClient storageClient;
    private static StorageServer storageServer;
    //通过静态代码块初始化连接
    static {
        try {
            String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
            ClientGlobal.init(filePath);
            trackerClient = new TrackerClient();
            trackerServer = trackerClient.getConnection();
            storageServer = trackerClient.getStoreStorage(trackerServer);
        } catch (Exception e) {
            logger.error("FastDFS Client Init Fail!", e);
        }
    }

    /**
     * 上传
     *
     * @param file
     * @return
     */
    public static String[] upload(FastDFSFile file) {
        logger.info("FileName:" + file.getName() + "FileLength:" + file.getContent().length);
        Long startTime = System.currentTimeMillis();
        NameValuePair[] meta_list = new NameValuePair[1];
        meta_list[0] = new NameValuePair("auther", file.getAuthor());
        String[] uploadResults = null;
        try {
            storageClient = new StorageClient(trackerServer, storageServer);
            uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
        } catch (IOException e) {
            logger.error("IOException when upload  the file:" + file.getName(), e);
        } catch (Exception e) {
            logger.error("No IOException when upload the file:" + file.getName(), e);
        }
        logger.info("Upload spend time:" + (System.currentTimeMillis() - startTime) + " ms");
        if (uploadResults == null) {
            logger.error("Upload fail! errorCode:" + storageClient.getErrorCode());
        }
        logger.info("Upload successfully! Group name:" + uploadResults[0] + " remoteFileName:" + uploadResults[1]);
        return uploadResults;
    }

    public static String getTrackerUrl() {
        return trackerServer.getInetSocketAddress().getHostName();//获取服务器Ip:192.168.174.128 但这种种方式获取方式有点慢 耗时约1.2s,在单机下当然可以从conf里直接读取,但集群的话好像只能这样取...
    }
}

4.4.3封装文件上传工具类:

public class FileUtil {
    private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);

    public static String upload(MultipartFile multipartFile) throws IOException {
        String fileAbsolutePath[] = {};
        String fileName = multipartFile.getOriginalFilename();
        String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
        byte[] buffer = null;
        InputStream inputStream = null;
        try {
            inputStream = multipartFile.getInputStream();
            if (inputStream != null) {
                int len = inputStream.available();
                buffer = new byte[len];
                inputStream.read(buffer);
            }
            FastDFSFile fastDFSFile = new FastDFSFile(fileName, buffer, ext);
            fileAbsolutePath = FastDFSClient.upload(fastDFSFile);
            if (fileAbsolutePath == null) {
                logger.error("upload file fail! please try again");
            }
        } catch (Exception e) {
            logger.error("upload file Exception:", e);
        } finally {
            inputStream.close();
        }
        String path = FastDFSClient.getTrackerUrl() + "/" + fileAbsolutePath[0] + "/" +fileAbsolutePath[1];//获取上传后的文件的访问全路径
        return path;
    }
}

4.4.4编写文件上传的controller

@Controller
@RequestMapping
public class FileUploadController {
    @RequestMapping("")
    public String index() {
        return "index.html";
    }

    @RequestMapping("/upload")
    @ResponseBody
    public String upload(@RequestParam("file") MultipartFile file) throws Exception {
        if (file.isEmpty()){
            return "空的你上传个屁啊";
        }
        return FileUtil.upload(file);
    }
}

4.4.5编写文件上传的页面index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>欢迎观临老汉的FastDFS</h1>
<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" value="上传" name="file">
    <input type="submit" value="提交">
</form>
</body>
</html>

页面比较丑,讲究着看吧...

4.5 测试

提交后会把上传后的文件访问路径返回给我:

复制后在浏览器中访问:

 可以看到刚刚上传的图片已经正确显示,在服务器的对应目录下也可以找到刚刚上传的文件,没毛病.

上传速度也是飞一般的快:

如果上传的是其他文件,比如视频或者excel等都没有问题,只要不要太大,都没问题.

上面的全部代码可以去我github拉取,我已经上传过了:https://github.com/laohanjianshen/springboot-fdfs.git

如果公司有6台及以上的服务器,可以考虑用FastDFS搭建自己的文件存储系统,可以省下购买第三方服务的钱.

发布了89 篇原创文章 · 获赞 70 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/lovexiaotaozi/article/details/86680000