VUE+ELEMENTUI el-upload照片墙手动上传多张图片 保存和修改功能前后端完整实现

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

VUE+ELEMENTUI el-upload照片墙手动上传多张图片 保存和修改功能前后端完整实现

el-upload照片墙上传的方式是,选择完一个文件后,就立马上传,而不是多个文件一块上传。这个细节在我写的时候没注意到,以至于时间被耗费,神经要抓狂。
将自动上传改为手动上传方式的话,就需要我们自己创建新的formdata对象,以便得到选择的图片文件,能传到后端。后端使用MultipartFile[] multipartFiles接收。
点击保存按钮时,需要对form表单数据入库和图片文件上传到本地两部分操作。实现的思路是,当图片上传成功后返回图片的name集合,将集合传到后端,然后对name集合循环进行入库即可。
效果:
在这里插入图片描述
如下:

前端

<template>
	<el-dialog :title="!dataForm.id ? '新增' : '修改'" :close-on-click-modal="false" :visible.sync="visible">
		<el-form :model="dataForm" :rules="dataRule" ref="dataForm" @keyup.enter.native="dataFormSubmit()" label-width="80px">
			<el-row>
				<el-col>
					<el-form-item label="单位名称" prop="groupName">
						<el-input v-model="dataForm.groupName" placeholder="单位名称"></el-input>
					</el-form-item>
				</el-col>
			</el-row>
			<el-row>
				<el-col>
					<el-form-item label="负责人" prop="groupManager">
						<el-input v-model="dataForm.groupManager" placeholder="负责人"></el-input>
					</el-form-item>
				</el-col>
			</el-row>
			<el-row>
				<el-col>
					<el-form-item label="联系方式" prop="telephone">
						<el-input v-model="dataForm.telephone" placeholder="联系方式" maxlength="11"></el-input>
					</el-form-item>
				</el-col>
			</el-row>
			<el-row>
				<el-col>
					<el-form-item :class="{hide:hideUpload}">
						<el-upload ref="upload" action="#" multiple :limit="limit" :file-list="dataForm.imgFileList" list-type="picture-card"
						 :on-preview="handlePictureCardPreview" :on-change="OnChange" :on-remove="handleRemove" :on-exceed="handleExceed"
						 accept="image/jpeg,image/png" :auto-upload="false">
							<i class="el-icon-plus"></i>
							<div class="el-upload__tip" slot="tip">只能上传jpg/png文件,最多上传5张且单张图片不超过5M
							</div>
						</el-upload>
						<el-dialog :visible.sync="dialogVisible" append-to-body>
							<img width="100%" :src="dialogImageUrl" alt="">
						</el-dialog>
					</el-form-item>
				</el-col>
			</el-row>
		</el-form>

		<span slot="footer" class="dialog-footer">
			<el-button @click="visible = false">取消</el-button>
			<el-button type="primary" @click="submitUpload()">确定</el-button>
		</span>
	</el-dialog>
</template>
<script>
	import {
		isMobile
	} from '@/utils/validate'
	export default {
		data() {
			var validateMobile = (rule, value, callback) => {
				if (!isMobile(value)) {
					callback(new Error('联系方式格式错误'))
				} else {
					callback()
				}
			}
			return {
				visible: false,
				uploadUrl: '',
				dialogImageUrl: '',
				dialogVisible: false,
				limit: 5,
				hideUpload: false, //是否显示上传图片的加号
				imgInfoList: [], //包含图片的id,name,size的集合
				imgNameList: [], //后端返回的上传图片的name集合,传到后端
				imgSize: [], //后端返回的上传图片的imgSize集合,传到后端
				deleteImgFileList: [], //存已被删除了的图片的id
				dataForm: {
					id: 0,
					groupName: '',
					groupManager: '',
					telephone: '',
					imgFileList: []//绑定用户上传的图片List
				},
				dataRule: {
					groupName: [{
						required: true,
						message: '单位名称不能为空',
						trigger: 'blur'
					}],
					groupManager: [{
						required: true,
						message: '负责人不能为空',
						trigger: 'blur'
					}],
					telephone: [{
						required: true,
						message: '联系方式不能为空',
						trigger: 'blur'
					}]
				}
			}
		},
		methods: {
			//点击上传图片
			submitUpload() {
				let formData = new FormData(); //  用FormData存放上传文件
				this.dataForm.imgFileList.forEach(file => {
					console.log(file.raw)
					console.log(file.size)
					formData.append('file', file.raw)
				})
				this.$http({
					url: this.uploadUrl,
					method: 'post',
					data: formData,
					headers: {
						"Content-Type": "multipart/form-data"
					}
				}).then(({
					data
				}) => {
					if (data && data.code === 0) {
						for (var i = 0; i < data.imgNameList.length; i++) {
							this.imgNameList.push(data.imgNameList[i].name)
							this.imgSize.push(data.imgNameList[i].size)
						}
						this.dataFormSubmit()
						this.$refs.upload.clearFiles();
					} else {
						this.$message.error(data.msg)
					}
				})
			},
			//预览图片时
			handlePictureCardPreview(file) {
				this.dialogImageUrl = file.url
				this.dialogVisible = true
			},
			OnChange(file, fileList) {
				const isType = file.type === 'image/jpeg' || 'image/png'
				const isLt5M = file.size / 1024 / 1024 < 5

				if (!isType) {
					this.$message.error('上传头像图片只能是 JPG 格式!');
					fileList.pop()
				}
				if (!isLt5M) {
					this.$message.error('上传头像图片大小不能超过 5MB!');
					fileList.pop()
				}
				this.dataForm.imgFileList.push(file)
				this.hideUpload = fileList.length >= this.limit

			},
			//删除图片时
			handleRemove(file, fileList) {
				if (file.id) {
					console.log('删除了已被上传过的图片')
					console.log(file.id)
					this.deleteImgFileList.push(file.id)
				}
				this.dataForm.imgFileList = fileList
				this.hideUpload = fileList.length >= this.limit
			},
			//文件超出个数限制时
			handleExceed(files, fileList) {
				this.$message.warning(`当前限制选择 5 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);
			},
			//获取图片信息
			getImgInfo(id) {
				this.$http({
					url: this.$http.adornUrl('/sys/sysgroup/queryImgByGroupId'),
					method: 'get',
					params: this.$http.adornParams({
						'id': id
					})
				}).then(({
					data
				}) => {
					if (data && data.code === 0) {
						if (data.imgInfoList.length === 5) {
							this.hideUpload = true
						}
						for (var i = 0; i < data.imgInfoList.length; i++) {
							this.dataForm.imgFileList.push({
								"url": window.SITE_CONFIG.imgUrl + data.imgInfoList[i].fileName,
								'name': data.imgInfoList[i].fileName,
								'size': data.imgInfoList[i].imgSize,
								"id": data.imgInfoList[i].id
							})
						}
					}
				})
			},

			init(id) {
				this.dataForm.imgFileList = []
				this.imgNameList = []
				this.imgSize = []
				this.deleteImgFileList = []
				this.dataForm.id = id || 0
				this.visible = true
				this.hideUpload = false
				this.uploadUrl = this.$http.adornUrl(`/sys/sysgroup/upload?token=${this.$cookie.get('token')}`)
				this.$nextTick(() => {
					this.$refs['dataForm'].resetFields()
					if (this.dataForm.id) {
						//回显图片
						this.getImgInfo(id)
						this.$http({
							url: this.$http.adornUrl(`/sys/sysgroup/info/${this.dataForm.id}`),
							method: 'get',
							params: this.$http.adornParams()
						}).then(({
							data
						}) => {
							if (data && data.code === 0) {
								this.dataForm.groupName = data.sysGroupEntity.groupName
								this.dataForm.groupManager = data.sysGroupEntity.groupManager
								this.dataForm.telephone = data.sysGroupEntity.telephone
							}
						})
					}
				})
			},
			// 表单提交
			dataFormSubmit() {
				this.$refs['dataForm'].validate((valid) => {
					if (valid) {

						this.$http({
							url: this.$http.adornUrl(`/sys/sysgroup/${!this.dataForm.id ? 'save' : 'update'}`),
							method: 'post',
							params: this.$http.adornParams({
								'id': this.dataForm.id || undefined,
								'groupName': this.dataForm.groupName,
								'groupManager': this.dataForm.groupManager,
								'telephone': this.dataForm.telephone,
								'imgNameList': this.imgNameList.join(","),
								'deleteImgFileList': this.deleteImgFileList.join(","),
								'imgSize': this.imgSize.join(","),
								'cuser': this.$cookie.get('userId'),
								'muser': this.$cookie.get('userId')
							})
						}).then(({
							data
						}) => {
							if (data && data.code === 0) {
								this.$message({
									message: '操作成功',
									type: 'success',
									duration: 1500,
									onClose: () => {
										this.hideUpload = false
										this.visible = false
										this.$emit('refreshDataList')
									}
								})
							} else {
								this.$message.error(data.msg)
							}

						})

					}
				})
			}
		}
	}
</script>
<style>
	.hide .el-upload--picture-card {
		display: none;
	}
</style>

后端

controller.java
/**
     * 上传文件
     */
    @PostMapping("/upload")
    public R upload(@RequestParam("file") MultipartFile[] multipartFiles, HttpServletRequest request) throws Exception {
        // 从配置文件获取存文件路径
        Properties properties = new Properties();
        InputStream inputStream = SysGroupController.class.getResourceAsStream("/page.properties");
        properties.load(inputStream);
        String uploadPath = properties.getProperty("uploadPath");
        int singleImgSize = Integer.valueOf(properties.getProperty("singleImgSize"));
        List<Map<String,Object>> imgNameList=new ArrayList<>();
        for (int i = 0; i < multipartFiles.length; i++) {
            MultipartFile file = multipartFiles[i];
            if (file.isEmpty()) {
                throw new RRException("文件上传失败");
            }
            //文件大小不超过5M
            if (!UploadFileUtils.checkFileSize(file.getSize(), singleImgSize, "M")) {
                throw new RRException("文件大小不能超过5M");
            }
            // 获取文件名称,包含后缀
            String fileName = file.getOriginalFilename();
            //避免文件名字重复
            String uuid = UUID.randomUUID().toString().replaceAll("\\-", "");
            //获取文件后缀
            String suffix = fileName.substring(fileName.lastIndexOf("."));
            //重命名后的文件名
            fileName = uuid + suffix;
            Map<String,Object> imgMap=new HashMap<>();
            imgMap.put("name",fileName);
            imgMap.put("size",file.getSize());
            imgNameList.add(imgMap);
            //上传文件到本地
            UploadFileUtils.fileupload(file.getBytes(), uploadPath, fileName);
        }
        return R.ok().put("imgNameList", imgNameList);
    }

 /**
     * 根据sys_group.id查询上传的图片
     */
    @RequestMapping("/queryImgByGroupId")
    public R queryImgByGroupId(@RequestParam Long id) {
        List<Map<String,Object>> imgInfoList = sysGroupService.queryImgByGroupId(id);
        return R.ok().put("imgInfoList", imgInfoList);
    }
 /**
     * sys_group新增
     */
    @RequestMapping("/save")
    public R save(@RequestParam Map<String, Object> params) {
        try {
            sysGroupService.groupSave(params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.ok();
    }


    /**
     * sys_group修改
     */
    @RequestMapping("/update")
    public R update(@RequestParam Map<String, Object> params) {
        try {
            sysGroupService.groupUpdate(params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.ok();
    }

serviceImpl.java
/**
     * sys_group新增
     */
    @Transactional
    @Override
    public void groupSave(Map<String, Object> params) throws IOException {
        SysGroupEntity sysGroupEntity = new SysGroupEntity();
        sysGroupEntity.setGroupName(params.get("groupName").toString());
        sysGroupEntity.setGroupManager(params.get("groupManager").toString());
        sysGroupEntity.setTelephone(params.get("telephone").toString());
        sysGroupEntity.setCuser(Long.parseLong(params.get("cuser").toString()));
        sysGroupDao.groupSave(sysGroupEntity);

        // 从配置文件获取存文件路径
        Properties properties = new Properties();
        InputStream inputStream = SysGroupServiceImpl.class.getResourceAsStream("/page.properties");
        properties.load(inputStream);
        String uploadPath = properties.getProperty("uploadPath");

        if (!params.get("imgNameList").equals("") && !params.get("imgSize").equals("")) {
            String imgNameArr[] = params.get("imgNameList").toString().split(",");
            String imgSizeArr[] = params.get("imgSize").toString().split(",");
            for (int i = 0; i < imgNameArr.length; i++) {
                Map<String, Object> fileParams = new HashMap<>();
                fileParams.put("fkId", sysGroupEntity.getId());
                fileParams.put("fileType", 1);
                fileParams.put("fileName", imgNameArr[i]);
                fileParams.put("filePath", uploadPath + imgNameArr[i]);
                fileParams.put("sortNo", i + 1);
                fileParams.put("imgSize", Long.parseLong(imgSizeArr[i]));
                fileParams.put("cuser", Long.parseLong(params.get("cuser").toString()));
                sysGroupDao.sysFileSave(fileParams);
            }
        }


    }


    /**
     * sys_group修改
     */
    @Transactional
    @Override
    public void groupUpdate(Map<String, Object> params) throws Exception {
        sysGroupDao.groupUpdate(params);
        /*
        判断用户是否将之前上传过的图片删除掉,修改为其他图片
        如果是,就根据删除掉的图片的ID从数据库中删除掉
         */
        if (!params.get("deleteImgFileList").equals("")) {
            String deleteImgFileArr[] = params.get("deleteImgFileList").toString().split(",");
            for (int i = 0; i < deleteImgFileArr.length; i++) {
                sysGroupDao.sysFileDeleteById(Long.parseLong(deleteImgFileArr[i]));
            }
        }

        // 从配置文件获取存文件路径
        Properties properties = new Properties();
        InputStream inputStream = SysGroupController.class.getResourceAsStream("/page.properties");
        properties.load(inputStream);
        String uploadPath = properties.getProperty("uploadPath");

        if (!params.get("imgNameList").equals("") && !params.get("imgSize").equals("")) {
            String imgNameArr[] = params.get("imgNameList").toString().split(",");
            String imgSizeArr[] = params.get("imgSize").toString().split(",");
            for (int i = 0; i < imgNameArr.length; i++) {
                Map<String, Object> fileParams = new HashMap<>();
                fileParams.put("fkId", Long.parseLong(params.get("id").toString()));
                fileParams.put("fileType", 1);
                fileParams.put("fileName", imgNameArr[i]);
                fileParams.put("filePath", uploadPath + imgNameArr[i]);
                fileParams.put("sortNo", i + 1);
                fileParams.put("imgSize", Long.parseLong(imgSizeArr[i]));
                fileParams.put("muser", Long.parseLong(params.get("cuser").toString()));
                sysGroupDao.sysFileUpdate(fileParams);
            }
        }
    }


/**
     * 根据sys_group.id查询上传的图片
     */
    @Override
    public List<Map<String, Object>> queryImgByGroupId(Long id) {
        return sysGroupDao.queryImgByGroupId(id);
    }
dao.xml

我这里的分组信息要和图片信息对应起来,根据分组ID关联的。这就又遇到了一个问题:在新建分组时,分组数据此刻还没入库要怎么获取到分组ID呢??其实这个问题我也是第一次遇见,后来询问了我们领导才知道这个问题是可以解决的,在SQL中用 SELECT @@IDENTITY即可。我真的是太菜了。。。

<!--void groupSave(SysGroupEntity sysGroupEntity);-->
    <!-- 指定结果类型resultType,keyProperty是属性,自动返回到属性id中,order是次序,after是指获取id是在于插入后 -->
    <insert id="groupSave" parameterType="io.renren.modules.sys.entity.SysGroupEntity">
        INSERT INTO sys_group (
        group_name,
        group_manager,
        telephone,
        cdate,
        cuser )
        VALUES(
        #{groupName},
        #{groupManager},
        #{telephone},
        NOW( ),
        #{cuser})

        <selectKey resultType="java.lang.Long" keyProperty="id" order="AFTER">
            SELECT @@IDENTITY
        </selectKey>
    </insert>

    <!--void groupUpdate(@Param("pm")Map<String,Object> params);-->
    <update id="groupUpdate" parameterType="Map">
        UPDATE
            sys_group
            SET group_name = #{pm.groupName},
            group_manager=#{pm.groupManager},
            telephone=#{pm.telephone},
            mdate=NOW( ),
            muser=#{pm.muser}
            WHERE id=#{pm.id}
    </update>

这个是图片信息的数据表:
<!--void sysFileSave(@Param("pm")Map<String,Object> params);-->
    <insert id="sysFileSave" parameterType="Map">
        INSERT INTO sys_file (
        fk_id,
        fileType,
        fileName,
        filePath,
        sortNo,
        imgSize,
        cdate,
        cuser )
        VALUES(
        #{pm.fkId},
        #{pm.fileType},
        #{pm.fileName},
        #{pm.filePath},
        #{pm.sortNo},
        #{pm.imgSize},
        NOW( ),
        #{pm.cuser})
    </insert>

    <!--void sysFileUpdate(@Param("pm")Map<String,Object> params);-->
    <update id="sysFileUpdate" parameterType="Map">
        INSERT INTO sys_file (
        fk_id,
        fileType,
        fileName,
        filePath,
        sortNo,
        imgSize,
        mdate,
        muser )
        VALUES(
        #{pm.fkId},
        #{pm.fileType},
        #{pm.fileName},
        #{pm.filePath},
        #{pm.sortNo},
        #{pm.imgSize},
        NOW( ),
        #{pm.muser})
    </update>



  <!--根据sys_group.id查询上传的图片-->
    <!--List<Map<String,Object>> queryImgByGroupId(Long id);-->
    <select id="queryImgByGroupId" parameterType="java.lang.Long" resultType="Map">
        SELECT
            id,fileName,imgSize
        FROM
            sys_file
        WHERE
            fk_id = #{id}
    </select>

  <!--sys_file根据ID删除-->
    <!--void sysFileDeleteById(Long id);-->
    <delete id="sysFileDeleteById" parameterType="java.lang.Long">
        DELETE FROM sys_file WHERE id=#{id}
    </delete>

    <!--sys_file根据fk_id删除-->
    <!--void sysFileDeleteByFkId(Long id);-->
    <delete id="sysFileDeleteByFkId" parameterType="java.lang.Long">
        DELETE FROM sys_file WHERE fk_id=#{id}
    </delete>
R.java
import org.apache.http.HttpStatus;

import java.util.HashMap;
import java.util.Map;

/**
 * 返回数据
 * 
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2016年10月27日 下午9:59:27
 */
public class R extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;
	
	public R() {
		put("code", 0);
		put("msg", "success");
	}
	
	public static R error() {
		return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
	}
	
	public static R error(String msg) {
		return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
	}
	
	public static R error(int code, String msg) {
		R r = new R();
		r.put("code", code);
		r.put("msg", msg);
		return r;
	}

	public static R ok(String msg) {
		R r = new R();
		r.put("msg", msg);
		return r;
	}
	
	public static R ok(Map<String, Object> map) {
		R r = new R();
		r.putAll(map);
		return r;
	}
	
	public static R ok() {
		return new R();
	}

	public R put(String key, Object value) {
		super.put(key, value);
		return this;
	}
}

UploadFileUtils.java上传文件工具类
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * 上传文件工具类
 *
 * @author ZYR
 * @date 2019/11/29
 */
public class UploadFileUtils {

    /**
     * 通过该方法将在指定目录下添加指定文件
     *
     * @param file     文件的二进制
     * @param filePath 文件路径
     * @param fileName 文件名
     * @throws IOException
     */
    public static void fileupload(byte[] file, String filePath, String fileName) throws IOException {
        //目标目录
        File targetfile = new File(filePath);
        if (!targetfile.exists()) {
            targetfile.mkdirs();
        }
        //判断后缀名是否为允许的后缀名
        if (checkFile(fileName.substring(fileName.lastIndexOf(".")))) {
            //二进制流写入
            FileOutputStream out = new FileOutputStream(filePath + fileName);
            out.write(file);
            out.flush();
            out.close();
        }
    }

    /**
     * 判断文件大小
     *
     * @param len  文件长度
     * @param size 限制大小
     * @param unit 限制单位(B,K,M,G)
     * @return
     */
    public static boolean checkFileSize(Long len, int size, String unit) {
        double fileSize = 0;
        if ("B".equals(unit.toUpperCase())) {
            fileSize = (double) len;
        } else if ("K".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1024;
        } else if ("M".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1048576;
        } else if ("G".equals(unit.toUpperCase())) {
            fileSize = (double) len / 1073741824;
        }
        if (fileSize > size) {
            return false;
        }
        return true;
    }


    /**
     * 判断是否为允许的上传文件类型,true表示允许
     */
    private static boolean checkFile(String suffix) {
        //设置允许上传文件类型
        String suffixList = "jpg,png,bmp,jpeg,ico,xls,doc,ppt,txt,zip,pdf,tar";
        // 获取文件后缀
        suffix = suffix.substring(1);
        if (suffixList.contains(suffix.trim().toLowerCase())) {
            return true;
        }
        return false;
    }
}

这个功能看似很简单,但需要做的细节有很多,虽然在大神们的手上半天能解决掉,但对于小菜菜的我来说,困扰我了好多天,哎。。。。。。。。
可能我写的还是有点不足不完善不精致,但由于这个功能对我来说太鸡肋太深刻,所以就将它作为我的第一篇博客啦 。

  • 23
    点赞
  • 88
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
以下是使用Vue3的el-upload组件上传多张图片的示例代码: ```html <template> <el-upload class="upload-demo" action="/upload" :on-success="handleSuccess" :before-upload="beforeUpload" multiple :limit="3" :auto-upload="false" :file-list="fileList" > <el-button size="small" type="primary">点击上传</el-button> <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div> </el-upload> </template> <script> import { ref } from 'vue'; export default { setup() { const fileList = ref([]); const beforeUpload = (file) => { const isJPG = file.type === 'image/jpeg' || file.type === 'image/png'; const isLt500K = file.size / 1024 < 500; if (!isJPG) { this.$message.error('只能上传jpg/png文件'); } if (!isLt500K) { this.$message.error('文件大小不能超过500kb'); } return isJPG && isLt500K; }; const handleSuccess = (response, file) => { this.$message.success('上传成功'); // 处理上传成功后的逻辑 }; return { fileList, beforeUpload, handleSuccess, }; }, }; </script> ``` 在上述代码中,我们使用了Vue3的`ref`函数来创建了一个响应式的`fileList`数组,于存储上传的文件列表。`beforeUpload`函数用于在上传之前进行文件类型和大小的校验,只有符合要求的文件才会被上传。`handleSuccess`函数用于处理上传成功后的逻辑,你可以在其中进行图片压缩和合并为zip文件的操作。 请注意,上述代码中的`action`属性需要根据你的实际情况进行修改,以指定上传文件的接口地址。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值