• FastDfS入门到精通


    一,FastDFS简介

      FastDFS是用c语言编写的一款开源的分布式文件系统,它是由淘宝资深架构师余庆编写并开源。FastDFS专为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。

    优势·:

      适合通用分部式,fastDFS非常适合存储图片等那些小文件,fastDFS不对文件进行分块,所以它就没有分块合并的开销,fastDFS网络通信采用socket,通信速度很快。

    二,服务器分为tracker和storage

    三,上传文件原理

    storage将文件id返回客户端

    id中包含的信息

    代码实现:

    1.工具类:

      1 import org.csource.common.NameValuePair;
      2 import org.csource.fastdfs.*;
      3 import org.slf4j.LoggerFactory;
      4 import org.springframework.core.io.ClassPathResource;
      5 
      6 import java.io.ByteArrayInputStream;
      7 import java.io.IOException;
      8 import java.io.InputStream;
      9 
     10 public class FastDFSClient {
     11     private static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class);
     12 
     13     /***
     14      * 初始化加载FastDFS的TrackerServer配置
     15      */
     16     static {
     17         try {
     18             String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();;
     19             ClientGlobal.init(filePath);
     20         } catch (Exception e) {
     21             logger.error("FastDFS Client Init Fail!",e);
     22         }
     23     }
     24 
     25     /***
     26      * 文件上传
     27      * @param file
     28      * @return
     29      */
     30     public static String[] upload(FastDFSFile file) {
     31         //获取文件的作者
     32         NameValuePair[] meta_list = new NameValuePair[1];
     33         meta_list[0] = new NameValuePair("author", file.getAuthor());
     34 
     35         //接收返回数据
     36         String[] uploadResults = null;
     37         StorageClient storageClient=null;
     38         try {
     39             //创建StorageClient客户端对象
     40             storageClient = getTrackerClient();
     41 
     42             /***
     43              * 文件上传
     44              * 1)文件字节数组
     45              * 2)文件扩展名
     46              * 3)文件作者
     47              */
     48             uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
     49         } catch (Exception e) {
     50             logger.error("Exception when uploadind the file:" + file.getName(), e);
     51         }
     52 
     53         if (uploadResults == null && storageClient!=null) {
     54             logger.error("upload file fail, error code:" + storageClient.getErrorCode());
     55         }
     56         //获取组名
     57         String groupName = uploadResults[0];
     58         //获取文件存储路径
     59         String remoteFileName = uploadResults[1];
     60         return uploadResults;
     61     }
     62 
     63     /***
     64      * 获取文件信息
     65      * @param groupName:组名
     66      * @param remoteFileName:文件存储完整名
     67      * @return
     68      */
     69     public static FileInfo getFile(String groupName, String remoteFileName) {
     70         try {
     71             StorageClient storageClient = getTrackerClient();
     72             return storageClient.get_file_info(groupName, remoteFileName);
     73         } catch (Exception e) {
     74             logger.error("Exception: Get File from Fast DFS failed", e);
     75         }
     76         return null;
     77     }
     78 
     79     /***
     80      * 文件下载
     81      * @param groupName
     82      * @param remoteFileName
     83      * @return
     84      */
     85     public static InputStream downFile(String groupName, String remoteFileName) {
     86         try {
     87             //创建StorageClient
     88             StorageClient storageClient = getTrackerClient();
     89 
     90             //下载文件
     91             byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
     92             InputStream ins = new ByteArrayInputStream(fileByte);
     93             return ins;
     94         } catch (Exception e) {
     95             logger.error("Exception: Get File from Fast DFS failed", e);
     96         }
     97         return null;
     98     }
     99 
    100 
    101     /***
    102      * 文件删除
    103      * @param groupName
    104      * @param remoteFileName
    105      * @throws Exception
    106      */
    107     public static void deleteFile(String groupName, String remoteFileName)
    108             throws Exception {
    109         //创建StorageClient
    110         StorageClient storageClient = getTrackerClient();
    111 
    112         //删除文件
    113         int i = storageClient.delete_file(groupName, remoteFileName);
    114     }
    115 
    116 
    117     /***
    118      * 获取Storage组
    119      * @param groupName
    120      * @return
    121      * @throws IOException
    122      */
    123     public static StorageServer[] getStoreStorages(String groupName)
    124             throws IOException {
    125         //创建TrackerClient
    126         TrackerClient trackerClient = new TrackerClient();
    127         //获取TrackerServer
    128         TrackerServer trackerServer = trackerClient.getConnection();
    129         //获取Storage组
    130         return trackerClient.getStoreStorages(trackerServer, groupName);
    131     }
    132 
    133     /***
    134      * 获取Storage信息,IP和端口
    135      * @param groupName
    136      * @param remoteFileName
    137      * @return
    138      * @throws IOException
    139      */
    140     public static ServerInfo[] getFetchStorages(String groupName,
    141                                                 String remoteFileName) throws IOException {
    142         TrackerClient trackerClient = new TrackerClient();
    143         TrackerServer trackerServer = trackerClient.getConnection();
    144         return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
    145     }
    146 
    147     /***
    148      * 获取Tracker服务地址
    149      * @return
    150      * @throws IOException
    151      */
    152     public static String getTrackerUrl() throws IOException {
    153         return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ ClientGlobal.getG_tracker_http_port()+"/";
    154     }
    155 
    156 
    157     /***
    158      * 获取Storage客户端
    159      * @return
    160      * @throws IOException
    161      */
    162     private static StorageClient getTrackerClient() throws IOException {
    163         TrackerServer trackerServer = getTrackerServer();
    164         StorageClient storageClient = new StorageClient(trackerServer, null);
    165         return  storageClient;
    166     }
    167 
    168 
    169     /***
    170      * 获取Tracker
    171      * @return
    172      * @throws IOException
    173      */
    174     private static TrackerServer getTrackerServer() throws IOException {
    175         TrackerClient trackerClient = new TrackerClient();
    176         TrackerServer trackerServer = trackerClient.getConnection();
    177         return  trackerServer;
    178     }
    179 }

    2.启动类

     1 import org.springframework.boot.SpringApplication;
     2 import org.springframework.boot.autoconfigure.SpringBootApplication;
     3 import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
     4 
     5 @SpringBootApplication
     6 @EnableEurekaClient
     7 public class FileApplication {
     8     public static void main(String[] args) {
     9         SpringApplication.run( FileApplication.class );
    10     }
    11 }

    3.FastDFSFile标准类

     1 public class FastDFSFile {
     2 
     3     //文件名字
     4     private String name;
     5     //文件内容
     6     private byte[] content;
     7     //文件扩展名
     8     private String ext;
     9     //文件MD5摘要值
    10     private String md5;
    11     //文件创建作者
    12     private String author;
    13 
    14     public FastDFSFile(String name, byte[] content, String ext, String height,
    15                        String width, String author) {
    16         super();
    17         this.name = name;
    18         this.content = content;
    19         this.ext = ext;
    20         this.author = author;
    21     }
    22 
    23     public FastDFSFile(String name, byte[] content, String ext) {
    24         super();
    25         this.name = name;
    26         this.content = content;
    27         this.ext = ext;
    28     }
    29 
    30     public String getName() {
    31         return name;
    32     }
    33 
    34     public void setName(String name) {
    35         this.name = name;
    36     }
    37 
    38     public byte[] getContent() {
    39         return content;
    40     }
    41 
    42     public void setContent(byte[] content) {
    43         this.content = content;
    44     }
    45 
    46     public String getExt() {
    47         return ext;
    48     }
    49 
    50     public void setExt(String ext) {
    51         this.ext = ext;
    52     }
    53 
    54     public String getMd5() {
    55         return md5;
    56     }
    57 
    58     public void setMd5(String md5) {
    59         this.md5 = md5;
    60     }
    61 
    62     public String getAuthor() {
    63         return author;
    64     }
    65 
    66     public void setAuthor(String author) {
    67         this.author = author;
    68     }
    69 }

    4.上传的类

     1 import org.springframework.web.bind.annotation.CrossOrigin;
     2 import org.springframework.web.bind.annotation.PostMapping;
     3 import org.springframework.web.bind.annotation.RequestParam;
     4 import org.springframework.web.bind.annotation.RestController;
     5 import org.springframework.web.multipart.MultipartFile;
     6 
     7 import java.io.IOException;
     8 
     9 @RestController
    10 @CrossOrigin
    11 public class FileController {
    12 
    13 
    14     @PostMapping("/upload")
    15     public String upload( @RequestParam("file") MultipartFile file){
    16         try {
    17             //1.获取文件名
    18             String fileName = file.getOriginalFilename();
    19             //2.获取文件内容
    20             byte[] bytes = file.getBytes();
    21             //3.获取文件扩展名 .
    22             String ext = fileName.substring( fileName.lastIndexOf( "." ) );
    23             //4.封装文件实体
    24             FastDFSFile fastDFSFile=new FastDFSFile( fileName,bytes,ext );
    25             //5.文件上传
    26             String[] result = FastDFSClient.upload( fastDFSFile );
    27             //6.返回结果
    28             String path = FastDFSClient.getTrackerUrl()+result[0]+"/"+result[1];
    29             return path;
    30 
    31         } catch (IOException e) {
    32             e.printStackTrace();
    33             return "";
    34         }
    35     }
    36 
    37 }

    yml文件

     1 server:
     2   port: 9008
     3 spring:
     4   application:
     5     name: file
     6   servlet:
     7     multipart:
     8       max-file-size: 10MB
     9       max-request-size: 10MB
    10   main:
    11     allow-bean-definition-overriding: true #当遇到同样名字的时候,是否允许覆盖注册
    12 eureka:
    13   client:
    14     service-url:
    15       defaultZone: http://127.0.0.1:6868/eureka
    16   instance:
    17     prefer-ip-address: true

    配置文件

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

    四,文件下载

    原理

    有tracker根据id中的信息来决定从哪个storage中查询

    五,项目级别运用

    (一)图片文件上传(对应1-5)

    1.文件校验(2)

    //文件校验
    if (file == null){
    ExceptionCast.cast(CommonCode.INVALIDATE_PARAMS);
    }

    2.上传文件(3)

     1     
     2         //上传文件
     3         String fileId = this.uploadFileToFastdfs(file);
     4         if (StringUtils.isEmpty(fileId)){
     5             ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_FILEISNULL);
     6         }
     7 
     8 private String uploadFileToFastdfs(MultipartFile file) {
     9 
    10 
    11         try {
    12 
    13             //初始化fastdfs
    14             this.initFastdfs();
    15 
    16             //编写上传功能
    17             TrackerClient trackerClient = new TrackerClient();
    18             TrackerServer trackerServer = null;
    19             trackerServer = trackerClient.getConnection();
    20             StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
    21             StorageClient1 storageClient1 = new StorageClient1(trackerServer,storageServer);
    22 
    23             String originalFilename = file.getOriginalFilename();
    24             String extName = originalFilename.substring(originalFilename.lastIndexOf(".")+1);
    25 
    26             String fileId = storageClient1.upload_file1(file.getBytes(), extName, null);
    27             return fileId;
    28 
    29         } catch (Exception e) {
    30             e.printStackTrace();
    31         }
    32 
    33         return null;
    34 
    35 
    36     }
    37 
    38 
    39     private void initFastdfs() {
    40         try {
    41             ClientGlobal.initByTrackers(tracker_servers);
    42             ClientGlobal.setG_network_timeout(network_timeout_in_seconds);
    43             ClientGlobal.setG_connect_timeout(connect_timeout_in_seconds);
    44             ClientGlobal.setG_charset(charset);
    45         } catch (Exception e) {
    46             e.printStackTrace();
    47         }
    48     }

    初始化fastDfs1

        private void initFastdfs() {
            try {
                ClientGlobal.initByTrackers(tracker_servers);
                ClientGlobal.setG_network_timeout(network_timeout_in_seconds);
                ClientGlobal.setG_connect_timeout(connect_timeout_in_seconds);
                ClientGlobal.setG_charset(charset);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    ,编写上传功能(4返回文件地址)

    String fileId = storageClient1.upload_file1(file.getBytes(), extName, null);
          return fileId;
    
     1     //编写上传功能
     2             TrackerClient trackerClient = new TrackerClient();
     3             TrackerServer trackerServer = null;
     4             trackerServer = trackerClient.getConnection();
     5             StorageServer storageServer = trackerClient.getStoreStorage(trackerServer);
     6             StorageClient1 storageClient1 = new StorageClient1(trackerServer,storageServer);
     7 
     8             String originalFilename = file.getOriginalFilename();
     9             String extName = originalFilename.substring(originalFilename.lastIndexOf(".")+1);
    10 
    11             String fileId = storageClient1.upload_file1(file.getBytes(), extName, null);
    12             return fileId;
    13 
    14         } catch (Exception e) {
    15             e.printStackTrace();
    16         }
    17 
    18         return null;

    3.存到mongodb(5,文件信息存到mongo库)

     1  //将文件的id存入mongodb
     2         FileSystem fileSystem = new FileSystem();
     3 
     4         //设置值
     5         //文件id
     6         fileSystem.setFileId(fileId);
     7         //文件在文件系统中的路径
     8         fileSystem.setFilePath(fileId);
     9         //业务标识
    10         fileSystem.setBusinesskey(businesskey);
    11         //标签
    12         fileSystem.setFiletag(filetag);
    13         //元数据
    14         if(StringUtils.isNotEmpty(metadata)){
    15             try {
    16                 Map map = JSON.parseObject(metadata, Map.class);
    17                 fileSystem.setMetadata(map);
    18             } catch (Exception e) {
    19                 e.printStackTrace();
    20             }
    21         }
    22         //名称
    23         fileSystem.setFileName(file.getOriginalFilename());
    24         //大小
    25         fileSystem.setFileSize(file.getSize());
    26         //文件类型
    27         fileSystem.setFileType(file.getContentType());
    28 
    29         fileSystemRepository.save(fileSystem);
    30 
    31         //返回结果
    32         return new UploadFileResult(CommonCode.SUCCESS,fileSystem);
    33     }

    (二)图片信息和课程信息绑定,并存到mysql(6-8)

    课程管理服务负责将(一)中上传的文件的图片地址,与对应课程id进行绑定并保存在mysql数据库,方便其他子系统使用。

    添加方法

    查询方法

    删除方法

     1     @Override
     2     @PostMapping("/coursepic/add")
     3     public ResponseResult addCoursePic(String courseId, String pic) {
     4         return courseService.addCoursePic(courseId,pic);
     5     }
     6     
     7    
     8     @Override
     9     @PreAuthorize("hasAuthority('course_pic_list')")
    10     @GetMapping("/coursepic/list/{courseId}")
    11     public CoursePic findCoursePic(@PathVariable("courseId") String courseId) {
    12         return courseService.findCoursePic(courseId);
    13     }
    14     @Override
    15     @DeleteMapping("/coursepic/delete")
    16     public ResponseResult delCoursePic(String courseId) {
    17         return courseService.delCoursePic(courseId);
    18     }

    servcie

       /**
         * 保存课程图片信息
         * @param courseId
         * @param pic
         * @return
         */
        public ResponseResult addCoursePic(String courseId, String pic) {
    
            Optional<CoursePic> coursePicOptional = coursePicRepository.findById(courseId);
    
            CoursePic coursePic = null;
    
            if (coursePicOptional.isPresent()){
                coursePic = coursePicOptional.get();
            }
    
            if (coursePic == null){
                coursePic = new CoursePic();
            }
    
            coursePic.setPic(pic);
            coursePic.setCourseid(courseId);
            coursePicRepository.save(coursePic);
            return new ResponseResult(CommonCode.SUCCESS);
        }
    
        /**
         * 查询课程图片
         * @param courseId
         * @return
         */
        public CoursePic findCoursePic(String courseId) {
    
            Optional<CoursePic> coursePicOptional = coursePicRepository.findById(courseId);
            if (coursePicOptional.isPresent()){
                return coursePicOptional.get();
            }
    
            return null;
        }
    
        /**
         * 删除课程图片
         * @param courseId 课程id
         * @return  ResponseResult(规范返回类型)
         */
        public ResponseResult delCoursePic(String courseId) {
    
            coursePicRepository.deleteById(courseId);
            return new ResponseResult(CommonCode.SUCCESS);
        }

    dao

    import com.xuecheng.filesystem.framework.domain.course.response.CoursePic;
    import org.springframework.data.jpa.repository.JpaRepository;

    public interface CoursePicRepository extends JpaRepository<CoursePic,String> {
    }


    当一个男人不再对你啰嗦,不再缠着你,不再没事找你,对你说话也客气了,也不再气你了。那么恭喜你,你已经成功的失去了他。别嫌弃男人幼稚,那是他喜欢你,爱你。女人说男人像小孩子一样不成熟,可又有谁知道,男人在自己喜欢的女人面前才像小孩子,如果不喜欢你了,不爱你了,他比你爸还成熟。
  • 相关阅读:
    Golang :索引值对的数组
    MySql-BlackHole:黑洞引擎
    golang fmt 中的 Sprintf、Fprintf和 Printf函数
    golang 中的 rune 和 byte
    mysql 全文索引
    Python 原始字符串
    如何给博客园(或者CSDN)设置域名访问
    CPU、内存、磁盘三者的关系
    018.redis 阶段性总结:1T 以上海量数据+10 万以上 QPS 高并发+ 99.99% 高可用
    017.redis 在实践中的一些常见问题以及优化思路(包含 linux 内核参数优化)
  • 原文地址:https://www.cnblogs.com/fengtangjiang/p/11122055.html
Copyright © 2020-2023  润新知