SpringMVC-文件上传

准备工作

首先对于表单中的enctype属性做一个了解

  1. application/x-www=form-urlencoded:默认方式,只处理表单中的value的属性值,采用这种编码方式的表单会将表单域中的值处理成URL编码方式
  2. multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会将文件域中的文件夜风撞到请求参数中
  3. text/plain:除了把空格改为“+”号外,其他字符不做编码处理,这种方式适合直接通过表单来发送邮件

文件上传是一个web项目中很常见的功能,在springmvc中有着很好的支持,但是springmvc默认上下文没有配置MultipartResolver,所以在做文件上传和下载前,需要配置MultipartResolver,

  1. 在原有包的基础上导入此包
1
2
3
4
5
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.3</version>
</dependency>
  1. 注册MultipartResolver实例,id必须为multipartResolver,id必须为multipartResolver,id必须为multipartResolver,不然报错
1
2
3
4
5
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="UTF-8"/>
<property name="maxUploadSize" value="10485760"/>
<property name="maxInMemorySize" value="40960"/>
</bean>

以下就不赘述springMVC的配置文件了

上传单个文件

页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>单个文件上传</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/singleFileUpload.do" method="post" enctype="multipart/form-data">
<p>
<input type="file" name="avatar" id="avatar">
</p>
<p>
<input type="submit">
</p>
</form>
</body>
</html>

controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@PostMapping("/singleFileUpload.do")
public String singleFileUploadDo(@RequestParam(value = "avatar",required = false) CommonsMultipartFile avatar,HttpServletRequest req, Model model) throws IOException {
//真实的保存上传文件的文件夹
String realSaveDirPath = req.getSession().getServletContext().getRealPath("/upload");
File dir = new File(realSaveDirPath);
if(!dir.exists()){
dir.mkdirs();
}
//文件的全称,包括后缀
String avatarWholeName = avatar.getOriginalFilename();
//文件的后缀
String suffix = avatarWholeName.substring(avatarWholeName.lastIndexOf('.')+1);
//这里可以对文件后缀做出一些逻辑处理,这里就不作处理了
//这里为了保证文件名一定不一致,所以加入一个UUID随机值
String uuidPath = UUID.randomUUID().toString().replaceAll("-","");
String realFileName = uuidPath.concat(avatarWholeName);
//文件的真实保存全路径
String realSavePath = realSaveDirPath.concat("/").concat(realFileName);
//这里也可以自己用流读写
avatar.transferTo(new File(realSavePath));
return "singleFileUpload";
}

上传多个文件

其实和上传单个文件很像,只要input控件的name属性是一样的,那它们就是一组,下面来看看代码

controller:(两法,个人偏向于第二种)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@PostMapping("/multiFileUpload.do")
public String multiFileUploadDo(@RequestParam(value = "file",required = false) CommonsMultipartFile[] files,HttpServletRequest req, Model model) throws IOException {
//真实的保存上传文件的文件夹
String realSaveDirPath = req.getSession().getServletContext().getRealPath("/upload/multipart");
File dir = new File(realSaveDirPath);
if(!dir.exists()){
dir.mkdirs();
}
for (int i = 0; i < files.length; i++) {
//文件的全称,包括后缀
String avatarWholeName = files[i].getOriginalFilename();
//文件的后缀
String suffix = avatarWholeName.substring(avatarWholeName.lastIndexOf('.')+1);
//这里可以对文件后缀做出一些逻辑处理,这里就不作处理了
//这里为了保证文件名一定不一致,所以加入一个UUID随机值
String uuidPath = UUID.randomUUID().toString().replaceAll("-","");
String realFileName = uuidPath.concat(avatarWholeName);
//文件的真实保存全路径
String realSavePath = realSaveDirPath.concat("/").concat(realFileName);
//这里也可以自己用流读写
files[i].transferTo(new File(realSavePath));
}
return "multiFileUpload";
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@PostMapping("/multiFileUpload.do")
public Map multiFileUploadDo(HttpServletRequest request) throws IOException {
String realPath = request.getServletContext().getRealPath("\\multipartUpload")+"\\";
CommonsMultipartResolver cmr = new CommonsMultipartResolver(request.getServletContext());
if(cmr.isMultipart(request)){
MultipartHttpServletRequest req = (MultipartHttpServletRequest) request;
MultiValueMap<String, MultipartFile> multiFileMap = req.getMultiFileMap();
for (String fieldName : multiFileMap.keySet()) {
String uuidPath = UUID.randomUUID().toString().replaceAll("-","");
//创建存放文件的文件夹
File dir = new File(realPath + uuidPath + fieldName);
dir.mkdirs();
List<MultipartFile> multipartFiles = multiFileMap.get(fieldName);
for (MultipartFile f : multipartFiles) {
//如果文件为空,则忽略,不然会报错
if(!f.isEmpty()){
f.transferTo(new File(dir.getPath()+"\\"+f.getOriginalFilename()));
}
}
}
}
return "multiFileUpload";
}

页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/multiFileUpload.do" method="post" enctype="multipart/form-data">
<p>
<input type="file" name="file">
</p>
<p>
<input type="file" name="file">
</p>
<p>
<input type="file" name="file">
</p>
<p>
<input type="file" name="file">
</p>
<p>
<input type="submit">
</p>
</form>
</body>
</html>

以上都是同步提交,下面我们使用异步提交并且将图片预览出来,这次只演示单个文件上传,多个文件上传同理。

异步提交并提供预览

Controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@PostMapping("/reg.do")
@ResponseBody
public Map reg(User user,String relativePath){
user.setAvatarUrl("\\upload\\".concat(relativePath));
HashMap<String, String> map = new HashMap<>();
System.out.println(user);
map.put("result","success");
return map;
}

@PostMapping("/singleFileUpload.do")
@ResponseBody
public Map singleFileUploadDo(@RequestParam(value = "avatar",required = false)CommonsMultipartFile avatar,
HttpServletRequest req) throws IOException {
Map<String, String> map = new HashMap<>();
if(avatar==null||avatar.isEmpty()){
map.put("result","fail");
return map;
}
//真实的保存上传文件的文件夹
String realSaveDirPath = req.getSession().getServletContext().getRealPath("/upload");
File dir = new File(realSaveDirPath);
if(!dir.exists()){
dir.mkdirs();
}
//文件的全称,包括后缀
String avatarWholeName = avatar.getOriginalFilename();
//文件的后缀
String suffix = avatarWholeName.substring(avatarWholeName.lastIndexOf('.')+1);
//这里可以对文件后缀做出一些逻辑处理,这里就不作处理了
//这里为了保证文件名一定不一致,所以加入一个UUID随机值
String uuidPath = UUID.randomUUID().toString().replaceAll("-","");
String realFileName = uuidPath.concat(avatarWholeName);
//文件的真实保存全路径
String realSavePath = realSaveDirPath.concat("/").concat(realFileName);
//这里也可以自己用流读写
avatar.transferTo(new File(realSavePath));
map.put("result","success");
//用来给页面显示图片
map.put("relativePath","\\upload\\".concat(realFileName));
//用来给前端判断是否需要再次上传
map.put("fileName",avatarWholeName);
return map;
}

页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>单个文件上传</title>
</head>
<body>
<form id="form" action="${pageContext.request.contextPath}/singleFileUpload.do" method="post" enctype="multipart/form-data">
<p>
<input type="text" placeholder="请输入用户名" name="userName" id="userName">
</p>
<p>
<input type="number" placeholder="请输入年龄" name="age" id="age">
</p>
<p>
<input type="file" name="avatar" id="avatar">
<div style="display: none" id="showimgcontainer">
<img id="showimg" width="400px" height="400px" style="border: solid 1px black"/>
</div>
</p>
<p>
<input type="button" id="submitBtn" value="注册">
</p>
</form>
<script src="${pageContext.request.contextPath}/static/js/jquery.min.js"></script>
<script src="${pageContext.request.contextPath}/static/js/jquery.form.min.js"></script>
<script type="text/javascript">
let fileName;
let relativePath;
$('#avatar').change(()=>{
if(fileName===$('#avatar')[0].files[0].name){
return;
}
let options = {
url: '${pageContext.request.contextPath}/singleFileUpload.do',
dataType:'text',
success(data){
data = JSON.parse(data);
if(data.result==='fail'){
alert("文件为空或者不存在");
return;
}
relativePath = data.relativePath;
fileName = data.fileName;
$('#showimgcontainer').show();
$('#showimg').attr('src',relativePath);
}
}
$('#form').ajaxSubmit(options);
})

$('#submitBtn').click(()=>{
$.ajax({
url: '${pageContext.request.contextPath}/reg.do',
method:'post',
data: {relativePath:relativePath,userName:$('#userName').val(),age:$('#age').val()},
success(data) {
if(data.result==='success'){
alert("注册成功");
window.location = '${pageContext.request.contextPath}/login';
}else {
alert("出错!请重试!");
}
}
})
})
</script>
</body>
</html>
给作者买杯咖啡吧~~~