FastDFS-Client Java源码改造为适用Nacos的方式

FastDFS-Client 源码的gitHub 地址:
https://github.com/happyfish100/fastdfs-client-java
这个Client的简单用法可自行去看博客:FastDFSClient集成SpringBoot 基础用法
简单用法主要是根据fdfs_client.conf 配置文件的配置来进行的,这样在打包发布后,配置文件不方便修改,对维护成本也有所增加。所以在这根据FastDFS-Client的源码进行改造,修改为使用application.yml配置文件就行fastdfs的配置,同时将配置文件存在Nacos中,以便后续生产改动服务器地址提供便利。

先看看改造后的工程(这里是做成了微服务的组件,通过加入依赖就可以使用):
在这里插入图片描述
工程的pom.xml如下(最主要的就是fastdfs-client-java 和 commons-pool2)另外的是工程的核心组件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
		 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<parent>
		<artifactId>syiti-components</artifactId>
		<groupId>com.syiti.dev</groupId>
		<version>2.0.0</version>
	</parent>
	<modelVersion>4.0.0</modelVersion>

	<artifactId>component-fastdfs</artifactId>

	<dependencies>
		<dependency>
			<groupId>org.csource</groupId>
			<artifactId>fastdfs-client-java</artifactId>
			<exclusions>
				<exclusion>
					<groupId>org.slf4j</groupId>
					<artifactId>slf4j-log4j12</artifactId>
				</exclusion>
			</exclusions>
			<version>1.27</version>
		</dependency>
		<dependency>
			<groupId>com.syiti.dev</groupId>
			<artifactId>component-core</artifactId>
		</dependency>
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-pool2</artifactId>
			<version>2.6.0</version>
		</dependency>
	</dependencies>

</project>

然后在properties包下创建FastdfsProperties配置文件实体类

package com.syiti.dev.component.fastdfs.properties;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;


/**
 * @author LinYoufeng
 * @date 2020-01-03 下午4:05
 */
@Data
@ConfigurationProperties(prefix = "fastdfs")
public class FastdfsProperties {

	/**
	 * 连接超时时间
	 */
	private String connectTimeout = "5";
	/**
	 * 网络超时时间
	 */
	private String networkTimeout = "30";
	/**
	 * 字符集编码
	 */
	private String charset = "UTF-8";
	/**
	 * 是否使用Token
	 */
	private String httpAntiStealToken = "false";
	/**
	 * Token加密密钥
	 */
	private String httpSecretKey = "";
	/**
	 * 跟踪器IP地址,多个使用分号隔开
	 */
	private String httpTrackerHttpPort = "";
	/**
	 * 连接池的连接对象最大个数
	 */
	private String trackerServers = "";
	/**
	 * 连接池的最大空闲对象个数
	 */
	private String connectionPoolMaxTotal = "18";
	/**
	 * 连接池的最小空闲对象个数
	 */
	private String connectionPoolMaxIdle = "18";
	/**
	 * Nginx服务器IP,多个使用分号分割
 	 */
	private String connectionPoolMinIdle = "2";
	/**
	 *  获取连接对象时可忍受的等待时长(毫秒)
	 */
	private String nginxServers = "";

}

创建连接对象工厂类,在factory包下创建StorageClientFactory

package com.syiti.dev.component.fastdfs.factory;

import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;

/**
 * 用于创建连接对象的工厂类
 * @author LinYoufeng
 * @date 2020-01-03 下午4:02
 */
public class StorageClientFactory implements PooledObjectFactory<StorageClient> {

	@Override
	public PooledObject<StorageClient> makeObject() throws Exception {
		TrackerClient client = new TrackerClient();
		TrackerServer server = client.getConnection();
		return new DefaultPooledObject<>(new StorageClient(server, null));
	}

	@Override
	public void destroyObject(PooledObject<StorageClient> p) throws Exception {
		p.getObject().getTrackerServer().close();
	}

	@Override
	public boolean validateObject(PooledObject<StorageClient> p) {
		return false;
	}

	@Override
	public void activateObject(PooledObject<StorageClient> p) throws Exception {

	}

	@Override
	public void passivateObject(PooledObject<StorageClient> p) throws Exception {

	}
}

创建配置类

package com.syiti.dev.component.fastdfs.autoconfiguration;

import com.syiti.dev.component.fastdfs.properties.FastdfsProperties;
import com.syiti.dev.component.fastdfs.service.FastdfsClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author LinYoufeng
 * @date 2020-01-03 下午4:02
 */

@Configuration
@EnableConfigurationProperties(FastdfsProperties.class)
public class FastdfsAutoConfiguration {
	@Autowired
	private FastdfsProperties fastdfsProperties;

	@Bean
	@ConditionalOnMissingBean(FastdfsClientService.class)
	public FastdfsClientService fastdfsClientService() throws Exception {
		return new FastdfsClientService(fastdfsProperties);
	}
}

然后在service包下创建FastdfsClientService类,包括具体的上传操作

package com.syiti.dev.component.fastdfs.service;

import com.syiti.dev.component.fastdfs.factory.StorageClientFactory;
import com.syiti.dev.component.fastdfs.properties.FastdfsProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.FileInfo;
import org.csource.fastdfs.ProtoCommon;
import org.csource.fastdfs.StorageClient;

import java.util.Arrays;
import java.util.Properties;

import static java.lang.Math.abs;

/**
 * @author LinYoufeng
 * @date 2020-01-03 下午4:14
 */
@Slf4j
public class FastdfsClientService {

	/**
	 * SpringBoot加载的配置文件
	 */
	private FastdfsProperties fdfsProp;
	/**
	 * 连接池配置项
	 */
	private GenericObjectPoolConfig config;
	/**
	 * 转换后的配置条目
 	 */
	private Properties prop;
	/**
	 * 连接池
	 */
	private GenericObjectPool<StorageClient> pool;
	/**
	 * Nginx服务器地址
 	 */
	private String[] nginxServers;


	public FastdfsClientService(FastdfsProperties fdfsProp) throws Exception {
		this.fdfsProp = fdfsProp;

		init();
		create();
		info();
	}

	/**
	 * 初始化全局客户端
	 */
	private void init() throws Exception {
		this.prop = new Properties();
		log.info("FastDFS: reading config file...");
		log.info("FastDFS: fastdfs.connect_timeout_in_seconds=" + this.fdfsProp.getConnectTimeout());
		log.info("FastDFS: fastdfs.network_timeout_in_seconds=" + this.fdfsProp.getNetworkTimeout());
		log.info("FastDFS: fastdfs.charset=" + this.fdfsProp.getCharset());
		log.info("FastDFS: fastdfs.http_anti_steal_token=" + this.fdfsProp.getHttpAntiStealToken());
		log.info("FastDFS: fastdfs.http_secret_key=" + this.fdfsProp.getHttpSecretKey());
		log.info("FastDFS: fastdfs.http_tracker_http_port=" + this.fdfsProp.getHttpTrackerHttpPort());
		log.info("FastDFS: fastdfs.tracker_servers=" + this.fdfsProp.getTrackerServers());
		log.info("FastDFS: fastdfs.connection_pool_max_total=" + this.fdfsProp.getConnectionPoolMaxTotal());
		log.info("FastDFS: fastdfs.connection_pool_max_idle=" + this.fdfsProp.getConnectionPoolMaxIdle());
		log.info("FastDFS: fastdfs.connection_pool_min_idle=" + this.fdfsProp.getConnectionPoolMinIdle());
		log.info("FastDFS: fastdfs.nginx_servers=" + this.fdfsProp.getNginxServers());

		this.prop.put("fastdfs.connect_timeout_in_seconds", this.fdfsProp.getConnectTimeout());
		this.prop.put("fastdfs.network_timeout_in_seconds", this.fdfsProp.getNetworkTimeout());
		this.prop.put("fastdfs.charset", this.fdfsProp.getCharset());
		this.prop.put("fastdfs.http_anti_steal_token", this.fdfsProp.getHttpAntiStealToken());
		this.prop.put("fastdfs.http_secret_key", this.fdfsProp.getHttpSecretKey());
		this.prop.put("fastdfs.http_tracker_http_port", this.fdfsProp.getHttpTrackerHttpPort());
		this.prop.put("fastdfs.tracker_servers", this.fdfsProp.getTrackerServers());
		ClientGlobal.initByProperties(this.prop);
	}

	/**
	 * 显示初始化信息
	 */
	private void info() {
		log.info("FastDFS parameter: ConnectionPoolMaxTotal ==> " + this.pool.getMaxTotal());
		log.info("FastDFS parameter: ConnectionPoolMaxIdle ==> " + this.pool.getMaxIdle());
		log.info("FastDFS parameter: ConnectionPoolMinIdle ==> " + this.pool.getMinIdle());
		log.info("FastDFS parameter: NginxServer ==> " + Arrays.toString(this.nginxServers));
		log.info(ClientGlobal.configInfo());
	}

	/**
	 * 创建连接池
	 */
	private void create() {
		this.config = new GenericObjectPoolConfig();
		log.info("FastDFS Client: Creating connection pool...");
		this.config.setMaxTotal(Integer.parseInt(this.fdfsProp.getConnectionPoolMaxTotal()));
		this.config.setMaxIdle(Integer.parseInt(this.fdfsProp.getConnectionPoolMaxIdle()));
		this.config.setMinIdle(Integer.parseInt(this.fdfsProp.getConnectionPoolMinIdle()));
		StorageClientFactory factory = new StorageClientFactory();
		this.pool = new GenericObjectPool<StorageClient>(factory, this.config);
		this.nginxServers = this.fdfsProp.getNginxServers().split(",");
	}

	/**
	 * Nginx服务器负载均衡算法
	 *
	 * @param servers 服务器地址
	 * @param address 客户端IP地址
	 * @return 可用的服务器地址
	 */
	private String getNginxServer(String[] servers, String address) {
		int size = servers.length;
		int i = address.hashCode();
		int index = abs(i % size);
		return servers[index];
	}

	public String getNginxServer(){
		if (this.nginxServers.length > 0){
			return "http://"+this.nginxServers[0];
		}
		return null;
	}

	/**
	 * 上传文件,适合上传图片
	 *
	 * @param buffer 字节数组
	 * @param ext    扩展名
	 * @return 文件组名和ID
	 */
	public String[] autoUpload(byte[] buffer, String ext) throws Exception {
		String[] upload = this.upload(buffer, ext, null);
		return upload;
	}

	/**
	 * 带有防盗链的下载
	 *
	 * @param fileGroup       文件组名
	 * @param remoteFileName  远程文件名称
	 * @param clientIpAddress 客户端IP地址
	 * @return 完整的URL地址
	 */
	public String autoDownloadWithToken(String fileGroup, String remoteFileName, String clientIpAddress) throws Exception {
		int ts = (int) (System.currentTimeMillis() / 1000);
		String token = ProtoCommon.getToken(remoteFileName, ts, ClientGlobal.getG_secret_key());
		String nginx = this.getNginxServer(this.nginxServers, clientIpAddress);
		return "http://" + nginx + "/" + fileGroup + "/" + remoteFileName + "?token=" + token + "&ts=" + ts;
	}

	/**
	 * 不带防盗链的下载,如果开启防盗链会导致该方法抛出异常
	 *
	 * @param fileGroup       文件组名
	 * @param remoteFileName  远程文件ID
	 * @param clientIpAddress 客户端IP地址,根据客户端IP来分配Nginx服务器
	 * @return 完整的URL地址
	 */
	public String autoDownloadWithoutToken(String fileGroup, String remoteFileName, String clientIpAddress) throws Exception {
		if (ClientGlobal.getG_anti_steal_token()) {
			log.error("FastDFS Client: You've turned on Token authentication.");
			throw new Exception("You've turned on Token authentication.");
		}
		String nginx = this.getNginxServer(this.nginxServers, clientIpAddress);
		return "http://" + nginx + fileGroup + "/" + remoteFileName;
	}

	/**
	 * 通过本地文件上传
	 *
	 * @param localFileName 本地文件名称
	 * @param fileExtName   文件扩展名
	 * @param metadata      文件的元数据
	 * @return 文件组名和ID
	 */
	public String[] upload(String localFileName, String fileExtName, NameValuePair[] metadata) throws Exception {
		StorageClient client = this.pool.borrowObject();
		final String[] strings = client.upload_file(localFileName, fileExtName, metadata);
		this.pool.returnObject(client);
		return strings;
	}

	/**
	 * 通过字节数组上传
	 *
	 * @param fileBuff    文件的字节数组
	 * @param fileExtName 扩展名
	 * @param metadata    元数据
	 * @return 文件组名和ID
	 */
	public String[] upload(byte[] fileBuff, String fileExtName, NameValuePair[] metadata) throws Exception {
		StorageClient client = this.pool.borrowObject();
		String[] strings = client.upload_file(fileBuff, fileExtName, metadata);
		this.pool.returnObject(client);
		return strings;
	}



	/**
	 * 通过字节数组上传附加文件
	 *
	 * @param buff        字节数组
	 * @param offset      偏移量
	 * @param len         长度
	 * @param fileExtName 扩展名
	 * @param metadata    元数据
	 * @return 文件组名和ID
	 */
	public String[] uploadAppenderFile(byte[] buff, int offset, int len, String fileExtName, NameValuePair[] metadata) throws Exception {
		StorageClient client = this.pool.borrowObject();
		String[] strings = client.upload_appender_file(buff, offset, len, fileExtName, metadata);
		this.pool.returnObject(client);
		return strings;
	}

	/**
	 * 通过字节数组上传附加文件
	 *
	 * @param buff        字节数组
	 * @param fileExtName 扩展名
	 * @param metadata    元数据
	 * @return 文件组名和ID
	 */
	public String[] uploadAppenderFile(byte[] buff, String fileExtName, NameValuePair[] metadata) throws Exception {
		StorageClient client = this.pool.borrowObject();
		String[] strings = client.upload_appender_file(buff, fileExtName, metadata);
		this.pool.returnObject(client);
		return strings;
	}

	/**
	 * 追加文件
	 *
	 * @param groupName        组名
	 * @param appenderFileName 追加文件名称
	 * @param buff             文件字节数组
	 * @return 返回0表示成功
	 */
	public int appendFile(String groupName, String appenderFileName, byte[] buff) throws Exception {
		StorageClient client = this.pool.borrowObject();
		int i = client.append_file(groupName, appenderFileName, buff);
		this.pool.returnObject(client);
		return i;
	}



	/**
	 * 修改文件
	 *
	 * @param groupName        组名
	 * @param appenderFileName 追加文件名称
	 * @param fileOffset       偏移量
	 * @param buff             字节数组
	 * @return 返回0表示成功
	 */
	public int modify(String groupName, String appenderFileName, long fileOffset, byte[] buff) throws Exception {
		StorageClient client = this.pool.borrowObject();
		int i = client.modify_file(groupName, appenderFileName, fileOffset, buff);
		this.pool.returnObject(client);
		return i;
	}

	/**
	 * 修改文件
	 *
	 * @param groupName        组名
	 * @param appenderFileName 追加文件名称
	 * @param fileOffset       偏移量
	 * @param buff             字节数组
	 * @param waitTimeMillis   等待时间
	 * @return 返回0表示成功
	 */
	public int modify(String groupName, String appenderFileName, long fileOffset, byte[] buff, long waitTimeMillis) throws Exception {
		StorageClient client = this.pool.borrowObject(waitTimeMillis);
		int i = client.modify_file(groupName, appenderFileName, fileOffset, buff);
		this.pool.returnObject(client);
		return i;
	}

	/**
	 * 删除文件
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @return 返回0表示成功
	 */
	public int delete(String groupName, String remoteFileName) throws Exception {
		StorageClient client = this.pool.borrowObject();
		int i = client.delete_file(groupName, remoteFileName);
		this.pool.returnObject(client);
		return i;
	}


	/**
	 * 文件分片
	 *
	 * @param groupName    组名
	 * @param appenderName 输出源文件名称
	 * @return 返回0表示成功
	 */
	public int truncate(String groupName, String appenderName) throws Exception {
		StorageClient client = this.pool.borrowObject();
		int i = client.truncate_file(groupName, appenderName);
		this.pool.returnObject(client);
		return i;
	}


	/**
	 * 文件分片
	 *
	 * @param truncatedFileSize 分片大小
	 * @param groupName         组名
	 * @param appenderName      输出源文件名称
	 * @return 返回0表示成功
	 */
	public int truncate(long truncatedFileSize, String groupName, String appenderName) throws Exception {
		StorageClient client = this.pool.borrowObject();
		int i = client.truncate_file(groupName, appenderName, truncatedFileSize);
		this.pool.returnObject(client);
		return i;
	}


	/**
	 * 下载文件
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @return 返回0表示成功
	 */
	public byte[] download(String groupName, String remoteFileName) throws Exception {
		StorageClient client = this.pool.borrowObject();
		byte[] bytes = client.download_file(groupName, remoteFileName);
		this.pool.returnObject(client);
		return bytes;
	}

	/**
	 * 下载文件
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @param waitTimeMillis 等待时间
	 * @return 返回0表示成功
	 */
	public byte[] download(String groupName, String remoteFileName, long waitTimeMillis) throws Exception {
		StorageClient client = this.pool.borrowObject(waitTimeMillis);
		byte[] bytes = client.download_file(groupName, remoteFileName);
		this.pool.returnObject(client);
		return bytes;
	}



	/**
	 * 下载文件
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @param localFileName  本地文件名称
	 * @return 返回0表示成功
	 */
	public int download(String groupName, String remoteFileName, String localFileName) throws Exception {
		StorageClient client = this.pool.borrowObject();
		int i = client.download_file(groupName, remoteFileName, localFileName);
		this.pool.returnObject(client);
		return i;
	}

	/**
	 * 下载文件
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @param localFileName  本地文件名称
	 * @param waitTimeMillis 等待时间
	 * @return 返回0表示成功
	 */
	public int download(String groupName, String remoteFileName, String localFileName, long waitTimeMillis) throws Exception {
		StorageClient client = this.pool.borrowObject(waitTimeMillis);
		int i = client.download_file(groupName, remoteFileName, localFileName);
		this.pool.returnObject(client);
		return i;
	}

	/**
	 * 获取元数据
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @return 键值对数组
	 */
	public NameValuePair[] getMetadata(String groupName, String remoteFileName) throws Exception {
		StorageClient client = this.pool.borrowObject();
		NameValuePair[] metadata = client.get_metadata(groupName, remoteFileName);
		this.pool.returnObject(client);
		return metadata;
	}

	/**
	 * 获取元数据
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @param waitTimeMillis 等待时间
	 * @return 键值对数组
	 */
	public NameValuePair[] getMetadata(String groupName, String remoteFileName, long waitTimeMillis) throws Exception {
		StorageClient client = this.pool.borrowObject(waitTimeMillis);
		NameValuePair[] metadata = client.get_metadata(groupName, remoteFileName);
		this.pool.returnObject(client);
		return metadata;
	}

	/**
	 * 设置元数据
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @param metadata       元数据
	 * @param flag           更新设置:ProtoCommon.STORAGE_SET_METADATA_FLAG_OVERWRITE 表示重写所有; ProtoCommon.STORAGE_SET_METADATA_FLAG_MERGE 表示没有就插入,有就更新
	 * @return 返回0表示成功
	 */
	public int setMetadata(String groupName, String remoteFileName, NameValuePair[] metadata, byte flag) throws Exception {
		StorageClient client = this.pool.borrowObject();
		int i = client.set_metadata(groupName, remoteFileName, metadata, flag);
		this.pool.returnObject(client);
		return i;
	}


	/**
	 * 获取文件信息
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @return 返回文件信息
	 */
	public FileInfo getFileInfo(String groupName, String remoteFileName) throws Exception {
		StorageClient client = this.pool.borrowObject();
		FileInfo file_info = client.get_file_info(groupName, remoteFileName);
		this.pool.returnObject(client);
		return file_info;
	}

	/**
	 * 获取文件名称
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件名称
	 * @param waitTimeMillis 等待时长
	 * @return 返回文件信息
	 */
	public FileInfo getFileInfo(String groupName, String remoteFileName, long waitTimeMillis) throws Exception {
		StorageClient client = this.pool.borrowObject(waitTimeMillis);
		FileInfo file_info = client.get_file_info(groupName, remoteFileName);
		this.pool.returnObject(client);
		return file_info;
	}

	/**
	 * 查询文件信息
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件信息
	 * @return 返回文件信息
	 */
	public FileInfo queryFileInfo(String groupName, String remoteFileName) throws Exception {
		StorageClient client = this.pool.borrowObject();
		FileInfo fileInfo = client.query_file_info(groupName, remoteFileName);
		this.pool.returnObject(client);
		return fileInfo;
	}

	/**
	 * 查询文件信息
	 *
	 * @param groupName      组名
	 * @param remoteFileName 远程文件信息
	 * @param waitTimeMillis 等待时间
	 * @return 返回文件信息
	 */
	public FileInfo queryFileInfo(String groupName, String remoteFileName, long waitTimeMillis) throws Exception {
		StorageClient client = this.pool.borrowObject(waitTimeMillis);
		FileInfo fileInfo = client.query_file_info(groupName, remoteFileName);
		this.pool.returnObject(client);
		return fileInfo;
	}
}

最后通过创建注解类

package com.syiti.dev.component.fastdfs.annotation;

import com.syiti.dev.component.fastdfs.autoconfiguration.FastdfsAutoConfiguration;
import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

/**
 * @author LinYoufeng
 * @date 2020-01-03 下午4:01
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(FastdfsAutoConfiguration.class)
@Documented
public @interface EnableFastdfsClient {
}

在源码上包装后,使用这个组件说明:
FastDFS 组件使用说明:
使用FastDFS 组件分以下四步:
1.加依赖:

<dependency>
   <groupId>com.syiti.dev</groupId>
   <artifactId>component-fastdfs</artifactId>
   <version>2.0.0</version>
</dependency>

2.在启动类上加入注解
@EnableDiscoveryClient
@EnableFastdfsClient

3.写配置文件 application.yml
fastdfs:
charset: UTF-8
connect-timeout: 5
network-timeout: 30
http-tracker-http-port: 1080
connection-pool-max-idle: 20
connection-pool-max-total: 20
connection-pool-min-idle: 2
nginx-servers: 192.168.0.192:1080
tracker-servers: 192.168.0.192:22122

4.在需要使用FastDFS 的具体业务实现类上加入 Service
@Autowired
private FastdfsClientService fastdfsClientService;

完成以上四步即可直接使用相关的上传、删除等功能。
fastdfsClientService.autoUpload(xx,xx)

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
FastDFS服务端有两个角色:跟踪器(tracker)和存储节点(storage)。跟踪器主要做调度工作,在访问上起负载均衡的作用。 存储节点存储文件,完成文件管理的所有功能:就是这样的存储、同步和提供存取接口,FastDFS同时对文件的metadata进行管理。所谓文件的meta data就是文件的相关属性,以键值对(key value)方式表示,如:width=1024,其中的key为width,value为1024。文件metadata是文件属性列表,可以包含多个键值对。 跟踪器和存储节点都可以由一台或多台服务器构成。跟踪器和存储节点中的服务器均可以随时增加或下线而不会影响线上服务。其中跟踪器中的所有服务器都是对等的,可以根据服务器的压力情况随时增加或减少。 为了支持大容量,存储节点(服务器)采用了分卷(或分组)的组织方式。存储系统由一个或多个卷组成,卷与卷之间的文件是相互独立的,所有卷的文件容量累加就是整个存储系统中的文件容量。一个卷可以由一台或多台存储服务器组成,一个卷下的存储服务器中的文件都是相同的,卷中的多台存储服务器起到了冗余备份和负载均衡的作用。 在卷中增加服务器时,同步已有的文件由系统自动完成,同步完成后,系统自动将新增服务器切换到线上提供服务。 当存储空间不足或即将耗尽时,可以动态添加卷。只需要增加一台或多台服务器,并将它们配置为一个新的卷,这样就扩大了存储系统的容量。 FastDFS中的文件标识分为两个部分:卷名和文件名,二者缺一不可。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值