上傳文件接口設計,SpringBoot + MinIO/S3 文件服務實現:FileService 接口與 FileServiceImpl 詳解

在企業項目中,文件上傳和管理是非常常見的需求。本文基于 芋道源碼 的實現,介紹如何封裝一個通用的 文件服務 FileService,支持:

  • 文件上傳(保存數據庫記錄 + 存儲文件到 S3/MinIO 等對象存儲)

  • 文件下載與刪除

  • 文件分頁查詢

  • 生成預簽名上傳地址(適合前端直傳場景)


一、FileService 接口設計

首先定義 統一的文件服務接口,抽象業務邏輯,便于后續擴展。

public interface FileService {/*** 獲得文件分頁*/PageResult<FileDO> getFilePage(FilePageReqVO pageReqVO);/*** 保存文件,并返回訪問路徑*/String createFile(@NotEmpty byte[] content, String name, String directory, String type, String module);/*** 生成預簽名地址信息(前端直傳場景)*/FilePresignedUrlRespVO getFilePresignedUrl(@NotEmpty String name, String directory);/*** 數據庫中保存文件*/Long createFile(FileCreateReqVO createReqVO);/*** 刪除文件*/void deleteFile(Long id) throws Exception;/*** 獲得文件內容(下載)*/byte[] getFileContent(Long configId, String path) throws Exception;
}

接口設計要點

  1. 上傳文件:支持傳入字節數組,自動處理文件名、路徑、MIME 類型等。

  2. 預簽名地址:便于前端直傳文件,提升性能。

  3. 刪除文件:既刪除存儲器里的物理文件,也刪除數據庫記錄。

  4. 查詢分頁:方便后臺管理。


二、FileServiceImpl 實現類

@Service
public class FileServiceImpl implements FileService {// 控制路徑是否帶日期/時間戳static boolean PATH_PREFIX_DATE_ENABLE = true;static boolean PATH_SUFFIX_TIMESTAMP_ENABLE = true;@Resourceprivate FileConfigService fileConfigService;@Resourceprivate FileMapper fileMapper;@Overridepublic PageResult<FileDO> getFilePage(FilePageReqVO pageReqVO) {if ("all".equals(pageReqVO.getModule())) {pageReqVO.setModule(null);}return fileMapper.selectPage(pageReqVO);}@Override@SneakyThrowspublic String createFile(byte[] content, String name, String directory, String type, String module) {// 1. 補全文件信息if (StrUtil.isEmpty(type)) {type = FileTypeUtils.getMineType(content, name);}if (StrUtil.isEmpty(name)) {name = DigestUtil.sha256Hex(content);}if (StrUtil.isEmpty(FileUtil.extName(name))) {String extension = FileTypeUtils.getExtension(type);if (StrUtil.isNotEmpty(extension)) {name = name + extension;}}// 2. 生成上傳路徑String path = generateUploadPath(name, directory);// 3. 上傳文件FileClient client = fileConfigService.getMasterFileClient();Assert.notNull(client, "客戶端(master) 不能為空");String url = client.upload(content, path, type);// 4. 保存數據庫fileMapper.insert(new FileDO().setConfigId(client.getId()).setName(name).setPath(path).setUrl(url).setModule(module).setType(type).setSize(content.length));return url;}@VisibleForTestingString generateUploadPath(String name, String directory) {String prefix = PATH_PREFIX_DATE_ENABLE? LocalDateTimeUtil.format(LocalDateTimeUtil.now(), PURE_DATE_PATTERN): null;String suffix = PATH_SUFFIX_TIMESTAMP_ENABLE ? String.valueOf(System.currentTimeMillis()) : null;if (StrUtil.isNotEmpty(suffix)) {String ext = FileUtil.extName(name);if (StrUtil.isNotEmpty(ext)) {name = FileUtil.mainName(name) + "_" + suffix + "." + ext;} else {name = name + "_" + suffix;}}if (StrUtil.isNotEmpty(prefix)) {name = prefix + "/" + name;}if (StrUtil.isNotEmpty(directory)) {name = directory + "/" + name;}return name;}@Override@SneakyThrowspublic FilePresignedUrlRespVO getFilePresignedUrl(String name, String directory) {String path = generateUploadPath(name, directory);FileClient client = fileConfigService.getMasterFileClient();FilePresignedUrlRespDTO dto = client.getPresignedObjectUrl(path);return BeanUtils.toBean(dto, FilePresignedUrlRespVO.class,object -> object.setConfigId(client.getId()).setPath(path));}@Overridepublic Long createFile(FileCreateReqVO createReqVO) {FileDO file = BeanUtils.toBean(createReqVO, FileDO.class);fileMapper.insert(file);return file.getId();}@Overridepublic void deleteFile(Long id) throws Exception {FileDO file = validateFileExists(id);FileClient client = fileConfigService.getFileClient(file.getConfigId());Assert.notNull(client, "客戶端({}) 不能為空", file.getConfigId());client.delete(file.getPath());fileMapper.deleteById(id);}private FileDO validateFileExists(Long id) {FileDO file = fileMapper.selectById(id);if (file == null) {throw exception(FILE_NOT_EXISTS);}return file;}@Overridepublic byte[] getFileContent(Long configId, String path) throws Exception {FileClient client = fileConfigService.getFileClient(configId);Assert.notNull(client, "客戶端({}) 不能為空", configId);return client.getContent(path);}
}

三、核心邏輯拆解

1. 文件路徑生成策略

  • 是否按日期分目錄:20250908/xxx.png

  • 是否加時間戳后綴:避免文件名沖突

  • 可擴展為 UUID、Hash 等

2. 文件存儲

  • 通過 FileClient 統一抽象,可以對接 MinIO、阿里云 OSS、七牛云、AWS S3 等。

  • 上傳成功后,數據庫保存一條記錄(包括 url、路徑、大小、類型、模塊分類等)。

3. 文件刪除

  • 先校驗數據庫記錄是否存在

  • 調用存儲器客戶端刪除物理文件

  • 再刪除數據庫記錄

4. 文件預簽名 URL

  • 用于前端直傳文件到對象存儲,避免文件先經過后端。

  • 返回結構中包含:uploadUrldownloadUrlpathconfigId 等信息。


四、應用場景

  • 后臺管理系統:上傳/下載合同、報表、Excel

  • 移動端 App:上傳頭像、圖片、視頻

  • 大文件上傳:通過預簽名直傳,提升性能

  • 多存儲支持:可按業務模塊選擇不同的存儲配置


五、總結

通過 FileService + FileServiceImpl 的設計,我們實現了:

? 文件上傳、下載、刪除
? 文件路徑唯一性控制
? 文件分頁查詢
? 預簽名直傳(提升性能)
? 存儲器解耦(支持多云對象存儲)

這種實現方式已經是 企業級最佳實踐,可以非常方便地擴展到不同的云存儲平臺。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/96610.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/96610.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/96610.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MVC 依賴注入(DI)與服務全解析(附避坑實戰)

依賴注入的核心概念 依賴注入&#xff08;DI&#xff09;是一種設計模式&#xff0c;通過將對象的依賴關系從內部創建轉移到外部傳遞&#xff0c;實現解耦。在 MVC 框架中&#xff0c;DI 容器負責管理對象的生命周期和依賴關系&#xff0c;開發者只需聲明依賴&#xff0c;容器…

【實證分析】上市公司經營風險數據集-含代碼(2000-2022年)

數據簡介&#xff1a;上市公司經營風險涉及多維度、多層次的復雜因素&#xff0c;本文章參考王竹泉-經營風險與營運資金融資決策對上市公司經驗風險進行測算&#xff0c;經營風險是該公司息稅折舊攤銷前利潤率的標準差&#xff0c;經營風險是該公司息稅折舊攤銷前利潤率的標準差…

領碼方案|Windows 下 PLT → PDF 轉換服務超級完整版:異步、權限、進度

摘要 面向 Windows 平臺&#xff0c;使用 ASP.NET Core Web API 結合 Ghostscript.NET 庫&#xff0c;實現 PLT&#xff08;HPGL&#xff09;→PDF 的純庫調用轉換&#xff0c;無需外部進程。支持同步與異步模式&#xff0c;采用 JWTRBAC 進行權限治理&#xff0c;任務狀態存儲…

瀏覽器兼容性問題全解:CSS 前綴、Grid/Flex 布局兼容方案與跨瀏覽器調試技巧

1. 瀏覽器兼容性與前綴問題 不同瀏覽器&#xff08;尤其是老版本 IE、Edge、Safari&#xff09;對新特性&#xff08;比如 CSS 變量、Grid、Flex 等&#xff09;的支持程度不一&#xff0c;需要使用廠商前綴&#xff08;-webkit-、-moz- 等&#xff09;或降級方案。新手往往忽…

【Android View】事件分發機制

參考文獻 https://juejin.cn/post/6844904041487532045https://juejin.cn/post/6844903894103883789#heading-12https://www.jianshu.com/p/dea72779a6b7 文章目錄

【大數據相關】ClickHouse命令行與SQL語法詳解

ClickHouse命令行與SQL語法詳解一、ClickHouse命令行與SQL語法詳解第一部分&#xff1a;ClickHouse SQL 命令行客戶端 (clickhouse-client)1. 基礎連接2. 核心命令行參數3. 數據導入與導出實戰第二部分&#xff1a;ClickHouse SQL 語法詳解1. DDL (數據定義語言)2. DML (數據操…

學習日記-CSS-day53-9.11

1.CSS介紹知識點核心內容重點CSS定義層疊樣式表&#xff0c;用于內容修飾和樣式展現英文全稱cascading style sheetsCSS作用實現HTML內容與樣式分離&#xff0c;提高開發效率對比傳統HTML元素單獨設置樣式的低效方式學習建議掌握常用功能即可&#xff0c;重點在打通前后端數據通…

Maven中optional的作用

目的&#xff1a; 控制依賴傳遞 &#xff1a;將依賴標記為可選&#xff0c;這樣當其他模塊依賴common-component時&#xff0c;不會自動繼承Elasticsearch依賴。這遵循了"依賴最小化"原則&#xff0c;避免不必要的庫被引入到不需要它們的模塊中。模塊化設計 &#xf…

藍橋杯算法之基礎知識(7)---排序題的快排和歸并排序

一、快排》快排方法&#xff0c;就三步1.隨便選一個值作為基準值x2.拿選中的這個x值劃分隊列為左右兩個區間&#xff08;左邊的都小于x&#xff0c;右邊的都大于x&#xff09;3.然后遞歸左區間和右區間就行》代碼舉例&#xff1a;#qs排序#1 6 7 8 6 5 4 #先找比較點&#xff0c…

緩存未命中

緩存未命中&#xff08;Cache Miss&#xff09; 發生在 CPU 訪問某塊內存時&#xff0c;該地址不在當前緩存&#xff08;L1/L2/L3&#xff09;中&#xff0c;導致程序被迫從更慢的內存&#xff08;RAM&#xff09;讀取數據&#xff0c;嚴重拖慢程序執行速度。 &#x1f4cd; 一…

AR眼鏡:化工安全生產的技術革命

在石化企業的壓縮機組巡檢中&#xff0c;佩戴AR眼鏡的巡檢員眼前實時顯示著設備溫度場分布和振動頻譜曲線&#xff0c;單臺設備巡檢時間從45分鐘縮短至18分鐘。這不僅是效率的提升&#xff0c;更是化工安全生產的一場智能革命。一、行業痛點&#xff1a;傳統化工巡檢的困境與挑…

消息中間件RabbitMQ(從入門到精通)

RabbitMQ概念_MQ 消息隊列 MQ全稱Message Queue(消息隊列),是在消息的傳輸過程中保存消息的容器。多用于系統之間的異步通信。 同步通信相當于兩個人當面對話,你一言我一語。必須及時回復 異步通信相當于通過第三方轉述對話,可能有消息的延遲,但不需要二人時刻保持聯系。…

前端學習之后端java小白(五)之多表查詢/事務

一、多表查詢概念二、概述 1. 內連接隱式內連接 SELECT 字段列表 FROM 表1&#xff0c;表2... WHERE 條件顯示內連接SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 條件2. 外連接 左外連接SELECT 列名 FROM 左表 LEFT [OUTER] JOIN 右表 ON 連接條件;右外連接SELECT 列名…

Java全棧學習筆記34

# JDBCjava database connection Java 數據庫連接技術## JDBC 驅動程序如果需要通過jdbc技術連接關系型數據庫&#xff0c;就需要為jdbc提供一個該數據庫的驅動。驅動程序由對應的數據庫廠商提供。mysql提供了針對于各種語言的驅動程序。去官網下載和java相關的驅動即可## JDB…

如何為MySQL中的JSON字段設置索引

背景 MySQL在2015年中發布的5.7.8版本中首次引入了JSON數據類型。自此&#xff0c;它成了一種逃離嚴格列定義的方式&#xff0c;可以存儲各種形狀和大小的JSON文檔&#xff0c;例如審計日志、配置信息、第三方數據包、用戶自定義字段等。 雖然MySQL提供了讀寫JSON數據的函數&am…

【學習日記】

1.上午看了會面經&#xff0c;八股&#xff0c;很多看不懂1.5排查本地mysql服務啟動問題2.刷了兩道題翻轉二叉樹的Dfs和bfs遞歸方法&#xff0c;看了幾分鐘看懂了&#xff0c;一開始刷題&#xff0c;沒有這種感覺&#xff0c;可能思維上升了3.下午做了會ppt4.看了ssm的一個gith…

本地大模型部署指南-Ollama與HuggingFace對比

在本地部署大模型時&#xff0c;用 Ollama 和 Hugging Face (HF) 確實有很大區別&#xff0c;涉及系統、硬件、訓練、推理方式&#xff0c;以及能否查看模型源代碼。下面我分幾個維度說明&#xff1a; 系統和安裝 Ollama 定位是「開箱即用」的本地大模型運行環境。 自帶運行時&…

河北周邊有哪些比較靠譜的智算中心?

河北省通過算力普惠、綠色能源、數據開放、金融支持四大支柱政策&#xff0c;推動智算中心高質量發展。河北及周邊地區的智算中心已形成高可靠性、先進技術和戰略協同的布局。那么&#xff0c;河北周邊有哪些比較靠譜的智算中心&#xff1f;一、河北周邊智算中心盤點?1、尚航懷…

電動汽車充電標準之 — 國標 GB/T 18487《電動汽車傳導充電系統》 簡介

GB/T 18487 的全稱是 《電動汽車傳導充電系統》 &#xff0c;它是中國電動汽車充電領域最基礎、最核心的國家標準之一。該標準規定了電動汽車傳導充電系統的通用要求、通信協議、安全要求等&#xff0c;是整個中國充電基礎設施建設的基石。 與您之前了解的IEC 61851類似&#x…

溫濕度傳感器如何守護工業制造?

在工業制造、農業養殖、倉儲物流乃至文物保護等領域&#xff0c;環境溫濕度的精確監測是保障品質與安全的關鍵。溫濕度傳感器作為無聲的守護者&#xff0c;如何通過穩定可靠的數據采集&#xff0c;為現代工業生產的精細化與智能化管理提供堅實基礎&#xff1f;本文將深入探討其…