- 问题
我用el-upload上传图片,再上一篇文章已经解决了,el-upload上传图片给SpringBoot后端,但是又发现了新的问题,果然bug是一个个的冒出来的。新的问题是el-upload编辑时回显图片的保存。- 问题描述:回显图片需要将默认的
file-list
设置为data中的属性,以设置默认值。如下,设置为imgList
- 问题描述:回显图片需要将默认的
<el-upload
action=""
list-type="picture-card"
multiple
:on-change="handlChange"
:file-list="imgList"
:on-error="handleErr"
ref="upload"
:limit="10"
accept=".jpg,.png,.jpeg"
:on-exceed="handleMaxNum"
:auto-upload="false">
<i slot="default" class="el-icon-plus"></i>
<div slot="file" slot-scope="{file}">
<img
class="el-upload-list__item-thumbnail"
:src="file.url" alt=""
>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
但是这样的自己设置的值,他的格式是这样的:
this.imgList = this.imgList.map(url => ({
url: url,
})
与自己上传文件通过:file_list
得到的内容不同,(也就是如果你有个添加图片的功能,有个编辑图片的功能,编辑功能你要设置初始值,但是他们的imgList不一样),有图为证
这会导致什么呢?首先,我们需要将imgList的文件转成FormData格式的文件传给后端,通过获取file-ist,可以通过:on-change="handlChange"
获取
handleChange(file, fileList) {
this.imgList = fileList;
},
- 如果你是添加图片的功能的时候,他是没问题的,可以直接使用
formData.append('files', item.raw);
转成FormData的类型。 - 但是如果你是要回显图片再保存,即编辑的功能,这个时候你要设置初始值,即用上面所说的方式设置。这种格式的的imgList,就不能直接使用
formData.append('files', item.raw);
这种方式转成FormData,而要使用fetch的方式
- 解决
下面是解决的代码,可以先对imgList的url进行判断,因为自己上传的url开头是不带"blob"的,顺便说一下,因为fetch是异步的,所以要通过设置Promise,等fetch全部执行完再进行保存图片,否则FormData还是会为空
this.imgList.forEach(item => {
let url = item.url;
if(url.startsWith("blob")){
formData.append('files', item.raw);
}
else {
let promise = fetch(url, {
headers: new Headers({
'Origin': location.origin
}),
mode: 'no-cors'
}
)
.then(response => response.blob())
.then(blob => {
// 创建 URL 对象以便提取文件名
let filename = url.split('/').pop();
// 创建一个虚拟的 File 对象
let file = new File([blob], filename, {type: 'image/bmp,image/jpeg,image/png,image/webp'});
console.log(file)
formData.append('files', file);
})
.catch(error => {
console.error('Failed to fetch image:', error);
});
promises.push(promise);
}
});
Promise.all(promises).then(() => {
console.log("formdata", formData)
let uri = "/" + newAttractionId
saveImgs(uri, formData)
.then(resPic => {
if (resPic.data.success) {
// this.$message({
// type:"success",
// message:resPic.data.msg
// })
} else {
this.$message({
type: "info",
message: resPic.data.msg
})
}
}).catch(err => {
console.log("出错", err)
})
整合主要代码如下
<el-button size="mini" @click="handleEdit(scope.$index, scope.row)">编辑</el-button>
<el-dialog :title="title" :visible.sync="editFormVisible" width="35%" @click="closeDialog">
<el-form-item label="图片" prop="imgList">
<!-- :file-List可以填默认值-->
<el-upload
action=""
list-type="picture-card"
multiple
:on-change="handleChange"
:file-list="imgList"
:on-error="handleErr"
ref="upload"
:limit="10"
accept=".jpg,.png,.jpeg"
:on-exceed="handleMaxNum"
:auto-upload="false">
<i slot="default" class="el-icon-plus"></i>
<div slot="file" slot-scope="{file}">
<img
class="el-upload-list__item-thumbnail"
:src="file.url" alt=""
>
<span class="el-upload-list__item-actions">
<span
class="el-upload-list__item-preview"
@click="handlePictureCardPreview(file)"
>
<i class="el-icon-zoom-in"></i>
</span>
<span
class="el-upload-list__item-delete"
@click="handleRemove(file)"
>
<i class="el-icon-delete"></i>
</span>
</span>
</div>
</el-upload>
</el-form-item>
</el-form>
data() {
imgList: [],
}
methods: {
handleRemove(file) {
let arr = this.$refs.upload.uploadFiles
console.log("arr是",arr)
// 2.从pics数组中,找到图片对应的索引值
let index = arr.indexOf(file)
// 3.调用splice方法,移除图片信息
arr.splice(index, 1)
this.imgList=arr
console.log(this.imgList)
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
},
handleChange(file, fileList) {
this.imgList = fileList;
},
handleMaxNum() {
this.$message({
type: "info",
message: "最多选择10张图片"
})
},
// 编辑、增加页面保存方法
subm**加粗样式**itForm(editData) {
this.loading = true
this.$refs[editData].validate(valid => {
if (valid) {
attractionSave(this.editForm)
.then(res => {
this.editFormVisible = false
// console.log(res)
if (res.data.success) {
let newAttractionId = res.data.attractionId
//信息保存成功后,保存图片
if ( newAttractionId != '') {
let formData = new FormData(); // 用 FormData 存放上传文件
// 将图片转为 FormData 格式
let promises = [];
this.imgList.forEach(item => {
let url = item.url;
if(url.startsWith("blob")){
formData.append('files', item.raw);
}
else {
let promise = fetch(url, {
headers: new Headers({
'Origin': location.origin
}),
mode: 'no-cors'
}
)
.then(response => response.blob())
.then(blob => {
// 创建 URL 对象以便提取文件名
let filename = url.split('/').pop();
// 创建一个虚拟的 File 对象
let file = new File([blob], filename, {type: 'image/bmp,image/jpeg,image/png,image/webp'});
console.log(file)
formData.append('files', file);
})
.catch(error => {
console.error('Failed to fetch image:', error);
});
promises.push(promise);
}
});
Promise.all(promises).then(() => {
console.log("formdata", formData)
let uri = "/" + newAttractionId
saveImgs(uri, formData)
.then(resPic => {
if (resPic.data.success) {
// this.$message({
// type:"success",
// message:resPic.data.msg
// })
} else {
this.$message({
type: "info",
message: resPic.data.msg
})
}
}).catch(err => {
console.log("出错", err)
})
})
}
this.$message({
type: 'success',
message: res.data.msg
})
} else {
this.$message({
type: 'info',
message: res.data.msg
})
}
}
)
.catch(err => {
this.editFormVisible = false
this.loading = false
this.$message.error('保存失败,请稍后再试!')
console.log(err)
return false
})
var that = this
setTimeout(function () {
that.loading = false;
that.getData()
}, 1000)
} else {
this.loading = false
return false
}
}
)
},
//显示编辑界面
handleEdit: function (index, row) {
this.editFormVisible = true
if (row != undefined && row != 'undefined') {
this.title = '修改';
this.imgList=row.imgList
this.imgList = this.imgList.map(url => ({
url: url,
}));
console.log("list", this.imgList)
}
}
</el-dialog>
同时,附上SpringBoot业务层代码
@Override
public ResJson savePicture(List<MultipartFile> files, String attractionLocationById) {
ResJson resJson = new ResJson();
// 获取文件夹中所有文件的列表
File file1 = new File(attractionLocationById);
File[] folderFiles = file1.listFiles();
// 创建一个 HashSet,用于存储上传文件的名称
Set<String> uploadedFileNames = new HashSet<>();
if(files==null) {
for (File folderFile : folderFiles) {
if (folderFile.delete()) {
System.out.println("删除文件: " + folderFile.getName() + " 成功");
} else {
System.out.println("删除文件: " + folderFile.getName() + " 失败");
}
}
file1.delete();
return null;
}
for (MultipartFile file : files) {
uploadedFileNames.add(file.getOriginalFilename());
}
System.out.println("uploadedFileNames = " + uploadedFileNames);
//删除图片,其实只要全部删除,再重新下载即可,考虑到图片数量可能多,就搞成判断了
if(folderFiles!=null) {
// 遍历文件夹中的文件
for (File folderFile : folderFiles) {
String folderFileName = folderFile.getName();
// 如果文件夹中的文件不在上传的文件列表中,则删除该文件
if (!uploadedFileNames.contains(folderFileName)) {
System.out.println(folderFileName);
if (folderFile.delete()) {
System.out.println("删除文件: " + folderFile.getName() + " 成功");
} else {
System.out.println("删除文件: " + folderFile.getName() + " 失败");
}
}
else{
uploadedFileNames.remove(folderFileName);
}
}
}
// 保存上传的文件
for (MultipartFile file : files) {
try {
String originalFilename = file.getOriginalFilename();
//如果已经有了,在上面的被移除了,只有在剩下的没被排除内的就下载
if(uploadedFileNames.contains(originalFilename)) {
// 构建真实的文件路径
Path path = Paths.get(attractionLocationById + originalFilename);
// 确保目录路径存在
Files.createDirectories(path.getParent());
// 将上传文件保存到指定位置
file.transferTo(path);
System.out.println("图片保存成功");
System.out.println("保存+1");
}
resJson.setMsg("图片保存成功");
resJson.setSuccess(true);
} catch (IOException e) {
e.printStackTrace();
System.out.println("上传失败");
resJson.setMsg("图片保存失败");
resJson.setSuccess(false);
}
}
return resJson;
}