Docker搭建FastDFS+FastDHT+Nginx+SpringBoot

一、前言:

Docker:是一种轻量级的虚拟化方式,Docker在运行应用上跟传统的虚拟机方式相比具有显著优势(简化运维安装复杂环境、占内存少、启动和停止环境快);
FastDFS:一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储、文件同步、文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。
FastDHT:避免大量重复文件导致磁盘资源的浪费,需要对重复文件做去重处理;
Nginx:做storage负载均衡、反向代理、缓存 ;

二、环境

1.系统:CentOS Linux release 7.6.1810 (Core),命令:cat /etc/redhat-release
2.内核:3.10.0-957.10.1.el7.x86_64,命令:uname -a
注意:Docker 要求 CentOS 系统的内核版本在 3.10以上,通过 uname -r 命令查看当前的内核版本。
3.服务器所需外网。

三、搭建

3.1tracker搭建

3.1.1拉取tracker镜像,并运行容器

命令1:

docker run -dit -p 180:80 -p 22122:22122 --name tracker1 --restart=always imlzw/fastdfs-tracker

3.1.2修改跟踪器配置

命令1:(查看tracker容器信息IP)

docker inspect tracker1

如图1:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第1张图片
tracker容器IP为:172.17.0.5
命令2:(进入tracker容器)

docker exec -it tracker1 /bin/bash

命令3:(也可以通过挂载方式,到外部进行修改)

vi /etc/fdfs/client.conf

如图2:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第2张图片
将图中tracker_server=172.17.0.2:22122,修改为tracker_server=172.17.0.5:22122

修改前 修改后
tracker_server=172.17.0.2:22122 tracker_server=172.17.0.5:22122

命令3:

mkdir /home/imlzw/fastdfs/client

命令4:(退出tracker容器)

exit

命令5:(重启tracker容器)

docker restart tracker1

3.2storage1搭建

3.2.1拉取storage镜像,并运行容器

注意:如果storage多节点,命令可以重复执行,但是容器端口、名称等信息不能一致(单节点搭建可忽略这句话)
比如:docker run -dit -p 281:80 -p 23001:23000 -p11412:11411 --name storage2 --restart=always imlzw/fastdfs-storage-dht
命令1:

docker run -dit -p 280:80 -p 23000:23000 -p11411:11411 --name storage1  --restart=always  imlzw/fastdfs-storage-dht

3.2.2修改storage配置

命令2:(查看storage容器信息IP)

docker inspect storage1

如图3(storage1):
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第3张图片
storage1容器IP为:172.17.0.6
命令4:(进入storage1)

docker exec -it storage1 /bin/bash

命令5:

vi /etc/fdfs/storage.conf

如图4
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第4张图片
将tracker_server=tracker1:22122,修改为172.17.0.5:22122(tracker的ip和端口),去掉tracker_server=tracker2:22122,如果tracker做两个节点集群可以自行添加并修改。

修改前 修改后
tracker_server=tracker1:22122 172.17.0.5:22122

3.2.3修改FastDHT配置

命令1:

vi /etc/fdht/fdht_client.conf

如图5:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第5张图片
将base_path=/home/yuqing/fastdht,修改为/home/imlzw/fastdfs/fastdht

修改前 修改后
base_path=/home/yuqing/fastdht base_path=/home/imlzw/fastdfs/fastdht

命令2:

vi /etc/fdht/fdht_servers.conf

如图6:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第6张图片
将group0 = 172.17.0.4:11411,改为172.17.0.6:11411(改为storage的ip和端口),去掉group0 = 172.17.0.5:11411,如果storage是多节点集群自行添加。

修改前 修改后
group0 = 172.17.0.4:11411 group0 = 172.17.0.6:11411

命令3:

exit

命令4:

docker restart storage1

3.3FastDFS+FastDHT整合测试

命令1:(提前准备一张图1.jpg 复制到tracker1目录下)

docker cp /usr/local/1.jpg tracker1:/

命令2:(进入tracker容器)

docker exec -it tracker1 /bin/bash

如图7:
在这里插入图片描述
命令3:(最好执行两次以上,看看是否去重)

/usr/bin/fdfs_upload_file /etc/fdfs/client.conf /1.jpg

如图8:
在这里插入图片描述
命令4:

exit

命令5:

docker exec -it storage1 /bin/bash

命令6:

cd /home/imlzw/fastdfs/storage/data/00/00

命令7:

ll

如图9:
在这里插入图片描述
说明:FastDFS+FastDHT整合成功!!!

第一次上传返回的结果为:rBEABlyiGIWAV6EYAABB77YyMB4866.jpg,之后每次重复上传的话都是返回一个指向第一次上传的文件的软链接。也就保证了文件只保存了一份。当所有的软链接都被删除的时候,原始文件也会从FastDFS中被删除。

3.4修改storage下Nginx配置

命令1:

vi /etc/fdfs/mod_fastdfs.conf

如图9:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第7张图片
将tracker_server=tracker1:22122,修改为172.17.0.5:22122(tracker的ip和端口),去掉tracker_server=tracker2:22122,如果tracker做两个节点集群可以自行添加并修改。

connect_timeout=10
tracker_server=172.17.0.5:22122
url_have_group_name = true

命令2:(修改nginx配置)

vi /usr/local/nginx/conf/nginx.conf
修改前 修改后
location /M00 { root /home/imlzw/fastdfs/storage/data/;ngx_fastdfs_module;} location ~/group([0-9])/M00 { #alias /home/imlzw/fastdfs/storage/data/;ngx_fastdfs_module;}

命令3:(去掉防盗链,正常是需要的)

vi /etc/fdfs/http.conf
修改前 修改后
http.anti_steal.check_token=true http.anti_steal.check_token=false

命令4:

exit

命令5:

docker restart storage1

3.5测试结果

本地访问地址:http://192.168.8.21:280/group1/M00/00/00/rBEABlyiS0qACGPmAABB77YyMB4134.jpg
如图10:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第8张图片

以上单节点已搭建成功!!!

3.7 storage2搭建

步骤跟3.2storage1搭建命令一样,重复执行即可。其中要注意的是:容器名称、端口等信息不能一致。

3.7.1其中注意的细节

命令1:

docker inspect storage2

如图11:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第9张图片

storage2:IP为172.17.0.7,端口为:23001,fdht端口为:11412

3.7.2两台storage的fdht_servers.conf配置:

storage1:fdht_servers.conf storage2:fdht_servers.conf
group_count = 1 group0 = 172.17.0.6:11411 group0 = 172.17.0.7:11412 group_count = 1 group0 = 172.17.0.6:11411 group0 = 172.17.0.7:11412

3.7.3两台storage整合测试结果:

storage1 storage2
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第10张图片 Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第11张图片

3.7.4配置tracker中nginx负载均衡和反向代理配置:

命令1:

docker exec -it tracker1 /bin/bash

命令2:

vi /usr/local/nginx/conf/nginx.conf

修改后如图12:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第12张图片

	
    upstream fdfs_group1 {
        server 172.17.0.6 weight=1 max_fails=2 fail_timeout=30s;
        server 172.17.0.7 weight=1 max_fails=2 fail_timeout=30s;
    }
    
    location ~/group([0-9])/M00 {
    	proxy_pass http://fdfs_group1;
    	expires 30d;
    }

命令3:(nginx重启)

/usr/local/nginx/sbin/nginx -s reload

3.7.4.1测试

如图13:
Docker搭建FastDFS+FastDHT+Nginx+SpringBoot_第13张图片
测试成功!!!

3.8 tracker中nginx缓存配置

3.8.1tracker中nginx.conf缓存配置修改

#user  nobody;
worker_processes  1;

error_log  logs/error.log;
error_log  logs/error.log  notice;
error_log  logs/error.log  info;

pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /usr/local/nginx/logs/access.log  main;

    sendfile        on;
    tcp_nopush     on;
    keepalive_timeout  65;
	#设置缓存
    server_names_hash_bucket_size 128; 
    client_header_buffer_size 32k; 
    large_client_header_buffers 4 32k; 
    client_max_body_size 300m; 

    proxy_redirect off; 
	proxy_set_header Host $http_host; 
	proxy_set_header X-Real-IP $remote_addr; 
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
	proxy_connect_timeout 90; 
	proxy_send_timeout 90; 
	proxy_read_timeout 90; 
	proxy_buffer_size 16k; 
	proxy_buffers 4 64k; 
	proxy_busy_buffers_size 128k; 
	proxy_temp_file_write_size 128k; 
	
	#设置缓存存储路径,存储方式,分别内存大小,磁盘最大空间,缓存期限
	proxy_cache_path /fastdfs/cache/nginx/proxy_cache levels=1:2 
	keys_zone=http-cache:200m max_size=1g inactive=30d; 
	proxy_temp_path /fastdfs/cache/nginx/proxy_cache/tmp; 

	#负载均衡配置(权重)
	upstream fdfs_group1 { 
                server 172.17.0.6 weight=1 max_fails=2 fail_timeout=30s;
                server 172.17.0.7 weight=1 max_fails=2 fail_timeout=30s;
	}

    server {
        listen       80;
        server_name  localhost;

        access_log  /usr/local/nginx/logs/host.access.log  main;

        location / {
            root   html;
            index  index.html index.htm;
        }

		location /group1/M00 { 
			proxy_next_upstream http_502 http_504 error timeout invalid_header; 
			proxy_cache http-cache; 
			proxy_cache_valid 200 304 12h; 
			proxy_cache_key $uri$is_args$args; 
			proxy_pass http://fdfs_group1; 
			expires 30d; 
		} 
	
		#清除缓存的访问权限
		location ~/purge(/.*) { 
			allow 127.0.0.1; 
			allow 192.168.8.0/24; 
			deny all; 
			proxy_cache_purge http-cache $1$is_args$args; 
		} 

        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
}

3.8.2 添加ngx_cache_purge模块

ngx_cache_purge模块的作用:用于清除指定url的缓存,否则nginx启动报错:
nginx: [emerg] unknown directive “proxy_cache_purge” in /home/data/websrv/nginx/conf/nginx.conf:75
例如:
http://192.168.8.21:180/purge/group1/M00/00/00/rBEABlyjRUKAOykcAABB7x0RIA4797.jpg

命令1:(进入tracker1)

docker exec -it tracker1 /bin/bash

命令2:(创建下载目录)

mkdir /home/install

命令3:

wget http://labs.frickle.com/files/ngx_cache_purge-2.3.tar.gz

命令4:

tar -zxvf ngx_cache_purge-2.3.tar.gz

命令5:

mv ngx_cache_purge-2.3.tar.gz /usr/local/

命令6:

cd /home/imlzw/fastdfs/download/nginx/nginx-1.11.7

命令7:

./configure --prefix=/usr/local/nginx  --add-module=/usr/local/ngx_cache_purge-2.3

命令8:(注意这里只要make ,不要make install会覆盖)

make

命令9:

/usr/local/nginx/sbin/./nginx -s stop

命令10:

cd /usr/local/nginx/sbin/

命令11:

cp /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.back

命令12:

cp /home/imlzw/fastdfs/download/nginx/nginx-1.11.7/objs/nginx /usr/local/nginx/sbin/nginx

命令13:

/usr/local/nginx/sbin/./nginx -s reload

3.9 防盗链配置

3.9.1 防盗链说明

FastDFS内置防盗链采用Token的方式。Token是带时效的,也就是说在设定的时间范围内,比如1分钟,token是有效的。token包含了文件id、时间戳ts和密钥。FastDFS在URL中带上当前时间戳和带时效的token,参数名分别为ts和token。Token的生成和校验都是在服务端,因此不会存在安全问题。形如
http://192.168.8.21:8080/download2?fileUrl=192.168.8.21:180/group1/M00/00/00/rBEABlyjRUKAOykcAABB7x0RIA4797.jpg?token=39427bb27274de88c5fe6cac05c90312&ts=1554519896

3.9.2 http.conf中参数说明

http.anti_steal.check_token:是否做token检查,默认值为false,打开true。
http.anti_steal.token_ttl:token TTL,即生成token的有效时长,秒为单位。
http.anti_steal.secret_key:生成token的密钥,尽量设置得长一些,千万不要泄露出去。
http.anti_steal.token_check_fail:token检查失败,返回的文件内容,需指定本地文件名或者页面。

3.9.2修改storage中http.conf

命令1:(进入storage容器)

docker exec -it storage /bin/bash

命令2:

vi /etc/fdfs/http.conf
修改前 修改后
http.anti_steal.check_token=false http.anti_steal.check_token=true

注意:这里其他都使用默认值

3.9.2 client代码实现

    /**获取防盗链链接
     * @return
     */
    public String getSecurityUrl(){
		//fid为从数据库中读出的值
		String fid="group1/M00/00/00/rBEAA1yoPpeAFLLWAACMSn8JadI335.jpg";
		String substring = fid.substring(fid.indexOf("/")+1);
		System.out.println("name:" + substring);
		//unix时间戳 以秒为单位
		int ts = (int) (System.currentTimeMillis() / 1000);
		//秘钥,在storage下/etc/fdfs/http.conf===》http.anti_steal.secret_key=FastDFS1234567890(默认)
		String secret_key = "FastDFS1234567890";
		String token=new String();
		try {
			token= ProtoCommon.getToken(substring, ts, secret_key);
		} catch (Exception e) {
			e.printStackTrace();
		}
		 StringBuilder sb = new StringBuilder();
		 sb.append("192.168.8.21:180/");
		 sb.append(fid);
		 sb.append("?token=").append(token);
		 sb.append("&ts=").append(ts);
    	return "防盗链URL:" + sb;
    }

3.10 客户端配置

3.10.1 客户端配置说明

1.采取springboot整合FastDFS客服端
2.采取直接部署CentOS 7
3.所需依赖:https://github.com/leechenxiang/fastdfs-client-java
4.运行项目:java -jar images-0.0.1-SNAPSHOT.jar
5.源码地址:https://github.com/wenmingsen/fastdfs_images

3.10.2 fdfs_client.conf配置

connect_timeout = 2
network_timeout = 30
charset = UTF-8
http.tracker_http_port = 180
http.anti_steal_token = on
http.secret_key = FastDFS1234567890

tracker_server = 172.17.0.5:22122

3.10.3 FastDFSFile文件对象类代码


import java.util.Arrays;

public class FastDFSFile {
    private String name;
    private byte[] content;
    private String ext;
    private String md5;
    private String author;
    //省略getter、setter
	public FastDFSFile(String name, byte[] content, String ext) {
		super();
		this.name = name;
		this.content = content;
		this.ext = ext;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public byte[] getContent() {
		return content;
	}
	public void setContent(byte[] content) {
		this.content = content;
	}
	public String getExt() {
		return ext;
	}
	public void setExt(String ext) {
		this.ext = ext;
	}
	public String getMd5() {
		return md5;
	}
	public void setMd5(String md5) {
		this.md5 = md5;
	}
	public String getAuthor() {
		return author;
	}
	public void setAuthor(String author) {
		this.author = author;
	}
	@Override
	public String toString() {
		return "FastDFSFile [name=" + name + ", content="
				+ Arrays.toString(content) + ", ext=" + ext + ", md5=" + md5
				+ ", author=" + author + "]";
	}
    
}

3.10.4 FastDFSUtil类代码

import org.csource.common.NameValuePair;
import org.csource.fastdfs.ClientGlobal;
import org.csource.fastdfs.FileInfo;
import org.csource.fastdfs.StorageClient;
import org.csource.fastdfs.StorageServer;
import org.csource.fastdfs.TrackerClient;
import org.csource.fastdfs.TrackerServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class FastDFSUtil {
	private static Logger LOGGER = LoggerFactory.getLogger(FastDFSUtil.class);
	private static String classPath = FastDFSUtil.class.getProtectionDomain()
			.getCodeSource().getLocation().getPath();
	private static String FASTDFS_CLIENT_CONF = "/fastdfs-downloads/fdfs_client.conf";
	private static String COMMON_PATH = "http://192.168.8.21/";
	private static TrackerClient trackerClient = null;
	private static TrackerServer trackerServer = null;
	private static StorageClient storageClient = null;
	private static StorageServer storageServer = null;
	// 默认下载路径
	private static String DOWNLOAD_PATH = "/fastdfs-downloads";// "D:/Documents/Downloads";


	static{
		try {
			ClientGlobal.init(FASTDFS_CLIENT_CONF);
			trackerClient = new TrackerClient();
			trackerServer = trackerClient.getConnection();
			storageServer = trackerClient.getStoreStorage(trackerServer);
			storageClient = new StorageClient(trackerServer, storageServer);
		} catch (Exception e) {
			throw new RuntimeException("init exception");
		}
	}
	
	/**
	 * 下载
	 * @param file 图片信息对象
	 * @return
	 */
	public static String[] upload(FastDFSFile file) {
	    LOGGER.info("File Name: " + file.getName() + "File Length:" + file.getContent().length);

	    NameValuePair[] meta_list = new NameValuePair[1];
	    meta_list[0] = new NameValuePair("author", file.getAuthor());

	    long startTime = System.currentTimeMillis();
	    String[] uploadResults = null;
	    try {
	        storageClient = new StorageClient(trackerServer, storageServer);
	        uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
	    } catch (Exception e) {
			e.printStackTrace();
			LOGGER.error("图片上传失败,e:" + e);
			throw new RuntimeException("upload exception");
		}
	    LOGGER.info("upload_file time used:" + (System.currentTimeMillis() - startTime) + " ms");
	    if (uploadResults == null) {
	        LOGGER.error("upload file fail, error code:" + storageClient.getErrorCode());
	    }
	    String groupName = uploadResults[0];
	    String remoteFileName = uploadResults[1];

	    LOGGER.info("upload file successfully!!!" + "group_name:" + groupName + ", remoteFileName:" + " " + remoteFileName);
	    return uploadResults;
	}

	/**
	 * 上传文件
	 * 
	 * @param imgUrl
	 *            文件路径
	 * @return 文件上传后的返回路径
	 */
	public static String upload(String imgUrl) {
		NameValuePair[] metaDataList = null;
		return upload(imgUrl, metaDataList);
	}

	/**
	 * 上传文件,元信息作为文件属性上传到fastdfs服务器
	 * 
	 * @param imgUrl
	 *            文件路径
	 * @param metaDataList
	 *            元信息
	 * @return 文件上传后的返回路径
	 */
	public static String upload(String imgUrl, NameValuePair[] metaDataList) {
		// 取文件扩展名,不要“.”
		String fileExtName = imgUrl.substring(imgUrl.lastIndexOf(".") + 1);
		return upload(imgUrl, fileExtName, metaDataList);
	}

	/**
	 * 上传文件
	 * 
	 * @param fileUrl
	 *            上传文件路径
	 * @param fileExtName
	 *            文件类型(扩展名),如:jpg,txt
	 * @param metaDataList
	 *            元信息
	 * @return 文件上传后的返回路径
	 */
	public static String upload(String fileUrl, String fileExtName,
			NameValuePair[] metaDataList) {
		try {
			String fileIds[] = storageClient.upload_file(fileUrl, fileExtName,
					metaDataList);
			LOGGER.info("图片上传成功,返回路径:" + fileIds[0] + "/" + fileIds[1]);
			return COMMON_PATH + fileIds[0] + "/" + fileIds[1];
		} catch (Exception e) {
			e.printStackTrace();
			LOGGER.error("图片上传失败,e:" + e);
			throw new RuntimeException("upload exception");
		}
	}

	/**
	 * 下载文件
	 * 
	 * @param group
	 *            组,如:“group1”
	 * @param file
	 *            文件路径,不要组名前面部分,如:“M00/00/00/wKgI2luKxXyARIzqAABh2n7xkfg929.jpg”
	 * @param storePath
	 *            存储路径,如:“D:/test_fastDFS/新建文件夹/sss”
	 */
	public static byte[] download(String group, String filePath, String storePath) {
		try {
			byte[] file_buff;
			System.out.println("group:" + group);
			System.out.println("file:" + filePath);
			file_buff = storageClient.download_file(group, filePath);
/*			IOUtils.write(file_buff, new FileOutputStream(new File(storePath
					+ "/" + file.substring(file.lastIndexOf("/") + 1))));*/
			return file_buff;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("download exception");
		}
	}

	/**
	 * 文件下载
	 * 
	 * @param fileAddr
	 *            文件访问地址,如:
	 *            "http://192.168.8.110/fastdfs/group2/M00/00/00/wKgI2luKZaKACY_jAACQB3kqNKg127.jpg"
	 */
	public static byte[] download(String fileAddr) {
		return download(fileAddr, DOWNLOAD_PATH);
	}

	/**
	 * 文件下载
	 * 
	 * @param file文件访问地址
	 *            ,如:
	 *            "http://192.168.8.110/fastdfs/group2/M00/00/00/wKgI2luKZaKACY_jAACQB3kqNKg127.jpg"
	 * @param storePath存储路径
	 *            ,如:“D:/test_fastDFS/新建文件夹/sss”
	 */
	public static byte[] download(String fileAddr, String storePath) {
		int start = fileAddr.indexOf("group");
		String group = fileAddr.substring(start, start + 6);
		String newFile = fileAddr.substring(start + 7);
		return download(group, newFile, storePath);
	}

	/**
	 * 获取文件信息
	 * 
	 * @param group
	 *            组,如:group1
	 * @param file
	 *            文件路径,如:M00/00/00/wKgI2VuNfBmANpG6AAB7lbxNbKo940.jpg
	 * @return
	 */
	public static FileInfo getFileInfo(String group, String filePath) {
		try {
			FileInfo fileInfo = storageClient.get_file_info(group, filePath);
			LOGGER.info("fileInfo:" + fileInfo);
			return fileInfo;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("gets file info exception");
		}
	}

	/**
	 * 获取文件元信息
	 * 
	 * @param group
	 * @param file
	 * @return
	 */
	public static NameValuePair[] getFileMataData(String group, String file) {
		try {
			NameValuePair[] metas = storageClient.get_metadata(group, file);
			return metas;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("gets file metadata exception");
		}
	}

	/**
	 * 删除文件:0:成功;2:文件不存在;其他:文件删除出错
	 * 
	 * @param file文件访问地址
	 *            ,如:
	 *            "http://192.168.8.110/fastdfs/group2/M00/00/00/wKgI2luKZaKACY_jAACQB3kqNKg127.jpg"
	 */
	public static int delete(String fileAddr) {
		int start = fileAddr.indexOf("group");
		String group = fileAddr.substring(start, start + 6);
		String newFile = fileAddr.substring(start + 7);
		return delete(group, newFile);
	}

	/**
	 * 删除文件:0:成功;2:文件不存在;其他:文件删除出错
	 * 
	 * @param group
	 *            组,如:group1
	 * @param file
	 *            文件路径,如:M00/00/00/wKgI2VuNfBmANpG6AAB7lbxNbKo940.jpg
	 * @return
	 */
	public static int delete(String group, String file) {
		try {
			int num = storageClient.delete_file(group, file);
			return num;
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("deletes file exception");
		}
	}
	
	public static String getTrackerUrl(){
		return "http://192.168.8.21:180/";
	}

}


3.10.5 ImagesTestController类代码

import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.csource.fastdfs.ProtoCommon;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.images.util.FastDFSFile;
import com.images.util.FastDFSUtil;

/**
 * @Description
 * @Author wms
 * @Date 2019/4/4
 */
@RestController
public class ImagesTestController {
	
	private static Logger LOGGER = LoggerFactory.getLogger(ImagesTestController.class);
	   
	/**
	 * 测试项目启动
	 * @return
	 */
    @RequestMapping("/index")
    public String index(){
    	return "index";
    }
    
    /**
     * 上传文件
     * @param file
     */
    @RequestMapping("upload")
    public String upload(MultipartFile multipartFile){
    	
    	 String[] fileAbsolutePath={};
    	 InputStream inputStream = null;
    	 try {
         String fileName = multipartFile.getOriginalFilename();
         String ext = fileName.substring(fileName.lastIndexOf(".") + 1);
         byte[] file_buff = null;
         inputStream = multipartFile.getInputStream();
         if(inputStream!=null){
             int len1 = inputStream.available();
             file_buff = new byte[len1];
             inputStream.read(file_buff);
         }
         FastDFSFile file = new FastDFSFile(fileName, file_buff, ext);
             fileAbsolutePath = FastDFSUtil.upload(file);
         } catch (Exception e) {
             LOGGER.error("upload file Exception!",e);
         } finally {
             try {
                 inputStream.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
         if (fileAbsolutePath==null) {
             LOGGER.error("upload file failed,please upload again!");
         }
         String path=FastDFSUtil.getTrackerUrl()+fileAbsolutePath[0]+ "/"+fileAbsolutePath[1];
         System.out.println("path:" + path);
         return "path:" + path;
    }
    
    /**
     * 下载文件
     * @param fileUrl
     *  文件访问地址,如:
	 *	"http://192.168.8.110/fastdfs/group2/M00/00/00/wKgI2luKZaKACY_jAACQB3kqNKg127.jpg"
     * @param response
     */
    @RequestMapping("/download")
    public void download(@RequestParam("fileUrl")String fileUrl, HttpServletResponse response){
    	ServletOutputStream outputStream = null;
    	try {
    		System.out.println("fileUrl:" + fileUrl);
    		byte[] bytes = FastDFSUtil.download(fileUrl);
	        response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileUrl.substring(fileUrl.lastIndexOf("/") + 1), "UTF-8"));
	        response.setCharacterEncoding("UTF-8");
	        
	        outputStream = response.getOutputStream();
	        outputStream.write(bytes);
	        System.out.println("success");
	        
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                outputStream.flush();
                outputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    	System.out.println("fail");
    }
    
    /**
     * 删除
     * 
     * @param fileUrl
     *	文件访问地址,如:
	 *	"http://192.168.8.110/fastdfs/group2/M00/00/00/wKgI2luKZaKACY_jAACQB3kqNKg127.jpg"
     * @return
     */
    @RequestMapping
    public String delete(@RequestParam("fileUrl")String fileUrl){
    	try{
    		FastDFSUtil.delete(fileUrl);
    		return "deleteSuccess";
    	}
    	catch (Exception e) {
    		e.printStackTrace();
    	}
    	return "deleteFail";
    }
    
}

3.11 说明

1.docker镜像是网上找的,tracker用的是imlzw/fastdfs-tracker(整合了nginx),storage是imlzw/fastdfs-storage-dht(整合了nginx和FastDHT)。如果有更好镜像,相对会简单很多。希望大神推荐推荐,某人不才,暂时没研究写FastDFS+FastDHT+Nginx镜像!
2.一台tracker和两台storage,nginx做负载均衡和反向代理 、缓存。

你可能感兴趣的:(Docker搭建FastDFS+FastDHT+Nginx+SpringBoot)