版权声明:本文为博主原创文章,遵循 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;
}
}
这个功能看似很简单,但需要做的细节有很多,虽然在大神们的手上半天能解决掉,但对于小菜菜的我来说,困扰我了好多天,哎。。。。。。。。
可能我写的还是有点不足不完善不精致,但由于这个功能对我来说太鸡肋太深刻,所以就将它作为我的第一篇博客啦 。