SpringBoot集成FastDFS上传系统实现方案

1.简介

FastDFS是一种开源轻量级分布式文件上传系统,它对文件的管理包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决大容量存储负载均衡问题。

因为其搭建成本高、维护成本高不适合小型项目,但是其文件是存储在存储服务器中安全性较高。

FastDFS架构图:

FastDFS分为2部分,Tracker Server端,Storager Server端;

Tracker Server端为FastDFS的管理端,Tracker Server集群一个主机多个备机,主备之间通过心跳检测保证管理端的高可用,用户请求存储文件首先调用Tracker Server,

内部实现负载均衡,返回给客户端Client一个Storager Server服务器地址,客户端获取Storager Server地址值后调用存储,存储结束后返回客户端一个存储路径。

Storager Server端为存储端,由多态存储服务器集群,一台服务器由一主机和一台备机组成,主机存储后冗余备份至备机,实现存储服务的容灾特性。

上传时序图:

上传后返回路径:

group1:组名

M00:虚拟磁盘路径

02/44/:存储服务器在虚拟磁盘看目录下创建2级目录,用于存储文件

xxxxxxxx.sh:文件名,通过特定的条件生成的不可重复的文件名

2.实现步骤

2.1导入相关依赖包

<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>

2.2在服务resources目录下创建fdfs_client.conf配置文件,配置上传参数

connect_timeout = 60
network_timeout = 60
charset = UTF-8
http.tracker_http_port = 8080 # 文件访问端口号
tracker_server = 192.168.200.128:22122 # 文件改动端口号

2.3创建application.yml配置文件

spring:
  servlet:
    multipart:
      max-file-size: 10MB 
      max-request-size: 10MB
server:
  port: 9008
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:6868/eureka
  instance:
    prefer-ip-address: true
feign:
  hystrix:
    enabled: true

2.4创建文件上传实体类

/**
 * 文件上传实体类
 */
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) {
        super();
        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;
    }

    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 getMd5() {
        return md5;
    }

    public void setMd5(String md5) {
        this.md5 = md5;
    }

    public String getAuthor() {
        return author;
    }

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

2.4创建文件上传工具类

/**
 * fastDFS文件上传工具类
 */
public class FastDFSClient {
   private static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class);

   /***
    * 初始化加载FastDFS的TrackerServer配置
    */
   static {
      try {
         String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();;
         ClientGlobal.init(filePath);
      } catch (Exception e) {
         logger.error("FastDFS Client Init Fail!",e);
      }
   }

   /***
    * 文件上传
    * @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 = getTrackerClient();

         /***
          * 文件上传
          * 1)文件字节数组
          * 2)文件扩展名
          * 3)文件作者
          */
         uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
      } catch (Exception e) {
         logger.error("Exception when uploadind the file:" + file.getName(), e);
      }

      if (uploadResults == null && storageClient!=null) {
         logger.error("upload file fail, error code:" + storageClient.getErrorCode());
      }
      //获取组名
      String groupName = uploadResults[0];
      //获取文件存储路径
      String remoteFileName = uploadResults[1];
      return uploadResults;
   }

   /***
    * 获取文件信息
    * @param groupName:组名
    * @param remoteFileName:文件存储完整名
    * @return
    */
   public static FileInfo getFile(String groupName, String remoteFileName) {
      try {
         StorageClient storageClient = getTrackerClient();
         return storageClient.get_file_info(groupName, remoteFileName);
      } catch (Exception e) {
         logger.error("Exception: Get File from Fast DFS failed", e);
      }
      return null;
   }

   /***
    * 文件下载
    * @param groupName
    * @param remoteFileName
    * @return
    */
   public static InputStream downFile(String groupName, String remoteFileName) {
      try {
         //创建StorageClient
         StorageClient storageClient = getTrackerClient();

         //下载文件
         byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
         InputStream ins = new ByteArrayInputStream(fileByte);
         return ins;
      } catch (Exception e) {
         logger.error("Exception: Get File from Fast DFS failed", e);
      }
      return null;
   }


   /***
    * 文件删除
    * @param groupName
    * @param remoteFileName
    * @throws Exception
    */
   public static void deleteFile(String groupName, String remoteFileName)
         throws Exception {
      //创建StorageClient
      StorageClient storageClient = getTrackerClient();

      //删除文件
      int i = storageClient.delete_file(groupName, remoteFileName);
   }


   /***
    * 获取Storage组
    * @param groupName
    * @return
    * @throws IOException
    */
   public static StorageServer[] getStoreStorages(String groupName)
         throws IOException {
      //创建TrackerClient
      TrackerClient trackerClient = new TrackerClient();
      //获取TrackerServer
      TrackerServer trackerServer = trackerClient.getConnection();
      //获取Storage组
      return trackerClient.getStoreStorages(trackerServer, groupName);
   }

   /***
    * 获取Storage信息,IP和端口
    * @param groupName
    * @param remoteFileName
    * @return
    * @throws IOException
    */
   public static ServerInfo[] getFetchStorages(String groupName,
                                                String remoteFileName) throws IOException {
      TrackerClient trackerClient = new TrackerClient();
      TrackerServer trackerServer = trackerClient.getConnection();
      return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
   }

   /***
    * 获取Tracker服务地址
    * @return
    * @throws IOException
    */
   public static String getTrackerUrl() throws IOException {
      return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ ClientGlobal.getG_tracker_http_port()+"/";
   }


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


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

2.5编写文件上传controller类

/**
 * 文件操作controller
 * @author ZJ
 */
@RestController
@RequestMapping("/file")
public class FileController {

    /**
     * <input type="file" name="file"/>
     * @param file
     * @return
     */
    @PostMapping
    public Result fileUpload(MultipartFile file) {
        try {
            //1. 获取完整的文件名
            String fileName = file.getOriginalFilename();
            //2. 获取文件扩展名
            if (StringUtils.isEmpty(fileName)) {
                throw new RuntimeException("文件不存在");
            }
            String ext = fileName.substring(fileName.lastIndexOf("."));
            //3. 获取文件内容
            byte[] contents = file.getBytes();
            //4. 创建上传文件实体类
            FastDFSFile fastDFSFile = new FastDFSFile(fileName, contents, ext);
            //5. 调用上传文件工具方法, 上传, 并返回存储后的文件路径和文件名
            String[] path = FastDFSClient.upload(fastDFSFile);
            //6. 返回上传后的路径和文件名
            String url = FastDFSClient.getTrackerUrl() + path[0] + "/" + path[1];
            return new Result(true, StatusCode.OK, "上传成功", path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return new Result(false, StatusCode.ERROR, "上传失败");
    }
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值