FastDFS 安装 及 整合 SpringBoot 和 Swagger 项目 进行测试

31 篇文章 1 订阅
19 篇文章 0 订阅

FastDFS官网

FastDFS是什么?

参考百度百科

FastDFS是一个 使用c 语言编写的一款开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。

FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

FastDFS 简介

Fast DFS系统有三个角色:跟踪服务器(Tracker Server)、存储服务器(Storage Server)和客户端(Client)。client请求Tracker server 进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载,在底层存储上通过逻辑的分组概念,使得通过在同组内配置多个Storage,从而实现软RAID10。

FastDFS充分考虑了冗余备份、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

Tracker server:跟踪服务器,主要做调度工作,起到均衡的作用;负责管理所有的Storage server和group,每个storage在启动后会连接Tracker,告知自己所属group等信息,并保持周期性心跳。tracker上的元信息都是由storage汇报的信息生成的,本身不需要持久化任何数据,这样使得tracker非常容易扩展,直接增加tracker机器即可扩展为tracker cluster来服务,cluster里每个tracker之间是完全对等的,所有的tracker都接受stroage的心跳信息,生成元数据信息来提供读写服务,tracker根据storage的心跳信息,建立group==>[storage server list]的映射表。
Storage server:存储服务器,主要提供容量和备份服务;以group为单位,每个group内部可以有多台storage server,数据互为备份。客户端上传的文件最终存储在storage服务器上,Storage server没有实现自己的文件系统,而是利用操作系统的文件系统来管理文件,可以将storage称为存储服务器。storage可配置多个数据存储目录,比如有10块磁盘,分别挂载在/data/disk1-/data/disk10,则可将这10个目录都配置为storage的数据存储目录。
Client:客户端,上传下载数据的服务器,也就是我们自己的项目所部署在的服务器。FastDFS向使用者提供基本文件访问接口,比如upload、download、append、delete等,以客户端库的方式提供给用户使用

在这里插入图片描述
跟踪器和存储节点都可以由一台多台服务器构成。跟踪器和存储节点中的服务器均可以随时增加或下线而不会影响线上服务。其中跟踪器中的所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。

FastDFS 存储策略

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

在卷中增加服务器时,同步已有的文件由系统自动完成,同步完成后,系统自动将新增服务器切换到线上提供服务。

当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就扩大了存储系统的容量。

FastDFS中的文件标识分为两个部分:卷名和文件名,二者缺一不可。

上传文件交互过程:

  1. client询问tracker上传到的storage,不需要附加参数;
  2. tracker返回一台可用的storage;
  3. client直接和storage通讯完成文件上传。
    在这里插入图片描述

下载文件交互过程:
在这里插入图片描述

  1. client询问tracker下载文件的storage,参数为文件标识(卷名和文件名);
  2. tracker返回一台可用的storage;
  3. client直接和storage通讯完成文件下载。

需要说明的是,client为使用FastDFS服务的调用方,client也应该是一台服务器,它对tracker和storage的调用均为服务器间的调用。

Docker安装FastDFS

查看fastdfs版本 docker search fastdfs

[root@bogon ~]# docker search fastdfs
NAME                           DESCRIPTION                                     STARS     OFFICIAL   AUTOMATED
season/fastdfs                 FastDFS                                         74                   
ygqygq2/fastdfs-nginx          整合了nginx的fastdfs                                27                   [OK]
luhuiguo/fastdfs               FastDFS is an open source high performance d…   25                   [OK]
morunchang/fastdfs             A FastDFS image                                 20                   
qbanxiaoli/fastdfs             FastDFS+FastDHT(单机+集群版)                         12                   [OK]
delron/fastdfs                                                                 12                   
moocu/fastdfs                  fastdfs5.11                                     9                    
ecarpo/fastdfs-storage                                                         4                    
lionheart/fastdfs-tracker      just have a try on autobuilded -_-#             3                    [OK]
ecarpo/fastdfs                                                                 3                    
imlzw/fastdfs-tracker          fastdfs的tracker服务                               3                    [OK]
。。。。。。。。。。。。               
[root@bogon ~]# 

拉取delron/fastdfs 版 ,当然你也可以选择其他的镜像,配置会有所不同,有些镜像内没有Nginx相关配置

docker pull delron/fastdfs

在这里插入图片描述
构建tracker容器,用于启动跟踪服务器,起到调度的作用。

docker run -d --network=host --name tracker -v /var/fdfs/tracker:/var/fdfs delron/fastdfs tracker

构建Storage容器 修改自己的ip 192.168.230.137

docker run -d --network=host --name storage -e TRACKER_SERVER=192.168.230.137:22122 -v /var/fdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage

可以查看一下 docker ps
在这里插入图片描述

进入容器修改配置

docker exec -it tracker bash

修改配置

vi /etc/fdfs/client.conf

将配置 tracker_server=你自己的ip:22122
在这里插入图片描述
到这其实fastDFS就配好了

整合项目测试

	整合SpringBoot和 swagger-ui接口文档 进行图片上传测试

pom.xml中导入依赖:

        <!--Swagger-UI API文档生产工具-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

        <!-- FastDFS依赖 -->
        <dependency>
            <groupId>com.github.tobato</groupId>
             <artifactId>fastdfs-client</artifactId>
               <version>1.26.5</version>
        </dependency>

在yml文件中配置信息

spring:
  servlet:
    multipart:
      # 最大支持文件大小
      max-file-size: 100MB
      # 最大支持请求大小
      max-request-size: 100MB
      
# 分布式文件系统FDFS配置
fdfs:
  # 链接超时
  connect-timeout: 600
  # 读取时间
  so-timeout: 600
  # 生成缩略图参数
  thumb-image:
    width: 150
    height: 150
    #连接FastDFS服务器
  tracker-list: 192.168.230.137:22122

添加Swagger-UI的配置


package com.jq.swagger;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2 
public class SwaggerConfig {

    @Bean
    public Docket createRestApi(){
           //访问地址:http://localhost:8080/swagger-ui.html#/
           //不一定是8080,启用那个服务就用那个端口
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                //为当前包下controller生成API文档
                .apis(RequestHandlerSelectors.basePackage("com.jq.order.controller"))
                //为有@Api注解的Controller生成API文档
         //.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
                //为有@ApiOperation注解的方法生成API文档
            //  .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build();
    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("订单模块api接口文档")   // 文档标题
                .description("订单模块api接口文档")  // 文档描述
                .contact("jq")  // 设置联系人
                .version("1.0")  //版本号
                .build();
    }

}

添加FastDFS配置

package com.jq.fastdfs;

import com.github.tobato.fastdfs.FdfsClientConfig;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.annotation.Import;
import org.springframework.jmx.support.RegistrationPolicy;

@Configuration
@Import(FdfsClientConfig.class)
// Jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class DfsConfig {
}

创建 FileDfsUtil 工具类

package com.jq.fastdfs;

import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;

@Component
public class FileDfsUtil {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileDfsUtil.class);

    @Resource
    private FastFileStorageClient storageClient ;

    /**
     * 上传文件*/
     public String upload(MultipartFile file) throws Exception{
         StorePath storePath = storageClient.uploadFile(file.getInputStream(),file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()),null);
         return storePath.getFullPath() ;
     }

    /**
     * 删除文件
     */
     public void deleteFile(String fileUrl) {
                if (StringUtils.isEmpty(fileUrl)) {
                        LOGGER.info("fileUrl == >>文件路径为空...");
                       return;
                 }
              try {
                      StorePath storePath = StorePath.parseFromUrl(fileUrl);
                      storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
                  } catch (Exception e) {
                   LOGGER.info(e.getMessage());
                }
            }

		 /**
     * 下载文件
     *
     * @param imgName 文件URL
     * @return 文件字节
     * @throws IOException
     */
    public byte[] downloadFile(String imgName) throws IOException {
        String group = imgName.substring(0, imgName.indexOf("/"));
        String path = imgName.substring(imgName.indexOf("/") + 1);
        DownloadByteArray downloadByteArray = new DownloadByteArray();
        byte[] bytes = fastFileStorageClient.downloadFile(group, path, downloadByteArray);
        return bytes;
    }
}

新建File控制层 注意在com.jq.order.controller目录下建不然访问不到

package com.jq.order.controller;

import com.jq.fastdfs.FileDfsUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;

@RestController
@RequestMapping("FileController")
@Api(tags = "FileController", description = "上传控制器")
public class FileController {

    @Resource
     private FileDfsUtil fileDfsUtil ;


    /**
    * 文件上传
     */
     @ApiOperation(value="上传文件", notes="测试FastDFS文件上传")
     @RequestMapping(value = "/uploadFile",headers="content-type=multipart/form-data", method = RequestMethod.POST)
     public ResponseEntity<String> uploadFile (@ApiParam("属性名") @RequestParam("file") MultipartFile file){
                 String result ;
                try{
                         String path = fileDfsUtil.upload(file) ;
                         if (!StringUtils.isEmpty(path)){
                                 result = path ;
                            } else {
                                result = "上传失败" ;
                           }
                    } catch (Exception e){
                        e.printStackTrace() ;
                       result = "服务异常" ;
                   }
                 return ResponseEntity.ok(result);
            }

    /**
      * 文件删除
      */
    @ApiOperation(value="删除文件", notes="测试FastDFS\"删除文件")
    @RequestMapping(value = "/deleteByPath", method = RequestMethod.GET)
     public ResponseEntity<String> deleteByPath (){
                String filePathName = "group1/M00/00/00/wKjmiWCky6eALOBVAAb5PMwaVHw792.jpg" ;
                fileDfsUtil.deleteFile(filePathName);
               return ResponseEntity.ok("SUCCESS") ;
         }


     /**
     * 文件下载
     */
    @ApiOperation(value="下载文件", notes="测试FastDFS\"下载文件")
    @RequestMapping(value = "/download", method = RequestMethod.GET)
    public void downloadFile(String imgName, HttpServletResponse response) throws IOException {
        byte[] bytes = fileDfsUtil.downloadFile(imgName);
        // 这里只是为了整合fastdfs,所以写死了文件格式。需要在上传的时候保存文件名。下载的时候使用对应的格式
        response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode("imgName.jpg", "UTF-8"));
        response.setCharacterEncoding("UTF-8");
        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            outputStream.write(bytes);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


}

启动项目 5057 为自己服务端口
访问 http://localhost:5057/swagger-ui.html

一 :上传步骤
在这里插入图片描述
在这里插入图片描述
选择一个照片,发请求测试
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
访问地址 192.168.230.137 为虚拟机ip:8888/图片.jpg

http://192.168.230.137:8888/group1/M00/00/00/wKjmiWCky6eALOBVAAb5PMwaVHw792.jpg

效果:
在这里插入图片描述

二:下载步骤

复制上传回调的图片全称
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
图片储存地址
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jq1223

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值