目录
一、SpringBoot整合FastDFS依赖
FastDFS的依赖在Maven中央仓库中是没有的,需要自己下载源码编译打包。
Githup地址:https://github.com/happyfish100/fastdfs-client-java
Gitee地址:https://gitee.com/fastdfs100/fastdfs-client-java
打包
mvn clean install
在SpringBoot项目中引入依赖
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.32-SNAPSHOT</version>
</dependency>
二、FastDFS的配置
官方提供了两种配置方式
1. conf 配置文件、所在目录、加载优先顺序
配置文件名fdfs_client.conf(或使用其它文件名xxx_yyy.conf)
文件所在位置可以是项目classpath(或OS文件系统目录比如/opt/):
/opt/fdfs_client.conf
C:\Users\James\config\fdfs_client.conf
优先按OS文件系统路径读取,没有找到才查找项目classpath,尤其针对linux环境下的相对路径比如:
fdfs_client.conf
config/fdfs_client.conf
connect_timeout = 2
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 80
http.anti_steal_token = no
http.secret_key = FastDFS1234567890
tracker_server = 10.0.11.247:22122
tracker_server = 10.0.11.248:22122
tracker_server = 10.0.11.249:22122
connection_pool.enabled = true
connection_pool.max_count_per_entry = 500
connection_pool.max_idle_time = 3600
connection_pool.max_wait_time_in_ms = 1000
注1:tracker_server指向您自己IP地址和端口,1-n个
注2:除了tracker_server,其它配置项都是可选的
2. properties 配置文件、所在目录、加载优先顺序
配置文件名 fastdfs-client.properties(或使用其它文件名 xxx-yyy.properties)
文件所在位置可以是项目classpath(或OS文件系统目录比如/opt/):
/opt/fastdfs-client.properties
C:\Users\James\config\fastdfs-client.properties
优先按OS文件系统路径读取,没有找到才查找项目classpath,尤其针对linux环境下的相对路径比如:
fastdfs-client.properties
config/fastdfs-client.properties
fastdfs.connect_timeout_in_seconds = 5
fastdfs.network_timeout_in_seconds = 30
fastdfs.charset = UTF-8
fastdfs.http_anti_steal_token = false
fastdfs.http_secret_key = FastDFS1234567890
fastdfs.http_tracker_http_port = 80
fastdfs.tracker_servers = 10.0.11.201:22122,10.0.11.202:22122,10.0.11.203:22122
fastdfs.connection_pool.enabled = true
fastdfs.connection_pool.max_count_per_entry = 500
fastdfs.connection_pool.max_idle_time = 3600
fastdfs.connection_pool.max_wait_time_in_ms = 1000
注1:properties 配置文件中属性名跟 conf 配置文件不尽相同,并且统一加前缀"fastdfs.",便于整合到用户项目配置文件
注2:fastdfs.tracker_servers 配置项不能重复属性名,多个 tracker_server 用逗号","隔开
注3:除了fastdfs.tracker_servers,其它配置项都是可选的
3. 加载配置示例
加载原 conf 格式文件配置:
ClientGlobal.init("fdfs_client.conf");
ClientGlobal.init("config/fdfs_client.conf");
ClientGlobal.init("/opt/fdfs_client.conf");
ClientGlobal.init("C:\\Users\\James\\config\\fdfs_client.conf");
加载 properties 格式文件配置:
ClientGlobal.initByProperties("fastdfs-client.properties");
ClientGlobal.initByProperties("config/fastdfs-client.properties");
ClientGlobal.initByProperties("/opt/fastdfs-client.properties");
ClientGlobal.initByProperties("C:\\Users\\James\\config\\fastdfs-client.properties");
加载 Properties 对象配置:
Properties props = new Properties();
props.put(ClientGlobal.PROP_KEY_TRACKER_SERVERS, "10.0.11.101:22122,10.0.11.102:22122");
ClientGlobal.initByProperties(props);
加载 trackerServers 字符串配置:
String trackerServers = "10.0.11.101:22122,10.0.11.102:22122";
ClientGlobal.initByTrackers(trackerServers);
4. 检查加载配置结果
System.out.println("ClientGlobal.configInfo(): " + ClientGlobal.configInfo());
ClientGlobal.configInfo(): {
g_connect_timeout(ms) = 5000
g_network_timeout(ms) = 30000
g_charset = UTF-8
g_anti_steal_token = false
g_secret_key = FastDFS1234567890
g_tracker_http_port = 80
g_connection_pool_enabled = true
g_connection_pool_max_count_per_entry = 500
g_connection_pool_max_idle_time(ms) = 3600000
g_connection_pool_max_wait_time_in_ms(ms) = 1000
trackerServers = 10.0.11.101:22122,10.0.11.102:22122
}
三、FastFDS在SpringBoot中的使用
1. 在yml中添加自定义fastdfs配置
fastdfs:
# 连接fastdfs的ip地址
tracker-servers: 192.168.241.135:22122
# 上传图片或文件后访问的基础URL
access-url: http://192.168.241.135
2. 封装FastDFS文件上传下载工具类
package cn.bear.fastdfs;
import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Properties;
/**
* FastDFS 文件存储客户端
*
* @author Job
*/
@Component
public class FastDFSClient {
@Value("${fastdfs.access-url}")
private String accessUrl;
@Value("${fastdfs.tracker-servers}")
private String trackerServers;
private StorageClient storageClient;
/**
* 初始化存储客户端
*/
public void initClient() {
try {
Properties props = new Properties();
props.put(ClientGlobal.PROP_KEY_TRACKER_SERVERS, trackerServers);
ClientGlobal.initByProperties(props);
TrackerClient tracker = new TrackerClient();
TrackerServer trackerServer = tracker.getTrackerServer();
StorageServer storageServer = null;
storageClient = new StorageClient(trackerServer, storageServer);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
}
}
/**
* 关闭连接客户端
*/
public void closeClient() {
if (storageClient != null) {
try {
storageClient.close();
} catch (Exception e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
/**
* 上传文件
*
* @param file
* @return
*/
public StorePath upload(MultipartFile file) {
try {
initClient();
String filename = file.getOriginalFilename();
byte[] fileBuff = file.getBytes();
String fileExtName = filename.substring(filename.lastIndexOf(".") + 1);
NameValuePair[] metaList = new NameValuePair[2];
metaList[0] = new NameValuePair("fileName", filename);
String[] result = storageClient.upload_file(fileBuff, fileExtName, metaList);
return new StorePath(result[0], result[1]);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
} finally {
closeClient();
}
}
/**
* 上传文件
*
* @param groupName 组名,如:group1
* @param file
* @return
*/
public StorePath upload(String groupName, MultipartFile file) {
try {
initClient();
String filename = file.getOriginalFilename();
byte[] fileBuff = file.getBytes();
String fileExtName = filename.substring(filename.lastIndexOf(".") + 1);
NameValuePair[] metaList = new NameValuePair[2];
metaList[0] = new NameValuePair("fileName", filename);
String[] result = storageClient.upload_file(groupName, fileBuff, fileExtName, metaList);
return new StorePath(result[0], result[1]);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
} finally {
closeClient();
}
}
/**
* 上传文件
*
* @param fileBuff 文件字节数据
* @param fileExtName 文件后缀 如 jpeg docx 等
* @param metaList 可用于存储文件信息,比如文件名称、上传人等
* @return
*/
public StorePath upload(byte[] fileBuff, String fileExtName, NameValuePair[] metaList) {
try {
initClient();
String[] result = storageClient.upload_file(fileBuff, fileExtName, metaList);
return new StorePath(result[0], result[1]);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
} finally {
closeClient();
}
}
/**
* 上传文件
*
* @param groupName 集群部署时可使用指定组名上传
* @param fileBuff 文件字节数据
* @param fileExtName 文件后缀 如 jpeg docx 等
* @param metaList 可用于存储文件信息,比如文件名称、上传人等
* @return
*/
public StorePath upload(String groupName, byte[] fileBuff, String fileExtName, NameValuePair[] metaList) {
try {
initClient();
String[] result = storageClient.upload_file(groupName, fileBuff, fileExtName, metaList);
return new StorePath(result[0], result[1]);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
} finally {
closeClient();
}
}
/**
* 下载文件
*
* @param fullPath 文件的完整路径,如:group1/M00/00/00/wKjxh2ZhIjmAOQ9jADQRFXpJaxc66.jpeg
* @param response
*/
public void download(String fullPath, HttpServletResponse response) {
StorePath storePath = parseFromUrl(fullPath);
String groupName = storePath.getGroup();
String remoteFilename = storePath.getPath();
// 获取路径中的文件名称
String fileName = remoteFilename.substring(remoteFilename.lastIndexOf("/") + 1);
download(fileName, groupName, remoteFilename, response);
}
/**
* 下载文件
*
* @param fileName 指定的文件名称,如:test001.jpeg
* @param fullPath 文件的完整路径,如:group1/M00/00/00/wKjxh2ZhIjmAOQ9jADQRFXpJaxc66.jpeg
* @param response
*/
public void specificDownload(String fileName, String fullPath, HttpServletResponse response) {
StorePath storePath = parseFromUrl(fullPath);
String groupName = storePath.getGroup();
String remoteFilename = storePath.getPath();
download(fileName, groupName, remoteFilename, response);
}
/**
* 下载文件
*
* @param groupName 组名,如:group1
* @param remoteFilename 文件在服务器中的路径,如;M00/00/00/wKjxh2ZhIjmAOQ9jADQRFXpJaxc66.jpeg
* @param response
*/
public void download(String groupName, String remoteFilename, HttpServletResponse response) {
// 获取路径中的文件名称
String fileName = remoteFilename.substring(remoteFilename.lastIndexOf("/") + 1);
download(fileName, groupName, remoteFilename, response);
}
/**
* 下载文件
*
* @param fileName 指定的文件名称,如:test001.jpeg
* @param groupName 组名,如:group1
* @param remoteFilename 文件在服务器中的路径,如;M00/00/00/wKjxh2ZhIjmAOQ9jADQRFXpJaxc66.jpeg
* @param response
*/
public void download(String fileName, String groupName, String remoteFilename, HttpServletResponse response) {
try {
initClient();
DownloadStream fileStream = new DownloadStream(response.getOutputStream());
// 设置发送到客户端的响应的内容类型
response.setContentType("application/download");
// 指定客户端下载的文件的名称
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
storageClient.download_file(groupName, remoteFilename, fileStream);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
} finally {
closeClient();
}
}
/**
* 删除文件
*
* @param fullPath 文件的完整路径,如:group1/M00/00/00/wKjxh2ZhIjmAOQ9jADQRFXpJaxc66.jpeg
* @return
*/
public void delete(String fullPath) {
StorePath storePath = parseFromUrl(fullPath);
delete(storePath.getGroup(), storePath.getPath());
}
/**
* 删除文件
*
* @param groupName 组名,如:group1
* @param remoteFilename 文件在服务器中的路径,如;M00/00/00/wKjxh2ZhIjmAOQ9jADQRFXpJaxc66.jpeg
* @return
*/
public void delete(String groupName, String remoteFilename) {
try {
initClient();
storageClient.delete_file(groupName, remoteFilename);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
} finally {
closeClient();
}
}
/**
* 获取文件的名称信息
*
* @param fullPath 文件URL路径,如:group1/M00/00/00/wKjxh2ZhVuuAEAyZAAGkO7PPJ4w858.jpg
* @return
*/
public NameValuePair[] getMetadata(String fullPath) {
StorePath storePath = parseFromUrl(fullPath);
return getMetadata(storePath.getGroup(), storePath.getPath());
}
/**
* 获取文件的名称信息
*
* @param groupName 组名,如:group1
* @param remoteFilename 文件路径,如:M00/00/00/wKjxh2ZhVuuAEAyZAAGkO7PPJ4w858.jpg
* @return
*/
public NameValuePair[] getMetadata(String groupName, String remoteFilename) {
try {
initClient();
return storageClient.get_metadata(groupName, remoteFilename);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
} finally {
closeClient();
}
}
/**
* 查询文件信息
*
* @param groupName 组名
* @param remoteFilename 文件在服务器中的路径,如;M00/00/00/wKjxh2ZhIjmAOQ9jADQRFXpJaxc66.jpeg
* @return
*/
public FileInfo queryFileInfo(String groupName, String remoteFilename) {
try {
initClient();
return storageClient.query_file_info(groupName, remoteFilename);
} catch (IOException e) {
throw new RuntimeException(e);
} catch (MyException e) {
throw new RuntimeException(e);
} finally {
closeClient();
}
}
/**
* 解析文件Url
*
* @param fullPath 文件URL路径,如:group1/M00/00/00/wKjxh2ZhVuuAEAyZAAGkO7PPJ4w858.jpg
* @return
*/
public StorePath parseFromUrl(String fullPath) {
if (fullPath.isEmpty()) {
throw new RuntimeException("解析文件路径不能为空");
}
String group = getGroupName(fullPath);
int pathStartPos = fullPath.indexOf(group) + group.length() + 1;
String path = fullPath.substring(pathStartPos, fullPath.length());
return new StorePath(group, path);
}
private String getGroupName(String fullPath) {
String[] paths = fullPath.split("/");
if (paths.length == 1) {
throw new RuntimeException("解析文件路径错误,有效的路径样式为(group/path) 而当前解析路径为".concat(fullPath));
} else {
String[] var2 = paths;
int var3 = paths.length;
for (int var4 = 0; var4 < var3; ++var4) {
String item = var2[var4];
if (item.indexOf("group") != -1) {
return item;
}
}
throw new RuntimeException("解析文件路径错误,被解析路径url没有group,当前解析路径为".concat(fullPath));
}
}
/**
* 文件路径响应对象
*/
public class StorePath {
private String group;
private String path;
public StorePath() {
}
public StorePath(String group, String path) {
this.group = group;
this.path = path;
}
public String getGroup() {
return this.group;
}
public void setGroup(String group) {
this.group = group;
}
public String getPath() {
return this.path;
}
public void setPath(String path) {
this.path = path;
}
public String getFullPath() {
return this.group.concat("/").concat(this.path);
}
public String getAccessUrl() {
return accessUrl.concat("/").concat(this.group).concat("/").concat(this.path);
}
public String toString() {
return "StorePath [group=" + this.group + ", path=" + this.path + ", fullPath=" + this.getFullPath() + "]";
}
}
}
3. FastDFS文件上传下载Controller
package cn.bear.controller;
import cn.bear.basic.controller.BaseController;
import cn.bear.basic.result.AjaxResult;
import cn.bear.fastdfs.FastDFSClient;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.FileInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
@RequestMapping("/fastDfs")
@Api(tags = "FastDFS文件上传下载")
public class FastDFSController extends BaseController {
@Autowired
private FastDFSClient fastDFSClient;
@PostMapping("/upload")
@ApiOperation("文件上传")
public AjaxResult upload(@RequestPart MultipartFile file) throws IOException {
String filename = file.getOriginalFilename();
byte[] bytes = file.getBytes();
String fileExtName = filename.substring(filename.lastIndexOf(".") + 1);
NameValuePair[] metaList = new NameValuePair[2];
metaList[0] = new NameValuePair("fileName", filename);
metaList[1] = new NameValuePair("author", "Job");
FastDFSClient.StorePath storePath = fastDFSClient.upload(bytes, fileExtName, metaList);
System.out.println(storePath);
return success(storePath);
}
@GetMapping("/download")
@ApiOperation("文件下载")
public void downloadClient(String fileName, String groupName, String remoteFilename, HttpServletResponse response) {
fastDFSClient.download(fileName, groupName, remoteFilename, response);
}
@DeleteMapping("/delete")
@ApiOperation("文件删除")
public AjaxResult deleteClient(String fullPath) {
fastDFSClient.delete(fullPath);
return success();
}
@GetMapping("/getMetadata")
@ApiOperation("获取文件元数据信息")
public AjaxResult getMetadata(String remoteFilename) {
NameValuePair[] metadata = fastDFSClient.getMetadata(remoteFilename);
System.out.println(metadata);
return success(metadata);
}
@GetMapping("/queryFileInfo")
@ApiOperation("查询文件信息")
public AjaxResult queryFileInfo(String groupName, String remoteFilename) {
FileInfo fileInfo = fastDFSClient.queryFileInfo(groupName, remoteFilename);
System.out.println(fileInfo);
return success(fileInfo);
}
}
其他的就是根据实际业务需求继续扩展了
四、FastDFS的安装部署
点击查看:https://blog.csdn.net/m0_72760334/article/details/139558912