文件上传

Spring MVC对文件上传做了简化,在Spring Boot中对此做了更进一步的简化,文件上传更为方便。

Java中的文件上传一共涉及两个组件,一个是CommonsMultipartResolver,另一个是StandardServletMultipartResolver,其中 CommonsMultipartResolver使用commons-fileupload来处理multipart 请求,而StandardServletMultipartResolver则是基于Servlet 3.0来处理multipart 请求的,因此若使用StandardServletMultipartResolver,则不需要添加额外的jar包。Tomcat 7.0开始就支持Servlet 3.0 了,因此可以直接使用StandardServletMultipartResolver。而在Spring Boot 提供的文件上传自动化配置类MultipartAutoConfiguration中,默认也是采用StandardServletMultipartResolver,部分源码如下:

public class MultipartAutoConfiguration {...@Bean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME)@ConditionalOnMissingBean(MultipartResolver.class)public StandardServletMultipartResolver multipartResolver() {StandardServletMultipartResolver multipartResolver = new StandardServletMultipartResolver();multipartResolver.setResolveLazily(this.multipartProperties.isResolveLazily());return multipartResolver;}}

根据这里的配置可以看出,如果开发者没有提供 MultipartResolver,那么默认采用的MultipartResolver就是StandardServletMultipartResolver。因此,在Spring Boot中上传文件甚至可以做到零配置。下面来看具体上传过程。

1. 单文件上传

1.1 单文件上传简单实现

首先创建一个Spring Boot项目并添加spring-boot-starter-web 依赖。
然后在resources目录下的static目录中创建一个upload.html文件,内容如下:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title></head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data"><input type="file" name="uploadFile" value="请选择文件"><input type="submit" value="上传">
</form>
</body>
</html>

这是一个很简单的文件上传页面,上传接口是/upload,注意请求方法是 post,enctype是multipart/form-data。

enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。

默认地,表单数据会编码为 “application/x-www-form-urlencoded”。就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 “+” 加号,特殊符号转换为 ASCII HEX 值)。

描述
application/x-www-form-urlencoded 在发送前编码所有字符(默认)
multipart/form-data 不对字符编码。在使用包含文件上传控件的表单时,必须使用该值。
text/plain 空格转换为 “+” 加号,但不对特殊字符编码。

接着创建文件上传处理接口,代码如下:

@RestController
public class FileUploadController {SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");@PostMapping("/upload")public String upload(MultipartFile uploadFile, HttpServletRequest req) {String realPath =req.getSession().getServletContext().getRealPath("/uploadFile/");String format = sdf.format(new Date());File folder = new File(realPath + format);String filePath="";if (!folder.isDirectory()) {folder.mkdirs();String oldName = uploadFile.getOriginalFilename();String newName = UUID.randomUUID().toString() +oldName.substring(oldName.lastIndexOf("."), oldName.length());try {uploadFile.transferTo(new File(folder, newName));filePath = req.getScheme() + "://" + req.getServerName() + ":" +req.getServerPort() + "/uploadFile/" + format + newName;} catch (IOException e) {e.printStackTrace();return "上传失败! ";}}return filePath;}
}

代码解释:

  • 第7~12代码表示规划上传文件的保存路径为项目运行目录下的uploadFile文件夹,并在文件夹中通过日期对所上传的文件归类保存。
  • 第13~15行代码表示给上传的文件重命名,这是为了避免文件重名。第17行是文件保存操作。
  • 第18~20行是生成上传文件的访问路径,并将访问路径返回。

最后在浏览器中进行测试。
运行项目,在浏览器中输入“http://localhost:8080/upload.html”进行文件上传

单击“请选择文件”按钮上传文件,文件上传成功后,会返回上传文件的访问路径

1.2 单文件上传优化

但是这样做还是有问题,上传图片到服务器根路径下的文件夹里,若重启服务器,图片又无法访问,这是因为每次重启服务器之后,都会在系统临时文件夹内,创建一个新的服务器,图片就保存在这里,若重启,又会产生一个新的服务器,此时访问的就是新服务器的图片资源,而图片根本就不在新服务器内。还有就是上面一个传相同日期的文件的时候会出现无法上传文件。

而且,系统的临时文件夹会定期清理,很有可能导致以前上传的文件丢失。

  • windows的临时文件夹位置:
C:\Users\User\AppData\Local\Temp
  • Linux的临时文件夹位置:
/tmp

以方案4为例,在windows上进行

application.yml文件中自定义图片保存位置

设置的图片保存路径的末尾必须有 /,代码中默认保存路径最后已经带有/
Linux上的路径示例: /usr/developmentTool/myproject/bookstoreAPI/files/images/
Windows上的路径 示例: E:/images/

file-save-path: E:/uploadFile/

改变原来的代码

@RestController
public class FileUploadController1 {@Value("${file-save-path}")private String fileSavePath;SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");@PostMapping("/upload1")public String upload(MultipartFile uploadFile, HttpServletRequest req) {String filePath = "";String format = sdf.format(new Date());File folder = new File(fileSavePath + format);if (!folder.isDirectory()) {folder.mkdirs();String oldName = uploadFile.getOriginalFilename();String newName = UUID.randomUUID().toString() +oldName.substring(oldName.lastIndexOf("."), oldName.length());try {uploadFile.transferTo(new File(folder, newName));filePath = req.getScheme() + "://" + req.getServerName() + ":" +req.getServerPort() + "/uploadFile/" + format + newName;} catch (IOException e) {e.printStackTrace();return "上传失败! ";}}String oldName = uploadFile.getOriginalFilename();String newName = UUID.randomUUID().toString() +oldName.substring(oldName.lastIndexOf("."), oldName.length());try {uploadFile.transferTo(new File(folder, newName));filePath = req.getScheme() + "://" + req.getServerName() + ":" +req.getServerPort() + "/uploadFile/" + format + newName;} catch (IOException e) {e.printStackTrace();return "上传失败! ";}return filePath;}
}

如果选择这种方式不能忘记对静态资源的映射

配置资源映射(重点

@Configuration
public class WebConfig implements WebMvcConfigurer {/*** 图片保存路径,自动从yml文件中获取数据*   示例: E:/images/*/@Value("${file-save-path}")private String fileSavePath;@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {/*** 配置资源映射* 意思是:如果访问的资源路径是以“/images/”开头的,* 就给我映射到本机的“E:/images/”这个文件夹内,去找你要的资源* 注意:E:/images/ 后面的 “/”一定要带上*/registry.addResourceHandler("/uploadFile/**").addResourceLocations("file:"+fileSavePath);}
}
最后在浏览器中进行测试。

运行项目,在浏览器中输入“http://localhost:8080/upload.html”进行文件上传,和上面效果一样,但是可以在指定的地址下找到上传的文件.

静态资源位置除了classpath下面的4个路径之外,还有一个"/",因此这里的图片虽然是静态资源却可以直接访问到。

至此,一个简单的图片上传逻辑就完成了,对于开发者而言,只需要专注于图片上传的业务逻辑,而不需要在配置上花费太多时间。
当然,如果开发者需要对图片上传的细节进行配置,也是允许的,代码如下:

#是否开启文件上传支持,默认为true。
spring. servlet.multipart.enabled=true
#文件写入磁盘的阈值,默认为0。
spring.servlet.multipart.file-size-threshold=0
#上传文件的临时保存位置。
spring.servlet.multipart.location=E:\ltemp
#上传的单个文件的最大大小,默认为1MB。
spring.servlet.multipart.max-file-size=1MB
#多文件上传时文件的总大小,默认为10MB。
spring.servlet.multipart.max-request-size=10MB
#文件是否延迟解析,默认为false。
spring.servlet.multipart.resolve-lazily=false

2. 多文件上传

多文件上传和单文件上传基本一致,首先修改HTML文件,代码如下:

@RestController
public class FileUploadController2 {@Value("${file-save-path}")private String fileSavePath;ArrayList<String> mylist=new ArrayList();SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd/");@PostMapping("/uploads")public ArrayList upload(MultipartFile[] uploadFiles, HttpServletRequest req) {String filePath = "";for(MultipartFile uploadFile:uploadFiles){String format = sdf.format(new Date());File folder = new File(fileSavePath + format);if (!folder.isDirectory()) {folder.mkdirs();String oldName = uploadFile.getOriginalFilename();String newName = UUID.randomUUID().toString() +oldName.substring(oldName.lastIndexOf("."), oldName.length());try {uploadFile.transferTo(new File(folder, newName));filePath = req.getScheme() + "://" + req.getServerName() + ":" +req.getServerPort() + "/uploadFile/" + format + newName;} catch (IOException e) {e.printStackTrace();}}String oldName = uploadFile.getOriginalFilename();String newName = UUID.randomUUID().toString() +oldName.substring(oldName.lastIndexOf("."), oldName.length());try {uploadFile.transferTo(new File(folder, newName));filePath = req.getScheme() + "://" + req.getServerName() + ":" +req.getServerPort() + "/uploadFile/" + format + newName;} catch (IOException e) {e.printStackTrace();}mylist.add(filePath);}return mylist;}
}

运行项目,在浏览器中输入“http://localhost:8080/uploads.html”进行文件上传,在选择文件时安住ctrl多选文件上传,和上面效果一样,可以在指定的地址下找到上传的文件.

SpringBoot文件上传相关推荐

  1. 补习系列(11)-springboot 文件上传原理

    一.文件上传原理 一个文件上传的过程如下图所示: 浏览器发起HTTP POST请求,指定请求头: Content-Type: multipart/form-data 服务端解析请求内容,执行文件保存处 ...

  2. SpringBoot文件上传源码解析

    一.SpringMVC文件上传源码分析前言(这部分我觉得原作者写的很好) 该如何研究SpringMVC的文件上传的源码呢? 研究源码并不是仅仅知道程序是怎样运行的,而应该从宏观的角度.不同的立场去看待 ...

  3. 解决Springboot文件上传报错,java.io.FileNotFoundException: D:\System\Temp\tomcat.819...00.tmp (系统找不到指定的文件。)

    Springboot文件上传,csdn上的方法无非是下面这两个: imgFile.transferTo(imageFolder); // 方法一/*** 方法二* FileUtils.copyInpu ...

  4. springboot文件上传下载实战 ——文件上传、下载、在线打开、删除

    springboot文件上传下载实战 文件上传 文件上传核心 UserFileController 文件上传测试 文件下载与在线打开 文件下载.在线打开核心 UserFileController 文件 ...

  5. springboot文件上传下载实战 —— 登录功能、展示所有文件

    springboot文件上传下载实战 创建项目 pom.xml 数据库建表与环境准备 建表SQL 配置文件 application.properties 整体架构 前端页面 登录页面 login.ht ...

  6. SpringBoot文件上传异常之提示The temporary upload location xxx is not valid

    SpringBoot文件上传异常之提示The temporary upload location xxx is not valid 参考文章: (1)SpringBoot文件上传异常之提示The te ...

  7. SpringBoot 文件上传 通过Content-Type和文件头判断文件类型

    SpringBoot 文件上传 通过Content-Type和文件头判断文件类型 一.关于MIME MIME的全称是Multipurpose Internet Mail Extensions,即多用途 ...

  8. springboot文件上传、下载使用ftp工具将文件上传至服务器

    springboot文件上传.下载使用ftp工具 首先在服务器搭建ftp服务 配置文件(在application.properties中) # Single file max size multipa ...

  9. springboot文件上传,单文件上传和多文件上传,以及数据遍历和回显

    springboot文件上传,单文件上传和多文件上传 项目结构及pom.xml 创建文件表单页面 编写javabean 编写controller映射 MultipartFile类 @RequestPa ...

  10. SpringBoot文件上传和下载

    SpringBoot文件上传和下载 一.SpringBoot文件上传 1.SpringMVC文件上传 1.Client处理 选择文件(1)form表单 选择文件 method="post&q ...

最新文章

  1. 分布式定时任务xxl-job的常用姿势都集齐了,So Easy!
  2. Error in variable_response could not find function “variable_response“
  3. Windows2003实用技巧
  4. Spotify模式并非“敏捷涅磐”
  5. php 小数末尾进1,PHP小数点最后一位加1、减1
  6. php自动加载基类文件
  7. Qt学习之路(10): Meta-Object系统
  8. linux学习之lvm2逻辑卷管理
  9. EF RepositoryBase 参考示例【转】
  10. 拨号上网和宽带上网的区别分析
  11. word分栏及序号对齐
  12. three.js 构建简单的房间
  13. 接口用例设计从哪些方面考虑
  14. 申请实用新型专利的流程
  15. Android中拍照完就给图片加水印,Android调用相机拍照并添加水印
  16. 【从0到1搭建LoRa物联网】11、ASR6505 LoRaWAN通信
  17. Unity灯光渲染之自发光材质
  18. Java字符串首尾显示,中间隐藏
  19. 华为信息中心配置命令,很全
  20. linux sh gt tty,如何将简单的Shell转换成为完全交互式的TTY

热门文章

  1. 求助:truffle unbox pet-shop时truffle test出错
  2. 用户要进行远程登录 必须在自己的计算机上,大学计算机基础上机考试题库3
  3. 实验一 网络流量捕获实验
  4. 廖雪峰python教程之python基础
  5. MySQL (四)------DML操作表记录-增删改【重点】DQL操作表记录-查询【重点】
  6. 【SQL自学打卡|DAY17】——多表查询
  7. thinkphp3.2乐观锁源码解读与优化
  8. GIMP--GNU Image Manipulation Program
  9. linux centos安装scp,CentOS使用不了scp命令怎么办?
  10. 微信小程序-wxml笔记(更新中)