前言
我們在做項目的時候經(jīng)常會遇到文件的上傳與下載。你們是怎么做的呢?現(xiàn)在有一個技術(shù)可以非常簡單的實現(xiàn)這個功能——fastDFS
簡介
FastDFS是一個分布式文件系統(tǒng),使用FastDFS可以非常容易搭建一套高性能的文件服務(wù)器集群提供文件上傳、下載服務(wù)。
原理
它主要包含兩個部分, Tracker server
和 Storage server
客戶端請求 Tracker server 進行文件上傳、下載,通過 Tracker server 調(diào)度最終由 Storage server 完成文件上傳和下載。
Tracker server主要是用來進行負載均衡和調(diào)度。其實它就是一個調(diào)度服務(wù)器,通過一些策略找到Storage server來提供文件上傳服務(wù)。而Storage server的主要作用就是用來進行文件存儲。我們上傳上來的數(shù)據(jù)最終也是存儲到Storage服務(wù)器上的。需要注意的一點就是它本身是沒有實現(xiàn)自己的文件系統(tǒng),而是利用操作系統(tǒng)上的文件系統(tǒng)來管理文件的。所以Storage被稱為存儲服務(wù)器。
文件上傳示意圖:
文件下載示意圖:文章來源:http://www.zghlxwxcb.cn/news/detail-724733.html
如何使用
- 導(dǎo)入依賴
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
<version>1.26.7</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
- 編寫配置文件
server.port=8080
# ===================================================================
# 分布式文件系統(tǒng)FDFS配置
# ===================================================================
fdfs.so-timeout = 1501
fdfs.connect-timeout = 601
#縮略圖生成參數(shù)
fdfs.thumb-image.width= 150
fdfs.thumb-image.height= 150
#TrackerList參數(shù),支持多個
fdfs.tracker-list=10.199.12.106:22122
#訪問路徑
fdfs.web-server-url=http://10.199.12.106:8888/
- 代碼
創(chuàng)建一個工具類
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadCallback;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
@Component
public class FastDFSClientUtil {
@Autowired
private FastFileStorageClient storageClient;
/**
* 上傳
* @param file 文件類
* @return fileId 文件Id,包含group和uri的完整路徑 EG=>>MO/22/22/**.jpg
* @throws IOException
*/
public String uploadFile(MultipartFile file) throws IOException {
StorePath storePath = storageClient.uploadFile((InputStream) file.getInputStream(), file.getSize(),FilenameUtils.getExtension(file.getOriginalFilename()), null);
return storePath.getFullPath();
}
/**
* 刪除
* @param filePath 文件的fileId 包含分組,EG=>>group1/M00/22/22/***.**
*/
public void delFile(String filePath) {
storageClient.deleteFile(filePath);
}
/**
* 下載
* @param groupName 分組id EG=>> group10
* @param path 文件uri 分組之后的內(nèi)容[不含開頭的/] EG=>>MO/22/22/kkk.jpg
* @return 文件的字節(jié)數(shù)組
*/
public byte[] download(String groupName, String path) throws IOException {
InputStream ins = storageClient.downloadFile(groupName, path, new DownloadCallback<InputStream>() {
@Override
public InputStream recv(InputStream ins) throws IOException {
// 將此ins返回給上面的ins
return ins;
}
});
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while ((rc = ins.read(buff, 0, 100)) > 0) {
byteArrayOutputStream.write(buff, 0, rc);
}
return byteArrayOutputStream.toByteArray();
}
}
實現(xiàn)功能文章來源地址http://www.zghlxwxcb.cn/news/detail-724733.html
import com.doria.fastdfs.utils.FastDFSClientUtil;
import com.github.tobato.fastdfs.exception.FdfsServerException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
@RestController
@RequestMapping("/file")
@Slf4j
public class FileController {
// 引入客戶端工具類
@Autowired
private FastDFSClientUtil fastDFSClientUtil;
// 獲取respon稍后向前端頁面寫入圖片
@Autowired
private HttpServletResponse response;
// 讀取調(diào)度服務(wù)所在服務(wù)器稍后可以進行拼接,便于下次直接填寫,這里由于nginx監(jiān)聽的是80端口,所以沒有配置端口。默認訪問80
@Value("${fileServerUrl}")
private String fileServerUrl;
@PostMapping("/upload")
public String uploadFile(MultipartFile file) {
try {
// 判斷文件是否存在
if (file == null) {
throw new RuntimeException("文件不存在");
}
// 獲取文件的完整名稱
String originalFilename = file.getOriginalFilename();
if (StringUtils.isEmpty(originalFilename)) {
throw new RuntimeException("文件不存在");
}
// 獲取到返回的fileId
String url = fastDFSClientUtil.uploadFile(file);
// 拼接返回
return fileServerUrl + url;
} catch (Exception e) {
e.printStackTrace();
}
return "文件上傳失敗";
}
// 刪除文件[這里僅作測試用,實際中不會這樣直接在controller刪除
// 是會根據(jù)業(yè)務(wù)從數(shù)據(jù)庫中拿到url進行刪除同時刪除數(shù)據(jù)庫關(guān)聯(lián)數(shù)據(jù),注意被占用無法刪除]
@DeleteMapping("/del")
public String delFile(@RequestParam String fileId) {
try {
fastDFSClientUtil.delFile(fileId);
return "刪除成功";
} catch (Exception e) {
e.printStackTrace();
}
return "刪除失敗";
}
/**
* 文件下載,頁面直接訪問我們這個服務(wù)器,在頁面眼里,直接從我們這個服務(wù)拿到了文件,而我們?nèi)astdfs服務(wù)器獲取文件
* 前方的ip端口我們可以固定一個服務(wù)器,ip就是當前方法所在服務(wù)器的ip,前端找到我們。我們再去給他下載轉(zhuǎn)發(fā)
* 也可以將這個服務(wù)部署在fastdfs的本地,然后通過springcloud即時發(fā)現(xiàn)服務(wù)調(diào)用下載服務(wù)
* @param groupName
* @param path
*/
@GetMapping("/download")
public void download(@RequestParam String groupName, @RequestParam String path) {
try {
// 拆分獲取出文件名稱,方便一會寫入的時候?qū)懗稣_的文件名(url中的文件名和服務(wù)器中是一致的,至少默認是這樣的)
String[] split = path.split("/");
String imgName=split[split.length-1];
// 設(shè)置請求頭為附件模式
response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(imgName, "UTF-8"));
// 調(diào)用客戶端獲取文件字節(jié)碼
byte[] imageByte = fastDFSClientUtil.download(groupName, path);
// 從response獲取響應(yīng)流
ServletOutputStream outputStream = response.getOutputStream();
// 向流寫入數(shù)據(jù)
outputStream.write(imageByte);
// 關(guān)流
outputStream.close();
}catch (FdfsServerException e){
log.error("文件不存在");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
到了這里,關(guān)于fastDFS實現(xiàn)文件上傳與下載的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!