您好,登錄后才能下訂單哦!
SpringBoot中怎么將文件上傳至 FastDFS,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
FastDFS 是一個開源的輕量級分布式文件系統,它解決了大數據量存儲和負載均衡等問題,特別適合以中小文件(建議范圍:4 KB < file_size < 500 MB)為載體的在線服務,如相冊網站、視頻網站等
FastDFS 由 C 語言開發,支持 Linux、FreeBSD 等 UNIX 系統類 Google FS,不是通用的文件系統,只能通過專有 API 訪問,目前提供了 C、Java 和 PHP API,為互聯網應用量身定做,解決了大容量文件存儲問題,追求高性能和高擴展性,FastDFS 可以看做是基于文件的 Key Value Pair 存儲系統,稱作分布式文件存儲服務會更合適。
文件不分塊存儲,上傳的文件和 OS 文件系統中的文件一一對應
支持相同內容的文件只保存一份,節約磁盤空間
下載文件支持 HTTP 協議,可以使用內置 Web Server,也可以和其他 Web Server 配合使用
支持在線擴容
支持主從文件
存儲服務器上可以保存文件屬性(meta-data)V2.0 網絡通信采用 libevent,支持大并發訪問,整體性能更好
FastDFS 服務端有三個角色:跟蹤服務器(Tracker Server)、存儲服務器(Storage Server)和客戶端(Client)
Tracker Server:跟蹤服務器,主要做調度工作,起負載均衡的作用。在內存記錄集群中所有存儲組和存儲服務器的狀態信息,是客戶端和數據服務器交互的樞紐。相比 GFS 中的 Master 更為精簡,不記錄文件索引信息,占用的內存量很少。
Storage Server:存儲服務器(又稱存儲節點或數據服務器),文件和文件屬性(Meta Data)都保存到存儲服務器上。Storage Server 直接利用 OS 的文件系統調用管理文件。
Client:客戶端,作為業務請求的發起方,通過專有接口,使用 TCP/IP 協議與跟蹤器服務器或存儲節點進行數據交互。FastDFS 向使用者提供基本文件訪問接口,如 upload、download、append、delete 等,以客戶端庫的方式提供給用戶使用。
Tracker 相當于 FastDFS 的大腦,不論是上傳還是下載都是通過 Tracker 來分配資源;客戶端一般可以使用 Ngnix 等靜態服務器來調用或者做一部分的緩存;存儲服務器內部分為卷(或者叫做組),卷與卷之間是平行的關系,可以根據資源的使用情況隨時增加,卷內服務器文件相互同步備份,以達到容災的目的。
首先客戶端請求 Tracker 服務獲取到存儲服務器的 IP 地址和端口;
然后客戶端根據返回的 IP 地址和端口號請求上傳文件;
存儲服務器接收到請求后生產文件,并且將文件內容寫入磁盤并返回給客戶端 file_id、路徑信息、文件名等信息,客戶端保存相關信息上傳完畢。
客戶端帶上文件名信息請求 Tracker 服務獲取到存儲服務器的 IP 地址和端口;
然后客戶端根據返回的 IP 地址和端口號請求下載文件,存儲服務器接收到請求后返回文件給客戶端。
本節示例項目會在上一節項目的基礎上進行構建開發,從前端上傳文件到后臺后,直接傳遞到 FastDFS 集群中,并返回文件存儲的地址。
引入 FastDFS 的 Java 客戶端:
<dependency> <groupId>org.csource</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27-SNAPSHOT</version> </dependency>
項目 resources 目錄下添加fdfs_client.conf
文件,配置文件設置了連接的超時時間、編碼格式以及 tracker_server 地址等信息。
connect_timeout = 60 # 連接超時時間 network_timeout = 60 # 網絡超時時間 charset = UTF-8 # 編碼格式 http.tracker_http_port = 8080 #tracker 端口 http.anti_steal_token = no #token 防盜鏈功能 http.secret_key = 123456 #密鑰 # tracer server 列表,多個 tracer server 的話,分行列出 tracker_server = 192.168.53.85:22122 tracker_server = 192.168.53.86:22122
封裝 FastDFSFile,文件基礎信息包括文件名、內容、文件類型、作者等。
public class FastDFSFile { private String name; private byte[] content; private String ext; private String md5; private String author; //省略getter、setter }
接下來封裝 FastDFSClient 類,FastDFSClient 主要封裝最基礎的操作,包含上傳、下載、刪除等方法。FastDFSFile 任務可以是 FastDFS 上傳文件的封裝,操作時每一個文件對應一個實例。
首先在類加載的時候讀取配置信息,并進行初始化。
static { try { String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath(); //ClientGlobal.init 方法會讀取配置文件,并初始化對應的屬性。 ClientGlobal.init(filePath); } catch (Exception e) { logger.error("FastDFS Client Init Fail!",e); } }
文件上傳
使用 FastDFS 提供的客戶端 storageClient 來進行文件上傳,最后將上傳結果返回。
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; StorageClient storageClient=null; try { //獲取 storageClient = getStorageClient(); //上傳 uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list); } catch (IOException e) { logger.error("IO Exception when uploadind the file:" + file.getName(), e); } catch (Exception e) { logger.error("Non IO Exception when uploadind the file:" + file.getName(), e); } logger.info("upload_file time used:" + (System.currentTimeMillis() - startTime) + " ms"); //驗證上傳結果 if (uploadResults == null && storageClient!=null) { logger.error("upload file fail, error code:" + storageClient.getErrorCode()); } //上傳文件成功會返回 groupName。 logger.info("upload file successfully!!!" + "group_name:" + uploadResults[0] + ", remoteFileName:" + " " + uploadResults[1]); return uploadResults; }
NameValuePair,主要存儲文件的一些基礎屬性,如作者信息、創建時間等;
getStorageClient(),封裝了獲取客戶端的方法。
首先獲取 TrackerServer 信息,使用 TrackerServer 構建出每次操作的客戶端實例 StorageClient。詳細代碼如下:
private static StorageClient getStorageClient() throws IOException { TrackerServer trackerServer = getTrackerServer(); StorageClient storageClient = new StorageClient(trackerServer, null); return storageClient; }
下面為封裝獲取 TrackerServer 的方法:
private static TrackerServer getTrackerServer() throws IOException { TrackerClient trackerClient = new TrackerClient(); TrackerServer trackerServer = trackerClient.getConnection(); return trackerServer; }
獲取文件
根據 groupName 和文件名獲取文件信息。group 也可稱為卷,同組內服務器上的文件是完全相同的,同一組內的 storage server 之間是對等的,文件上傳、刪除等操作可以在任意一臺 storage server 上進行。
public static FileInfo getFile(String groupName, String remoteFileName) { try { storageClient = new StorageClient(trackerServer, storageServer); return storageClient.get_file_info(groupName, remoteFileName); } catch (IOException e) { logger.error("IO Exception: Get File from Fast DFS failed", e); } catch (Exception e) { logger.error("Non IO Exception: Get File from Fast DFS failed", e); } return null; }
下載文件
根據 storageClient 的 API 獲取文件的字節流并返回:
public static InputStream downFile(String groupName, String remoteFileName) { try { StorageClient storageClient = getStorageClient(); byte[] fileByte = storageClient.download_file(groupName, remoteFileName); InputStream ins = new ByteArrayInputStream(fileByte); return ins; } catch (IOException e) { logger.error("IO Exception: Get File from Fast DFS failed", e); } catch (Exception e) { logger.error("Non IO Exception: Get File from Fast DFS failed", e); } return null; }
刪除文件
根據文件名和組刪除對應的文件;當使用 FastDFS 時,直接調用 FastDFSClient 對應的方法即可。
public static void deleteFile(String groupName, String remoteFileName) throws Exception { StorageClient storageClient = getStorageClient(); int i = storageClient.delete_file(groupName, remoteFileName); logger.info("delete file successfully!!!" + i); }
從 MultipartFile 中讀取文件信息,然后使用 FastDFSClient 將文件上傳到 FastDFS 集群中,封裝一個 saveFile() 方法用來調用上面封裝的 FastDFS 工具類,將 MultipartFile 文件上傳到 FastDFS 中,并返回上傳后文件的地址信息。
public String saveFile(MultipartFile multipartFile) throws IOException { String[] fileAbsolutePath={}; String fileName=multipartFile.getOriginalFilename(); String ext = fileName.substring(fileName.lastIndexOf(".") + 1); byte[] file_buff = null; InputStream inputStream=multipartFile.getInputStream(); if(inputStream!=null){ int len1 = inputStream.available(); file_buff = new byte[len1]; inputStream.read(file_buff); } inputStream.close(); FastDFSFile file = new FastDFSFile(fileName, file_buff, ext); try { fileAbsolutePath = FastDFSClient.upload(file); //upload to fastdfs } catch (Exception e) { logger.error("upload file Exception!",e); } if (fileAbsolutePath==null) { logger.error("upload file failed,please upload again!"); } String path=FastDFSClient.getTrackerUrl()+fileAbsolutePath[0]+ "/"+fileAbsolutePath[1]; return path; }
當上傳請求傳遞到后端時,調用上面方法 saveFile()。
@PostMapping("/upload") public String singleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { if (file.isEmpty()) { redirectAttributes.addFlashAttribute("message", "Please select a file to upload"); return "redirect:uploadStatus"; } try { String path=saveFile(file); redirectAttributes.addFlashAttribute("message", "You successfully uploaded '" + file.getOriginalFilename() + "'"); redirectAttributes.addFlashAttribute("path","file path url '" + path + "'"); } catch (Exception e) { logger.error("upload file failed",e); } return "redirect:/uploadStatus"; }
上傳成功之后,將文件的路徑展示到頁面,效果圖如下:
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。