前言
需要实现文件上传功能需要 MultipartResolver
接口的实现类的实例,这样才可以实现文件上传
而 MultipartResolver
有两个实现类:
StandardServletMultipartResolver
:springboot 中以自动配置完成,直接使用即可CommonsMultipartResolver
:springmvc中使用的是CommonsMultipartResolver,需要在springmvc中配置其bean,其兼容性较好,也是传统ssm中使用
而在 MultipartAutoConfiguration 类中为 springboot 配置了其 StandardServletMultipartResolver
的bean
@AutoConfiguration
@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 {
@Bean(
name = {"multipartResolver"}
)
@ConditionalOnMissingBean({MultipartResolver.class})
public StandardServletMultipartResolver multipartResolver() {
StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();
multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());
return multipartResolver;
}
}
在配置文件中可以通过 spring.servlet.multipart.
来配置文件上传设置。
第一种 单文件上传
1、页面准备
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/load" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="上传">
</form>
</body>
</html>
在 from 表单中通过 enctype 来设置表单的数据构成,
multipart/form-data
:是指表单数据有多部分构成,既有文本数据,又有文件等二进制数据的意思。
默认情况下,enctype
的值是 application/x-www-form-urlencoded
,不能用于文件上传,只有使用了 multipart/form-data
,才能完整的传递文件数据。
文件上传输入框中必须要有 name 属性,且控制器方法中的参数名也需和 name 属性值对应,否则传输到控制器中不存在。
2、控制器方法
@RestController
public class UploadFileController {
//设置时间格式
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
@PostMapping("/load")
public String upload(MultipartFile file, HttpServletRequest req){//参数名需要与form表单中设置的 name属性值对应上,否则获取到的为null
//1、处理文件位置
//文件存放位置
String realPath = req.getServletContext().getRealPath("/");
//按照时间格式划分
String format = sdf.format(new Date());
String path = realPath + format;
//文件夹
File folder = new File(path);
//判断文件是否存在
if (!folder.exists()){//不存在,则创建
//这里需要使用mkdirs,因为为多层目录
folder.mkdirs();
}
//2、处理文件名
//获取文件后缀+文件名
String oldName = file.getOriginalFilename();
//将后缀加到新的文件名上
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
//文件保存
file.transferTo(new File(folder,newName));
//获取请求协议 获取主机名 获取端口
String s = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + format + newName;//文件的访问路径
return s;
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}
第二种 多文件上传
方式一:一步多文件
1、页面准备
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/load2" method="post" enctype="multipart/form-data">
<input type="file" name="files" multiple>
<input type="submit" value="上传">
</form>
</body>
</html>
在页面中将输入文件框中添加 mutiple
属性,表示可以上传多个文件
文件上传输入框中必须要有 name 属性,且控制器方法中的参数名也需和 name 属性值对应,否则传输到控制器中不存在。
2、控制器方法
@RestController
public class UploadFileController2 {
//设置时间格式
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
@PostMapping("/load2")
public void upload(MultipartFile[] files, HttpServletRequest req){//参数名需要与form表单中设置的 name属性值对应上,否则获取到的为null
//1、处理文件位置
//文件存放位置
String realPath = req.getServletContext().getRealPath("/");
//按照时间格式划分
String format = sdf.format(new Date());
String path = realPath + format;
//文件夹
File folder = new File(path);
//判断文件是否存在
if (!folder.exists()){//不存在,则创建
//这里需要使用mkdirs,因为为多层目录
folder.mkdirs();
}
try {
for (MultipartFile file : files) {
//2、处理文件名
//获取文件后缀+文件名
String oldName = file.getOriginalFilename();
//将后缀加到新的文件名上
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
//文件保存
file.transferTo(new File(folder, newName));
//获取请求协议 获取主机名 获取端口
String s = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + format + newName;//文件的访问路径
System.out.println("s = " + s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
与单文件上传类似,不过在文件保存时,需要放在循环中,依次保存
异常捕获 与 循环同时存在时,需要将 循环放置于 异常捕获中,这样效率高一点
方式二:多步多文件
1、页面准备
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/load3" method="post" enctype="multipart/form-data">
<input type="file" name="file1">
<input type="file" name="file2">
<input type="submit" value="上传">
</form>
</body>
</html>
在页面中设置多个 文件上传框,来实现多文件上传
2、控制器方法
@RestController
public class UploadFileController3 {
//设置时间格式
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
@PostMapping("/load3")
public void upload(MultipartFile file1,MultipartFile file2, HttpServletRequest req){//参数名需要与form表单中设置的 name属性值对应上,否则获取到的为null
//1、处理文件位置
//文件存放位置
String realPath = req.getServletContext().getRealPath("/");
//按照时间格式划分
String format = sdf.format(new Date());
String path = realPath + format;
//文件夹
File folder = new File(path);
//判断文件是否存在
if (!folder.exists()){//不存在,则创建
//这里需要使用mkdirs,因为为多层目录
folder.mkdirs();
}
//2、处理文件名
//获取文件后缀+文件名
String oldName1 = file1.getOriginalFilename();
//将后缀加到新的文件名上
String newName1 = UUID.randomUUID().toString() + oldName1.substring(oldName1.lastIndexOf("."));
try {
//文件保存
file1.transferTo(new File(folder,newName1));
//获取请求协议 获取主机名 获取端口
String s = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + format + newName1;//文件的访问路径
System.out.println("s = " + s);
} catch (IOException e) {
e.printStackTrace();
}
//2、处理文件名
//获取文件后缀+文件名
String oldName2 = file2.getOriginalFilename();
//将后缀加到新的文件名上
String newName2 = UUID.randomUUID().toString() + oldName2.substring(oldName2.lastIndexOf("."));
try {
//文件保存
file2.transferTo(new File(folder,newName2));
//获取请求协议 获取主机名 获取端口
String s = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + format + newName2;//文件的访问路径
System.out.println("s = " + s);
} catch (IOException e) {
e.printStackTrace();
}
}
}
在控制器方法中的参数,需要设置相同名称、数量的参数来与页面中文件上传框中对应
第三种 ajax文件上传
此方式也可进行多文件上传,方式与上述差不多。
1、页面准备
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://code.jquery.com/jquery-3.7.0.js" integrity="sha256-JlqSTELeR4TLqP0OG9dxM7yDPqX1ox/HfgiSLBj8+kM=" crossorigin="anonymous"></script>
</head>
<body>
<div id="result"></div>
<input type="file" id="file">
<input type="button" value="上传" onclick="fileUpLoad()">
<script>
function fileUpLoad() {
var file = $("#file")[0].files[0];
var formData = new FormData();
formData.append("file",file);
$.ajax({
type:'post',
url:'/loadajax',
processData:false,
contentType:false,
data:formData,
success:function (msg){
$("#result").html(msg);
}
})
}
</script>
</body>
</html>
2、控制器方法
public class AjaxUploadFileController {
//设置时间格式
SimpleDateFormat sdf = new SimpleDateFormat("/yyyy/MM/dd/");
@PostMapping("/loadajax")
public String upload(MultipartFile file, HttpServletRequest req){//参数名需要与form表单中设置的 name属性值对应上,否则获取到的为null
//1、处理文件位置
//文件存放位置
String realPath = req.getServletContext().getRealPath("/");
//按照时间格式划分
String format = sdf.format(new Date());
String path = realPath + format;
//文件夹
File folder = new File(path);
//判断文件是否存在
if (!folder.exists()){//不存在,则创建
//这里需要使用mkdirs,因为为多层目录
folder.mkdirs();
}
//2、处理文件名
//获取文件后缀+文件名
String oldName = file.getOriginalFilename();
//将后缀加到新的文件名上
String newName = UUID.randomUUID().toString() + oldName.substring(oldName.lastIndexOf("."));
try {
//文件保存
file.transferTo(new File(folder,newName));
//获取请求协议 获取主机名 获取端口
String s = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + format + newName;//文件的访问路径
return s;
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
}