Springboot文件上传功能的实现
作者:Starbright. 发布时间:2021-09-20 12:48:47
1.新建文件上传页面
在static目录中新建upload-test.html,上传页面代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>springboot文件上传测试</title>
</head>
<body>
<form action="/uploadFile" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<input type="submit" value="文件上传" />
</form>
</body>
</html>
其中后端处理文件上传的请求地址为/uploadFile,请求方法为POST。在文件上传时需要设置form表单的enctype属性为“multipart/form-data”。
效果图如下:
2.新建文件上传处理Controller类
在controller包下新建UploadController类并编写实际的文件上传逻辑代码,如下所示:
package ltd.newbee.mall.controller;
import ltd.newbee.mall.util.PageResult;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
@Controller
public class UploadController {
//文件保存路径为在D盘下的upload文件夹,可以按照自己的习惯修改
private final static String FILE_UPLOAD_PATH = "D:\\upload\\";
@RequestMapping(value = "/uploadFile",method = RequestMethod.POST)
@ResponseBody
public String uploadFile(@RequestParam("file") MultipartFile file){
if (file.isEmpty()){
return "文件上传失败";
}
String fileName = file.getOriginalFilename();
String suffixName = fileName.substring(fileName.lastIndexOf("."));
//生成文件名称通用方法
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
Random r = new Random();
StringBuilder tempName = new StringBuilder();
tempName.append(sdf.format(new Date())).append(r.nextInt(100)).append(suffixName);
String newFileName = tempName.toString();
try {
//保存文件
byte[] bytes = file.getBytes();
Path path = Paths.get(FILE_UPLOAD_PATH+newFileName);
Files.write(path,bytes);
}catch (IOException e){
e.printStackTrace();
}
return "上传成功";
}
}
由于Spring Boot已经自动配置了StandardServletMultipartResolver类来处理文件上传请求,因此能够直接在控制器方法中使用MultipartFile读取文件信息。 @RequestParam中文件名称属性需要与前端页面中input文件输入框设置的name属性一致。如果文件为空则返回上传失败,如果不为空则根据日期生成一个新的文件名,读取文件流程并写入指定的路径中,最后返回上传成功的提示信息。
需要注意的是文件上传路径的设置。在上述代码中设置的文件保存路径为D:\upload\,即在D盘下的upload文件夹。如果项目部署在Linux系统中的话,写法与此不同。比如想要把文件上传到/opt/newbee/upload目录下,就需要把路径设置的代码改为private final static String FILE_UPLOAD_PATH = “/opt/newbee/upload/”。这一点需要注意,两种系统的写法存在一些差异。如果文件存储目录还没有创建的话,首先需要创建该目录,然后启动项目进行文件上传测试。
3.文件上传功能测试
在编码完成后,启动Spring Boot项目。在启动成功后,打开浏览器并输入测试页面地址:
http://localhost:8080/upload-test.html
打开后选择上传的文件,然后上传,显示成功。
检查本机upload目录下是否有改文件(注意这里需要在对应的位置建立好upload文件夹)
另外,在Spring Boot项目中支持单个文件的最大值默认为1MB,支持单个请求最大值默认10 MB。如果选择了大于默认值的文件进行上传,比如一个1.2MB的文件或者一个11MB的请求,就会报错。
4.文件上传路径回显
Spring Boot项目与普通Spring项目的目录结构不同,并没有webapp目录,因此无法与普通的Java Web项目一样,上传文件到webapp目录中并直接根据目录进行访问。Spring Boot项目中通常使用自定义静态资源映射目录,以此来实现文件上传整个流程的闭环。比如在前文文件上传案例中,在文件上传到upload目录后,会增加一个自定义静态资源映射配置,使得在upload下的静态资源可以通过该映射地址被访问到。
新建config包并在config包中新增SpringBootWebMvcConfigurer类,实现代码如下所示:
package ltd.newbee.mall.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class SpringBootWebMvcConfigurer implements WebMvcConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry){
registry.addResourceHandler("/upload/**").addResourceLocations("file:D:\\upload\\");
}
}
通过以上代码配置,所有以“/upload/”开头的静态资源在请求时都会映射到D盘的upload目录下。路径的设置与前文中上传文件的设置目录类似,不同系统的文件路径的写法不同(比如Linux和Windows)。同时需要注意在设置静态资源映射路径时,路径前需要添加“file:”前缀。
最后修改一下在文件上传时的返回信息,把路径拼装好并返回到页面上,以便于功能测试,UploadController代码的修改如下所示:
return "上传成功,地址为:/upload/"+newFileName;
最后启动项目进行测试
检查对应目录下是否有文件
上传成功完成。
5.多文件上传功能实现
首先,在static目录中新建upload-same-file-name.html,页面代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多文件上传测试(文件名相同)</title>
</head>
<body>
<form action="/uploadFilesBySameName" method="post" enctype="multipart/form-data">
<input type="file" name="files"/><br><br>
<input type="file" name="files"/><br><br>
<input type="file" name="files"/><br><br>
<input type="file" name="files"/><br><br>
<input type="file" name="files"/><br><br>
<input type="submit" value="文件上传"/>
</form>
</body>
</html>
多文件上传页面与单文件上传页面类似,不同点是新增了4个文件输入框,文件输入框的name属性统一命名为files,文件名完全一致。后端处理文件上传的请求地址为/uploadFilesBySameName,请求方法为POST。
在UploadController类中新增uploadFilesBySameName()方法,用于处理在文件名相同时的多文件上传问题,新增代码如下所示:
@RequestMapping(value = "/uploadFileBySameName",method = RequestMethod.POST)
@ResponseBody
public String uploadFileBySameName(@RequestPart MultipartFile[] files){
if (files == null|| files.length==0){
return "参数错误";
}
if (files.length>5){
return "文件最多上传5个";
}
String uploadResult = "上传成功,地址为:<br>";
for (MultipartFile file:files){
String fileName = file.getOriginalFilename();
if (StringUtils.isEmpty(fileName)){
//表示无文件信息,跳出当前循环
continue;
}
String suffixName = fileName.substring(fileName.lastIndexOf("."));
//生成文件名称的通用方法
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
Random r = new Random();
StringBuilder tempName = new StringBuilder();
tempName.append(sdf.format(new Date())).append(r.nextInt(100)).append(suffixName);
String newFileName = tempName.toString();
try {
//保存文件
byte[] bytes = file.getBytes();
Path path = Paths.get(FILE_UPLOAD_PATH+newFileName);
Files.write(path,bytes);
uploadResult += "/upload/" + newFileName + "<br>";
}catch (IOException e){
e.printStackTrace();
}
}
return uploadResult;
}
与单文件在上传时的uploadFile()方法相比,多文件上传有两处改动。
第一,文件参数在接收时的代码改动。在多文件上传并接收参数时使用的是@RequestPart注解,且接收的文件参数是一个数组MultipartFile。而单文件在上传时使用的是@RequestParam注解,接收的文件是单个对象。
第二,文件在保存时增加循环逻辑。多文件保存的处理方式与单文件在上传时比较类似,只是增加了循环逻辑,对接收的MultipartFile数组中每一个文件进行存储操作,最后拼接文件的地址信息并返回。
另外一个需要注意的知识点,多文件上传在接收参数时,参数名称files需要完全对应input框中的name属性。比如本次演示,在upload-same-file-name.html文件中所有文件输入框的name属性都是files;在后端处理时,uploadFilesBySameName()方法的参数名称也定义为files,两个名称是对应的。如果所有文件输入框的name属性都改为uploadFiles,那么uploadFilesBySameName()方法的参数名称也需要改为uploadFiles,否则接收的文件对象数组为空。
在编码完成后,启动Spring Boot项目。在在启动成功后打开浏览器并输入多图上传的测试页面地址:
http://localhost:8080/upload-same-file-name.html
实际效果:
6.文件名不同时的多文件上传处理
首先,在static目录中新建upload-different-file-name.html,页面代码如下所示:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>多文件上传测试(文件名不同)</title>
</head>
<body>
<form action="/uploadFilesByDifferentName" method="post" enctype="multipart/form-data">
<input type="file" name="files1"/><br><br>
<input type="file" name="files2"/><br><br>
<input type="file" name="files3"/><br><br>
<input type="file" name="files4"/><br><br>
<input type="file" name="files5"/><br><br>
<input type="submit" value="文件上传"/>
</form>
</body>
</html>
然后,在UploadController类中新增uploadFilesByDifferentName()方法,用于处理文件名在不相同时的多文件上传,新增代码如下所示:
@RequestMapping(value = "/uploadFilesByDifferentName",method = RequestMethod.POST)
@ResponseBody
public String uploadFilesByDifferentName(HttpServletRequest httpServletRequest Request){
List<MultipartFile> multipartFiles = new ArrayList<>(8);
//如果不是文件上传请求则不处理
if (!standardServletMultipartResolver.isMultipart(httpServletRequest)){
return "请选择文件";
}
//将HttpServletRequest 对象转换为MultipartHttpServletRequest对象,并读取文件
MultipartHttpServletRequest multiRequest =(MultipartHttpServletRequest)httpServletRequest;
Iterator<String> iter = multiRequest.getFileNames();
int total=0;
while (iter.hasNext()){
if (total>5) {
return "最多上传5个文件";
}
total+=1;
MultipartFile file = multiRequest.getFile(iter.next());
multipartFiles.add(file);
}
if (CollectionUtils.isEmpty(multipartFiles)) {
return "请选择文件";
}
if (multipartFiles != null && multipartFiles.size()>5){
return "文件最多上传5个";
}
String uploadResult = "上传成功,地址为:<br>";
for(int i=0;i<multipartFiles.size();i++){
String fileName = multipartFiles.get(i).getOriginalFilename();
if (StringUtils.isEmpty(fileName)){
//表示无文件信息,跳出当前循环
continue;
}
String suffixName = fileName.substring(fileName.lastIndexOf("."));
//生成文件名称的通用方法
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss");
Random r = new Random();
StringBuilder tempName = new StringBuilder();
tempName.append(sdf.format(new Date())).append(r.nextInt(100)).append(suffixName);
String newFileName = tempName.toString();
try {
//保存文件
byte[] bytes = multipartFiles.get(i).getBytes();
Path path = Paths.get(FILE_UPLOAD_PATH+newFileName);
Files.write(path,bytes);
uploadResult += "/upload/" + newFileName + "<br>";
}catch (IOException e){
e.printStackTrace();
}
}
return uploadResult;
}
与文件名相同时的多文件上传的uploadFilesBySameName()方法相比,文件名不同时的改动只有一处,即文件参数在接收时的代码做了改动。在读取文件信息时的逻辑是自行实现的代码逻辑,首先调用isMultipart()方法判断当前请求是否为文件上传请求,如果不是则不进行处理,如果是文件上传请求,则HttpServletReques对象转换为MultipartHttpServletRequest对象,并读取文件数据,在读取完成后再依次进行存储。存储文件的过程与之前的逻辑一致,最后拼接文件的地址信息并返回。
另外,需要判断当前请求是否为文件上传请求时要用到StandardServletMultipart Resolver类isMultipart()方法。前文中提到的StandardServletMultipartResolver类已经自动配置,所以可以直接在UploadController类中使用@Autowired注解注入,代码如下所示:
@Autowired
private StandardServletMultipartResolver standardServletMultipartResolver;
测试成功
来源:https://blog.csdn.net/LingDIHong/article/details/130090563


猜你喜欢
- 当只需要两个图像合并的时候,可以简单的使用gdi+,把两个图像画到一个画布上面实现合并bitmap.当需要将许多bitmap合并时,由于bi
- 基于 kotlin/coroutine/retrofit/jetpack 打造,100来行代码,用法超级简单舒适设置默认Retrofit工厂
- 什么是反射?反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动
- 方式一:基于现有控件进行扩展,如基于button进行扩展,UI可直接用xmal进行编辑设计,逻辑用xaml.cs进行编辑方法二:直接创建wp
- MyBatis-Plus是通过version机制实现乐观锁的。大致思路:取出记录,携带记录的当前version;更新记录的时候,比较记录当前
- 详解java 中Spring jsonp 跨域请求的实例jsonp介绍  
- SpringMVC * path路径的坑SpringMVC提供了很方便的 * 供我们开发使用。在配置文件中通过<mvc:mapping
- 背景工作中遇到业务诉求是通过OpenCV对图片进行一些判断操作和优化,这里是看了部分不错的文章,希望总结一个自己的学习过程,温故而知新,有不
- 前文说到 优雅的使用枚举参数 和 实现原理,本文继续说一下如何在 RequestBody 中优雅使用枚举。本文先上实战,说一下如何实现。在
- Java的集合类是一种特别有用的工具,它可以用于存储数量不等的多个对象,并可以实现常用的数据结构,如栈、队列等。Java集合还可以用于板寸具
- 目录1、简介2、适用情况3、mybatis-plus前期准备(工程将以 H2 作为默认数据库进行演示)1、使用 Spring Initial
- 在编写脚本的过程中我们会遇到一些小问题比如一个的变量 为了在其他脚本中可以调用 我们需要写成public类型的这样的话在Inspector面
- Android 实现全屏显示的几种方法整理A、设置主题实现全屏直接在AndroidManifest.xml文件中设定Activity主题为全
- 在android studio中存储数据有三个方法,分别是:(1)简单存储——SharedPreferences(2)文件存储:内部存储——
- 本文实例为大家分享了Java使用开源Rxtx实现串口通讯的具体代码,供大家参考,具体内容如下使用方法:windows平台:1、把rxtxPa
- 1、spring原理内部最核心的就是IOC了,动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射,反射其
- java实现数据加密问题,具体代码如下所示:package Array;import java.util.Scanner;/*某个公司采用电
- 一、 简介Opitonal是java8引入的一个新类,目的是为了解决空指针异常问题。本质上,这是一个包含有可选值的包装类,这意味着 Opti
- 概述事务管理对于企业应用来说是至关重要的,即使出现异常情况,它也可以保证数据的一致性。Spring Framework对事务管理提供了一致的
- HashMap的get()方法的NullPointerException今天写代码发现一个 bug,HashMap的 get() 方法一直报