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。
1 |
<!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不会重复的新文件名–>文件保存操作–>返回执行结果
1 |
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中进行细节配置。
1 #是否开启文件上传,默认为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