1、功能场景:
文件上传是非常常见的功能,几乎所有的办公系统、文档管理系统、APP、微信公帐号、小程序等都会使用文件上传。
Java文件上传可采用两种方式:
①基于CommonsMultipartResolver使用commons-fileupload,即我们常说的文件流处理。
②基于Servlet3.0,用StandardServletMultipartResolver来处理multipart请求。Spring-boot进一步简化了文件上传配置,提供自动化配置类MultipartAutoConfiguration,所以不需要额外添加jar包,非常简单。文本采用这种方式。
2、技术要点:
①创建Spring-boot项目,并添加最基本的Spring Web依赖。
②在resource/static目录中创建一个upload.html静态网页,用于前端上传附件并提交至文件上传处理接口。
③创建文件上传处理接口FileUploadController用于接收处理文件。
④在src/main下面创建一个webapp文件夹,再在webapp下面创建uploadFile文件夹,用于保存上传的文件,最终形成src/main/webapp/uploadFile目录
⑤application.properties对文件大小、临时存放位置、是否延迟解析等进行配置。(如无特殊需求,可不进行此项操作)
项目结构树为:
3、技术实现:
1、编写upload.html,这是一个很简单的文件上传页面,上传的接口是/upload。
注意:①请求的方法是post,enctype是multipart/form-data。
②input type="file" 行中,单文件上传不需要添加multiple,多文件上传需要添加multiple。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多文件上传</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="uploadFile" value="请选择文件" multiple>
<input type="submit" value="上传">
</form>
</body>
</html>
2、①编写文件创建处理接口,接收upload.html传入的文件,保存在项目运行目录下的uploadFile文件夹,并在文件夹中通过日期对所上传的文件归类保存,即为uploadFile/2021-07-16/文件名(带后缀)。
②为了防止文件重名,我们用UUID对上传文件进行重命名。
③最后我们将新文件的访问路径返回,通过该路径可以直接访问上传的新文件。
代码执行步骤如下:设置文件保存路径-->创建保存文件夹-->循环接收上传的文件-->将原文件名修改为使用UUID不会重复的新文件名-->文件保存操作-->返回执行结果
package com.example.demohelloworld;
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 javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
@RestController
public class FileUploadController {
//POST请求接口为/upload
@PostMapping(value = "/upload",produces = "application/json;charset=utf-8")
//@RequestParam指向前端input file的name,加入HttpServletRequest请求
public String upload(@RequestParam("uploadFile") MultipartFile[] multipartFiles, HttpServletRequest request){
//设置当前日期
String uploaddate= new SimpleDateFormat("yyyy-MM-dd").format(new Date());
//设置文件上传保存文件路径:保存在项目运行目录下的uploadFile文件夹+当前日期
String savepath = request.getSession().getServletContext().getRealPath("/uploadFile/")+uploaddate;
//创建文件夹,当文件夹不存在时,创建文件夹
File folder = new File(savepath);
if(!folder.isDirectory()){
folder.mkdir();
}
//建立一个listmap的返回参数
List<Map<String,Object>> listmap =new ArrayList<>();
//建立一个循环分别接收多文件
for(MultipartFile file:multipartFiles){
//重命名上传的文件,为避免重复,我们使用UUID对文件分别进行命名
String oldname=file.getOriginalFilename();//getOriginalFilename()获取文件名带后缀
//UUID去掉中间的"-",并将原文件后缀名加入新文件
String newname= UUID.randomUUID().toString().replace("-","")
+oldname.substring(oldname.lastIndexOf("."));
//建立每一个文件上传的返回参数
Map<String,Object> map=new HashMap<>();
//文件保存操作
try {
file.transferTo(new File(folder,newname));
//建立新文件路径,在前端可以直接访问如http://localhost:8080/uploadFile/2021-07-16/新文件名(带后缀)
String filepath=request.getScheme()+"://"+request.getServerName()+":"+
request.getServerPort()+"/uploadFile/"+uploaddate+"/"+newname;
//写入返回参数
map.put("[oldname]",oldname);
map.put("[newname]",newname);
map.put("[filepath]",filepath);
map.put("[result]","成功!");
listmap.add(map);
}catch (IOException ex){
//操作失败报错并写入返回参数
ex.printStackTrace();
map.put("[oldname]",oldname);
map.put("[newname]",newname);
map.put("[filepath]","");
map.put("[result]","失败!");
}
}
//将执行结果返回
return listmap.toString();
}
}
3、运行程序,输入http://localhost:8080/upload,选择多文件(如果只能选择单文件,则需要添加multiple,上文有讲述),点击上传,文件上传成功后会返回一个listmap数组,包含[原文件名]、[新文件名]、[新文件访问路径]、[执行结果]。
filepath路径即为新文件的访问路径,可以直接访问。
我们输入这个路径就可以看到刚刚上传的图片。即可以访问上传的静态资源。
4、至此,一个简单的利用Spring-boot实现文件上传功能就做完了。对于新手而言,我们只需要专注于上传业务逻辑,而不需要在配置上花费太多时间。
当然,如果对上传文件大小、临时存放位置、是否延迟解析等有要求,我们可以在application.properties中进行细节配置。
#是否开启文件上传,默认为true spring.servlet.multipart.enabled=true #写入磁盘阈值,默认为0 spring.servlet.multipart.file-size-threshold=0 #上传文件临时存放位置 spring.servlet.multipart.location=D:\\temp #上传的单个文件的最大大小,默认为1MB spring.servlet.multipart.max-file-size=1MB #多文件上传文件的总大小,默认为10MB spring.servlet.multipart.max-request-size=10MB #文件是否延迟解析,默认为false spring.servlet.multipart.resolve-lazily=false