SpringBoot文件上传(MVC情况和webFlux情况)
MVC情况
引入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency> <dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
前台(两个js框架自行下载)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Index</title>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
min-height: 100%;
} .header {
padding: 1px;
position: relative;
left: 0;
top: 0;
width: 100%;
height: 70px;
background-color: #4E3384;
color: #c7acff;
} .header h2 {
text-align: center;
} .header a {
display: block;
position: absolute;
top: 18px;
right: 15px;
padding: 8px 15px;
background-color: #a27bf1;
color: #fff;
border-radius: 3px;
text-decoration: none;
} .container {
min-height: 100%;
} .main {
max-width: 1200px;
margin: 30px auto;
text-align: center;
} .file-wrap {
position: relative;
padding: 8px 10px;
background-color: #ad0660;
color: #fff;
text-decoration: none;
font-size: 14px;
border-radius: 3px;
margin: 60px 25px;
display: inline-block;
} .file-wrap:hover {
background-color: #d80b7a;
} .file-input {
font-size: 0;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
cursor: pointer;
opacity: 0;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h2>文件上传</h2>
</div>
<div class="main">
<a href="javascript:;" class="file-wrap">单文件上传
<input type="file" id="singleFile" name="singleFile" class="file-input">
</a>
<a href="javascript:;" class="file-wrap">多文件上传
<input type="file" id="multiFile" name="multiFile" class="file-input" multiple>
</a>
<div id="imgDiv"></div>
</div>
</div>
<script th:src="@{js/jquery-3.3.1.min.js}"></script>
<script th:src="@{js/ajaxfileupload.js}"></script>
<script> $(document).on('change', '#singleFile', function () {
$.ajaxFileUpload({
url: '/upload/single', // 用于文件上传的服务器端请求地址
secureuri: false, // 是否需要安全协议,一般设置为false
fileElementId: 'singleFile', // 文件上传域的ID
dataType: 'json', // 返回值类型 一般设置为json
// 服务器成功响应处理函数
success: function (data, status) {
alert(data.msg);
if (data.code == 1){
$('#imgDiv').append($('<img src="'+ data.data +'">'));
}
},
// 服务器响应失败处理函数
error: function (data, status, e) {
alert(e);
}
});
$('#singleFile').val('');
}) $(document).on('change', '#multiFile', function () {
$.ajaxFileUpload({
url: '/upload/multi', // 用于文件上传的服务器端请求地址
secureuri: false, // 是否需要安全协议,一般设置为false
fileElementId: 'multiFile', // 文件上传域的ID
dataType: 'json', // 返回值类型 一般设置为json
// 服务器成功响应处理函数
success: function (data, status) {
alert(data.msg);
if (data.code == 1){
for (var i = 0; i < data.data.length; i++){
$('#imgDiv').append($('<img src="'+ data.data[i] +'">'));
}
}
},
// 服务器响应失败处理函数
error: function (data, status, e) {
alert(e);
}
});
$('#multiFile').val('');
}) </script>
</body>
</html>
最后是Java代码
这个是通用的返回结果
package com.example.demo; import lombok.Data; @Data
public class BaseResponse<T> { private T data;
private int code = 1; // 0-false;1-true;默认1
private String msg = "success";
}
下面是核心上传代码(一个单文件上传,一个多文件上传)
package com.example.demo; import org.apache.commons.io.FileUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
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.util.ArrayList;
import java.util.Date;
import java.util.List; @RestController
@RequestMapping("/upload")
public class FileController { @PostMapping("/single")
public BaseResponse<String> single(@RequestParam("singleFile") MultipartFile file, HttpServletRequest req) throws IOException {
String fileName = file.getOriginalFilename();
String fileType = fileName.substring(fileName.lastIndexOf("."));
String newFileName = new Date().getTime() + "";
String fileSize = FileUtils.byteCountToDisplaySize(file.getSize());
System.out.println("文件名:" + fileName);
System.out.println("文件大小:" + fileSize);
String path = req.getServletContext().getRealPath("/MyFiles/"); // 保存在项目运行目录下的MyFiles文件夹
File targetFile = new File(path + newFileName + fileType);
FileUtils.copyInputStreamToFile(file.getInputStream(), targetFile);
String imgPath = targetFile.getPath();
System.out.println("保存路径:" + imgPath);
// String url = req.getScheme() + "://" + req.getServerName() + req.getContextPath() +
// "/MyFiles/" + newFileName + fileType;
String url = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath() +
"/MyFiles/" + newFileName + fileType;
System.out.println("URL:" + url);
BaseResponse<String> response = new BaseResponse<>();
response.setData(url);
return response;
} @PostMapping("/multi")
public BaseResponse<List<String>> multi(@RequestParam("multiFile") MultipartFile[] files, HttpServletRequest req) throws IOException {
List<String> urls = new ArrayList<>();
for (MultipartFile file : files){
String fileName = file.getOriginalFilename();
String fileType = fileName.substring(fileName.lastIndexOf("."));
String newFileName = new Date().getTime() + "";
String fileSize = FileUtils.byteCountToDisplaySize(file.getSize());
System.out.println("文件名:" + fileName);
System.out.println("文件大小:" + fileSize);
String path = req.getServletContext().getRealPath("/MyFiles/");
File targetFile = new File(path + newFileName + fileType);
FileUtils.copyInputStreamToFile(file.getInputStream(), targetFile);
String imgPath = targetFile.getPath();
System.out.println("保存路径:" + imgPath);
String url = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath() +
"/MyFiles/" + newFileName + fileType;
System.out.println("URL:" + url);
urls.add(url);
System.out.println("=======================================");
} BaseResponse<List<String>> response = new BaseResponse<>();
response.setData(urls);
return response;
}
}
最后你可以配置上传文件大小,在application.properties
spring.servlet.multipart.max-file-size=5MB
spring.servlet.multipart.max-request-size=10MB
后台打印:
WebFlux情况(Spring5的新产品)
这种情况不同于SpringMVC,我只能以我目前开发的情况来说明。我们是前后端分离的项目,前端用vue+vuetify+VueX+Axios,大概思路就是搞一个按钮,当change事件发生就执行上传操作。
<v-btn dark small color="blue darken-1">上传文件
<input type="file" id="pbFileInput" class="file-input" @change="uploadFile('pbFileInput')"/>
</v-btn>
..
// id 为文件域的id
uploadFile: function(id){
let me = this;
let formData = new window.FormData();
formData.append('file',document.querySelector('#'+id).files[0])
let options = { // 设置axios的参数
headers: {
'Content-Type': 'multipart/form-data'
}
}
me.$store.state.axios.post('/upload',formData, options)
.then(function (response) {
let data = response.data;
if (data.code == 0){
console.log(data);
document.querySelector('#'+id).value = ''; // 解决上传第二次不能选择同一文件
} else{
console.log(data.msg)
}
})
.catch(function (error) {
console.log(error);
}); }
后端(这个是借鉴网友的代码,还可以用)
private static final String BASE_PATH = "/MyFiles/"; @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<BaseResponse<String>> requestBodyFlux(@RequestPart("file") FilePart filePart) throws IOException {
String base = BASE_PATH; // 存放在当前磁盘的根目录
System.out.println(filePart.filename());
Path path = Paths.get(base);
if (!Files.exists(path)){
Files.createDirectories(path);
}
Path file = Files.createFile(Paths.get(base + filePart.filename())); // 方法一
AsynchronousFileChannel channel =
AsynchronousFileChannel.open(file, StandardOpenOption.WRITE);
DataBufferUtils.write(filePart.content(), channel, 0)
.doOnComplete(() -> {
System.out.println("finish");
})
.subscribe(); // 方法二
// filePart.transferTo(file.toFile()); System.out.println(file.toString()); BaseResponse<String> response = new BaseResponse<>();
response.setData(filePart.filename()); // 把文件名传回给前端
return Mono.just(response);
}
填坑:网友的代码也不是万能的哦
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public Mono<BaseResponse<String>> requestBodyFlux(@RequestPart("file") FilePart filePart, @RequestHeader("uniqueId") String uniqueId) throws IOException {
String base = baseConfiguration.getPbUploadPath(); // 存放在当前磁盘的根目录
if (StringUtils.isEmpty(uniqueId)){
uniqueId = randomNumber(); // 每个pb协议有个独立的文件夹名称
}
String filename = filePart.filename();
log.info("=======================上传文件=======================");
log.info(filename);
log.info(uniqueId);
Path path = Paths.get(org.apache.commons.lang3.StringUtils.appendIfMissing(base, "/") + uniqueId + "/");
if (!Files.exists(path)){
Files.createDirectories(path);
}
// 如果存在同名文件,先删除
Path targetPath = Paths.get(org.apache.commons.lang3.StringUtils.appendIfMissing(base, "/") + uniqueId + "/" + filename);
if (Files.exists(targetPath)){
boolean b = Files.deleteIfExists(targetPath);
log.info("已存在同名文件:" + filename + ",先删除:" + b);
}
// 再建立新的
Path tempFile = Files.createFile(targetPath); // 方法一
AsynchronousFileChannel channel =
AsynchronousFileChannel.open(tempFile, StandardOpenOption.WRITE);
DataBufferUtils.write(filePart.content(), channel, 0)
.doOnComplete(() -> {
log.info("文件写入完毕...");
// 不关闭的话如果再上传同一个文件,会报错:java.nio.file.AccessDeniedException,因为资源被占用,无法删除
log.info("文件流关闭...");
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
log.info("文件流关闭失败...");
}
})
.subscribe(); // 方法二
// filePart.transferTo(tempFile.toFile()); log.info(tempFile.toString());
log.info("=======================--------======================="); BaseResponse<String> response = new BaseResponse<>();
response.setData(filename + "," + uniqueId); // 把唯一id和文件名传回给前端
return Mono.just(response);
}
生成随机文件夹名字
private String randomNumber(){
long time = new Date().getTime();
String s = time + "";
Random random = new Random();
for (int i = 0; i < 4; i++){
s += random.nextInt(10);
}
return s;
}
我已经测试这种方式可以行得通
SpringBoot文件上传(MVC情况和webFlux情况)的更多相关文章
- 补习系列(11)-springboot 文件上传原理
目录 一.文件上传原理 二.springboot 文件机制 临时文件 定制配置 三.示例代码 A. 单文件上传 B. 多文件上传 C. 文件上传异常 D. Bean 配置 四.文件下载 小结 一.文件 ...
- 【SpringBoot】07.SpringBoot文件上传
SpringBoot文件上传 1.编写html文件在classpath下的static中 <!DOCTYPE html> <html> <head> <met ...
- springboot文件上传下载简单使用
springboot的文件上传比较简单 一.使用默认的Resolver:StandardServletMultipartResolver controller package com.mydemo.w ...
- SpringBoot从入门到精通十一(SpringBoot文件上传的两种方法)
前言 在企业级项目开发过程中,上传文件是最常用到的功能.SpringBoot集成了SpringMVC,当然上传文件的方式跟SpringMVC没有什么出入. 本章目标 使用SpringBoot项目完成单 ...
- springboot文件上传报错
异常信息: org.springframework.web.multipart.MultipartException: Could not parse multipart servlet reques ...
- SpringBoot 文件上传临时文件路径问题
年后放假回来,一向运行OK的项目突然图片上传不了了,后台报错日志如下: java.io.IOException: The temporary upload location [/tmp/tomcat. ...
- springboot 文件上传大小配置
转自:https://blog.csdn.net/shi0299/article/details/69525848 springboot上传文件大小的配置有两种,一种是设置在配置文件里只有两行代码,一 ...
- SpringBoot文件上传下载
项目中经常会有上传和下载的需求,这篇文章简述一下springboot项目中实现简单的上传和下载. 新建springboot项目,前台页面使用的thymeleaf模板,其余的没有特别的配置,pom代码如 ...
- Springboot 文件上传(带进度条)
1. 相关依赖 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http ...
随机推荐
- phpstorm本地怎么上传到服务器
连接服务器 菜单栏找到[工具/Tools]->[Deployment/部署]->[Confinguration…/配置…]. 点加号(+),添加一台服务器,填写名称,选择类型为SFTP,点 ...
- 啰嗦的 java,简洁的 lombok —— lombok 的使用及简单实现单例模式注解
lombok 是什么? lombok 是一个非常神奇的 java 类库,会利用注解自动生成 java Bean 中烦人的 Getter.Setting,还能自动生成 logger.ToString.H ...
- FelxCell常用属性设置(未完待续......)
this.grid1.AllowUserPaste//返回或设置是否允许用户粘贴文字和格式 grid1.Cell(Rows, 1).WrapText = true;//设置单元格自动换行
- git window安装与注册邮箱用户名
1.git window版本下载 https://git-scm.com/downlods 下载完后点击安装包安装,一直下一步就行; 2.验证安装是否成功 在开始菜单里找到“Git”->“Git ...
- saiku环境搭建
说明:搭建saiku环境,BI展示工具. 环境说明: os:windows7 jdk:jdk1.6.0_43 tomcat:apache-tomcat-7.0.62 saiku:saiku-ui-2. ...
- HashMap源码分析(二)
前言:上篇文章,笔者分析了jdk1.7中HashMap的源码,这里将对jdk1.8的HashMap的源码进行分析. 注:jdk版本:jdk1.8.0_172 1.再看put操作 public V pu ...
- [十二省联考2019]D1T2字符串问题
嘟嘟嘟 省选Day1真是重大失误,T2连暴力都没时间写. 上周五重新答了遍Day1,竟然搞了187分吼吼吼吼. T2按40分写的暴力,结果竟然得了60分. 稍微说一下暴力吧:预处理哈希,对于一组支配关 ...
- cordova 自定义 plugin
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/qq_30879415/article/details/81265455准备工作安装cordovanp ...
- Cookies, Claims and Authentication in ASP.NET Core(转载)
Most of the literature concerning the theme of authentication in ASP.NET Core focuses on the use of ...
- 15 Django REST Framework 给api添加自定义搜索条件
一.ListModelMixin源码 # 源码 class ListModelMixin(object): """ List a queryset. "&quo ...