Spring MVC 文件上传
Spring MVC文件上传
在应用系统中,文件上传是非常常用的系统功能,Spring MVC为上传文件提供了良好的支持。首先Spring MVC的文件上传是通过MultipartResolver(Multipart解析器)处理的,MultipartResolver是一个接口,它有两个实现类,具体说明如下:
| 实现类 | 依赖要求 | 备注 |
|---|---|---|
CommonsMultipartResolver |
依赖Apache下的fileupload项目 | 需要导入第三方依赖包 |
StandardServletMultipartResolver |
依赖Servlet3.0及以上版本 | 无需第三方依赖,Spring 3.1后支持 |
StandardServletMultipartResolver上传实现
核心配置类(ServletConfig)
@Configuration
@ComponentScan(basePackages = "com.controller")
@EnableWebMvc // 以注解的方式驱动 Spring MVC(包含注解映射的HandlerMapping及HandlerAdapter等相关组件)
public class ServletConfig implements WebMvcConfigurer {
private final MessageSource messageSource;
public ServletConfig(MessageSource messageSource) {
this.messageSource = messageSource;
}
/**
* 配置静态资源不被拦截
* 静态资源:css, js, 图片, 视频, 音频, 文档
* @param registry 资源处理器
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**") // 静态资源的url:根路径下
.addResourceLocations("/public/"); // 静态资源存放的位置(访问链接无需包含public)
}
/**
* 处理跨域问题(全局),局部跨域使用@CrossOrigin注解
* @param registry 跨域处理器
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 允许所有的请求跨域
.allowedOrigins("http://localhost:5173") // 跨域来源(携带cookie时不可设为*)
.allowedHeaders("*") // 允许所有的请求头
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD") // 允许的请求方式
.allowCredentials(true) // 允许携带cookie
.maxAge(3600); // 跨域访问有效期:1小时
}
/**
* 配置视图解析器
* @param registry 视图解析器
*/
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.viewResolver(
new InternalResourceViewResolver("/WEB-INF/pages/", ".jsp")
);
}
@Bean
public MultipartResolver multipartResolver() {
return new StandardServletMultipartResolver();
}
}
关键说明:
MultipartResolver的Bean名称必须为multipartResolver(Spring约定),若方法名不一致需显式指定:@Bean(name = "multipartResolver")- 该配置类通过
@EnableWebMvc启用注解驱动的Spring MVC,同时配置了静态资源、跨域、视图解析器等基础功能
Servlet容器配置(WebConfig)
StandardServletMultipartResolver需要通过Servlet容器配置启用Servlet3.0的Multipart解析,需继承AbstractAnnotationConfigDispatcherServletInitializer类:
package com.config;
import jakarta.servlet.MultipartConfigElement;
import jakarta.servlet.ServletRegistration;
import org.jspecify.annotations.Nullable;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
/**
* Root WebApplicationContext 配置类
*/
@Override
protected Class<?> @Nullable [] getRootConfigClasses() {
return new Class[]{RootConfig.class};
}
/**
* Servlet WebApplicationContext 配置类
*/
@Override
protected Class<?> @Nullable [] getServletConfigClasses() {
return new Class[]{ServletConfig.class};
}
/**
* 前端控制器 DispatcherServlet 拦截的请求
* /: 所有请求(包含jsp)
* /*: 所有请求(不包含jsp)
* *.suffix:以指定后缀结尾的请求
*/
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
/**
* 设置文件上传的配置
* @param registration Servlet 动态加载配置
*/
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
// 设置允许上传的单个文件大小:5M(-1表示不限制)
var singleMax = 5 * 1024 * 1024;
// 设置允许上传的总文件大小:20M(-1表示不限制)
var totalMax = 20 * 1024 * 1024;
registration.setMultipartConfig(
new MultipartConfigElement(
null, // location:临时文件存放路径(null使用Servlet容器默认目录)
singleMax, // maxFileSize:单个文件最大大小
totalMax, // maxRequestSize:总文件最大大小
0 // fileSizeThreshold:内存阈值(0表示所有文件直接写入临时文件)
)
);
}
}
MultipartConfigElement参数说明:
| 参数 | 说明 |
|---|---|
| location | 临时文件存放路径(未完成上传/超出内存阈值的文件),null使用容器默认目录(需保证目录有读写权限) |
| maxFileSize | 单个文件最大大小(字节),-1表示无限制 |
| maxRequestSize | 单次请求总文件大小(字节),-1表示无限制 |
| fileSizeThreshold | 内存阈值,超过该值的文件写入临时目录,0表示所有文件直接写入临时文件 |
控制器实现(FileController)
package com.controller;
import com.response.ResponseResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
@RestController
public class FileController {
@PostMapping("/file/upload")
public ResponseResult upload(MultipartFile[] avatar) throws IOException {
if(avatar != null) {
var paths = new ArrayList<String>();
for(var file : avatar) {
if(!file.isEmpty()) {
// 替换为实际的文件存储路径
var target = new File("你自己的路径" + file.getOriginalFilename());
file.transferTo(target); // 保存文件到指定路径
// 构造文件访问URL(需与静态资源配置对应)
paths.add("http://localhost:8080/avatar/" + file.getOriginalFilename());
}
}
return ResponseResult.ok(paths);
}
return ResponseResult.fail("上传文件为空");
}
}
说明:
- 接收前端传递的多文件(参数名
avatar需与前端FormData的key一致) - 通过
file.transferTo(target)方法将文件保存到指定路径 - 返回文件访问URL列表或错误信息
前端实现(Vue3)
<template>
<div>
<input type="file" name="avatar"/> <br/>
<input type="file" name="avatar"/> <br/>
<input type="file" name="avatar"/> <br/>
<button @click="handleClick()">上传</button>
</div>
</template>
<script setup>
import request from '@/utils/request';
async function handleClick() {
// 获取所有文件输入框
let nodes = document.getElementsByName("avatar")
let files = []
// 收集非空文件
for (let element of nodes) {
let file = element.files[0]
if (file) files.push(file)
}
console.log(files)
// 构造FormData(文件上传必须使用FormData格式)
const params = new FormData()
for(let file of files) {
console.log(file)
params.append("avatar", file) // key需与后端接口参数名一致
}
console.log(params)
// 发送文件上传请求
const {data: result} = await request.post("/file/upload", params, {
headers: {
'Content-Type': 'multipart/form-data' // 显式指定内容类型
}
})
console.log(result.data)
}
</script>
关键注意事项(request.js配置)
请求拦截器中禁止手动设置Content-Type,需由浏览器自动处理(FormData格式会自动生成正确的Content-Type并包含边界标识):
// request.js 正确配置示例
request.interceptors.request.use(
(config) => {
// 错误示例(若存在需删除):
// config.headers['Content-Type'] = 'application/json'
// config.headers['Content-Type'] = 'multipart/form-data'
// 正确做法:只添加token等通用请求头,不修改Content-Type
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
(error) => Promise.reject(error)
)
使用StandardServletMultipartResolver实现Spring MVC文件上传的核心步骤:
- 配置
MultipartResolver的Bean(名称必须为multipartResolver) - 通过
WebConfig配置文件上传的大小限制、临时目录等参数 - 编写控制器接收并处理上传文件
- 前端使用FormData格式提交文件,且不手动设置
Content-Type - 确保跨域、静态资源访问等基础配置正确

浙公网安备 33010602011771号