摘要:利用StreamingResponseBody来防止内存溢出,实现大文件下载。
一、配置异步请求超时时间
1 /** 2 * @Description: 异步请求配置类 3 * @Date: Created in 17:19 2025/1/5 4 * @Author: Cenobitor 5 * @Modified By: 6 * @since 0.1.0 7 */ 8 @Configuration 9 @EnableWebMvc 10 public class WebConfig implements WebMvcConfigurer { 11 12 @Override 13 public void configureAsyncSupport(AsyncSupportConfigurer configurer) { 14 configurer.setTaskExecutor(taskExecutor()); 15 // 超时时间设置为6000s 16 configurer.setDefaultTimeout(TimeUnit.SECONDS.toMillis(6000)); 17 } 18 19 private AsyncTaskExecutor taskExecutor() { 20 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 21 executor.setCorePoolSize(10); // 核心线程数 22 executor.setMaxPoolSize(20); // 最大线程数 23 executor.setQueueCapacity(500); // 队列容量 24 executor.setThreadNamePrefix("Async-"); 25 executor.initialize(); 26 return executor; 27 } 28 }
二、本地、远程文件下载请求接口
1 @RequestMapping( "/downloadFile") 2 public ResponseEntity<StreamingResponseBody> downloadFile() { 3 long start = System.currentTimeMillis(); 4 try { 5 Path filePath = Paths.get("E:\\macOS Catalina 10.15 正式版 19A583 macOShome.com.dmg"); 6 StreamingResponseBody responseBody = outputStream -> { 7 try (InputStream inputStream = Files.newInputStream(filePath)) { 8 StreamUtils.copy(inputStream, outputStream); 9 } 10 }; 11 HttpHeaders header = new HttpHeaders(); 12 header.setContentDispositionFormData("attachment", "macOS.dmg"); 13 header.setContentType(MediaType.APPLICATION_OCTET_STREAM); 14 return new ResponseEntity<>(responseBody,header, HttpStatus.OK); 15 } catch (Exception e) { 16 throw new RuntimeException(e); 17 } finally { 18 long end = System.currentTimeMillis(); 19 System.out.println("downloadFile cost: " + (end - start) + "ms"); 20 } 21 } 22 23 @RequestMapping( "/downloadRemoteFile") 24 public ResponseEntity<StreamingResponseBody> downloadRemoteFile() { 25 long start = System.currentTimeMillis(); 26 try { 27 StreamingResponseBody responseBody = outputStream -> { 28 URL resourceUrl = new URL("https://cdn.mysql.com/Downloads/MySQL-9.1/mysql-9.1.0-winx64-debug-test.zip"); 29 try (InputStream inputStream = new UrlResource(resourceUrl).getInputStream()) { 30 StreamUtils.copy(inputStream, outputStream); 31 } 32 }; 33 HttpHeaders header = new HttpHeaders(); 34 header.setContentDispositionFormData("attachment", "mysql.zip"); 35 header.setContentType(MediaType.APPLICATION_OCTET_STREAM); 36 return new ResponseEntity<>(responseBody,header, HttpStatus.OK); 37 } catch (Exception e) { 38 throw new RuntimeException(e); 39 } finally { 40 long end = System.currentTimeMillis(); 41 System.out.println("downloadFile cost: " + (end - start) + "ms"); 42 } 43 }
三、前端页面代码
1 <template> 2 <div class="download-wrap"> 3 <el-button type="primary" icon="el-icon-download" size="sm>ll" @click="downloadFile">下载文件</el-button> 4 <el-button type="primary" icon="el-icon-download" size="sm>ll" @click="downloadRemoteFile">下载远程文件</el-button> 5 </div> 6 </template> 7 8 <script> 9 import axios from "axios"; 10 11 export default { 12 name: 'HelloWorld', 13 props: { 14 msg: String 15 }, 16 17 methods:{ 18 downloadFile() { 19 console.log('下载文件开始'); 20 const downloadUrl = 'http://localhost:8080/downloadFile'; // 文件下载的链接 21 window.open(downloadUrl); 22 console.log('下载文件完成'); 23 }, 24 downloadRemoteFile() { 25 console.log('下载文件开始'); 26 const downloadUrl = 'http://localhost:8080/downloadRemoteFile'; // 文件下载的链接 27 window.open(downloadUrl); 28 console.log('下载文件完成'); 29 }, 30 }, 31 mounted() { 32 axios.get('http://localhost:8080/hello').then(res => { 33 console.log(res); 34 }); 35 }, 36 } 37 </script>