FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。FastDFS为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
FastDFS服务端有两个角色:跟踪器(tracker)和存储节点(storage)。跟踪器主要做调度工作,在访问上起负载均衡的作用。
存储节点存储文件,完成文件管理的所有功能:就是这样的存储、同步和提供存取接口,FastDFS同时对文件的metadata进行管理。所谓文件的meta data就是文件的相关属性,以键值对(key value)方式表示,如:width=1024,其中的key为width,value为1024。文件metadata是文件属性列表,可以包含多个键值对。
跟踪器和存储节点都可以由一台或多台服务器构成。跟踪器和存储节点中的服务器均可以随时增加或下线而不会影响线上服务。其中跟踪器中的所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。
为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用。
在卷中增加服务器时,同步已有的文件由系统自动完成,同步完成后,系统自动将新增服务器切换到线上提供服务。
当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就扩大了存储系统的容量。
FastDFS中的文件标识分为两个部分:卷名和文件名,二者缺一不可。
以上是相关百度介绍,这里我们先介绍如何使用,后期我会更新如何搭建一个Fastdfs服务器。
使用FastDFS上传图片文件并且访问。
- 第一步:配置好一个服务器:
这里我的ip地址为192.168.188.146
- 在需要上传图片的项目中导入Maven依赖和相关配置文件:
<!--fastdfs相关的依赖和文件上传的依赖-->
<dependency>
<groupId>org.csource.fastdfs</groupId>
<artifactId>fastdfs</artifactId>
<version>1.27</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
在资源文件夹下创建conf配置文件
fdfs_client.conf配置文件内容如下:
tracker_server=192.168.188.146:22122
- 在springmvc配置文件解析器:
<!--文件上传解析器-->
<!--注意:id名字必须叫这个-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"></property>
<!-- 设定文件上传的最大值5MB,5*1024*1024 -->
<property name="maxUploadSize" value="5242880"></property>
</bean>
- 前端使用angularjs来上传文件:
$scope.upload = function () {
// 创建formData对象,指定文件参数
var formData = new FormData();
formData.append("file",file.files[0]);//一个文件
$http({
url:'http://localhost:9102/upload.do',
method:'POST',
data:formData,
headers: {'Content-Type':undefined},
transformRequest: angular.identity
}).success(function (resp) {
// alert(resp.message)
if(resp.success){
$scope.imageEntity.url = resp.message;
}
});
}
- 后端控制器代码:
@RestController
public class UploadController {
String url = "http://192.168.188.146/";
@RequestMapping("/upload")
public Result upload(MultipartFile file) throws Exception{
String url="";//定义保存上传后的图片url
try {
FastDFSClient client = new FastDFSClient("config/fdfs_client.conf");
//文件扩展名
String originalFilename = file.getOriginalFilename();
String extName = originalFilename.substring(originalFilename.lastIndexOf(".") + 1, originalFilename.length());
String s = client.uploadFile(file.getBytes(), extName);
url = this.url + s;
return Result.ok(url);
} catch (Exception e) {
e.printStackTrace();
}
return Result.fail("上传失败");
}
}
Result这个类是我自己定义的一个结果类:
public class Result {
private boolean success;//true 操作成功 false 操作失败
private String message; //提示信息
private Object data; //查询到的数据封装到data属性上
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public Result(boolean success, String message, Object data) {
this.success = success;
this.message = message;
this.data = data;
}
public Result(boolean success, String message) {
this.success = success;
this.message = message;
}
public Result() {
}
//返回的result中是不带有data数据
public static Result ok(String message){
Result result = new Result(true, message);
return result;
}
//返回的result中带有data数据的
public static Result ok(String message,Object data){
Result result = new Result(true, message,data);
return result;
}
//返回失败的结果对象
public static Result fail(String message){
Result result = new Result(false, message);
return result;
}
}
- FastDFSClient工具类代码如下:
public class FastDFSClient {
private TrackerClient trackerClient = null;
private TrackerServer trackerServer = null;
private StorageServer storageServer = null;
private StorageClient1 storageClient = null;
public FastDFSClient(String conf) throws Exception {
if (conf.contains("classpath:")) {
conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
}
ClientGlobal.init(conf);
trackerClient = new TrackerClient();
trackerServer = trackerClient.getConnection();
storageServer = null;
storageClient = new StorageClient1(trackerServer, storageServer);
}
/**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
* @param fileName 文件全路径
* @param extName 文件扩展名,不包含(.)
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(String fileName, String extName, NameValuePair[] metas) throws Exception {
String result = storageClient.upload_file1(fileName, extName, metas);
return result;
}
public String uploadFile(String fileName) throws Exception {
return uploadFile(fileName, null, null);
}
public String uploadFile(String fileName, String extName) throws Exception {
return uploadFile(fileName, extName, null);
}
/**
* 上传文件方法
* <p>Title: uploadFile</p>
* <p>Description: </p>
* @param fileContent 文件的内容,字节数组
* @param extName 文件扩展名
* @param metas 文件扩展信息
* @return
* @throws Exception
*/
public String uploadFile(byte[] fileContent, String extName, NameValuePair[] metas) throws Exception {
String result = storageClient.upload_file1(fileContent, extName, metas);
return result;
}
public String uploadFile(byte[] fileContent) throws Exception {
return uploadFile(fileContent, null, null);
}
public String uploadFile(byte[] fileContent, String extName) throws Exception {
return uploadFile(fileContent, extName, null);
}
}