Interface FileStorage
- All Known Implementing Classes:
AzureBlobFileStorage, LocalFileStorage, S3FileStorage, SftpFileStorage
public interface FileStorage
統一檔案儲存介面
整合暫存區與永久區操作,支援多種儲存後端(Local、Azure Blob、S3、Database、SFTP)。
設計原則
- 框架層純 Java 介面,不依賴 Spring
- 業務層只需處理 fileId,不需關心儲存細節
- fileId 格式:
yyyy-MM-dd/HH/filename-shortUuid.ext - 串流優先:使用 InputStream 避免大檔案載入記憶體
- 呼叫端負責關閉 InputStream
使用流程
// 1. 準備暫存上傳
StagingUploadInfo info = fileStorage.prepareStaging(tenantId, filename, contentType, size);
// 2. 完成暫存上傳
fileStorage.completeStagingUpload(tenantId, info.tempId(), inputStream, size);
// 3. 持久化到永久區
String fileId = fileStorage.persist(tenantId, info.tempId());
// 4. 讀取永久區檔案
FileMetadata meta = fileStorage.getMetadata(tenantId, fileId).orElseThrow();
try (InputStream is = fileStorage.getInputStream(tenantId, 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 tenantId, String tempId, InputStream content, long size) 完成暫存上傳 - 統一上傳流程的第二步void刪除永久區檔案voiddeleteStaged(String tenantId, String tempId) 刪除暫存檔案boolean檢查永久區檔案是否存在booleanexistsStaged(String tenantId, String tempId) 檢查暫存檔案是否存在getInputStream(String tenantId, String fileId) 取得永久區檔案的 InputStreamgetMetadata(String tenantId, String fileId) 取得永久區檔案的 MetadatagetStagedInputStream(String tenantId, String tempId) 取得暫存檔案的 InputStreamgetStagedMetadata(String tenantId, String tempId) 取得暫存檔案的 Metadata取得儲存類型名稱取得檔案的存取 URL將暫存檔案持久化到永久區prepareStaging(String tenantId, String filename, String contentType, long size) 準備暫存上傳 - 統一上傳流程的第一步store(String tenantId, String filename, InputStream content, String contentType, long size) 直接儲存檔案到永久區(跳過暫存)
-
Method Details
-
prepareStaging
FileStorage.StagingUploadInfo prepareStaging(String tenantId, String filename, String contentType, long size) 準備暫存上傳 - 統一上傳流程的第一步
前端先呼叫此方法取得上傳 URL,再透過 PUT 上傳檔案內容。 此設計讓所有儲存類型(Local、Database、S3)使用統一的前端上傳邏輯。
- Parameters:
tenantId- 租戶 IDfilename- 原始檔名contentType- MIME 類型size- 檔案大小- Returns:
- StagingUploadInfo(含 tempId 和上傳 URL)
-
completeStagingUpload
完成暫存上傳 - 統一上傳流程的第二步
接收 PUT 請求的檔案內容,完成暫存區上傳。 此方法由 Controller 在收到 PUT 請求時呼叫。
- Parameters:
tenantId- 租戶 IDtempId- 暫存檔案 ID(由 prepareStaging 回傳)content- 檔案內容的 InputStreamsize- 檔案大小- Throws:
IllegalArgumentException- 若 tempId 不存在或已過期
-
getStagedMetadata
取得暫存檔案的 Metadata- Parameters:
tenantId- 租戶 IDtempId- 暫存檔案 ID- Returns:
- 檔案 Metadata,若不存在則回傳 empty
-
getStagedInputStream
取得暫存檔案的 InputStream- Parameters:
tenantId- 租戶 IDtempId- 暫存檔案 ID- Returns:
- InputStream(呼叫端負責關閉)
- Throws:
FileNotFoundException- 若檔案不存在
-
existsStaged
-
deleteStaged
-
persist
將暫存檔案持久化到永久區
自動生成唯一的 fileId,格式為
yyyy-MM-dd/HH/filename-shortUuid.ext。 業務層只需儲存回傳的 fileId,不需關心檔案實際儲存位置。- Parameters:
tenantId- 租戶 IDtempId- 暫存檔案 ID- Returns:
- fileId(唯一識別碼,同時也是可讀的路徑格式)
- Throws:
IllegalArgumentException- 若暫存檔案不存在
-
store
直接儲存檔案到永久區(跳過暫存)- Parameters:
tenantId- 租戶 IDfilename- 原始檔名(用於生成 fileId)content- 檔案內容的 InputStreamcontentType- MIME 類型size- 檔案大小- Returns:
- fileId
-
getMetadata
取得永久區檔案的 Metadata- Parameters:
tenantId- 租戶 IDfileId- 檔案 ID- Returns:
- 檔案 Metadata,若不存在則回傳 empty
-
getInputStream
取得永久區檔案的 InputStream- Parameters:
tenantId- 租戶 IDfileId- 檔案 ID- Returns:
- InputStream(呼叫端負責關閉)
- Throws:
FileNotFoundException- 若檔案不存在
-
exists
-
delete
-
getUrl
取得檔案的存取 URL
注意:此方法僅適用於雲端儲存(S3、Azure Blob),可回傳 Presigned URL 或 CDN URL。 對於 Local 和 Database 儲存類型,此方法會拋出
UnsupportedOperationException, 因為檔案下載應由業務層 Controller 實作以確保權限控管。- Parameters:
tenantId- 租戶 IDfileId- 檔案 ID- Returns:
- 存取 URL(僅雲端儲存支援)
- Throws:
UnsupportedOperationException- 若儲存類型不支援 URL 存取(如 Local、Database)
-
getStorageType
-