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

启动项目:http://localhost:8080/

后台打印:

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情况)的更多相关文章

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

    目录 一.文件上传原理 二.springboot 文件机制 临时文件 定制配置 三.示例代码 A. 单文件上传 B. 多文件上传 C. 文件上传异常 D. Bean 配置 四.文件下载 小结 一.文件 ...

  2. 【SpringBoot】07.SpringBoot文件上传

    SpringBoot文件上传 1.编写html文件在classpath下的static中 <!DOCTYPE html> <html> <head> <met ...

  3. springboot文件上传下载简单使用

    springboot的文件上传比较简单 一.使用默认的Resolver:StandardServletMultipartResolver controller package com.mydemo.w ...

  4. SpringBoot从入门到精通十一(SpringBoot文件上传的两种方法)

    前言 在企业级项目开发过程中,上传文件是最常用到的功能.SpringBoot集成了SpringMVC,当然上传文件的方式跟SpringMVC没有什么出入. 本章目标 使用SpringBoot项目完成单 ...

  5. springboot文件上传报错

    异常信息: org.springframework.web.multipart.MultipartException: Could not parse multipart servlet reques ...

  6. SpringBoot 文件上传临时文件路径问题

    年后放假回来,一向运行OK的项目突然图片上传不了了,后台报错日志如下: java.io.IOException: The temporary upload location [/tmp/tomcat. ...

  7. springboot 文件上传大小配置

    转自:https://blog.csdn.net/shi0299/article/details/69525848 springboot上传文件大小的配置有两种,一种是设置在配置文件里只有两行代码,一 ...

  8. SpringBoot文件上传下载

    项目中经常会有上传和下载的需求,这篇文章简述一下springboot项目中实现简单的上传和下载. 新建springboot项目,前台页面使用的thymeleaf模板,其余的没有特别的配置,pom代码如 ...

  9. Springboot 文件上传(带进度条)

    1. 相关依赖 pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http ...

随机推荐

  1. Swiper4.x使用方法

    1.首先加载插件,需要用到的文件有swiper.min.js和swiper.min.css文件.可下载Swiper文件或使用CDN. <!DOCTYPE html> <html> ...

  2. Web前端-CSS必备知识点

    Web前端-CSS必备知识点 css基本内容,类选择符,id选择符,伪类,伪元素,结构,继承,特殊性,层叠,元素分类,颜色,长度,url,文本,字体,边框,块级元素,浮动元素,内联元素,定位. 链接: ...

  3. Linux常用查找命令

    第一种:grep命令 示例: 第二种:find命令 示例: 第三种:locate命令 示例: 第四种:whereis命令 示例: 第五种:which命令 示例:

  4. Mac10.12下Python3.4调用oracle

    最近,由于项目的短信平台对其它浏览器兼容,只支持IE,但是我们移动端自动化需要测试iphone手机,必须要连接MAC系统下,众所周知,MAC对IE的不友好性,故没办法通过短信平台在UI层自动化获取短信 ...

  5. 【Spring Cloud笔记】 断路器-hystrix

    在微服务架构中,一个微服务的超时失败可能导致瀑布式连锁反映,Spring Cloud Netflix 的断路器Hystrix通过自主反馈,防止了这种情况发生.下面介绍简单的断路器使用方法. [step ...

  6. Linux 下的 python 虚拟环境 + vim快捷方式

    day04虚拟环境 https://www.cnblogs.com/pyyu/p/9015317.html 博客 关闭防火墙: systemctl stop firewalld # 关闭防火前 sys ...

  7. 为什么区块链和加密行业需要 Web 3?

    为什么区块链和加密行业需要 Web 3? “由于人们都想从互联网上获得好处,互联网已经演变成了一个导致不公平和分裂的引擎,它被强大的力量所支配,并且任由其摆布.“——万维网之父.互联网先驱 Tim B ...

  8. arts打卡 从排序数组中删除重复项

    Algorithm 从排序数组中删除重复项     给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组 ...

  9. ESP8266最小系统

    http://www.dnsj88.com/Products/esp12f.html https://gitai.me/2017/04/Re-Zero-Starting-in-IoT/

  10. (n)e(m)

    经常会看到类似于 1e30 9e5 类似的表达式 (我一个蒟蒻不懂啊) 于是 给自己解释解释 那么 nem就是 n乘以10的m次方 (哈哈哈哈,我简直是太弱了)