Interface FileStorage
- All Known Implementing Classes:
AzureBlobFileStorage, LocalFileStorage, S3FileStorage, SftpFileStorage, TransactionAwareFileStorage
public interface FileStorage
統一檔案儲存介面
整合暫存區與永久區操作,支援多種儲存後端(Local、Azure Blob、S3、Database、SFTP)。
設計原則
- 框架層純 Java 介面,不依賴 Spring
- 業務層只需處理 fileId,不需關心儲存細節
- fileId 格式:
yyyy-MM-dd/HH/filename-shortUuid.ext - 串流優先:使用 InputStream 避免大檔案載入記憶體
- 呼叫端負責關閉 InputStream
關於 partition 參數
所有方法的第一個參數 partition 是儲存分區鍵——由呼叫端控制的路徑/key 前綴,
用來把不同範圍的檔案隔離在各自的儲存空間(如 {root}/files/{partition}/...)。
框架不對其值賦予業務語意,也不做跨分區守衛;它與 entity 層的多租戶機制
(TenantContext、Hibernate filter)無耦合。
- 多租戶:傳當前 tenant ID(如
TenantContext.getCurrentTenantId()),達成租戶間檔案隔離 - 單租戶:傳固定常數(如
"default"),所有檔案落在同一分區
注意:不可傳 null(部分後端會以其組路徑而 NPE);請用穩定非空字串。
使用流程
// 1. 準備暫存上傳
StagingUploadInfo info = fileStorage.prepareStaging(partition, filename, contentType, size);
// 2. 完成暫存上傳
fileStorage.completeStagingUpload(partition, info.tempId(), inputStream, size);
// 3. 持久化到永久區
String fileId = fileStorage.persist(partition, info.tempId());
// 4. 讀取永久區檔案
FileMetadata meta = fileStorage.getMetadata(partition, fileId).orElseThrow();
try (InputStream is = fileStorage.getInputStream(partition, fileId)) {
// 處理檔案內容
}
支援的儲存類型
- local - 本地檔案系統
- database - 資料庫 BLOB(有檔案大小限制)
- s3 - AWS S3 或相容服務(如 MinIO)
- azure - Azure Blob Storage(支援 Azurite 模擬器)
- sftp - SFTP 檔案伺服器(支援密碼/私鑰驗證)
-
Nested Class Summary
Nested ClassesModifier and TypeInterfaceDescriptionstatic final record檔案 Metadatastatic final record暫存上傳資訊 -
Method Summary
Modifier and TypeMethodDescriptionvoidcompleteStagingUpload(String partition, String tempId, InputStream content, long size) 完成暫存上傳 - 統一上傳流程的第二步void刪除永久區檔案voiddeleteStaged(String partition, String tempId) 刪除暫存檔案boolean檢查永久區檔案是否存在booleanexistsStaged(String partition, String tempId) 檢查暫存檔案是否存在getInputStream(String partition, String fileId) 取得永久區檔案的 InputStreamgetMetadata(String partition, String fileId) 取得永久區檔案的 MetadatagetStagedInputStream(String partition, String tempId) 取得暫存檔案的 InputStreamgetStagedMetadata(String partition, String tempId) 取得暫存檔案的 Metadata取得儲存類型名稱取得檔案的存取 URL將暫存檔案持久化到永久區prepareStaging(String partition, String filename, String contentType, long size) 準備暫存上傳 - 統一上傳流程的第一步store(String partition, String filename, InputStream content, String contentType, long size) 直接儲存檔案到永久區(跳過暫存)
-
Method Details
-
prepareStaging
FileStorage.StagingUploadInfo prepareStaging(String partition, String filename, String contentType, long size) 準備暫存上傳 - 統一上傳流程的第一步
前端先呼叫此方法取得上傳 URL,再透過 PUT 上傳檔案內容。 此設計讓所有儲存類型(Local、Database、S3)使用統一的前端上傳邏輯。
- Parameters:
partition- 儲存分區鍵filename- 原始檔名contentType- MIME 類型size- 檔案大小- Returns:
- StagingUploadInfo(含 tempId 和上傳 URL)
-
completeStagingUpload
完成暫存上傳 - 統一上傳流程的第二步
接收 PUT 請求的檔案內容,完成暫存區上傳。 此方法由 Controller 在收到 PUT 請求時呼叫。
- Parameters:
partition- 儲存分區鍵tempId- 暫存檔案 ID(由 prepareStaging 回傳)content- 檔案內容的 InputStreamsize- 檔案大小- Throws:
IllegalArgumentException- 若 tempId 不存在或已過期
-
getStagedMetadata
取得暫存檔案的 Metadata- Parameters:
partition- 儲存分區鍵tempId- 暫存檔案 ID- Returns:
- 檔案 Metadata,若不存在則回傳 empty
-
getStagedInputStream
取得暫存檔案的 InputStream- Parameters:
partition- 儲存分區鍵tempId- 暫存檔案 ID- Returns:
- InputStream(呼叫端負責關閉)
- Throws:
FileNotFoundException- 若檔案不存在
-
existsStaged
-
deleteStaged
-
persist
將暫存檔案持久化到永久區
自動生成唯一的 fileId,格式為
yyyy-MM-dd/HH/filename-shortUuid.ext。 業務層只需儲存回傳的 fileId,不需關心檔案實際儲存位置。- Parameters:
partition- 儲存分區鍵tempId- 暫存檔案 ID- Returns:
- fileId(唯一識別碼,同時也是可讀的路徑格式)
- Throws:
IllegalArgumentException- 若暫存檔案不存在
-
store
直接儲存檔案到永久區(跳過暫存)- Parameters:
partition- 儲存分區鍵filename- 原始檔名(用於生成 fileId)content- 檔案內容的 InputStreamcontentType- MIME 類型size- 檔案大小- Returns:
- fileId
-
getMetadata
取得永久區檔案的 Metadata- Parameters:
partition- 儲存分區鍵fileId- 檔案 ID- Returns:
- 檔案 Metadata,若不存在則回傳 empty
-
getInputStream
取得永久區檔案的 InputStream- Parameters:
partition- 儲存分區鍵fileId- 檔案 ID- Returns:
- InputStream(呼叫端負責關閉)
- Throws:
FileNotFoundException- 若檔案不存在
-
exists
-
delete
-
getUrl
取得檔案的存取 URL
注意:此方法僅適用於雲端儲存(S3、Azure Blob),可回傳 Presigned URL 或 CDN URL。 對於 Local 和 Database 儲存類型,此方法會拋出
UnsupportedOperationException, 因為檔案下載應由業務層 Controller 實作以確保權限控管。- Parameters:
partition- 儲存分區鍵fileId- 檔案 ID- Returns:
- 存取 URL(僅雲端儲存支援)
- Throws:
UnsupportedOperationException- 若儲存類型不支援 URL 存取(如 Local、Database)
-
getStorageType
-