FastDFS之文件上传/下载/删除

1、FastDFS简介

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、文件上传流程

客户端上传文件后存储服务器将文件 ID 返回给客户端,此文件 ID 用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名

组名:文件上传后所在的 storage 组名称,在文件上传成功后有storage 服务器返回,需要客户端自行保存。
虚拟磁盘路径:storage 配置的虚拟路径,与磁盘选项store_path*对应。如果配置了store_path0 则是 M00,如果配置了 store_path1 则是 M01,以此类推。
数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

3、搭建文件存储微服务

创建文件管理微服务 service_file,该工程主要用于实现文件上传以及文件删除等功能。

3.1 修改pom.xml,引入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring‐boot‐starter‐web</artifactId>
    </dependency>
    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs‐client‐java</artifactId>
        <version>1.27.0.0</version>
      </dependency>
</dependencies>

3.2 在resources文件夹下创建fasfDFS的配置文件fdfs_client.conf

# 连接超时时间,单位为秒。
connect_timeout=60
# 通信超时时间,单位为秒
network_timeout=60
# 字符集
charset=utf-8
# tracker的http端口:浏览器访问
http.tracker_http_port=8080
# Tracker服务器与外界通信的IP和端口:Java程序访问
tracker_server=192.168.33.133:22122

3.3 在resources文件夹下创建application.yml

server:
  port: 18082
spring:
  application:
    name: file
  servlet:
    multipart:
      max‐file‐size: 10MB
      max‐request‐size: 10MB
  main:
    allow‐bean‐definition‐overriding: true # 当遇到同样名字的时候,是否允许覆盖注册
eureka:
  client:
    service‐url:
      defaultZone: http://127.0.0.1:7001/eureka
  instance:
    prefer‐ip‐address: true
  • max-file-size是单个文件大小
  • max-request-size是设置总上传的数据大小

3.4 创建启动类

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

4、文件上传示例代码

4.1 文件信息封装

文件上传一般都有文件的名字、文件的内容、文件的扩展名、文件的md5值、文件的作者等相关属性,我们可以创建一个对象封装这些属性。

@Getter
@Setter
public class FastDFSFile {
    // 文件名字
    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
            height,String width, String author) {
        this.name = name;
        this.content = content;
        this.ext = ext;
        this.author = author;
    }

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

}

4.2、文件操作工具类

@Slf4j
public class FastDFSUtils {
    static {
       try{
           // 获得配置文件路径
           String file = new ClassPathResource("fsdf_client.conf").getPath();
           // 加载tracker配置信息
           ClientGlobal.init(file);
       } catch(Exception e){
           e.printStackTrace();
       }
    }

    /**
     * 文件上传方法
     * @param file
     * @return
     */
    public static String[] upload(FastDFSFile file) {
        // 获取文件的作者
        NameValuePair[] meta_list = new NameValuePair[1];
        meta_list[0] = new NameValuePair("author", file.getAuthor());
        // 接收返回数据
        String[] uploadResults = null;
        StorageClient storageClient = null;
        try {
            // 创建StorageClient客户端对象
            storageClient = getStorageClient();
            /**
             *  1)文件字节数组
             *  2)文件扩展名
             *  3)文件作者
             */
            uploadResults = storageClient.upload_file(file.getContent(),file.getExt(),meta_list);
        } catch (Exception e){
            log.error("Exception when uploadind the file:" +
                    file.getName(), e);
        }
        if (uploadResults == null && storageClient!=null) {
            log.error("upload file fail, error code:" +
                    storageClient.getErrorCode());
        }
        // 获取组名
        String groupName = uploadResults[0];
        // 获取文件存储路径
        String remoteFileName = uploadResults[1];
        return uploadResults;
    }


    /**
     * 文件下载
     * @param groupName  文件所在组名:group1
     * @param remoteFileName  文件的存储路径名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
     * @return
     */
    public static InputStream downloadFile(String groupName,String remoteFileName) throws Exception {
        // 1. 获得Storage客户端
        StorageClient storageClient = getStorageClient();
        // 2. 下载文件
        byte[] buf = storageClient.download_file(groupName, remoteFileName);
        // 3. 将字节数组转换为输入流
        return new ByteArrayInputStream(buf);
    }

    /** 文件删除
     * @param groupName  文件所在组名:group1
     * @param remoteFileName  文件的存储路径名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
     */
    public static void deleteFile(String groupName,String remoteFileName) throws Exception{
        getStorageClient().delete_file(groupName, remoteFileName);
    }

    /**
     * 获取文件信息
     * @param groupName  文件所在组名:group1
     * @param remoteFileName  文件的存储路径名 M00/00/00/wKghhV6FkViAfTuRAAGSbLHFVsM382.png
     * @return
     */
    public static FileInfo getFileInfo(String groupName, String remoteFileName) throws Exception {
        return getStorageClient().get_file_info(groupName, remoteFileName);
    }

    /**
     * 获取Tracker的信息
     * @throws Exception
     */
    public static String getTrackerInfo() throws IOException{
        // 获取TrackerServer对象
        TrackerServer trackerServer = getTrackerServer();
        // 获得Tracker的IP和端口
        String ip = trackerServer.getInetSocketAddress().getHostString();
        int port = ClientGlobal.getG_tracker_http_port();
        return "http://"+ip+":"+port+"/";
    }


    /**
     * * 获取Storage客户端
     */
    private static StorageClient getStorageClient() throws IOException {
        TrackerServer trackerServer = getTrackerServer();
        StorageClient storageClient = new StorageClient(trackerServer,
                null);
        return storageClient;
    }

    /*
     **
     * 获取Tracker服务器
     */
    private static TrackerServer getTrackerServer() throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerServer;
    }
}

4.3、文件上传控制器

@RestController
@CrossOrigin
public class FileController {

    @PostMapping("/upload")
    public Result uploadFile(@RequestParam("file") MultipartFile file) throws IOException {
        // 创建FastDFSFile对象:封装文件数据
        FastDFSFile fastDFSFile = new FastDFSFile(
                file.getOriginalFilename(),
                file.getBytes(),
                StringUtils.getFilenameExtension(file.getOriginalFilename()));
        // 调用工具类方法执行上传
        String[] uploadResults = FastDFSUtils.upload(fastDFSFile);
        // 获取组名
        String groupName = uploadResults[0];
        // 获取文件存储路径
        String remoteFileName = uploadResults[1];
        // 拼接访问地址
        String url = FastDFSUtils.getTrackerInfo() +groupName+"/"+remoteFileName;
        return new Result(true, StatusCode.OK, "上传成功",url);
    }
}
发布了24 篇原创文章 · 获赞 1 · 访问量 6396

猜你喜欢

转载自blog.csdn.net/pkxwyf/article/details/105299752