java应用整合fastdfs实现文件 上传及下载
对于fastdfs的安装部署请参阅另一篇博文:fastdfs安装篇
本篇主要讲在springboot项目中如何整合fastdfs实现文件上传 下载 及删除,
项目demo gitee 地址:git clone https://gitee.com/JackSong2019/fastdfs_demo.git
整合方式有两种,一种是fastdfs官方提供的 fastdfs-client-java,
另一种是其它开发者基于原作者YuQing与yuqin发布的java客户端的基础上进行了大量的重构的开源项目 fastDFS_Client
一、基于官方提供的fastdfs-client-java方式集成
github地址:https://github.com/happyfish100/fastdfs-client-java
1、引入依赖
注意版本:引入的fastdfs-client-java需在和安装的fastdf server端版本对应,否则上传过程中会出现异常
我使用的fastdfs server 为6.06,引入的依赖为1.30
<dependency>
<groupId>org.csource</groupId>
<artifactId>fastdfs-client-java</artifactId>
<version>1.30-SNAPSHOT</version>
</dependency>
注意:如果通过maven仓库下载失败,解决办法
第一种:使用maven从源码安装
mvn clean install
第二种:使用maven从jar文件安装 注意替换正确的版本号 version
mvn install:install-file -DgroupId=org.csource -DartifactId=fastdfs-client-java -Dversion=${version} -Dpackaging=jar -Dfile=fastdfs-client-java-${version}.jar
2、配置文件 可以用 .conf配置文件,也可用properties配置文件
2.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
配置文件内容
注1:tracker_server指向您自己IP地址和端口,1-n个
注2:除了tracker_server,其它配置项都是可选的
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
2.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
注1:properties 配置文件中属性名跟 conf 配置文件不尽相同,并且统一加前缀"fastdfs.",便于整合到用户项目配置文件
注2:fastdfs.tracker_servers 配置项不能重复属性名,多个 tracker_server 用逗号","隔开
注3:除了fastdfs.tracker_servers,其它配置项都是可选的
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
3、加载配置
3.1 .conf配置文件加载
// 加载原 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");
3.2 .properties 配置文件加载
// 加载 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);
3.3 字符串方式
// 加载 trackerServers 字符串配置:
String trackerServers = "10.0.11.101:22122,10.0.11.102:22122";
ClientGlobal.initByTrackers(trackerServers);
3.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
}
4、编写上传 下载 删除相关方法
package com.ydsz.util;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
public class FastdfsJavaClientUtil {
/**
* 获取tracker客户端
* @return
* @throws Exception
*/
public static StorageClient initStorageClient() throws Exception {
// 1、加载配置文件
ClientGlobal.init("E:\\study\\fastdfs_demo\\src\\main\\resources\\fdfs_client.conf");
// 2 创建一个trackerClient
TrackerClient tracker = new TrackerClient();
// 3 使用TrackerClient对象获取trackerServer对象
TrackerServer trackerServer = tracker.getTrackerServer();
// 4、创建一个StorageClient对象
return new StorageClient(trackerServer);
}
/**
* 关闭tracker
* @param storageClient
*/
public static void closeClient(StorageClient storageClient) {
if(storageClient == null) return;
try {
storageClient.close();
}catch (Exception e){
e.printStackTrace();
}catch (Throwable e){
e.printStackTrace();
}
}
/**
* @param file 上传的文件
* @throws Exception
*/
public static String[] upload(MultipartFile file) throws Exception{
InputStream inputStream = file.getInputStream();
int length = inputStream.available();
byte[] bytes = new byte[length];
inputStream.read(bytes);
NameValuePair[] metaList = new NameValuePair[1];
metaList[0] = new NameValuePair("fileName", file.getOriginalFilename());
StorageClient storageClient = initStorageClient();
String[] result = storageClient.upload_file(bytes, null, metaList);
closeClient(storageClient);
return result;
}
/**
* 下载文件
* @param groupName storage名
* @param fileKey 文件key
* @param localFileName 下载到本地的文件名
* @throws Exception
*/
public static void download(String groupName,String fileKey,String localFileName) throws Exception {
StorageClient storageClient = initStorageClient();
storageClient.download_file(groupName, fileKey,localFileName);
closeClient(storageClient);
}
/**
* 下载文件
* @param groupName storage名
* @param fileKey 文件key
* @throws Exception
*/
public static byte[] download(String groupName,String fileKey) throws Exception {
StorageClient storageClient = initStorageClient();
byte[] bytes = storageClient.download_file(groupName, fileKey);
closeClient(storageClient);
return bytes;
}
/**
* 删除文件
* @param groupName storage名
* @param fileKey 文件key
* @throws Exception
*/
public static void delFile(String groupName,String fileKey) throws Exception {
StorageClient storageClient = initStorageClient();
storageClient.delete_file(groupName, fileKey);
closeClient(storageClient);
}
}
二、基于fastDFS_Client集成
github地址:https://github.com/tobato/FastDFS_Client
fastDFS_Client 是在原作者YuQing与yuqih发布的java客户端基础上进行了大量重构工作,便于Java工作者学习与阅读。
当前客户端单元测试全部通过,服务端版本是FastDFS_V5.07
主要特性
对关键部分代码加入了单元测试,便于理解与服务端的接口交易,提高接口质量
将以前对byte硬解析风格重构为使用 对象+注解 的形式,尽量增强了代码的可读性
支持对服务端的连接池管理(commons-pool2)
支持上传图片时候检查图片格式,并且自动生成缩略图
在SpringBoot当中自动导入依赖
1.在项目Pom当中加入依赖
Maven依赖为
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.27.2</version>
</dependency>
在Maven当中配置依赖以后,SpringBoot项目将会自动导入FastDFS依赖
但注意 如果 是 1.26.4 以前的版本需要下面的方式引入
// 将FastDFS-Client客户端引入本地化项目的方式非常简单,
// 在SpringBoot项目/src/[com.xxx.主目录]/conf当中配置
/**
* 导入FastDFS-Client组件
* @author tobato
*
*/
@Configuration
@Import(FdfsClientConfig.class)
// 解决jmx重复注册bean的问题
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
public class ComponetImport {
// 导入依赖组件
}
// 只需要一行注解 @Import(FdfsClientConfig.class)就可以拥有带有连接池的FastDFS Java客户端了
2、application.yml当中配置fdfs相关参数
# ===================================================================
# 分布式文件系统FDFS配置
# ===================================================================
fdfs:
so-timeout: 1501
connect-timeout: 601
thumb-image: #缩略图生成参数
width: 150
height: 150
tracker-list: #TrackerList参数,支持多个
- 192.168.1.105:22122
- 192.168.1.106:22122
pool:
#从池中借出的对象的最大数目(配置为-1表示不限制)
max-total: -1
#获取连接时的最大等待毫秒数(默认配置为5秒)
max-wait-millis: 5000
#每个key最大连接数
max-total-per-key: 50
#每个key对应的连接池最大空闲连接数
max-idle-per-key: 10
#每个key对应的连接池最小空闲连接数
min-idle-per-key: 5
其中pool部分为连接池的管理参数
应用启动后拥有两个连接池管理对象:
Tracker连接池(TrackerConnectionManager)
Storage连接池(FdfsConnectionManager)
必要的时候可以注入这两个对象,跟踪打印并分析连接池的情况
3、使用接口服务对Fdfs服务端进行操作
3.1 接口说明
主要接口包括
TrackerClient - TrackerServer接口
GenerateStorageClient - 一般文件存储接口 (StorageServer接口)
FastFileStorageClient - 为方便项目开发集成的简单接口(StorageServer接口)
AppendFileStorageClient - 支持文件续传操作的接口 (StorageServer接口)
3.4 代码示例
package com.ydsz.controller;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadByteArray;
import com.github.tobato.fastdfs.domain.upload.FastFile;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.ydsz.util.FastdfsJavaClientUtil;
import org.apache.commons.lang3.StringUtils;
import org.csource.fastdfs.StorageServer;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
@RestController
@RequestMapping("/fastdfs")
public class FileClientController {
@Resource
FastFileStorageClient fastFileStorageClient;
// 自己服务器ip+端口
private String baseUrl ="http://127.0.0.1:80/";
/**
* 文件上传
* @param file
* @return
* @throws Exception
*/
@PostMapping("/upload")
public String upload(MultipartFile file) throws Exception {
StorePath storePath = fastFileStorageClient.uploadFile(file.getInputStream(),
file.getSize(),
StringUtils.substringAfterLast(file.getOriginalFilename(), "."),
null);
return baseUrl + storePath.getFullPath();
}
/**
* @param groupName
* @param fileKey
* @param response
* @throws Exception
*/
@PostMapping("/download")
public void download(String groupName, String fileKey, HttpServletResponse response) throws Exception {
byte[] download = fastFileStorageClient.downloadFile(groupName, fileKey, new DownloadByteArray());
// 将download以流的方式返回
response.getOutputStream().write(download);
}
/**
* 删除文件
* @param filePath 文件的完整路径
*/
@PostMapping("/delete")
public void delFile(String filePath) {
fastFileStorageClient.deleteFile(filePath);
}
}
4、上传文件大小配置 当上传较大文件时 可能会存在异常情况 增加以下配置即可解决
package com.ydsz.config;
import org.springframework.boot.web.servlet.MultipartConfigFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.unit.DataSize;
import javax.servlet.MultipartConfigElement;
@Configuration
public class FileConfig {
@Bean
public MultipartConfigElement multipartConfigElement() {
MultipartConfigFactory factory = new MultipartConfigFactory();
//单个文件最大 50MB
factory.setMaxFileSize(DataSize.ofBytes(50 * 1024 *1024));
/// 设置总上传数据总大小 200MB
factory.setMaxRequestSize(DataSize.ofBytes(200 * 1024 *1024));
return factory.createMultipartConfig();
}
}