可参考:>>>javaWeb 文件上传 【原生servlet】<<<
可参考:>>>SpringMVC的文件上传<<<
文章目录
一、前言
1、问题
-
以前只使用Spring MVC时,使用如下方式获得路径,在项目的out文件夹下
String path = request.getServletContext().getRealPath("/upload")
-
但是在SpringBoot中此方法获得的路径类似为: C:\Users\25293\AppData\Local\Temp\ tomcat.8080.3028400654015009944
-
并且,每次重新启动项目,都会生成一个新的文件夹(本地运行)
2、原因
-
当使用tomcat发布项目的时候,上传文件存放非常简单,因为可以随意操作项目路径下的资源。
但当使用SpringBoot的jar包发布项目时,不再能像以前一样操作文件了,而是只能使用InputStream读取里面的文件
3、解决办法
-
此时,我们有三种方式解决问题:
为它构建一个文件服务器;- 指定一个具体的绝对路径;
- 存放在与jar包同级的static文件夹下的upload文件夹(以下介绍的就是这种)。
-
其中,我们使用SpringBoot的工具类ResourceUtils获取路径
String path = ResourceUtils.getURL("classpath:").getPath() + "static/upload/";
-
此时路径位置为:
- 本地运行时:${项目路径}/target/classes/static/upload
- 发布到服务器运行时:${jar包所在路径}/static/upload
二、上传功能具体实现
1、导入依赖的jar包,配置application.yaml
- 正如Spring MVC,SpringBoot也使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。
- 因此,SpringBoot的文件上传还需要依赖Apache Commons FileUpload的组件。
<!--文件上传-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
- 配置application.yaml
# 文件上传
spring:
servlet:
multipart:
# 开启功能
enabled: true
# 单个文件最大10MB(默认1MB)
max-file-size: 10MB
# 请求最大20MB(默认10MB)
max-request-size: 20MB
# 静态路径
resources:
static-locations: classpath:static/,file:static/
- 关于配置静态路径,如果只是在本地跑项目,可能你感受不出来配置不配置的区别,但如果发布到服务器上,没有配置的话上传成功后无法访问
2、后端 FileController.java 和工具类 UploadFile.java
- FileController.java
package com.shiyq.controller;
import com.shiyq.util.UploadFile;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.ui.Model;
import org.springframework.web.multipart.MultipartFile;
@Controller
public class FileController {
/**
* 文件上传
* 采用file.Transto 来保存上传的文件
* @RequestParam("file") 将name=file控件得到的文件封装成CommonsMultipartFile对象
* 批量上传CommonsMultipartFile则为数组即可
*
* @param username 页面传来的普通输入框的值
* @param file 文件对象
* @return 跳转 查看上传的图片
*/
@RequestMapping("/upload")
public String fileUpload2(@RequestParam("username") String username,
@RequestParam("file") MultipartFile file,
Model model) {
if (file != null) {
String filePath = UploadFile.uploadFile(file);
model.addAttribute("filePath", filePath);
}
return "show";
}
}
- 工具类 UploadFile.java
package com.shiyq.util;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.UUID;
/**
* @author shiyq
* @create 2021-02-26 21:05
*/
public class UploadFile {
// 绝对路径
private static String absolutePath = "";
// 上传文件存放位置
private static String uploadDir = "static/upload/";
/**
* 单文件上传
* @param file 需要上传的文件
* @return 文件名
*/
public static String uploadFile(MultipartFile file) {
// 如果路径不存在则创建
createDirIfNotExists();
// 获取文件后缀名,如果不需要".",可以在最后+1,此处可增加对文件类型的筛选
String suffix = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
// 更改文件名,防重名
String headImg = UUID.randomUUID().toString() + suffix;
//通过CommonsMultipartFile的方法直接写文件
try{
file.transferTo(new File(absolutePath + headImg));
} catch (IOException e){
e.printStackTrace();
}
return headImg;
}
/**
* 创建与springboot打包的jar同级的static的upload文件夹
*/
public static void createDirIfNotExists() {
if (!absolutePath.isEmpty()) return;
//获取根目录
File path = null;
try {
path = new File(ResourceUtils.getURL("classpath:").getPath());
} catch (FileNotFoundException e) {
throw new RuntimeException("获取根目录失败,无法创建上传目录!");
}
if (!path.exists())
path = new File("");
absolutePath = path + uploadDir;
File uploadPath = new File(absolutePath);
if(!uploadPath.exists()) {
uploadPath.mkdirs();
}
}
}
2、前端 upload.html 和 show.html
- 上传表单 upload.html
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<body>
<!--
th标签:SpringBoot推荐使用的thymeleaf
enctype="multipart/form-data" 将表单转换为二进制进行传输,文件上传必须加上
POST:上传文件大小没有限制
-->
<form th:action="@{/upload}"
enctype="multipart/form-data"
method="post">
普通输入框:<input type="text" name="username"><br/>
<P><input type="file" name="file"></P>
<P><input type="submit" value="提交"></P>
</form>
</body>
</html>
- 查看上传的图片 show.html
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<body>
<img th:src="@{'/upload/'+${filePath}}"
</body>
</html>
三、异常
-
ConFileController.java中的
@RequestParam("file") MultipartFile file // 也可以写为 @RequestParam("file") CommonsMultipartFile file,
-
但此时会报异常
Resolved [org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'org.springframework.web.multipart.commons.CommonsMultipartFile'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile' to required type 'org.springframework.web.multipart.commons.CommonsMultipartFile': no matching editors or conversion strategy found]
-
有两种解决办法:
-
将 CommonsMultipartFile 替换为: MultipartFile
-
在配置SpringBoot类中加入如下Bean
@Bean public CommonsMultipartResolver getCommonsMultipartResolver() { CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(); multipartResolver.setMaxUploadSize(20971520); multipartResolver.setMaxInMemorySize(1048576); return multipartResolver; }
-