一、环境说明
CentOS7;防火墙关闭;虚拟机地址:192.168.0.40;
所有的文件我都放在我虚拟机的/home/cesec/EMQ/fastdfs下了,可以自定义目录,到时候下面的替换成自定义的目录即可;
因为之前该虚拟机上搭建了其他的东西,因此这次就指定别名了,直接通过ip和端口访问;
二、单机版搭建
1、下载安装 libfastcommon
1.1、下载libfastcommon
wget https://github.com/happyfish100/libfastcommon/archive/V1.0.7.tar.gz
1.2、解压进入文件夹
tar -zxvf V1.0.7.tar.gz
cd libfastcommon-1.0.7
1.3、编译、安装
./make.sh
./make.sh install
1.4、libfastcommon.so 安装到了/usr/lib64/libfastcommon.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
2、下载安装FastFDS
2.1、下载FastFDS
wget https://github.com/happyfish100/fastdfs/archive/V5.05.tar.gz
2.2、解压并进入文件夹
tar -zxvf V5.05.tar.gz
cd fastdfs-5.05
2.3、编译、安装
./make.sh
./make.sh install
2.4、FastDFS 服务脚本设置的 bin 目录是 /usr/local/bin, 但实际命令安装在 /usr/bin/ 下,建立 /usr/bin 到 /usr/local/bin 的软链接。
ln -s /usr/bin/fdfs_trackerd /usr/local/bin
ln -s /usr/bin/fdfs_storaged /usr/local/bin
ln -s /usr/bin/stop.sh /usr/local/bin
ln -s /usr/bin/restart.sh /usr/local/bin
3、配置FastDFS跟踪器(Tracker)
3.1、 进入 /etc/fdfs,复制 FastDFS 跟踪器样例配置文件 tracker.conf.sample,并重命名为 tracker.conf
cd /etc/fdfs
cp tracker.conf.sample tracker.conf
3.2、编辑tracker.conf ,标红的需要修改下,其它的默认即可
vim tracker.conf
http.server_port很容易冲突,最好修改了,这个在文件的最下面
3.3、创建tracker基础数据目录,即base_path对应的目录
mkdir -p /home/cesec/EMQ/fastdfs/tracker
3.4、防火墙如果开着的话进行该步骤,否则跳过,防火墙中打开跟踪端口(默认的22122)
vim /etc/sysconfig/iptables
添加如下端口行:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22122 -j ACCEPT
重启防火墙:
service iptables restart
3.5、启动Tracker,初次成功启动,会在/home/cesec/EMQ/fastdfs/tracker/ (配置的base_path)下创建 data、logs 两个目录。
service fdfs_trackerd start
查看 FastDFS Tracker 是否已成功启动 ,22122端口正在被监听,则算是Tracker服务安装成功。
关闭Tracker命令:
service fdfs_trackerd stop
设置Tracker开机启动:
chkconfig fdfs_trackerd on
关于tracker server 目录及文件结构 :
${base_path} |__data | |__storage_groups.dat:存储分组信息 | |__storage_servers.dat:存储服务器列表 |__logs | |__trackerd.log: tracker server 日志文件
4、配置 FastDFS 存储 (Storage)
4.1、进入 /etc/fdfs 目录,复制 FastDFS 存储器样例配置文件 storage.conf.sample,并重命名为 storage.conf
cd /etc/fdfs
cp storage.conf.sample storage.conf
4.2、编辑storage.conf,标红的需要修改,其它的默认即可。
vim storage.conf
4.3、创建Storage基础数据目录,对应base_path目录
mkdir -p /home/cesec/EMQ/fastdfs/storage
#这是配置的store_path0路径
mkdir -p /home/cesec/EMQ/fastdfs/file
4.4、 防火墙如果开着的话进行该步骤,否则跳过,防火墙中打开跟踪端口(默认的23000)
vim /etc/sysconfig/iptables
添加如下端口行:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 23000 -j ACCEPT
重启防火墙:
service iptables restart
4.5、启动 Storage,启动Storage前确保Tracker是启动的。初次启动成功,会在 /ljzsg/fastdfs/storage 目录下创建 data、 logs 两个目录。
service fdfs_storaged start
查看 Storage 是否成功启动,23000 端口正在被监听,就算 Storage 启动成功。
查看Storage和Tracker是否在通信:
/usr/bin/fdfs_monitor /etc/fdfs/storage.conf
关闭Storage命令:
service fdfs_storaged stop
设置 Storage 开机启动:
chkconfig fdfs_storaged on
4.6、Storage 目录,同 Tracker,Storage 启动成功后,在base_path 下创建了data、logs目录,记录着 Storage Server 的信息。
在 store_path0 目录下,创建了N*N个子目录:
5、文件上传测试
5.1、修改 Tracker 服务器中的客户端配置文件
cd /etc/fdfs
cp client.conf.sample client.conf
vim client.conf
修改如下配置即可,其它默认
5.2、上传测试,在linux内部执行如下命令上传 1.jpg 图片
/usr/bin/fdfs_upload_file /etc/fdfs/client.conf 1.jpg
上传成功后返回文件ID号:group1/M00/00/00/wKgAKF159D6AaOJ1AALKF34wl18657.jpg
返回的文件ID由group、存储目录、两级子目录、fileid、文件后缀名(由客户端指定,主要用于区分文件类型)拼接而成。
三、安装Nginx
上面将文件上传成功了,但我们无法下载。因此安装Nginx作为服务器以支持Http方式访问文件。Nginx只需要安装到StorageServer所在的服务器即可,用于访问文件。我这里由于是单机,TrackerServer和StorageServer在一台服务器上。
1、安装nginx所需环境
gcc 安装
yum install gcc-c++
PCRE pcre-devel 安装
yum install -y pcre pcre-devel
zlib 安装
yum install -y zlib zlib-devel
OpenSSL 安装
yum install -y openssl openssl-devel
2、安装Nginx
2.1、下载nginx
wget -c https://nginx.org/download/nginx-1.12.1.tar.gz
2.2、解压
tar -zxvf nginx-1.12.1.tar.gz
cd nginx-1.12.1
2.3、使用默认配置
./configure
2.4、编译、安装,修改端口号
make
make install
Nginx默认的是80端口,很容易冲突,最好修改一下,vim /usr/local/nginx/conf/nginx.conf
2.5、启动nginx
cd /usr/local/nginx/sbin/
./nginx
其它命令
./nginx -s stop
./nginx -s quit
./nginx -s reload
2.6、设置开机启动
vim /etc/rc.local
添加一行:
/usr/local/nginx/sbin/nginx
设置执行权限
chmod 755 rc.local
2.7、查看nginx的版本及模块
/usr/local/nginx/sbin/nginx -V
2.8、防火墙如果开着的话进行该步骤,否则跳过,防火墙中打开跟踪端口(默认的80,但是我修改为了6767)
vim /etc/sysconfig/iptables
添加如下端口行:
-A INPUT -m state --state NEW -m tcp -p tcp --dport 6767 -j ACCEPT
重启防火墙:
service iptables restart
3、访问文件
1、修改nginx.conf
vim /usr/local/nginx/conf/nginx.conf
添加如下行,将 /group1/M00 映射到 /home/cesec/EMQ/fastdfs/file/data
location /group1/M00 {
alias /home/cesec/EMQ/fastdfs/file/data;
}
# 重启nginx
/usr/local/nginx/sbin/nginx -s reload
2、在浏览器访问之前上传的图片、成功,
http://192.168.0.40:6767/group1/M00/00/00/wKgAKF159D6AaOJ1AALKF34wl18657.jpg
四、整合到SpringBoot中
1、pom.xml加入依赖
com.github.tobato
fastdfs-client
1.26.5
ch.qos.logback
logback-classic
2、application.yml加入参数
# FastDFS
# ===================================================================
# 分布式文件系统FDFS配置
# ===================================================================
fdfs:
so-timeout: 1501
connect-timeout: 601
thumb-image: #缩略图生成参数
width: 150
height: 150
web-server-url: http://192.168.0.40:6767/
tracker-list: 192.168.0.40:22122
3、添加FastDFS工具类
@Component
public class FastDFSClient {
private final Logger logger = LoggerFactory.getLogger(FastDFSClient.class);
@Autowired
private FastFileStorageClient storageClient;
@Autowired
private FdfsWebServer fdfsWebServer;
/**
* 上传文件
* @param file 文件对象
* @return 文件访问地址
* @throws IOException
*/
public String uploadFile(MultipartFile file) throws IOException {
StorePath storePath = storageClient.uploadFile(file.getInputStream(),file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()),null);
return getResAccessUrl(storePath);
}
/**
* 上传文件
* @param file 文件对象
* @return 文件访问地址
* @throws IOException
*/
public String uploadFile(File file) throws IOException {
FileInputStream inputStream = new FileInputStream (file);
StorePath storePath = storageClient.uploadFile(inputStream,file.length(), FilenameUtils.getExtension(file.getName()),null);
return getResAccessUrl(storePath);
}
/**
* 将一段字符串生成一个文件上传
* @param content 文件内容
* @param fileExtension
* @return
*/
public String uploadFile(String content, String fileExtension) {
byte[] buff = content.getBytes(Charset.forName("UTF-8"));
ByteArrayInputStream stream = new ByteArrayInputStream(buff);
StorePath storePath = storageClient.uploadFile(stream,buff.length, fileExtension,null);
return getResAccessUrl(storePath);
}
// 封装图片完整URL地址
private String getResAccessUrl(StorePath storePath) {
String fileUrl = fdfsWebServer.getWebServerUrl() + storePath.getFullPath();
return fileUrl;
}
/**
* 下载文件,返回字节数组
* @param fileUrl 文件url
* @return
*/
public byte[] downloadByte(String fileUrl) {
ConcurrentHashMap pathMap = getPath(fileUrl);
String groupName = pathMap.get("groupName");
String filePath = pathMap.get("filePath");
byte[] bytes = storageClient.downloadFile(groupName, filePath, new DownloadByteArray());
return bytes;
}
/**
* 下载文件,返回InputStream
* @param fileUrl 文件url
* @return
*/
public InputStream downloadInputStream(String fileUrl) {
ConcurrentHashMap pathMap = getPath(fileUrl);
String groupName = pathMap.get("groupName");
String filePath = pathMap.get("filePath");
InputStream ins = storageClient.downloadFile(groupName, filePath, new DownloadCallback(){
@Override
public InputStream recv(InputStream ins) throws IOException {
// 将此ins返回给上面的ins
return ins;
}}) ;
return ins ;
}
/**
* 下载文件,返回文件
* @param fileUrl 文件url
* @return
*/
public void downloadFile(String fileUrl, HttpServletRequest request, HttpServletResponse response){
try {
ConcurrentHashMap pathMap = getPath(fileUrl);
String groupName = pathMap.get("groupName");
String filePath = pathMap.get("filePath");
String fileName = pathMap.get("fileName");
InputStream input = storageClient.downloadFile(groupName, filePath, new DownloadCallback(){
@Override
public InputStream recv(InputStream input) throws IOException {
// 将此input返回给上面的input
return input;
}}) ;
//根据文件名获取 MIME 类型
System.out.println("fileName :" + fileName); // wKgAKF15nkOAdYczAACrr9cLDU4592.jpg
String contentType = request.getServletContext().getMimeType(fileName);
String contentDisposition = "attachment;filename=" + fileName;
// 设置头
response.setHeader("Content-Type",contentType);
response.setHeader("Content-Disposition",contentDisposition);
// 获取绑定了客户端的流
ServletOutputStream output = response.getOutputStream();
// 把输入流中的数据写入到输出流中
IOUtils.copy(input,output);
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 删除文件
* @param fileUrl 文件访问地址
* @return
*/
public void deleteFile(String fileUrl) {
if (StringUtils.isEmpty(fileUrl)) {
return;
}
try {
StorePath storePath = StorePath.parseFromUrl(fileUrl);
storageClient.deleteFile(storePath.getGroup(), storePath.getPath());
} catch (FdfsUnsupportStorePathException e) {
logger.warn(e.getMessage());
}
}
/**
* @Description: 将传过来的url切割成需要的url
* @Author: yelei
* @Date: 2019/9/12
*/
public ConcurrentHashMap getPath(String fileUrl){
ConcurrentHashMap pathMap = new ConcurrentHashMap<>();
String groupName = fileUrl.substring(fileUrl.indexOf("g"),fileUrl.indexOf("M") - 1);
String filePath = fileUrl.substring(fileUrl.indexOf("M"));
String fileName = fileUrl.substring(fileUrl.lastIndexOf("/")+1);
pathMap.put("groupName",groupName);
pathMap.put("filePath",filePath);
pathMap.put("fileName",fileName);
return pathMap;
}
}
4、测试
@Controller
@RequestMapping("fastdfs/")
public class TestController {
@Autowired
private FastDFSClient fastDFSClient;
@GetMapping()
public void test(HttpServletRequest request, HttpServletResponse response) throws IOException {
//上传
File file = new File("E:\\2.jpg");
String url = fastDFSClient.uploadFile(file);
System.out.println(url);
//下载
fastDFSClient.downloadFile("http://192.168.0.40:6767/group1/M00/00/00/wKgAKF15nkOAdYczAACrr9cLDU4592.jpg",request,response);
//删除
fastDFSClient.deleteFile("http://192.168.0.40:6767/group1/M00/00/00/wKgAKF15nkOAdYczAACrr9cLDU4592.jpg");
}
}