vue+element+springboot实现多张图片上传

     1.需求说明
     2.实现思路
     3.el-upload组件主要属性说明
     4.前端传递MultipartFile数组与服务端接收说明
     5.完整代码

1.需求说明

    动态模块新增添加动态功能,支持多张图片上传.实现过程中对el-upload组件不是很熟悉,踩了很多坑,当然也参考过别的文章,发现处理很复杂.这里记录最终实现结果,方便有同样问题的同学查看,避免浪费多余时间.下面是发布动态的页面,点击上传图片打开本地文件选择,点击确定完成动态发布功能.
在这里插入图片描述

2.实现思路

    多张图片上传逻辑(兼容单张图片上传,只需要修改最大上传图片数量为1):
    1.需要页面选择好所有图片之后调用服务端的图片上传接口,这样处理的原因是图片上传过程中会出现几种场景:

选择好图片之后要删除之前选择的某一张或某几张;
选择好图片之后要追加几张图片

如果按照选择一张就调用一次图片上传接口,不但会增加服务端调用次数,而且还会增加无效图片的存储成本.
    2.多张图片一次上传接口调用成功后返回多张图片的图片地址,再调用服务端动态发布接口,完成动态发布功能

3.el-upload组件主要属性说明

1.禁用选择图片自动上传功能
    action属性:图片上传服务端请求地址,在组件中属于必传,默认选择一张图片就要调用一次.按照上面梳理的逻辑需要禁用调用该功能,auto-upload设置为false即可.action由于是必传,所以此处设置为#
2.开启多选
    设置multiple设置为true,默认false,否则在出现的文件选择窗口中只能选择一个文件.
3.设置选择文件最大数量
    使用limit属性,超过最大数量的处理逻辑可以在on-exceed中实现,其中处理的逻辑是页面提示已超过最大数请重新选择.
4.显示已选择的图片列表
    设置file-list实现
5.选择好图片之后追加几张图片问题处理
    on-change可以监听选中的图片,一次性选择多个图片会执行多次,但是为保证业务处理逻辑执行成功,只需要最后一次on-change中添加业务处理,所以通过判断监听返回的fileList集合长度是否是最大来处理.自定义的fileList就是on-change中最后一次on-change监听返回的fileList集合信息.下文中自定义的imgUrlList为调用文件上传服务端组装的图片参数集合.服务端的file对象对应on-change监听file中的file.raw.

handleChange(file, fileList){let length = fileList.length	this.maxLength = Math.max(length, this.maxLength)setTimeout(() => {if(length !== this.maxLength) {return} else {this.fileList=fileList}})}

6.选择好图片之后删除已选中图片问题处理
    before-remove可以监听要进行删除的图片信息.每个图片中有一个唯一标识uid,通过唯一标识删除自定义fileList中的图片

handleRemove(file, fileList){this.fileList=this.fileList.filter(imgFile=>imgFile.uid != file.uid)},

4.前端传递MultipartFile[]与服务端接收说明

    服务端接口为post请求,请求方式为post表单提交.具体如下

@PostMapping("/uploadImg")public ResultVo uploadImg(@RequestParam(name = "multipartFiles") MultipartFile[] multipartFiles,@RequestParam(name = "fileType") Integer fileType) {String url = adminDriftService.adminUploadImg(multipartFiles,fileType);return ResultVoUtil.success(url);}

前端页面需要按照FormData类型进行传递,注意一下参数拼接:

let formData = new FormData();this.imgUrlList.map(img=>{formData.append("multipartFiles", img)})formData.append("fileType", 2)

5.完整代码

    前端:
dynamic.js:

export function uploadImg(formData) {return axios({url: 'uploadImg',method: 'POST',	data: formData})
}

新增动态弹窗:

<el-dialog title="新增动态" :visible.sync="addDynamicVisible"><el-form :model="addDynamicForm"><el-form-item label="用户昵称" :label-width="formLabelWidth"><el-select v-model="addDynamicForm.userId" filterable placeholder="请选择"><el-optionv-for="systemUser in systemUserList":key="systemUser.userId":label="systemUser.userName":value="systemUser.userId"></el-option></el-select></el-form-item><el-form-item label="动态文本内容" :label-width="formLabelWidth"><el-input v-model="addDynamicForm.contentText" autocomplete="off"></el-input></el-form-item><el-form-item label="动态图片" :label-width="formLabelWidth"><el-uploadaction="#":file-list="fileList":before-remove="handleRemove":auto-upload="false" :multiple="true" :on-change="handleChange":limit="9":on-exceed="handleExceed"list-type="picture"><el-button size="small" type="primary">点击上传</el-button><div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div></el-upload></el-form-item></el-form><div slot="footer" class="dialog-footer"><el-button @click="closeAddDynamic()">取 消</el-button><el-button type="primary" @click="addDynamicInfo()">确 定</el-button></div></el-dialog><script>			
import {findSystemUserList,addDynamic,uploadImg} from "@/api/dynamic";
export default {data() {return {addDynamicVisible:false, // 是否显示新增动态弹窗addDynamicForm:{}, // 新增动态内容systemUserList:[],  // 系统用户列表信息formLabelWidth: '120px',imgUrlList:[], // 上传文件地址集合fileList:[], // 上传文件本地显示图片集合(非服务器图片地址)maxLength:0 // 上传文件最大值}}methods:{// 图片列表删除之后处理操作handleRemove(file, fileList){this.fileList=this.fileList.filter(imgFile=>imgFile.uid != file.uid)},	// 每次打开本地文件选择窗口选择图片后处理操作		handleChange(file, fileList){let length = fileList.length	this.maxLength = Math.max(length, this.maxLength)setTimeout(() => {if(length !== this.maxLength) {return} else {this.fileList=fileList}})},	// 选择图片超过最大限制9张之后处理操作handleExceed(files, fileList){this.msgError("最多选取9张,请重新选择!")// 清空之前选择内容this.fileList=[]},// 添加动态操作addDynamicInfo(){// 参数校验if(!this.addDynamicForm.userId){this.msgError("请选择用户!")return}this.imgUrlList=this.fileList.map(file=>file.raw)this.serverUploadImg()},	  // 上传图片处理逻辑serverUploadImg() {let formData = new FormData();this.imgUrlList.map(img=>{formData.append("multipartFiles", img)})formData.append("fileType", 2)uploadImg(formData).then(res => {if (res.code === 200) {// 图片上传成功之后触发动态发布逻辑this.addDynamicForm.contentImg=res.datathis.serverAddDynamic()}else {this.msgError(res.msg)}}).catch(() => {this.msgError("请求失败")})},	// 动态发布逻辑serverAddDynamic() {addDynamic(this.addDynamicForm).then(res => {if (res.code === 200) {this.msgSuccess('添加成功!');this.addDynamicVisible=false;this.addDynamicForm={};this.imgUrlList=[];this.fileList=[];this.serverFindDynamicInfoList(this.queryInfo)}else {this.msgError(res.msg)}}).catch(() => {this.msgError("请求失败")})},	  }
</script>		

服务端文件批量上传:

  @ApiImplicitParams({@ApiImplicitParam(name = "multipartFiles",value = "图片集合",required = true, dataType = "MultipartFile[]"),@ApiImplicitParam(name = "fileType",value = "文件类型:1.用户图片:头像以及背景图;2.动态图",required = true,dataType = "Integer",paramType = "insert",example = "1")})@ApiOperation("上传图片")@PostMapping("/uploadImg")public ResultVo uploadImg(@NotNull(message = "文件对象不允许为空!") @RequestParam(name = "multipartFiles") MultipartFile[] multipartFiles,@NotNull(message = "文件类型不允许为空!") @RequestParam(name = "fileType") Integer fileType) {String url = service.adminUploadImg(multipartFiles,fileType);return ResultVoUtil.success(url);}

多张文件上传实现逻辑:

   public String adminUploadImg(MultipartFile[] multipartFiles, Integer fileType) {String imgUrlStr ="";for (int i = 0; i < multipartFiles.length; i++) {String url = aliYunService.uploadImg(multipartFiles[i], fileType,"");imgUrlStr=imgUrlStr+url;if(multipartFiles.length > 1  && i < multipartFiles.length-1){imgUrlStr=imgUrlStr+",";}}return imgUrlStr;}

图片上传具体实现逻辑:

public String uploadImg(MultipartFile multipartFile,Integer fileType,String fileNameParam) {// 返回文件地址String fileUrl = "";// 文件校验checkFile(multipartFile,fileType);// 文件上传路径// modify by txm 2023/3/24 图片类型修改为枚举String filePath = FilePathEnum.getOSSFilePath(fileType);String fileName = StrUtil.isBlank(fileNameParam) ?  multipartFile.getOriginalFilename():fileNameParam;String pathKey = StrUtil.concat(true,filePath,"/",fileName);// meta设置请求头OSS ossClient = new OSSClientBuilder().build(driftConfig.getEndpoint(), driftConfig.getOssAccessKeyId(), driftConfig.getOssAccessKeySecret());try {// 上传至阿里OSSossClient.putObject(driftConfig.getBucketName(), pathKey, new ByteArrayInputStream(multipartFile.getBytes()));fileUrl = driftConfig.getUrlPrefix() + pathKey;} catch (Exception e) {// modify by txm 2023/10/16 修改描述log.error("文件上传失败:{}", e.getMessage());throw new BusinessException("文件上传失败:请重试!");} finally {if (ossClient != null) {ossClient.shutdown();}}// 上传成功return fileUrl;}

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

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

相关文章

Spark RDD操作性能优化技巧

Apache Spark是一个强大的分布式计算框架&#xff0c;用于处理大规模数据。然而&#xff0c;在处理大数据集时&#xff0c;性能优化成为一个关键问题。本文将介绍一些Spark RDD操作的性能优化技巧&#xff0c;帮助大家充分利用Spark的潜力&#xff0c;并获得更快的处理速度。 …

2023.12.27 关于 Redis 数据类型 List 常用命令

目录 List 类型基本概念 List 类型特点 List 操作命令 LPUSH LPUSHX RPUSH RPUSHX LRANGE LPOP RPOP LINDEX LINSERT LREM LTRIM LSET 阻塞版本的命令 阻塞版本 和 非阻塞版本的区别 BLPOP & BRPOP List 类型基本概念 Redis 中的列表&#xff08;list&am…

第十一章 Stream消息驱动

Stream消息驱动 gitee:springcloud_study: springcloud&#xff1a;服务集群、注册中心、配置中心&#xff08;热更新&#xff09;、服务网关&#xff08;校验、路由、负载均衡&#xff09;、分布式缓存、分布式搜索、消息队列&#xff08;异步通信&#xff09;、数据库集群、…

Apache Commons JCS缓存解决方案

第1章&#xff1a;引言 大家好&#xff0c;我是小黑&#xff01;今天&#xff0c;咱们来聊聊Apache Commons JCS&#xff0c;一个Java界里的缓存大杀器。缓存技术&#xff0c;对于提高应用性能来说&#xff0c;就像是给它加了一剂兴奋剂&#xff0c;能让数据访问变得快如闪电。…

Qt(二):使用udp发送与接收图片

使用Qt来通过UDP协议发送和接收图片可以分为几个步骤。以下是一个基本的指南&#xff1a; 发送图片准备图片数据&#xff1a;首先&#xff0c;你需要将图片转换为可以在网络上传输的数据格式。通常&#xff0c;这涉及到将图片转换为字节数组。设置UDP套接字&#xff1a;在Qt中…

OpenCV-Python(21):OPenCV查找及绘制轮廓

1.认识轮廓 1.1 目标 理解什么是轮廓学习掌握找轮廓、绘制轮廓等学习使用cv2.findContours()、cv2.drawContours()函数的用法 1.2 什么是轮廓 在OpenCV中&#xff0c;轮廓是图像中连续的边界线的曲线&#xff0c;具有相同的颜色或者灰度&#xff0c;用于表示物体的形状。轮廓…

linux用户态与内核态通过字符设备交互

linux用户态与内核态通过字符设备交互 简述 Linux设备分为三类&#xff0c;字符设备、块设备、网络接口设备。字符设备只能一个字节一个字节读取&#xff0c;常见外设基本都是字符设备。块设备一般用于存储设备&#xff0c;一块一块的读取。网络设备&#xff0c;Linux将对网络…

web自动化(4)——POM设计重构

1. 什么是POM Page Object Model 是ui自动化测试中常见的封装方式。 原理&#xff1a;将页面封装为PO对象&#xff0c;然后通过面向对象的方式实现UI自动化 2. 封装原则 PO无需包含全部UI元素PO应当验证元素PO不应该包含断言PO不应该暴露元素 3. 怎么进行POM封装 面向对象…

Centos7:Jenkins+gitlab+node项目启动(2)

Centos7&#xff1a;Jenkinsgitlabnode项目启动(1) Centos7&#xff1a;Jenkinsgitlabnode项目启动(1)-CSDN博客 Centos7&#xff1a;Jenkinsgitlabnode项目启动(2) Centos7&#xff1a;Jenkinsgitlabnode项目启动(2)-CSDN博客 Centos7&#xff1a;Jenkinsgitlabnode项目启…

自动化网络故障修复管理

什么是故障管理 故障管理是网络管理的组成部分&#xff0c;涉及检测、隔离和解决问题。如果实施得当&#xff0c;网络故障管理可以使连接、应用程序和服务保持在最佳水平&#xff0c;提供容错能力并最大限度地减少停机时间。专门为此目的设计的平台或工具称为故障管理系统。 …

目标检测损失函数:IoU、GIoU、DIoU、CIoU、EIoU、alpha IoU、SIoU、WIoU原理及Pytorch实现

前言 损失函数是用来评价模型的预测值和真实值一致程度&#xff0c;损失函数越小&#xff0c;通常模型的性能越好。不同的模型用的损失函数一般也不一样。损失函数主要是用在模型的训练阶段&#xff0c;如果我们想让预测值无限接近于真实值&#xff0c;就需要将损失值降到最低…

vue3(十)-基础入门之Swiper轮播与自定义指令

一、Swiper html : 注意&#xff1a; class“swiper-wrapper”、class“swiper-slide” 等类名不能写错 <body><!-- 导入下载好的包或通过 CDN 导入vue、swiper.js、swiper.css --><!-- <script src"https://unpkg.com/vue3/dist/vue.global.js"&…

RK3568平台开发系列讲解(Linux系统篇)PWM系统编程

🚀返回专栏总目录 文章目录 一、什么是PWM二、PWM相关节点三、PWM应用编程沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇将介绍 PWM 的系统编程。 一、什么是PWM PWM,即脉冲宽度调制(Pulse Width Modulation)

【PowerMockito:编写单元测试过程中采用when打桩失效的问题】

问题描述 正如上图所示&#xff0c;采用when打桩了&#xff0c;但是&#xff0c;实际执行的时候还是返回null。 解决方案 打桩时直接用any() 但是这样可能出现一个mybatisplus的异常&#xff0c;所以在测试类中需要加入以下代码片段&#xff1a; Beforepublic void setUp() …

Awesome Chrome Form UI - 框架设计与基础实现

Money is not evil by itself. Its just paper with perceived value to obtain other things we value in other ways. If not money what is evil you may ask? Evil is the unquenchable, obsessive and moral bending desire for more. Evil is the bottomless,soulless …

解决VSCode中C/C++ Project Generator插件创建的项目只能运行单个程序的问题

初六&#xff0c;履霜&#xff0c;坚冰至。 释意&#xff1a;初六&#xff0c;当你踩着微霜之时&#xff0c;严寒与坚冰也就即将到来。 目录 一、前言 二、问题描述 三、解决方案 1、思路总结 2、思考过程 3、解决方案&#xff08;直接用&#xff0c;报错找我(&#xff8…

超声功率放大器怎么用

超声功率放大器是一种用于放大超声信号的设备&#xff0c;广泛应用于医疗领域、工业领域和科学研究中。它能够将超声信号的能量增加到足够大的水平&#xff0c;以便进行高强度超声疗法、材料加工和实验研究等应用。下面将详细介绍超声功率放大器的使用方法和其工作原理。 首先&…

数据结构——红黑树 and B-树

红黑树 根据平衡条件第4、5两点 最短路径&#xff0c;都是黑色 最长路径&#xff0c;红黑相间 最长是最短的两倍 B-树

《深入理解Java虚拟机(第三版)》读书笔记:Java内存区域与内存溢出异常、垃圾收集器与内存分配策略

下文是阅读《深入理解Java虚拟机&#xff08;第3版&#xff09;》这本书的读书笔记&#xff0c;如有侵权&#xff0c;请联系删除。 文章目录 第2章 Java内存区域与内存溢出异常2.2 运行时数据区域2.3 HotSpot虚拟机对象探秘 第3章 垃圾收集器与内存分配策略3.2 对象已死&…

安装Node修改Node镜像地址搭建Vue脚手架创建Vue项目

1、安装VSCode和Node 下载VSCode Visual Studio Code - Code Editing. Redefined 下载Node Node.js (nodejs.org) 检验是否安装成功&#xff0c;WinR,输入cmd命令&#xff0c;使用node -v可以查看到其版本号 2、修改镜像地址 安装好node之后&#xff0c;开始修改镜像地址 …