spring boot-MultipartFile 机制

在线体验各类最新模型,更有模型 免费Token 额度领取!
立即体验
简介: 本文详解了 Spring Boot 中 MultipartFile 的工作机制及大文件上传的解决方案。内容涵盖 MultipartFile 的解析流程、上传配置、Feign 上传大文件的内存问题及基于 RestTemplate 的流式上传实现。同时介绍了服务器端如何直接处理 application/octet-stream 类型的文件流,避免内存溢出问题。适合需要优化文件上传性能的开发者参考。

spring boot-MultipartFile 机制

spring boot MultipartFile 解析过程

bash

体验AI代码助手

代码解读

复制代码

sequenceDiagram  
participant Client as 客户端  
participant ServletContainer as Servlet容器  
participant Spring as Spring MVC  
  
Client->>ServletContainer: 发送multipart/form-data请求  
ServletContainer->>ServletContainer: 启动HTTP协议解析  
ServletContainer->>ServletContainer: 根据Content-Type识别multipart  
ServletContainer->>ServletContainer: 创建临时存储结构(内存/磁盘)  
ServletContainer->>Spring: 将解析后的数据封装为Request对象  
Spring->>Spring: 触发MultipartResolver解析  

只有在 MultipartFile.getBytes() 方法才会将文件数据加载到内存!!

上传时配置设置

yaml

体验AI代码助手

代码解读

复制代码

spring:  
servlet:  
multipart:  
enabled: true  
file-size-threshold: 1MB # 1MB 以下用内存,以上用磁盘  
max-file-size: 5GB # 单个文件最大  
max-request-size: 10GB # 整个请求最大  
location: /data/tmp # 指定专用临时目录  

问题

在使用 Feign 上传文件时,如果上传大文件会报错, Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: Required array length 2147483639 + 9 is too large

所以使用 RestTemplate 来实现

调用方

java

体验AI代码助手

代码解读

复制代码

/**  
* 使用@LoadBalanced注解不能进行流式上传  
* @return  
*/  
public RestTemplate getUploadRestTemplate() {  
    // 使用 Apache HttpClient 作为底层实现,使用 流式上传  
    CloseableHttpClient httpClient = HttpClients.custom()  
    .setMaxConnTotal(100) // 最大连接数  
    .setMaxConnPerRoute(20) // 每个路由的最大连接数  
    .build();  

    HttpComponentsClientHttpRequestFactory factory =  
    new HttpComponentsClientHttpRequestFactory(httpClient);  
    factory.setBufferRequestBody(false);  
    factory.setConnectTimeout(30_000); // 连接超时 30s  
    factory.setReadTimeout(300_000); // 读取超时 5min(大文件需延长)  
    return new RestTemplate(factory);  
}  
  
  
@PostMapping(value = "/file/upload")  
public String uploadStream(@RequestParam("file") MultipartFile file) throws IOException {  
    // 3. 构建 Multipart 请求体  
    // 2. 包装文件流为 Resource(关键:实现 contentLength() 返回 -1)  
    int bufSize = 64*1024; //默认8kb  
        Resource resource = new InputStreamResource(new BufferedInputStream(file.getInputStream(),bufSize)) {  
        @Override  
        public long contentLength() {  
        return -1; // 触发分块传输  
        }  

        @Override  
        public String getFilename() {  
        return file.getName(); // 确保服务器能获取文件名  
        }  
    };  

    file.transferTo();  

    // 4. 设置请求头  
    HttpHeaders headers = new HttpHeaders();  
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);  
    ResponseEntity<String> response =  
    //手动进行负载  
    getUploadRestTemplate().exchange("http://localhost:8081/upload-file4?name="+file.getOriginalFilename(),  
    HttpMethod.POST,  
    new HttpEntity<>(resource,headers), String.class);  

    System.out.println(JSON.toJSONString(response));  

    return "success";  
}  

这里比较坑的是加了@LoadBalanced 注解之后的RestTemplate ,会缓存 请求数据【详见InterceptingClientHttpRequest】,还是会报内存溢出,所以就不能加,如果要在微服务系统使用,要先自己使用负载均衡这套

服务器方

java

体验AI代码助手

代码解读

复制代码

  
//这样直接从request 获取文件流,就不解析MultipartFile,效率也要好点  
@PostMapping(value = "/upload-file4", consumes = "application/octet-stream")  
public String uploadStream3(HttpServletRequest request,@RequestParam("name") String name) throws Exception {  
    try (InputStream inputStream = request.getInputStream()) {  
    Files.copy(inputStream, Paths.get("d:/" + System.currentTimeMillis() + "_" + name));  
    return "Upload success!";  
    }  
}  

spring 处理 application/octet-stream 资源类型

spring boot 在处理 application/octet-stream 请求类型时,使用 ResourceHttpMessageConverter 类处理

ResourceHttpMessageConverter

读过程:

  • 支持流式读
  • 支持将数据全部加载到字节数组中(可能会导致内存溢出)

写过程:

  • 将数据先写入一个字节数组中(可能会导致内存溢出)


转载来源:https://juejin.cn/post/7494256062766465051

相关文章
|
Java Spring
RestTemplate上传文件解决方案
当对接文件上传模块时,需要对接上传文件的接口,而我们模块的数据是以字节数组存在的(已经操作过了的字节数组,存在于内存中)接口是以form-data的形式上传的,其中需要上传MultipartFIle,如果使用MultipartFile放入到请求的 fromMap中,然后再上传这个文件,会报(ByteArrayInputStream no serialized)的错误,也就是没有注入对应的bean的错误。。
5471 0
|
Java 应用服务中间件
SpringBoot:修改上传文件大小的限制+tomcat
SpringBoot:修改上传文件大小的限制+tomcat
1712 1
|
前端开发
File和MultipartFile互相转化工具类
File和MultipartFile互相转化工具类
2712 0
|
Java API 开发者
微服务——SpringBoot使用归纳——Spring Boot使用slf4j进行日志记录——slf4j 介绍
在软件开发中,`System.out.println()`常被用于打印信息,但大量使用会增加资源消耗。实际项目推荐使用slf4j结合logback输出日志,效率更高。Slf4j(Simple Logging Facade for Java)是一个日志门面,允许开发者通过统一方式记录日志,无需关心具体日志系统。它支持灵活切换日志实现(如log4j或logback),且具备简洁占位符和日志级别判断等优势。阿里巴巴《Java开发手册》强制要求使用slf4j,以保证日志处理方式的统一性和维护性。使用时只需通过`LoggerFactory`创建日志实例即可。
882 0
|
XML JSON Java
springboot文件上传,单文件上传和多文件上传,以及数据遍历和回显
本文介绍了在Spring Boot中如何实现文件上传,包括单文件和多文件上传的实现,文件上传的表单页面创建,接收上传文件的Controller层代码编写,以及上传成功后如何在页面上遍历并显示上传的文件。同时,还涉及了`MultipartFile`类的使用和`@RequestPart`注解,以及在`application.properties`中配置文件上传的相关参数。
springboot文件上传,单文件上传和多文件上传,以及数据遍历和回显
|
存储 前端开发 Java
SpringBoot使用云端资源url下载文件的接口写法
在Spring Boot中实现从云端资源URL下载文件的功能可通过定义REST接口完成。示例代码展示了一个`FileDownloadController`,它包含使用`@GetMapping`注解的方法`downloadFile`,此方法接收URL参数,利用`RestTemplate`下载文件,并将文件字节数组封装为`ByteArrayResource`返回给客户端。此外,通过设置HTTP响应头,确保文件以附件形式下载。这种方法适用于从AWS S3或Google Cloud Storage等云服务下载文件。
1444 7
Springboot Http文件的访问 Url 转换 MultipartFile ,File 转 MultipartFile
Springboot Http文件的访问 Url 转换 MultipartFile ,File 转 MultipartFile
1982 0
java引入本地 MultipartFile 实现多部分文件上传
在Java中,`MultipartFile`通常用于处理通过HTML表单上传的文件。但在某些情况下,需要直接从本地文件系统获取文件并上传。本文介绍如何创建一个实现了`MultipartFile`接口的本地类`LocalMultipartFile`,将本地文件转换为`MultipartFile`对象,简化文件上传流程。此方法适用于批量上传等场景,避免了表单上传的复杂性。代码示例展示了如何实现和使用该类进行文件上传操作。作者:华科云商小彭。链接:[稀土掘金](https://juejin.cn/post/7377559533785530431)。
818 18
|
存储 前端开发 Java
MultipartFile实现文件上传和下载(Springboot)
MultipartFile实现文件上传和下载(Springboot)
1450 0
|
存储 前端开发 Java
基于SpringBoot实现文件上传和下载(详细讲解And附完整代码)
基于SpringBoot实现文件上传和下载(详细讲解And附完整代码)