赞
踩
Fastdfs是用C语言编写的一款开源的分布式文件系统。Fastdfs为互联网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,使用 Fastdfs很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
Fastdfs架构包括Tracker server和Storage server。客户端请求Tracker server 进行文件上传、下载,通过 Tracker server 调度,最终由Storage server完成文件上传和下载。
Tracker server作用是负载均衡和调度,通过Tracker server在文件上传时可以根据一些策略找到Storage server 提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器。
Storage作用是文件存储,客户端上传的文件最终存储在Storage服务器上。
服务端两个角色:
Tracker:作用是负载均衡和调度
Storage:作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上
客户端上传文件后存储服务器将文件 ID 返回给客户端,此文件 ID 用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。如:/group1/M00/01/B2/CgAIC2Md0nWAKjOCAAQRef-xdIY168.jpg
组名/卷:文件上传后所在的Storage组名称,在文件上传成功后有Storage服务器返回,需要客户端自行保存
虚拟磁盘路径:Storage配置的虚拟路径,与磁盘选项 store_path*对应。如果配置了store_path0 则是 M00,如果配置了 store_path1 则是 M01,以此类推
数据两级目录:Storage服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件
文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息
0. storage会定期向tracker上传当前状态【心跳机制】
1. 客户端发送请求,请求tracker【调度中心】
2. tracker选择哪一个storage能使用,并且返回能用的storage
3. 客户端把上传的附件,上传到storage中去
4. storage会向客户端返回上传文件的路径
导入依赖
<!--fastdfs-->
<dependency>
<groupId>cn.bestwu</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.27</version>
</dependency>
<!--用来获取文件扩展名的包-->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.8.0</version>
</dependency>
添加配置文件fdfs_client.conf 到资源文件夹
tracker_server=123.207.27.208:22122
#22122是tracker的端口 - 上传
#访问直接使用域名:123.207.27.208
测试代码
// 1、加载配置文件,配置文件中的内容就是 tracker 服务的地址。
ClientGlobal.init("D:/maven_work/fastDFS-demo/src/fdfs_client.conf");
// 2、创建一个 TrackerClient 对象。直接 new 一个。
TrackerClient trackerClient = new TrackerClient();
// 3、使用 TrackerClient 对象创建连接,获得一个 TrackerServer 对象。
TrackerServer trackerServer = trackerClient.getConnection();
// 4、创建一个 StorageServer 的引用,值为 null
StorageServer storageServer = null;
// 5、创建一个 StorageClient 对象,需要两个参数 TrackerServer 对象、StorageServer 的引用
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
// 6、使用 StorageClient 对象上传图片。
//扩展名不带“.”
String[] strings = storageClient.upload_file("D:/pic/benchi.jpg", "jpg",null);
// 7、返回数组。包含组名和图片的路径。
/*
组名:group1
路径: M00/01/B3/CgAIC2Md3KGAGa0xAAALg4Ak6_M929.jpg
*/
for (String string : strings) {
System.out.println(string);
}
访问上传图片
http://123.207.27.208/group1/M00/01/B3/CgAIC2Md3KGAGa0xAAALg4Ak6_M929.jpg
package io.coderyeah.basic.util;
import org.csource.fastdfs.*;
/**
* fastDfs工具类
*/
public class FastDfsUtils {
//从classpath:resources中的内容最终会编译到classpath下
public static String CONF_FILENAME = FastDfsUtils.class.getClassLoader().getResource("fdfs_client.conf").getFile();
/**
* 上传文件
*
* @param file
* @param extName
* @return
*/
public static String upload(byte[] file, String extName) {
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
String fileIds[] = storageClient.upload_file(file, extName, null);
System.out.println(fileIds.length);
System.out.println("组名:" + fileIds[0]);
System.out.println("路径: " + fileIds[1]);
// /group1/M00/00/09/rBEACmKXF8-AUc6KAANsldwx3H4713.jpg
return "/" + fileIds[0] + "/" + fileIds[1];
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 上传文件
*
* @param extName
* @return
*/
public static String upload(String path, String extName) {
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
String fileIds[] = storageClient.upload_file(path, extName, null);
System.out.println(fileIds.length);
System.out.println("组名:" + fileIds[0]);
System.out.println("路径: " + fileIds[1]);
return "/" + fileIds[0] + "/" + fileIds[1];
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 下载文件
*
* @param groupName
* @param fileName
* @return
*/
public static byte[] download(String groupName, String fileName) {
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
byte[] b = storageClient.download_file(groupName, fileName);
return b;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 删除文件
*
* @param groupName
* @param fileName
*/
public static void delete(String groupName, String fileName) {
try {
ClientGlobal.init(CONF_FILENAME);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getConnection();
StorageServer storageServer = null;
StorageClient storageClient = new StorageClient(trackerServer, storageServer);
int i = storageClient.delete_file(groupName, fileName);
System.out.println(i == 0 ? "删除成功" : "删除失败:" + i);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("删除异常," + e.getMessage());
}
}
// public static void main(String[] args) {
// FastDfsUtils.delete("group1","M00/00/0F/oYYBAGJ6IGaAWQeOAAbMJw3URKE510.gif");
// }
}
package io.coderyeah.basic.controller;
import io.coderyeah.basic.Result;
import io.coderyeah.basic.util.FastDfsUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
@Api(value = "文件的上传和下载接口", tags = "fastDfs文件上传")
@RestController
@RequestMapping("/fastDfs")
public class FastDfsController {
/**
* // @RequestPart 对复杂表单项的处理,默认name="file",与上传文件的name属性值一致
*/
@ApiOperation("通过fastDfs文件上传到服务器")
@PostMapping()
public Result upload(@RequestPart(value = "file", required = true) MultipartFile file) {
// 1.截取文件后缀名 如png jpg
final String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
try {
// 2.将图片上传服务器将文件名返回前端
// /group1/M00/01/B2/CgAIC2Md0nWAKjOCAAQRef-xdIY168.jpg
final String filepath = FastDfsUtils.upload(file.getBytes(), suffix);
return Result.success(filepath,null); // 返回服务器文件路径
} catch (IOException e) {
e.printStackTrace();
return Result.fail("上传失败!" + e.getMessage());
}
}
@ApiOperation("删除文件")
@DeleteMapping()
public Result delete(@RequestParam("path") String path) {
try {
// 1.截取组名 /group1/M00/01/B2/CgAIC2Md0nWAKjOCAAQRef-xdIY168.jpg
// 1.1临时路径
final String tempPath = path.substring(1); // group1/M00/01/B2/CgAIC2Md0nWAKjOCAAQRef-xdIY168.jpg
final String groupName = tempPath.substring(0, tempPath.indexOf("/")); // group1
System.out.println(tempPath);
System.out.println(groupName);
// 2.远程路径
final String remotePath = tempPath.substring(tempPath.indexOf("/") + 1);
FastDfsUtils.delete(groupName, remotePath);
return Result.success(null);
} catch (Exception e) {
e.printStackTrace();
return Result.fail("删除失败" + e.getMessage());
}
}
}
前端:
1.准备el-upload上传组件
2.当我们点击上传按钮的时候,其实是在触发el-upload的action
3.action调用后端接口:http://localhost:8080/fastDfs
4.后端上传成功之后,返回到el-upload的:on-success="handleSuccess"
5.在handleSuccess中,将后端返回的resultObj绑定给模型层的logo
后端:
1.接收请求@RequestPart MultipartFile file
2.调用FastDfsUtils完成文件上传得到返回值path
3.然后将path设置给封装结果类的data传回给前端
<el-form-item prop="logo" label="店铺Logo">
<!--
:on-preview="handlePreview" - 点击图片名时触发此函数 - 可以在这里做放大功能,这里不做
:on-remove="handleRemove" - 点击删除时触发
:on-success="handleSuccess" - 上传成功之后触发
:file-list="fileList" - 文件列表
action="http://localhost:8080/fastDfs/" - 文件上传接口地址
-->
<el-upload class="upload-demo"
action="http://localhost:8080/fastDfs/"
:on-preview="handlePreview"
:on-remove="handleRemove"
:on-success="handleSuccess"
:file-list="fileList"
list-type="picture">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
</el-form-item>
方法:
//文件上传的业务逻辑
handleSuccess(response, file, fileList) {
this.shop.logo = response.data;
console.log(response.data)
},
//文件删除的业务逻辑
handleRemove(file, fileList) {
var filePath = file.response.data;
this.$http.delete("/fastDfs?path=" + filePath)
.then(res => {
if (res.data.success) {
this.$message({
message: '删除成功!',
type: 'success'
});
} else {
this.$message({
message: '删除失败!',
type: 'error'
});
}
})
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。