一.FastDFS介绍

FastDFS 是一个开源的高性能分布式文件系统(DFS)。 它的主要功能包括:文件存储,文件同步和文件访问,以及高容量和负载平衡。主要解决了海量数据存储问题,特别适合以中小文件(建议范围:4KB < file_size <500MB)为载体的在线服务。
FastDFS 系统有三个角色:跟踪服务器(Tracker Server)、存储服务器(Storage Server)和客户端(Client)。
Tracker Server:跟踪服务器,主要做调度工作,起到均衡的作用;负责管理所有的 storage server和 group,每个 storage 在启动后会连接 Tracker,告知自己所属 group 等信息,并保持周期性心跳。
Storage Server:存储服务器,主要提供容量和备份服务;以 group 为单位,每个 group 内可以有多台 storage server,数据互为备份。
Client:客户端,上传下载数据的服务器,也就是我们自己的项目所部署在的服务器。
存储节点Storage采用了分卷[Volume](或分组[group])的组织方式,存储系统由一个或多个组组成,组与组之间的文件是相互独立的,所有组的文件容量累加就是整个存储系统中的文件容量。
一个卷[Volume](组[group])可以由一台或多台存储服务器组成,一个组中的存储服务器中的文件都是相同的,组中的多台存储服务器起到了冗余备份和负载均衡的作用,数据互为备份,存储空间以group内容量最小的storage为准,所以建议group内的多个storage尽量配置相同,以免造成存储空间的浪费。

二.FastDFS服务器搭建

具体安装部署参考,注意,需要复制替换的文件,如果存在就不用替换

二.springboot整合FastDFS

刚开始按照帖子 ,用的1.26.1-RELEASE的fastdfs-client,在启动时发现报错ConnectManage的一个bean无法注册,因为已经注册过了,按照提示在配置文件中添加spring.main.allow-bean-definition-overriding=true ,再次启动发现还是存在错误,经过仔细查看这两个bean所在的类不一样,所以不能覆盖,而且都是在第三方jar包中,无法通过修改bean名称来解决,所以开始尝试用启动的时候重命名自己引入的这个类的bean的方式注册bean,后来发现之前存在项目中的bean是优先启动的,自己加入的这个jar包那个类的bean是后创建的,而且要在创建后才能去重命名, 如果重命名项目中以前的bean,则项目中别人使用该bean的地方都需要修改,影响比较大,只能尝试解决自己加入的这个包下的bean,后来在github官网( https://github.com/tobato/FastDFS_Client/blob/d866cd05e2930751c475cce8de6d109d532a0d93/src/test/java/com/github/tobato/fastdfs)看到,该jar包的新版本, 发现新版本中已经解决了该冲突, 所以使用该新版本,后来结合该github上的代码中的test内容,完成了开发;

下面是具体在开发中的实现:

引入jar包:

<!-- fdfs java客户端依赖 -->
    <dependency>
		<groupId>com.github.tobato</groupId>
		<artifactId>fastdfs-client</artifactId>
		 <version>1.27.2</version>
	</dependency>

启动类加注解:

@Import(FdfsClientConfig.class)

新增配置:

fdfs.connect-timeout=600
 fdfs.tracker-list=xx.xx.xx.xx:22122

代码实现:

package com.xxx.xxx.filebusiness;

import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.eos.runtime.core.TraceLoggerFactory;
import com.eos.system.logging.Logger;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.service.AppendFileStorageClient;

@Service("FastDFSClientService")
public class FastDFSClientService {
	
	private Logger logger = TraceLoggerFactory.getLogger(FastDFSClientService.class);
	
	@Autowired
	private AppendFileStorageClient storageClient;
	
	/**
	 * 上传文件
	 * @param file
	 * @return
	 * @throws IOException 
	 */
	public String uploadFile(MultipartFile file) throws IOException {
		byte[] bytes = file.getBytes();
		String originalFileName = file.getOriginalFilename();
		String extension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
		String fileName = file.getName();
		long fileSize = file.getSize();
		logger.info(originalFileName + ":" + fileName + ":" + fileSize + ":" + extension + ":" + bytes.length);
		StorePath path = storageClient.uploadFile(null, file.getInputStream(), fileSize, extension);
		return path.getFullPath();
	}
	  
	/**
	 * 下载文件
	 * @param filePath
	 * @throws IOException
	 */
	public void downloadFile(String filePath, HttpServletResponse response) throws IOException{
		String group = filePath.substring(0, filePath.indexOf("/"));
		String path = filePath.substring(filePath.indexOf("/") + 1);
		DownloadByteArray downloadByteArray = new DownloadByteArray();
        byte[] bytes = storageClient.downloadFile(group, path, downloadByteArray);
		response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(filePath, "UTF-8"));
		response.setCharacterEncoding("UTF-8");
		ServletOutputStream outputStream = null;
		try {
			outputStream = response.getOutputStream();
			outputStream.write(bytes);
		} catch (IOException e) {
			logger.error("文件下载失败!", e);
		} finally {
			try {
				outputStream.flush();
				outputStream.close();
			} catch (IOException e) {
				logger.error("文件下载失败!", e);
			}
		}
	}
}