SpringBoot實(shí)現(xiàn)文件下載的限速功能
前言
在文件下載過(guò)程中,如果不加以控制,可能會(huì)導(dǎo)致服務(wù)器帶寬被單個(gè)或少數(shù)用戶(hù)占用,影響其他用戶(hù)的訪(fǎng)問(wèn)體驗(yàn)。通過(guò)實(shí)現(xiàn)文件下載的限速,可以平衡帶寬資源的使用,確保所有用戶(hù)都有良好的下載體驗(yàn)。
實(shí)現(xiàn)思路
為了實(shí)現(xiàn)文件下載的限速,我們需要以下幾個(gè)關(guān)鍵步驟:
- 創(chuàng)建一個(gè)工具類(lèi),用于限制下載速率。
- 在控制器中使用該工具類(lèi)處理文件下載請(qǐng)求。
- 使用
StreamingResponseBody
實(shí)現(xiàn)流式響應(yīng),確保大文件可以逐步傳輸。
代碼實(shí)現(xiàn)
步驟1:創(chuàng)建限速工具類(lèi)
首先,我們創(chuàng)建一個(gè)限速工具類(lèi)RateLimiter
,該類(lèi)包含一個(gè)方法limitDownloadSpeed
,用于限制下載速率。
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * @desc: 文件工具類(lèi) * @author: shy * @date: 2024/06/28 11:27 */ public class FileUtil { private static final int BUFFER_SIZE = 1024; /** * 文件下載限速 * * @param in 輸入流 * @param out 輸出流 * @param bytesPerSecond 每秒允許下載的字節(jié)數(shù) * @throws IOException */ public static void limitDownloadSpeed(InputStream in, OutputStream out, int bytesPerSecond) throws IOException { byte[] buffer = new byte[BUFFER_SIZE]; int bytesRead; long bytesSent = 0; long startTime = System.currentTimeMillis(); try { while ((bytesRead = in.read(buffer)) != -1) { // 將數(shù)據(jù)寫(xiě)入輸出流 out.write(buffer, 0, bytesRead); bytesSent += bytesRead; if (bytesSent >= bytesPerSecond) { long elapsedTime = System.currentTimeMillis() - startTime; if (elapsedTime < 1000) { // 如果時(shí)間少于1秒,則休眠剩余時(shí)間 Thread.sleep(1000 - elapsedTime); } // 重置已發(fā)送字節(jié)計(jì)數(shù)和開(kāi)始時(shí)間 bytesSent = 0; startTime = System.currentTimeMillis(); } } } catch (InterruptedException e) { // 恢復(fù)線(xiàn)程的中斷狀態(tài) Thread.currentThread().interrupt(); throw new IOException("Thread was interrupted", e); } } }
解釋:
BUFFER_SIZE
:定義緩沖區(qū)大小。limitDownloadSpeed
:通過(guò)try-with-resources
管理InputStream
,根據(jù)設(shè)定的速率讀取數(shù)據(jù)并寫(xiě)入輸出流,控制傳輸速率。
步驟2:修改文件下載控制器
接下來(lái),我們?cè)诳刂破髦惺褂?code>StreamingResponseBody來(lái)實(shí)現(xiàn)文件下載,并調(diào)用限速工具類(lèi)的方法。
import java.io.File; import java.io.InputStream; import java.nio.file.Files; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody; import com.shy.admin.common.annotation.WithoutLogin; import com.shy.common.utils.FileUtil; /** * @desc: 文件下載Controller * @author: shy * @date: 2024/06/28 10:48 */ @RestController @RequestMapping("/file") public class FileController { // 每秒允許下載的字節(jié)數(shù)(例如100KB/s) private static final int BYTES_PER_SECOND = 1024 * 100; @WithoutLogin @GetMapping("/download/{filename}") public ResponseEntity<StreamingResponseBody> downloadFile(@PathVariable String filename) { // 獲取要下載的文件 File file = new File("D:\\tools\\" + filename); // 使用 StreamingResponseBody 實(shí)現(xiàn)流式響應(yīng)體 StreamingResponseBody responseBody = outputStream -> { try (InputStream inputStream = Files.newInputStream(file.toPath())) { // 調(diào)用限速方法 FileUtil.limitDownloadSpeed(inputStream, outputStream, BYTES_PER_SECOND); } }; // 返回 ResponseEntity,包含響應(yīng)頭和流式響應(yīng)體 return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName()) .contentType(MediaType.APPLICATION_OCTET_STREAM) .contentLength(file.length()) .body(responseBody); } }
解釋:
StreamingResponseBody
:實(shí)現(xiàn)流式響應(yīng)體,用于處理大文件的逐步傳輸。responseBody
:通過(guò)lambda表達(dá)式實(shí)現(xiàn)StreamingResponseBody
的writeTo
方法,在方法中使用try-with-resources
管理InputStream
,并調(diào)用RateLimiter
的方法實(shí)現(xiàn)限速。
工作流程
- 請(qǐng)求處理:當(dāng)客戶(hù)端發(fā)送下載請(qǐng)求時(shí),Spring 調(diào)用控制器方法
downloadFile
。 - 創(chuàng)建
StreamingResponseBody
:控制器方法創(chuàng)建StreamingResponseBody
實(shí)例。 - 返回
ResponseEntity
:控制器方法返回包含StreamingResponseBody
的ResponseEntity
,并設(shè)置適當(dāng)?shù)捻憫?yīng)頭(如Content-Disposition
和Content-Type
)。 - 調(diào)用
writeTo
方法:Spring 在準(zhǔn)備向客戶(hù)端發(fā)送響應(yīng)時(shí),調(diào)用StreamingResponseBody
的writeTo
方法,并傳入與客戶(hù)端連接的OutputStream
。 - 寫(xiě)入數(shù)據(jù):
writeTo
方法中,從文件輸入流讀取數(shù)據(jù),并通過(guò)RateLimiter
方法將數(shù)據(jù)寫(xiě)入OutputStream
,同時(shí)控制傳輸速率。
總結(jié)
通過(guò)以上步驟,我們成功在SpringBoot項(xiàng)目中實(shí)現(xiàn)了文件下載的限速功能。核心思路是通過(guò)一個(gè)限速工具類(lèi)控制數(shù)據(jù)傳輸速率,并使用StreamingResponseBody
實(shí)現(xiàn)流式響應(yīng),確保大文件可以逐步傳輸。這種設(shè)計(jì)既能有效控制帶寬資源的使用,又能提供良好的用戶(hù)下載體驗(yàn)。
以上就是SpringBoot實(shí)現(xiàn)文件下載的限速功能的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot文件下載限速的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- SpringBoot實(shí)現(xiàn)文件的上傳、下載和預(yù)覽功能
- SpringBoot上傳下載文件+oss實(shí)例
- SpringBoot中實(shí)現(xiàn)文件上傳、下載、刪除功能的步驟
- SpringBoot實(shí)現(xiàn)文件下載的四種方式
- Vue2+SpringBoot實(shí)現(xiàn)數(shù)據(jù)導(dǎo)出到csv文件并下載的使用示例
- SpringBoot+MinIO實(shí)現(xiàn)文件上傳、讀取、下載、刪除的使用示例
- SpringBoot+ruoyi框架文件上傳和下載的實(shí)現(xiàn)
- SpringBoot返回文件使前端下載的幾種方式小結(jié)
相關(guān)文章
SpringBoot項(xiàng)目的配置文件中設(shè)置server.port不生效問(wèn)題
這篇文章主要介紹了SpringBoot項(xiàng)目的配置文件中設(shè)置server.port不生效問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11IDEA?maven項(xiàng)目依賴(lài)無(wú)法解析問(wèn)題
這篇文章主要介紹了IDEA?maven項(xiàng)目依賴(lài)無(wú)法解析問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03JavaWeb實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)(2)
這篇文章主要介紹了JavaWeb實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)的第二篇,實(shí)現(xiàn)學(xué)生管理系統(tǒng)的查找和添加功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08Java數(shù)據(jù)結(jié)構(gòu)之線(xiàn)段樹(shù)中的懶操作詳解
對(duì)于線(xiàn)段樹(shù),若要求對(duì)區(qū)間中的所有點(diǎn)都進(jìn)行更新,可以引入懶操作。懶操作包括區(qū)間更新和區(qū)間查詢(xún)操作。本文將通過(guò)一個(gè)示例和大家詳細(xì)聊聊線(xiàn)段樹(shù)中的懶操作,需要的可以參考一下2022-10-10springboot時(shí)間格式化的五種方法總結(jié)(解決后端傳給前端的時(shí)間顯示不一致)
這篇文章主要給大家介紹了關(guān)于springboot時(shí)間格式化的五種方法,文中介紹的方法解決了后端傳給前端的時(shí)間顯示不一致,文中通過(guò)圖文以及代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01Java生成日期時(shí)間存入Mysql數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方法
本文主要介紹了Java生成日期時(shí)間存入Mysql數(shù)據(jù)庫(kù)的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03