springboot 文件上传示例(webuploader插件)
1.情景展示
文件上传,在开发过程中,经常会用到,springboot如何接收上传文件?
本文将以springboot为例,如何接收前端的文件请求;
上传文件使用插件更方便,这里我使用webuploader。
2.前端代码
第一步:准备webuploader插件放到项目当中;
由于,springboot在项目启动的时候,会自动将static目录下的静态资源(前端代码)加载到项目当中;
所以,我这里为了省事儿,就不创建web目录了;
而且springboot还会自动将resources/static目录下的index.html当做项目的欢迎页(我这里为了省事,就没有配置请求与页面想对照的映射关系)。
现在,我们来对前端代码进行整体认知;
一个要存放插件的位置:webuploader;
一个要展示插件的页面:index.html;
一个要处理文件上传的js:upload.js;
index.html需要引入:
webuploader.css和webuploader.js;
必须在webuploader.js引入之前引入jQuery.js(因为它依赖jQuery);
include.js包含的内容如下:
// 获取请求路径
var pathName = window.document.location.pathname;
// 通过截取得到项目名称
var baseUrl = pathName.substring(0, pathName.substr(1).indexOf('/') + 1);
用途:获取该项目的名称。
html的核心代码为:
<div id="filePicker" style="line-height:15px;" class="webuploader-container">
<div class="webuploader-pick">选择文件</div>
</div>
webuploader插件会通过init()方法,对filePicker这个div里面追加内容,例如:
js核心代码:
查看代码
/**
* 该插件批量上传的本质:
* 每个文件单独发送一个上传请求,所以,其本质还是单文件上传,而不是真正含义上的:一次请求包含多个文件。
*/
this.init = function () {
var state = 'pending';
var upUrl = baseUrl + '/file/upload.do';
var uploader = WebUploader.create({
auto: true, // 选择文件后自动上传,默认不自动上传需要触发
swf: baseUrl + '/webuploader/Uploader.swf', // swf文件路径
server: upUrl, // 上传文件的接口(替换成你们后端给的接口路径)
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#filePicker',
accept: {
//extensions: 'xls,xlsx', // 允许的文件后缀,不带点,多个用逗号分割,这里支持老版的Excel和新版的
mimeTypes: 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
// 说明:extensions没用,不生效
// 只有mimeTypes的值对应文件域的accept属性,仅能通过它来控制上传文件的类型
// 文件类型,也可以通过“.后缀名”的方式来实现,如:.xls,.xlsx
},
resize: false, // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
/* duplicate :true */ //可重复上传
});
/**
* 文件被加入队列之前触发
* @explain 主要用来传其它参数
*/
uploader.on('beforeFileQueued', function (file) {
var obj = new Object();
obj.THEMEID = $('#THEMEID').val();
uploader.options.formData = obj;
});
/**
* 上传成功
*/
uploader.on('uploadSuccess', function( file, result) {
alert(JSON.stringify(result));
});
/**
* 上传失败
*/
uploader.on('uploadError', function( file, result) {
// alert('文件上传失败!');
alert(JSON.stringify(result));
});
/**
* 上传完成
*/
uploader.on( 'uploadComplete', function( file ) {
});
uploader.on( 'all', function( type ) {
if ( type === 'startUpload' ) {
state = 'uploading';
} else if ( type === 'stopUpload' ) {
state = 'paused';
} else if ( type === 'uploadFinished' ) {
state = 'done';
}
});
}
HTML完整代码:
查看代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上传</title>
<link rel="stylesheet" type="text/css" href="webuploader/webuploader.css">
<script type="text/javascript" src="common/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript" src="webuploader/webuploader.js"></script>
<script type="text/javascript" src="common/js/include.js"></script>
<script type="text/javascript" src="upload.js"></script>
</head>
<body>
<h1>欢迎来到Marydon的博客园</h1>
<table border="0" cellpadding="0" cellspacing="0" style="width: 100%; height: 90%">
<tr>
<td style="text-align: center">
<div id="filePicker" style="line-height:15px;" class="webuploader-container">
<div class="webuploader-pick">选择文件</div>
</div>
</td>
<td>
<span style="color: #898989">备注:扫描文件格式为xls</span>
</td>
</tr>
</table>
</body>
</html>
注意:关键点在于,引入文件的路径问题,不要搞错了。
JAVASCRIPT完整代码:
查看代码
var upload = new Upload();
window.onload = function(){
// 不要忘了调用WebUploader的初始化函数
upload.init();
}
function Upload() {
var object = this;
/**
* 该插件批量上传的本质:
* 每个文件单独发送一个上传请求,所以,其本质还是单文件上传,而不是真正含义上的:一次请求包含多个文件。
*/
this.init = function () {
var uploadUrl = baseUrl + '/file/upload.do';
var uploader = WebUploader.create({
auto: true, // 选择文件后自动上传,默认不自动上传需要触发
swf: baseUrl + '/webuploader/Uploader.swf', // swf文件路径
server: uploadUrl, // 上传文件的接口(替换成你们后端给的接口路径)
// 选择文件的按钮。可选。
// 内部根据当前运行是创建,可能是input元素,也可能是flash.
pick: '#filePicker',
accept: {
//extensions: 'xls,xlsx', // 允许的文件后缀,不带点,多个用逗号分割,这里支持老版的Excel和新版的
mimeTypes: 'application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
// 说明:extensions没用,不生效
// 只有mimeTypes的值对应文件域的accept属性,仅能通过它来控制上传文件的类型
// 文件类型,也可以通过“.后缀名”的方式来实现,如:.xls,.xlsx
},
resize: false, // 不压缩image, 默认如果是jpeg,文件上传前会压缩一把再上传!
/* duplicate :true */ //可重复上传
});
/**
* 文件被加入队列之前触发
* @description 主要用来传其它参数
* @explain 我没有在这里演示,没有传其它参数
*/
uploader.on('beforeFileQueued', function (file) {
var obj = new Object();
obj.THEMEID = $('#THEMEID').val();
uploader.options.formData = obj;
});
/**
* 上传成功
*/
uploader.on('uploadSuccess', function( file, result) {
alert(JSON.stringify(result));
});
/**
* 上传失败
*/
uploader.on('uploadError', function( file, result) {
// alert('文件上传失败!');
alert(JSON.stringify(result));
});
};
}
注意:关键点在于,需要对插件WebUploader进行初始化。
3.后端代码
难点在于:如何接收前端发过来的请求?
其实,很简单:参数file的值就是MultipartFile类型的文件。
文件上传,上传的参数至少会有以下6个参数:
为了方便对于参数的使用,我用实体类来接收这些参数,这样,在后续用到的时候就会很方便。
查看代码
import lombok.Getter;
import lombok.Setter;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* 文件上传请求参数
* @description:
* @author: Marydon
* @date: 2022-01-10 15:38
* @version: 1.0
* @email: marydon20170307@163.com
*/
@Getter
@Setter
public class UploadParamsDto {
@NotBlank(message = "id:不能为空")
private String id;
@NotBlank(message = "name:不能为空")
private String name;
@NotBlank(message = "type:不能为空")
private String type;
@NotBlank(message = "lastModifiedDate:不能为空")
private String lastModifiedDate;
@NotBlank(message = "size:不能为空")
private String size;
@NotNull(message = "file:不能为空")
private MultipartFile file;
}
如果不需要对参数进行非空校验,删掉这些属性对应的注解即可。
JAVA控制层完成代码:
查看代码
import com.example.upload.web.dto.UploadParamsDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 文件上传控制层
* @description:
* @author: Marydon
* @date: 2022-01-10 10:16
* @version: 1.0
* @email: marydon20170307@163.com
*/
@Slf4j
@RestController
@RequestMapping("/file")
public class UploadController {
// 文件存放路径:项目路径/files
private static final String UPLOADED_FOLDER = System.getProperty("user.dir") + File.separator + "files";
/*
* 文件上传
* @attention: 不支持批量上传
* @description: 请求类型-multipart/form-data
* @date: 2022/1/11 10:23
* @param: paramsDto
* @return: java.util.Map
*/
@PostMapping("/upload.do")
public Map<String, Object> upload(@Validated UploadParamsDto paramsDto) {
// 即将返回的数据
Map<String, Object> resultMap = new HashMap<>(2);
resultMap.put("isSuccess", true);
resultMap.put("error", "");
Map<String, String> errorMap = new HashMap<>();
// 获取上传的文件
MultipartFile file = paramsDto.getFile();
// 新文件的文件名
String fileName = System.currentTimeMillis() + "_" + paramsDto.getName();
// 新文件的生成
File copyFile = new File(UPLOADED_FOLDER + File.separator + fileName);
// 目录不存在就自动创建
copyFile.mkdirs();
try {
// 将multipartfile文件转移到file对象所代表的文件中
// 该方法可以将文件夹直接变为文件
// 当copyFile代表的是一个目录时,正常情况文件是无法输入的,而transferTo()方法会将该目录直接变为文件并输入数据
file.transferTo(copyFile);
} catch (IOException e) {
e.printStackTrace();
log.error(e.getMessage());
// 如果报错,意味着该文件上传失败,将原文件名和报错信息返回
errorMap.put(paramsDto.getName(), e.getMessage());
}
if (!errorMap.isEmpty()) {
resultMap.put("error", errorMap);
}
return resultMap;
}
}
难点还有:如何获取保存文件的目录;
新文件名的命名规则;
文件的快速复制。
当然,如果只是根据上传的文件进行解析处理,而不保存的话,不会遇到以上3个问题。
说明:
请求格式:multipart/form-data;
返回格式:application/json。
另外,如果,需要对实体类UploadParamsDto进行参数校验,除了需要在它前面加注解@Validated外,还要引入对应的注解jar依赖。
<!--spring对参数进行校验:hibernate validator-->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
</dependency>
更多细节,我在之前的文章讲过。
4.效果展示
直接来到欢迎页
点击“选择文件”,选择要上传的文件,支持多选。
最终上传的文件存放位置
5.扩展
通过配置文件限制上传文件大小
如果,对上传文件的大小有限制的话,可以通过配置来实现。
查看代码
####spring配置####
####开发环境数据源配置
spring:
###文件上传大小限制
servlet:
multipart:
#是否支持批量上传(默认值 true)
enabled: true
#上传文件最大为 1M(默认值 1M)
max-file-size: 10MB
#上传请求最大为 10M(默认值 10M)
max-request-size: 10MB
#文件大小阈值,当大于这个阈值时将写入到磁盘,否则存在内存中(默认值0,即:直接将文件写入磁盘)
file-size-threshold: 0
#判断是否要延迟解析文件(默认值false)
resolve-lazily: false
#存放上传文件的临时目录
location:
禁止多选
WebUploader插件,默认支持多文件上传;
如果我们需要限制每次只允许上传一个文件的话,可以通过如下配置进行禁止。
pick对象里面声明multiple属性,并将值设为false。
pick: {
'id': '#filePicker',//文件上传按钮所在位置(通过ID来指定)
'multiple': false //禁止多选
},
页面初始化后,文本域没有multiple属性。
下面这种方式,会默认允许多选。
说明:
文件域的multiple属性,可以控制文件的单选和多选;
支持多选:声明multiple属性;
禁止多选:不声明multiple属性。
<input type="file" multiple="multiple">
文件域的accept属性,可以控制上传文件的文件类型。
方式一:
<input type="file" accept="文件对应的文件类型(mimetype),如:application/pdf">
方式二:推荐使用
<input type="file" accept="文件对应的文件后缀名(.文件名),如:.sql">
2023年3月27日15:31:48
上传jpg文件
当使用该插件上传jpg格式图片时,可能会上传失败,报错信息如下:
需要声明compress属性,如果不需要压缩的话,将值设为false即可。
var uploader = WebUploader.create({
auto: true,
swf: baseUrl + '/commons/js/ueditor/third-party/webuploader/Uploader.swf',
server: upUrl,
pick: '#filePicker',
method: 'POST',
resize: false,
compress: false,// 不声明将导致部分jpg文件无法上传
accept: {
title: 'Images',
extensions: 'gif,jpg,jpeg,bmp,png,pdf',
mimeTypes: 'image/*,application/pdf'
}
});
写在最后
哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!
相关推荐:
本文来自博客园,作者:Marydon,转载请注明原文链接:https://www.cnblogs.com/Marydon20170307/p/15794176.html