java MultipartFile+vue+element 批量上传文件、图片,与普通数据同时提交保存才上传到后端

news2025/1/21 2:54:00

一.背景

文件上传项目可参考:点击预览

1.最简单也是最普遍的做法是form表单提交,其实前端提交到后端也是难以离开form表单提交,
一般有两种方式来处理文件、图片上传:

  1. 先上传,获取返回路径,再整个表单提交后端保存;
  2. 普通数据与文件图片同时提交后端,由后端处理

优点比较

  1. 第一种可以优先处理文件上传,异步处理,节省用户提交loading的时间,特别是一些大文件
  2. 第二种在最后提交才进行文件处理,没有脏数据,节省了文件服务器空间和流量

缺点比较,可以说刚好相反,第一种只有一选择文件,马上就上传,用户可以在最后提交之前一直change文件,就可能不断上传了一些没必要的文件图片,造成了各种文件脏数据,除非通过某些逻辑去删除这些脏文件(定时刷数据或提交的时候判断用户最终保存的数据来删除脏数据)

这里作者采取第二种方式,相对于第一种,实现难度稍微大些

二.前端html实现

element上传官方文档
在这里插入图片描述
on-success、on-error其实就是上面说的第一种方式才会用到的,作者感觉element就是推荐用异步的方式来实现的,通过action提交到指定上传接口

前端实现源码

<el-form-item label="图片" :required="form.postsType !== '2'">
              <el-upload
                action=""
                list-type="picture-card"
                :auto-upload="false"
                :limit="9"
                :before-upload="beforeUpload"
                :on-change="handleChange"
                :on-preview="handlePictureCardPreview"
                :disabled="disabled"
                :on-remove="handleRemove">
                <i class="el-icon-plus"></i>
              </el-upload>
              <div style="font-size: 12px;color: #666;">
                只能上传jpg/png文件,且不超过 2MB,最多上传 9 张图片
              </div>
              <el-dialog :visible.sync="dialogVisible">
                <img width="100%" :src="dialogImageUrl" alt="">
              </el-dialog>
            </el-form-item>

同时定义属性

	 dialogImageUrl: '',//窗口预览图片路径
     dialogVisible: false,//预览窗口是否打开
     disabled: false,//是否禁用上传操作

源码解析:

  • :limit=“9” //最多可上传9张图片
  • :before-upload=“beforeUpload”//上传之前,即选择图片后调用方法
  • :on-change=“handleChange”//选择图片上传调用方法
  • :on-preview=“handlePictureCardPreview”//预览图片调用方法
  • :disabled=“disabled”//是否禁用上传操作
  • :on-remove=“handleRemove”//上传已选择的图片

三.js方法实现

js源码

	beforeUpload(file) {
        const isLt2M = file.size / 1024 / 1024 < 2;
        if (!isLt2M) {
          this.$message.error('上传头像图片大小不能超过 2MB!')
        }
        return isLt2M
      },
      handleRemove(file, fileList) {
        this.form.files = fileList;
        console.info(this.form);
      },
      handleChange(file, fileList){
        this.form.files = fileList;
        console.info(this.form);
      },
      handlePictureCardPreview(file) {
        this.dialogImageUrl = file.url;
        this.dialogVisible = true;
      },

源码解析:
方法意义上面已经说过了,其中this.form.files定义为一个数组,暂存上传的文件

form: {
  files: [],
  title: ''
},

组装数据请求上传到后端:

let formData = new FormData();
for (const file of this.form.files) {//多个文件全部都放到files
  if(file.raw) {
    formData.append('files', file.raw);
  }
}
formData.append('title',this.form.title);
add(formData).then(res => {
  this.loading = false;
  if(res.code === 200){
    this.$message.success(res.msg);
  }
},error => {
  this.loading = false;
})

四.java后端处理

controller:

	@PostMapping("/add")
    @ApiOperation(value = "添加", notes = "添加")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "title", value = "标题", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "files", value = "上传图片列表", required = false, dataType = "MultipartFile[]", paramType = "query")
    })
    public Result<Posts> add(
            @RequestParam("title")  String title,
            @RequestParam(value = "files",required = false) MultipartFile[] files
            ) {
        PostsReq postsReq = new PostsReq();
        postsReq.setTitle(title);
        postsReq.setFiles(files);
        return postsService.add(JwtUtil.getUserId(),postsReq);
    }

源码解析:
作者一开始是想着用@RequestBody注解来接收整个数据对象的,但是这样的话会报错,具体错误信息作者没有记录下来,大概的意思就是MultipartFile类型不支持,没有构造方法那一类的,然后看了一下MultipartFile的源码

居然是interface的~,原来如此(理所当然认为应该是class的,哈哈哈,难怪),有更加深入研究的同学麻烦留言也分享一下,感谢!

在这里插入图片描述
java文件上传处理实现:

    public String uploadImage(MultipartFile file) {
        if (file == null)
            throw new BizException("图片不能为空");

        //得到上传文件的文件名
        String fileName = file.getOriginalFilename();
        //以传入的字符串开头,到该字符串的结尾,前开后闭
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        long size = file.getSize();
        double mul = NumberUtil.div(size, (1024 * 1024), 2);
        // 自定义异常
        if (mul > 2)
            throw new BizException("图片大小不能大于2M");
        if (!isImage(suffixName))
            throw new BizException("不是图片格式");
        // 这里可以用uuid等 拼接新图片名
        String newFileName = UUID.randomUUID().toString().replace("-", "") + suffixName;
        // 创建路径
        String destFileName = fileUploadConfig.getImageRealPath() + File.separator + newFileName;
        File destFile = new File(destFileName);
        if (!destFile.getParentFile().exists())
            destFile.getParentFile().mkdirs();
        try {
            //将图片保存到文件夹里
            file.transferTo(new File(destFileName));
        } catch (IOException e) {
            e.printStackTrace();
            throw new BizException("图片上传错误");
        }
        //返回相对路径存储
        return fileUploadConfig.getImageMapperPath() + newFileName;
    }

    /**
     * 传进 .jpg  类似的格式 判断是否时图片格式
     * @param suffixName 图片格式后缀
     * @return
     */
    public static boolean isImage(String suffixName) {
        List<String> strings = Arrays.asList(".webp", ".png", ".jpg", ".jif", ".jpeg");
        return strings.contains(suffixName);
    }

有更加好的实现方式的,欢迎留言,大家分享,共同学习、共同进步~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/161218.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PyTorch实现基本的线性回归

线性回归理论知识参考文章&#xff1a;线性回归 下面我们将从零开始实现整个线性回归方法&#xff0c; 包括数据集生成、模型、损失函数和小批量随机梯度下降优化器。 1.导入 %matplotlib inline import random import torch from d2l import torch as d2l2.生成数据集 我们…

js垃圾回收(引用计数算法、标记清除算法、v8垃圾回收机制、浏览器性能监控、任务管理器、内存分析、JSBench)

目录 垃圾 可达对象 GC算法&#xff08;垃圾回收机制&#xff09; 引用计数算法 优点 缺点 标记清除算法 优点 缺点 标记整理算法 优点 缺点 V8 V8垃圾回收 新生代对象回收 晋升条件 老生代对象回收 性能监控Performance 浏览器任务管理器 内存分析 ​编…

Apache Doris 系列: 基础篇-BitMap索引

1. 测试数据准备 本文使用SSB&#xff08;Star-Schema-Benchmark&#xff09;的测试数据&#xff0c;读者也可以自行准备测试数据 1.1 编译ssb-dbgen 数据生成工具 ## 拉取Apache Doris源代码 git clone https://github.com/apache/doris.git## 编译ssb-dbgen cd doris/tool…

计算机网络复习之应用层

统一资源定位系统&#xff08;uniform resource locator;URL&#xff09;是因特网的万维网服务程序上用于指定信息位置的表示方法。它最初是由蒂姆伯纳斯李发明用来作为万维网的地址。现在它已经被万维网联盟编制为互联网标准RFC1738。邮局协议&#xff08;Post Office Protoco…

TDemo 备注文本的二种存贮方式

TDemo 备注纯文本的二种存贮方式 数据库使用过程中&#xff0c;对于TDeme控件&#xff0c;对应数据库的分为nvarchar(n)类型字段。 一、通常使用二种格式的文本&#xff1a; &#xff08;1&#xff09;单纯文本 &#xff08;2&#xff09;带换行符的文本 这二种格式&#xff0c…

Pdf 转换成Word如何在线转换?职场公认好用软件推荐

Pdf 转换成Word如何在线转换&#xff1f;生活中很多时候我们需要接触大量的办公文件&#xff0c;特别是利用office的三种常见的文件格式编辑各类文件&#xff0c;最常见的便是Word文件操作。为了更方便我们进行文件传输&#xff0c;大部分情况下我们会把格式排版完好的Word文档…

UDS诊断系列介绍08-19服务

本文框架1. 系列介绍1.1 19服务概述1.2 DTC故障码定义1.3 DTC状态位2. 19服务常用子服务2.1 19 01服务2.2 19 02服务2.3 19 04服务2.4 19 06服务2.5 19 0A服务2.6 否定响应3. Autosar系列文章快速链接1. 系列介绍 UDS&#xff08;Unified Diagnostic Services&#xff09;协议…

Android 深入系统完全讲解(15)

4 权限相关的知识 1 安卓权限 上层 APK 权限获取方式&#xff0c;配置 AndroidManifest.xml&#xff0c;系统会对应的给 gid&#xff0c;在创建进程的时候就带下去&#xff0c;这样子就可以访问对应的设备。 而系统相关的&#xff0c;会限制必须是 uidsystem 这类&#xff0c…

一年融资三轮,一文读懂亿格云这家公司

数字办公时代&#xff0c;网络安全是企业经营的底线工作。如何构建一个安全、稳定、高效的网络安全体系&#xff0c;是企业谋求发展的基础条件之一。近年&#xff0c;倡导“永不信任&#xff0c;始终验证”的零信任网络安全服务理念开始兴起。而国内致力于基于零信任理念构建办…

MySQL 行级锁(行锁、临键锁、间隙锁)

行级锁 行级锁&#xff0c;每次操作锁住对应的行数据。锁定粒度最小&#xff0c;发生锁冲突的概率最低&#xff0c;并发度最高。应用在InnoDB存储引擎中。 InnoDB的数据是基于索引组织的&#xff0c;行锁是通过对索引上的索引项加锁来实现的&#xff0c;而不是对记录加的锁。 1…

类和对象(上)

文章目录引用autoNULL&nullptr&0类和对象类的实例化默认成员函数构造函数析构函数拷贝构造函数运算符的重载赋值运算符的重载拷贝构造次数编译器优化前置后置> < ! - -const成员operator>>&&operator<<再谈构造函数初始化列表初始化expli…

使用Hi3861开发环境搭建

安装ubuntu ​ 文件夹的位置尽量选一个空间比较大的 内存也尽量分配大一点&#xff0c;不要到红色区域就行 固定分配&#xff0c;如果给它100G空间&#xff0c;他就会把这100G空间全部使用掉&#xff0c;动态分配&#xff0c;即使你给他100G内存&#xff0c;但实际使用的空间…

【自学Docker】Docker入门

Docker入门 Docker简介 Docker 是 Docker.Lnc 公司开源的一个基于 LXC 技术之上搭建的 Container 容器引擎&#xff0c;Docker 源代码托管在 Github上&#xff0c;Docker 是基于 Go 语言开发的并遵从 Apache2.0 协议开源。 Docker 属于 Linux 容器的一种封装&#xff0c;提供…

(十九)包装类

前言: 在我们讨论其他变量类型之间的相互转换时&#xff0c;我们需要了解一下Java的包装类&#xff0c;所谓包装类&#xff0c;就是能够直接将简单类型的变量表示为一个类&#xff0c;在执行变量类型的相互转换时&#xff0c;我们会大量使用这些包装类。Java共有六个包装类&…

pandas数据结构

文章目录Series创建series对象Series对象的属性DataFrame创建DataFrame对象Python 在数据处理上独步天下&#xff1a;代码灵活、开发快速&#xff1b;尤其是 Python 的 Pandas 包&#xff0c;无论是在数据分析领域、还是大数据开发场景&#xff0c;都具有显著的优势。Series S…

CesiumLab实例模型切片 CesiumLab系列教程

先解释下实例模型&#xff0c;实例模型使用 GPU instance 技术来渲染的模型&#xff0c;通常用来绘制大量几何体一致&#xff0c;但是位置姿态不同的对象&#xff0c;比如说森林场景&#xff0c;大量路灯&#xff0c;井盖等&#xff0c;如下图&#xff1a; 1.输入文件 目前输入…

【图文教程】Centos单机安装Redis

1.1.安装Redis依赖 Redis是基于C语言编写的&#xff0c;因此首先需要安装Redis所需要的gcc依赖&#xff1a; yum install -y gcc tcl1.2.上传安装包并解压 ​ 例如&#xff0c;凯哥将其放到了/usr/local/src 目录&#xff1a; 解压缩&#xff1a; tar -xzf redis-6.2.6.tar…

搞清clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTop

网页可见区域高:document.body.clientHeight 网页正文全文高:document.body.scrollHeight 网页可见区域高&#xff08;包括边线的高&#xff09;&#xff1a;document.body.offsetHeight 网页被卷去的高&#xff1a;document.body.scrollTop 屏幕分辨率高&#xff1a;window.sc…

SpringBoot实践(三十九):如何使用AOP

目录 直接使用Aspect 定义切面逻辑 模拟业务代码 测试输出 自定义注解方式 自定义切面注解 定义切入点逻辑 模拟业务代码 测试输出 面向切面&#xff08;AOP) 是spring重要特性&#xff0c;在功能上切面编程是面向对象编程的很好的补充&#xff0c;面向对象强调封装和开…

BAT 名企大厂做接口自动化如何高效使用 Requests ?

1080428 28.9 KBRequests是一个优雅而简单的python HTTP库&#xff0c;其实python内置了用于访问网络的资源模块&#xff0c;比如urllib&#xff0c;但是它不如requests简单&#xff0c;优雅&#xff0c;而且缺少许多实用功能。接下来的接口测试的学习和实战&#xff0c;都与re…