MultipartFile文件上传 (2) - DispatcherServlet#doDispatch 如何处理Multipart请求

目录

spring启动时的装配过程

StandardServletMultipartResolver

 启动时DispatcherServlet被装载进Tomcat

文件request请求的处理过程

磁盘缓存临时文件的创建

Form-data里不是文件的入参被添加进Request的Parameters集合里

缓存文件的删除


(62条消息) MultipartFile文件上传 (1) - Controller同时处理文件流和附加入参示例-优快云博客icon-default.png?t=N7T8https://blog.youkuaiyun.com/noob_can/article/details/124093033?spm=1001.2014.3001.5502

SpringBoot内嵌Tomcat(3)- 【组件结构及初始化】源码简析icon-default.png?t=N7T8https://my.oschina.net/u/3434392/blog/3213796

上文中,描述了 Tomcat的组件结构:

StandardEngine[Tomcat].StandardHost[localhost].TomcatEmbeddedContext[].StandardWrapper[dispatcherServlet]

 对于整个文件上传请求的处理流程,要结合Tomcat各组件层级结构和它们的加载初始化过程来理解。

spring启动时的装配过程

application.yml

spring.servlet.multipart:
    max-file-size: 10MB # 文件的最大大小
    max-request-size: 50MB # 请求的最大大小
    file-size-threshold: 0  #  文件大小阈值,当大于这个阈值时将写入到磁盘,否则在内存中。 默认值为0

自动装配: org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration

@ConditionalOnClass({ Servlet.class, StandardServletMultipartResolver.class, MultipartConfigElement.class })
@ConditionalOnProperty(prefix = "spring.servlet.multipart", name = "enabled", matchIfMissing = true)
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(MultipartProperties.class)
public class MultipartAutoConfiguration {
  
  

它实例化的3个对象:

  • MultipartProperties :它对上面3个参数有默认赋值。 @EnableConfigurationProperties

  • MultipartConfigElement :由MultipartProperties的参数创建而成,并在DispatcherServletAutoConfiguration里注入给创建的DispatcherServletRegistrationBean对象。

这里因为示例中没有配置“location” 属性, 所以这里初始值为空字符串。 最大文件字节、最大请求字节

  • StandardServletMultipartResolver :request请求的解析处理类,这里是创建的MultipartHttpServletRequest是StandardMultipartHttpServletRequest

StandardServletMultipartResolver

判定有文件流上传请求的依据: request的content-type是以‘multipart/’开头。

public class StandardServletMultipartResolver implements MultipartResolver {

	private boolean resolveLazily = false; // 在multipart类型请求进入时是否立即解析

	public void setResolveLazily(boolean resolveLazily) {
		this.resolveLazily = resolveLazily;
	}
	// 判定request的content-type 是 multipart
	public boolean isMultipart(HttpServletRequest request) {
		return StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/");
	}
    // 封装原request为StandardMultipartHttpServletRequest, 它里面有解析这种请求的处理方法
	@Override
	public MultipartHttpServletRequest resolveMultipart(HttpServletRequest request) throws MultipartException {
		return new StandardMultipartHttpServletRequest(request, this.resolveLazily);
	}
    // 这里是清理缓存文件, 需要配合tomcat的Servlet处理文件流的过程来理解!
	@Override
	public void cleanupMultipart(MultipartHttpServletRequest request) {
		if (!(request instanceof AbstractMultipartHttpServletRequest) ||
				((AbstractMultipartHttpServletRequest) request).isResolved()) {
			// To be on the safe side: explicitly delete the parts, but only actual file parts (for Resin compatibility)
			try {
				for (Part part : request.getParts()) {
					if (request.g
Spring Boot 中处理文件上传时,常用的方式是使用 `MultipartFile` 接口来接收上传的文件。`MultipartFile` 是 Spring 提供的封装,用于处理 HTTP 请求中的文件上传数据。 --- ### ✅ 示例:Spring Boot 接收单个文件上传 ```java import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; @RestController public class FileUploadController { @PostMapping("/upload") public String handleFileUpload(@RequestParam("file") MultipartFile file) { if (file.isEmpty()) { return "文件为空,请选择文件上传"; } try { // 保存文件到服务器 String uploadDir = "uploads/"; File dir = new File(uploadDir); if (!dir.exists()) { dir.mkdirs(); } String filePath = uploadDir + file.getOriginalFilename(); file.transferTo(new File(filePath)); return "文件上传成功: " + file.getOriginalFilename(); } catch (IOException e) { e.printStackTrace(); return "文件上传失败"; } } } ``` --- ### ✅ 示例:接收多个文件上传 ```java @PostMapping("/uploadMultiple") public String handleMultipleUpload(@RequestParam("files") MultipartFile[] files) { if (files.length == 0 || files[0].isEmpty()) { return "没有选择任何文件"; } for (MultipartFile file : files) { try { String filePath = "uploads/" + file.getOriginalFilename(); file.transferTo(new File(filePath)); } catch (IOException e) { e.printStackTrace(); return "部分文件上传失败"; } } return "共上传了 " + files.length + " 个文件"; } ``` --- ### 📌 常用方法说明 | 方法 | 描述 | |------|------| | `String getOriginalFilename()` | 获取上传文件的原始名称 | | `boolean isEmpty()` | 判断文件是否为空 | | `long getSize()` | 获取文件大小(字节) | | `byte[] getBytes()` | 获取文件内容的字节数组 | | `void transferTo(File dest)` | 将上传的文件写入目标文件中 | --- ### ⚙️ 配置文件上传大小限制(application.properties) 默认情况下,Spring Boot 对上传文件大小有限制,可以在 `application.properties` 或 `application.yml` 中调整: ```properties spring.servlet.multipart.enabled=true spring.servlet.multipart.max-file-size=10MB spring.servlet.multipart.max-request-size=10MB ``` > 注意:Spring Boot 2.4 之后使用 `spring.servlet.multipart`,旧版本使用 `spring.http.maxFileSize` 等。 --- ### ✅ 前端请求示例(HTML + FormData) ```html <form enctype="multipart/form-data"> <input type="file" name="file" /> <button type="button" onclick="uploadFile()">上传</button> </form> <script> function uploadFile() { const fileInput = document.querySelector('input[type="file"]'); const formData = new FormData(); formData.append("file", fileInput.files[0]); fetch("/upload", { method: "POST", body: formData }).then(res => res.text()).then(msg => { alert(msg); }); } </script> ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值