FastDFS安装并 spring 集成(包含 Nginx)

来源:互联网 发布:五毛钱特效软件 编辑:程序博客网 时间:2024/06/03 12:28

第一次写博客,不好之处请见谅

直入主题:
FastDFS 分布式文件系统的安装与使用(单节点)


服务器地址

跟踪服务器:120.77.41.37
存储服务器:120.77.41.37

服务器环境

环境:CentOS 7
用户: root
数据目录:/fastdfs (注:数据目录按你的数据盘挂载路径而定)

安装包

FastDFS v5.05
libfastcommon-master.zip(是从 FastDFS 和 FastDHT 中提取出来的公共 C 函数库)
fastdfs-nginx-module_v1.16.tar.gz
nginx-1.6.2.tar.gz
fastdfs_client_java._v1.25.tar.gz
源码地址:https://github.com/happyfish100/
下载地址:http://sourceforge.net/projects/fastdfs/files/
官方论坛:http://bbs.chinaunix.net/forum-240-1.html

所有跟踪服务器和存储服务器均执行如下操作:

编译和安装所需的依赖包:

# yum install make cmake gcc gcc-c++

安装 libfastcommon:

  • 上传或下载 libfastcommon-master.zip 到/usr/local/src 目录
  • 解压:

# cd /usr/local/src/
# unzip libfastcommon-master.zip
# cd libfastcommon-master

  • 编译、安装:

# ./make.sh
# ./make.sh install
libfastcommon 默认安装到了
/usr/lib64/libfastcommon.so
/usr/lib64/libfdfsclient.so

  • 因为 FastDFS 主程序设置的 lib 目录是/usr/local/lib,所以需要创建软链接:

# ln -s /usr/lib64/libfastcommon.so /usr/local/lib/libfastcommon.so
# ln -s /usr/lib64/libfastcommon.so /usr/lib/libfastcommon.so
# ln -s /usr/lib64/libfdfsclient.so /usr/local/lib/libfdfsclient.so
# ln -s /usr/lib64/libfdfsclient.so /usr/lib/libfdfsclient.so

安装 FastDFS

  • 上传或下载 FastDFS 源码包(FastDFS_v5.05.tar.gz)到 /usr/local/src 目录
  • 解压:

# cd /usr/local/src/
# tar -zxvf FastDFS_v5.05.tar.gz
# cd FastDFS

  • 编译、安装(编译前要确保已经成功安装了 libfastcommon)

# ./make.sh
# ./make.sh install
采用默认安装的方式安装,安装后的相应文件与目录:
A、服务脚本在:
/etc/init.d/fdfs_storaged
/etc/init.d/fdfs_tracker
B、配置文件在(样例配置文件):
/etc/fdfs/client.conf.sample
/etc/fdfs/storage.conf.sample
/etc/fdfs/tracker.conf.sample
C、命令工具在/usr/bin/目录下的:
fdfs_appender_test
fdfs_appender_test1
fdfs_append_file
fdfs_crc32
……

  • 因为 FastDFS 服务脚本设置的 bin 目录是/usr/local/bin,但实际命令安装在/usr/bin,可以进入 /user/bin 目录使用以下命令查看 fdfs 的相关命令:

# cd /usr/bin/
# ls | grep fdfs

  • 因此需要修改 FastDFS 服务脚本中相应的命令路径,也就是把/etc/init.d/fdfs_storaged 和/etc/init.d/fdfs_tracker 两个脚本中的/usr/local/bin 修改成/usr/bin:

# vi fdfs_trackerd

  • 使用查找替换命令进统一修改:%s+/usr/local/bin+/usr/bin

# vi fdfs_storaged

  • 使用查找替换命令进统一修改:%s+/usr/local/bin+/usr/bin

配置 FastDFS 跟踪器

复制 FastDFS 跟踪器样例配置文件,并重命名:

# cd /etc/fdfs/
# cp tracker.conf.sample tracker.conf

编辑跟踪器配置文件:

# vi /etc/fdfs/tracker.conf

修改的内容如下:

disabled=false
port=22122
base_path=/fastdfs/tracker
(其它参数保留默认配置,具体配置解释请参考官方文档说明: http://bbs.chinaunix.net/thread-1941456-1-1.html )

创建基础数据目录(参考基础目录 base_path 配置):

# mkdir -p /fastdfs/tracker

防火墙中打开跟踪器端口(默认为 22122):

# vi /etc/sysconfig/iptables

添加如下端口行:
   -A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT
重启防火墙:

# service iptables restart

启动 Tracker:

# /etc/init.d/fdfs_trackerd star

(初次成功启动,会在/fastdfs/tracker 目录下创建 data、logs 两个目录)
查看 FastDFS Tracker 是否已成功启动:

# ps -ef | grep fdfs

关闭 Tracker:

# /etc/init.d/fdfs_trackerd stop

设置 FastDFS 跟踪器开机启动:

# vi /etc/rc.d/rc.local

添加以下内容:

## FastDFS Tracker
/etc/init.d/fdfs_trackerd start


配置 FastDFS 存储

复制 FastDFS 存储器样例配置文件,并重命名:

# cd /etc/fdfs/
# cp storage.conf.sample storage.conf

编辑存储器样例配置文件:

# vi /etc/fdfs/storage.conf

修改的内容如下:

disabled=false
port=23000
base_path=/fastdfs/storage
store_path0=/fastdfs/storage
tracker_server=120.77.41.37:22122
http.server_port=8888
(其它参数保留默认配置,具体配置解释请参考官方文档说明: http://bbs.chinaunix.net/thread-1941456-1-1.html )

创建基础数据目录(参考基础目录 base_path 配置):

# mkdir -p /fastdfs/storage

防火墙中打开存储器端口(默认为 23000):

参考上面修改防火墙

启动 Storage:

# /etc/init.d/fdfs_storaged start

初次成功启动,会在/fastdfs/storage 目录下创建 data、logs 两个目录)

关闭 Storage:

# /etc/init.d/fdfs_storaged stop

设置 FastDFS 存储器开机启动:

# vi /etc/rc.d/rc.local

添加:

## FastDFS Storage
/etc/init.d/fdfs_storaged start


四、文件上传测试

修改 Tracker 服务器中的客户端配置文件:

# cp /etc/fdfs/client.conf.sample /etc/fdfs/client.conf
# vi /etc/fdfs/client.conf
修改内容如下:
base_path=/fastdfs/tracker
btracker_server=120.77.41.37:22122

执行如下文件上传命令:

# /usr/bin/fdfs_upload_file /etc/fdfs/client.conf /usr/local/src/FastDFS_v5.05.tar.gz

返回 ID 号:group1/M00/00/00/wKFHOASIOCO43242342XO.tar.gz
能返回以上文件 ID,说明文件上传成功)

在每个存储节点上安装 nginx

fastdfs-nginx-module 作用说明:

FastDFS 通过 Tracker 服务器,将文件放在 Storage 服务器存储,但是同组存储服务器之间需要进入文件复制,有同步延迟的问题。假设 Tracker 服务器将文件上传到了 120.77.41.37,上传成功后文件 ID 已经返回给客户端。此时 FastDFS 存储集群机制会将这个文件同步到同组存储 120.77.41.37,在文件还 没有复制完成的情况下,客户端如果用这个文件 ID 在 120.77.41.37 上取文件,就会出现文件无法访问的 错误。而 fastdfs-nginx-module 可以重定向文件连接到源服务器取文件,避免客户端由于复制延迟导致的 文件无法访问错误。(解压后的 fastdfs-nginx-module 在 nginx 安装时使用)

上传 fastdfs-nginx-module_v1.16.tar.gz 到/usr/local/src

解压

# cd /usr/local/src/
# tar -zxvf fastdfs-nginx-module_v1.16.tar.gz

修改 fastdfs-nginx-module 的 config 配置文件:

# cd fastdfs-nginx-module/src
# vi config
CORE_INCS=”$CORE_INCS /usr/local/include/fastdfs /usr/local/include/fastcommon/”
修改为:
CORE_INCS=”$CORE_INCS /usr/include/fastdfs /usr/include/fastcommon/”
注意:这个路径修改是很重要的,不然在 nginx 编译的时候会报错的)

上传当前的稳定版本 Nginx(nginx-1.6.2.tar.gz)到/usr/local/src 目录:

安装编译 Nginx 所需的依赖包:

# yum install gcc gcc-c++ make automake autoconf libtool pcre* zlib openssl openssl-devel

编译安装 Nginx(添加 fastdfs-nginx-module 模块):

# cd /usr/local/src/
# tar -zxvf nginx-1.6.2.tar.gz
# cd nginx-1.6.2
# ./configure –add-module=/usr/local/src/fastdfs-nginx-module/src
# make && make install

复制 fastdfs-nginx-module 源码中的配置文件到/etc/fdfs 目录,并修改:

# cp /usr/local/src/fastdfs-nginx-module/src/mod_fastdfs.conf /etc/fdfs/
# vi /etc/fdfs/mod_fastdfs.conf
修改以下配置:
connect_timeout=10
base_path=/tmp
tracker_server=120.77.41.37:22122
storage_server_port=23000
group_name=group1
url_have_group_name = true
store_path0=/fastdfs/storage

复制 FastDFS 的部分配置文件到/etc/fdfs 目录:

# cd /usr/local/src/FastDFS/conf
# cp http.conf mime.types /etc/fdfs/

在/fastdfs/storage 文件存储目录下创建软连接,将其链接到实际存放数据的目录:

# ln -s /fastdfs/storage/data/ /fastdfs/storage/data/M00

配置 Nginx:

简洁版 nginx 配置样例:

user root;
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 8888;
server_name localhost;
location ~/group([0-9])/M00 {
#alias /fastdfs/storage/data;
ngx_fastdfs_module;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html; }
} }

A、8888 端口值是要与/etc/fdfs/storage.conf 中的 http.server_port=8888 相对应,因为 http.server_port 默认为 8888,如果想改成 80,则要对应修改过来。B、Storage 对应有多个 group 的情况下,访问路径带 group 名,如/group1/M00/00/00/xxx,

对应的 Nginx 配置为:

location ~/group([0-9])/M00 {
ngx_fastdfs_module;
}

C、如查下载时如发现老报 404,将 nginx.conf 第一行 user nobody 修改为 user root 后重新启动。

防火墙中打开 Nginx 的 8888 端口

参考前边修改防火墙端口

启动 Nginx:

# /usr/local/nginx/sbin/nginx
ngx_http_fastdfs_set pid=xxx
(重启 Nginx 的命令为:/usr/local/nginx/sbin/nginx -s reload)

通过浏览器访问测试时上传的文件:

http://120.77.41.37:8888/group1/M00/00/00/rBIvKFll_-iAKwK9AAIpzOP593E159.jpg?token=f42b765ca5101374e831b123ce4f8fbe&ts=1499856871

浏览器成功访问

上传成功


FastDFS与 Spring 整合

xml配置文件:

<bean id="fastDFSFactory" class="com.anniweiya.fastdfs.FastDFSTemplateFactory" init-method="init">    <!--连接超时的时限,单位为秒-->    <property name="g_connect_timeout" value="60"/>    <!--网络超时的时限,单位为秒-->    <property name="g_network_timeout" value="80"/>    <!--防盗链配置-->    <property name="g_anti_steal_token" value="true"/>    <property name="g_secret_key" value="FastDFS1234567890"/>    <property name="poolConfig">      <bean class="com.anniweiya.fastdfs.pool.PoolConfig">        <!--池的大小-->        <property name="maxTotal" value="100"/>        <!--连接池中最大空闲的连接数-->        <property name="maxIdle" value="10"/>      </bean>    </property>    <!--tracker的配置 ","逗号分隔-->    <property name="tracker_servers" value="120.77.41.37:22122"/>    <!--HTTP访问服务的端口号-->    <property name="g_tracker_http_port" value="8080"/>    <!--nginx的对外访问地址,如果没有端口号,将取g_tracker_http_port配置的端口号 ","逗号分隔-->    <property name="nginx_address" value="120.77.41.37:8888"/>  </bean>  <!--注入模板类-->  <bean id="fastDFSTemplate" class="com.anniweiya.fastdfs.FastDFSTemplate">    <constructor-arg ref="fastDFSFactory"/>  </bean>

fastDFS自定义异常处理

/** *  * @Description: 文件上传异常  * @author: Aaron * @date: 2017年7月12日 下午6:56:09 */public class FastDFSException extends Exception {    // serialVersionUID : TODO    private static final long serialVersionUID = 1L;    @SuppressWarnings("unused")    //错误编码    private int errorCode = 0;    public FastDFSException(int errorCode) {        this.errorCode = errorCode;    }    public FastDFSException(String message, int errorCode) {        super(message);        this.errorCode = errorCode;    }    public FastDFSException(String message, Throwable cause, int errorCode) {        super(message, cause);        this.errorCode = errorCode;    }    public FastDFSException(Throwable cause, int errorCode) {        super(cause);        this.errorCode = errorCode;    }    public FastDFSException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace,                            int errorCode) {        super(message, cause, enableSuppression, writableStackTrace);        this.errorCode = errorCode;    }}

使用连接池创建连接

/** *  * @Description: 使用连接池创建连接  * @author: Aaron * @date: 2017年7月12日 下午6:57:05 */class ConnectionFactory extends BasePooledObjectFactory<StorageClient> {    private FastDFSTemplateFactory factory;    public ConnectionFactory(FastDFSTemplateFactory templateFactory) {        this.factory = templateFactory;    }    @Override    public StorageClient create() throws Exception {        TrackerClient trackerClient = new TrackerClient(factory.getG_tracker_group());        TrackerServer trackerServer = trackerClient.getConnection();        return new StorageClient(trackerServer, null);    }    @Override    public PooledObject<StorageClient> wrap(StorageClient storageClient) {        return new DefaultPooledObject<>(storageClient);    }    public PooledObject<StorageClient> makeObject() throws Exception {        return wrap(create());    }    public void destroyObject(StorageClient obj) throws Exception {        close(obj.getTrackerServer());    }    private void close(Closeable closeable) {        if (closeable != null) {            try {                closeable.close();            } catch (IOException ignored) {            }        }    }}

连接池工厂

/** *  * @Description: 连接池工厂 * @author: Aaron * @date: 2017年7月12日 下午6:58:09 */public class ConnectionPoolFactory {    private GenericObjectPool<StorageClient> pool;    public ConnectionPoolFactory(FastDFSTemplateFactory fastDFSTemplateFactory) {        pool = new GenericObjectPool<>(new ConnectionFactory(fastDFSTemplateFactory));    }    public StorageClient getClient() throws Exception {        return pool.borrowObject();    }    public void releaseConnection(StorageClient client) {        try {            pool.returnObject(client);        } catch (Exception ignored) {        }    }    /**     *      * @Description: 修改属性     * @param poolConfig     * @author: Aaron     * @date: 2017年7月12日 下午6:59:02     */    @SuppressWarnings("unused")    private void toConfig(PoolConfig poolConfig) {        pool.setMaxTotal(poolConfig.maxTotal);        pool.setMaxIdle(poolConfig.maxIdle);        pool.setMinIdle(poolConfig.minIdle);        pool.setTestOnBorrow(poolConfig.testOnBorrow);        pool.setMaxWaitMillis(poolConfig.maxWait);    }}

连接池配置类

/** *  * @Description: 连接池配置 * @author: Aaron * @date: 2017年7月12日 下午7:00:07 */public class PoolConfig {    public int maxIdle = 10;    public int minIdle = 0;    public int maxTotal = 10;    public long maxWait = -1L;    public boolean testOnBorrow = false;    public byte whenExhaustedAction = 1;    public boolean testOnReturn = false;    public boolean testWhileIdle = false;    public long timeBetweenEvictionRunsMillis = -1L;    public int numTestsPerEvictionRun = 3;    public long minEvictableIdleTimeMillis = 1800000L;    public long softMinEvictableIdleTimeMillis = -1L;    public boolean lifo = true;    public PoolConfig() {    }    public int getMaxIdle() {        return maxIdle;    }    public void setMaxIdle(int maxIdle) {        this.maxIdle = maxIdle;    }    public int getMinIdle() {        return minIdle;    }    public void setMinIdle(int minIdle) {        this.minIdle = minIdle;    }    public int getMaxTotal() {        return maxTotal;    }    public void setMaxTotal(int maxTotal) {        this.maxTotal = maxTotal;    }    public long getMaxWait() {        return maxWait;    }    public void setMaxWait(long maxWait) {        this.maxWait = maxWait;    }    public byte getWhenExhaustedAction() {        return whenExhaustedAction;    }    public void setWhenExhaustedAction(byte whenExhaustedAction) {        this.whenExhaustedAction = whenExhaustedAction;    }    public boolean isTestOnBorrow() {        return testOnBorrow;    }    public void setTestOnBorrow(boolean testOnBorrow) {        this.testOnBorrow = testOnBorrow;    }    public boolean isTestOnReturn() {        return testOnReturn;    }    public void setTestOnReturn(boolean testOnReturn) {        this.testOnReturn = testOnReturn;    }    public boolean isTestWhileIdle() {        return testWhileIdle;    }    public void setTestWhileIdle(boolean testWhileIdle) {        this.testWhileIdle = testWhileIdle;    }    public long getTimeBetweenEvictionRunsMillis() {        return timeBetweenEvictionRunsMillis;    }    public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {        this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;    }    public int getNumTestsPerEvictionRun() {        return numTestsPerEvictionRun;    }    public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {        this.numTestsPerEvictionRun = numTestsPerEvictionRun;    }    public long getMinEvictableIdleTimeMillis() {        return minEvictableIdleTimeMillis;    }    public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {        this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;    }    public long getSoftMinEvictableIdleTimeMillis() {        return softMinEvictableIdleTimeMillis;    }    public void setSoftMinEvictableIdleTimeMillis(long softMinEvictableIdleTimeMillis) {        this.softMinEvictableIdleTimeMillis = softMinEvictableIdleTimeMillis;    }    public boolean isLifo() {        return lifo;    }    public void setLifo(boolean lifo) {        this.lifo = lifo;    }}

文件信息描述

/** *  * @Description: 文件信息描述 * @author: Aaron * @date: 2017年7月12日 下午7:00:32 */public class FastDfsInfo implements java.io.Serializable {    // serialVersionUID : TODO    private static final long serialVersionUID = 4858945733404165431L;    private String group;    private String path;    private String fileAbsolutePath;    public FastDfsInfo(String group, String path) {        this.group = group;        this.path = path;    }    @Override    public String toString() {        return "FastDfsInfo{" + "group='" + group + '\'' +               ", path='" + path + '\'' +               '}';    }    public String getGroup() {        return group;    }    public void setGroup(String group) {        this.group = group;    }    public String getPath() {        return path;    }    public void setPath(String path) {        this.path = path;    }    public String getFileAbsolutePath() {        return fileAbsolutePath;    }    public void setFileAbsolutePath(String fileAbsolutePath) {        this.fileAbsolutePath = fileAbsolutePath;    }}

FastDFS 初始化工厂

/** *  * @Description: FastDFS 初始化 * @author: Aaron * @date: 2017年7月12日 下午7:04:21 */public class FastDFSTemplateFactory {    //连接超时时间    private int g_connect_timeout;    //网络超时时间    private int g_network_timeout;    //编码    private String g_charset;    //tracker 端口    private int g_tracker_http_port;    //防盗链token是否需要    private boolean g_anti_steal_token;    //FastDFS key    private String g_secret_key;    //tracker 地址    private List<String> tracker_servers;    //nginx 地址    private List<String> nginx_address;    private TrackerGroup g_tracker_group;    private PoolConfig poolConfig = new PoolConfig();    private String protocol = "http://";    private String sepapator = "/";    public void init() throws Exception {        if (g_connect_timeout <= 0) {            g_connect_timeout = ClientGlobal.DEFAULT_CONNECT_TIMEOUT;        }        if (g_network_timeout <= 0) {            g_network_timeout = ClientGlobal.DEFAULT_NETWORK_TIMEOUT;        }        g_connect_timeout *= 1000; //millisecond        g_network_timeout *= 1000; //millisecond        if (g_charset == null || g_charset.length() == 0) {            g_charset = "UTF-8";        }        if (g_tracker_http_port <= 0) {            g_tracker_http_port = 80;        }        if (tracker_servers == null || tracker_servers.isEmpty()) {            throw new FastDFSException("item \"tracker_server\"  not found", -1);        }        InetSocketAddress[] tracker_servers_socket = new InetSocketAddress[tracker_servers.size()];        for (int i = 0; i < tracker_servers.size(); i++) {            String str = tracker_servers.get(i);            String[] parts = str.split("\\:", 2);            if (parts.length != 2) {                throw new FastDFSException(                        "the value of item \"tracker_server\" is invalid, the correct format is host:port", -2);            }            tracker_servers_socket[i] = new InetSocketAddress(parts[0].trim(), Integer.parseInt(parts[1].trim()));        }        g_tracker_group = new TrackerGroup(tracker_servers_socket);        if (g_anti_steal_token) {            if (g_secret_key == null || "".equals(g_secret_key)) {                throw new FastDFSException("item \"secret_key\"  not found", -2);            }        }        setToGlobal();    }    private void setToGlobal() {        ClientGlobal.setG_connect_timeout(this.g_connect_timeout);        ClientGlobal.setG_network_timeout(this.g_network_timeout);        ClientGlobal.setG_charset(this.g_charset);        ClientGlobal.setG_tracker_http_port(this.g_tracker_http_port);        ClientGlobal.setG_anti_steal_token(this.g_anti_steal_token);        ClientGlobal.setG_secret_key(this.g_secret_key);        ClientGlobal.setG_tracker_group(this.g_tracker_group);    }    public PoolConfig getPoolConfig() {        if (poolConfig == null) {            return new PoolConfig();        }        return poolConfig;    }    public void setPoolConfig(PoolConfig poolConfig) {        this.poolConfig = poolConfig;    }    public int getG_connect_timeout() {        return g_connect_timeout;    }    public void setG_connect_timeout(int g_connect_timeout) {        this.g_connect_timeout = g_connect_timeout;    }    public int getG_network_timeout() {        return g_network_timeout;    }    public void setG_network_timeout(int g_network_timeout) {        this.g_network_timeout = g_network_timeout;    }    public String getG_charset() {        return g_charset;    }    public void setG_charset(String g_charset) {        this.g_charset = g_charset;    }    public int getG_tracker_http_port() {        return g_tracker_http_port;    }    public void setG_tracker_http_port(int g_tracker_http_port) {        this.g_tracker_http_port = g_tracker_http_port;    }    public boolean isG_anti_steal_token() {        return g_anti_steal_token;    }    public void setG_anti_steal_token(boolean g_anti_steal_token) {        this.g_anti_steal_token = g_anti_steal_token;    }    public String getG_secret_key() {        return g_secret_key;    }    public void setG_secret_key(String g_secret_key) {        this.g_secret_key = g_secret_key;    }    public List<String> getTracker_servers() {        return tracker_servers;    }    public void setTracker_servers(String tracker_servers) {        this.tracker_servers = Arrays.asList(tracker_servers.split(","));    }    public List<String> getNginx_address() {        return nginx_address;    }    public void setNginx_address(String nginx_address) {        this.nginx_address = Arrays.asList(nginx_address.split(","));    }    public TrackerGroup getG_tracker_group() {        return g_tracker_group;    }    public void setG_tracker_group(TrackerGroup g_tracker_group) {        this.g_tracker_group = g_tracker_group;    }    public String getProtocol() {        return protocol;    }    public void setProtocol(String protocol) {        this.protocol = protocol;    }    public String getSepapator() {        return sepapator;    }    public void setSepapator(String sepapator) {        this.sepapator = sepapator;    }}

FastDFS 模板类

/** *  * @Description: FastDFS 模板类  * @author: Aaron * @date: 2017年7月12日 下午7:01:03 */public class FastDFSTemplate {    private ConnectionPoolFactory connPoolFactory;    private FastDFSTemplateFactory factory;    public FastDFSTemplate(FastDFSTemplateFactory factory) {        this.connPoolFactory = new ConnectionPoolFactory(factory);        this.factory = factory;    }   /**    *     * @Description: 上传文件    * @param data    * @param ext 后缀,如:jpg、bmp(注意不带.)    * @return    * @throws FastDFSException    * @author: Aaron    * @date: 2017年7月12日 下午7:01:32    */    public FastDfsInfo upload(byte[] data, String ext) throws FastDFSException {        return this.upload(data, ext, null);    }   /**    *     * @Description: 上传文件    * @param data    * @param ext 后缀,如:jpg、bmp(注意不带.)    * @param values    * @return    * @throws FastDFSException    * @author: Aaron    * @date: 2017年7月12日 下午7:01:55    */    public FastDfsInfo upload(byte[] data, String ext, Map<String, String> values) throws FastDFSException {        NameValuePair[] valuePairs = null;        if (values != null && !values.isEmpty()) {            valuePairs = new NameValuePair[values.size()];            int index = 0;            for (Map.Entry<String, String> entry : values.entrySet()) {                valuePairs[index] = new NameValuePair(entry.getKey(), entry.getValue());                index++;            }        }        StorageClient client = getClient();        try {            String[] uploadResults = client.upload_file(data, ext, valuePairs);            String groupName = uploadResults[0];            String remoteFileName = uploadResults[1];            FastDfsInfo fastDfsInfo = new FastDfsInfo(groupName, remoteFileName);            if (factory != null) {                this.setFileAbsolutePath(fastDfsInfo);            }            return fastDfsInfo;        } catch (Exception e) {            throw new FastDFSException(e.getMessage(), e, 0);        } finally {            releaseClient(client);        }    }   /**    *     * @Description: 下载文件    * @param dfs    * @return    * @throws FastDFSException    * @author: Aaron    * @date: 2017年7月12日 下午7:02:27    */    public byte[] loadFile(FastDfsInfo dfs) throws FastDFSException {        return this.loadFile(dfs.getGroup(), dfs.getPath());    }   /**    *     * @Description: 下载文件    * @param groupName    * @param remoteFileName    * @return    * @throws FastDFSException    * @author: Aaron    * @date: 2017年7月12日 下午7:02:46    */    public byte[] loadFile(String groupName, String remoteFileName) throws FastDFSException {        StorageClient client = getClient();        try {            return client.download_file(groupName, remoteFileName);        } catch (Exception e) {            throw new FastDFSException(e.getMessage(), e, 0);        } finally {            releaseClient(client);        }    }   /**    *     * @Description: 删除文件    * @param dfs    * @throws FastDFSException    * @author: Aaron    * @date: 2017年7月12日 下午7:02:59    */    public void deleteFile(FastDfsInfo dfs) throws FastDFSException {        this.deleteFile(dfs.getGroup(), dfs.getPath());    }   /**    *     * @Description: 删除文件    * @param groupName    * @param remoteFileName    * @throws FastDFSException    * @author: Aaron    * @date: 2017年7月12日 下午7:03:13    */    public void deleteFile(String groupName, String remoteFileName) throws FastDFSException {        int code;        StorageClient client = getClient();        try {            code = client.delete_file(groupName, remoteFileName);        } catch (Exception e) {            throw new FastDFSException(e.getMessage(), e, 0);        } finally {            releaseClient(client);        }        if (code != 0) {            throw new FastDFSException(code);        }    }   /**    *     * @Description: 设置远程可访问路径    * @param group    * @param path    * @return    * @throws IOException    * @throws NoSuchAlgorithmException    * @throws MyException    * @author: Aaron    * @date: 2017年7月12日 下午7:03:34    */    public String setFileAbsolutePath(String group, String path)            throws IOException, NoSuchAlgorithmException, MyException {        int ts = (int) (System.currentTimeMillis() / 1000), port;        String token = "";        if (factory.isG_anti_steal_token()) {            token = ProtoCommon.getToken(path, ts, factory.getG_secret_key());            token = "?token=" + token + "&ts=" + ts;        }        List<String> addressList;        if (factory.getNginx_address() != null) {            addressList = factory.getNginx_address();        } else {            addressList = factory.getTracker_servers();        }        Random random = new Random();        int i = random.nextInt(addressList.size());        String[] split = addressList.get(i).split(":", 2);        if (split.length > 1) {            port = Integer.parseInt(split[1].trim());        } else {            port = factory.getG_tracker_http_port();        }        String address = split[0].trim();        return factory.getProtocol() +               address + ":" +               port +               factory.getSepapator() +               group +               factory.getSepapator() +               path + token;    }    public void setFileAbsolutePath(FastDfsInfo fastDfsInfo) throws IOException, NoSuchAlgorithmException, MyException {        fastDfsInfo.setFileAbsolutePath(this.setFileAbsolutePath(fastDfsInfo.getGroup(), fastDfsInfo.getPath()));    }    protected StorageClient getClient() {        StorageClient client = null;        while (client == null) {            try {                client = connPoolFactory.getClient();            } catch (Exception e) {                e.printStackTrace();            }        }        return client;    }    protected void releaseClient(StorageClient client) {        connPoolFactory.releaseConnection(client);    }}

测试类

/** *  * @Description: 测试连接  * @author: Aaron * @date: 2017年7月12日 下午7:08:59 */@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(locations = "classpath:spring-fastdfs.xml")public class MainTest {    @Resource    private FastDFSTemplate dfsTemplate;    @Test    public void testUploadAndDel() throws FastDFSException {        FastDfsInfo rv = dfsTemplate.upload("".getBytes(), "txt");        System.out.println(rv);        dfsTemplate.deleteFile(rv);    }    @Test    public void testPool() throws InterruptedException {        Runnable runnable = () -> {            try {                File file = new File("/Users/duhuifan/Downloads/edu-demo-fdfs/TestFile/aaron.jpg");                FileInputStream fis = new FileInputStream(file);                byte[] b = new byte[fis.available()];                fis.read(b);                Map<String, String> map = new HashMap<>();                FastDfsInfo rv = dfsTemplate.upload(b, "jpg", map);                System.out.println(rv.getFileAbsolutePath());                //dfsTemplate.deleteFile(rv);            } catch (Exception e) {                e.printStackTrace();            }        };        for (int i = 0; i < 1; i++) {            new Thread(runnable).start();        }        Thread.currentThread().join();    }}

GitHub项目源码

https://github.com/Aaron258/fastdfs-common.git