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属性,仅能通过它来控制上传文件的类型
                // 文件类型,也可以通过&ldquo;.后缀名&rdquo;的方式来实现,如:.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'
    }
});

 

写在最后

  哪位大佬如若发现文章存在纰漏之处或需要补充更多内容,欢迎留言!!!

 相关推荐:

posted @ 2022-01-12 19:12  Marydon  阅读(957)  评论(0编辑  收藏  举报