一、项目介绍
后端:springboot
前段: vue+element-ui组件
杂谈
图片上传在最近的项目中经常遇见,而且每次的需求也不一样。每次都能遇到新的坑,打算记录一下,写个demo方便下次使用。
二、测试
1. 图片上传组件
element UI 官方网站
图片上传组件(来自官网):
<el-upload
action=""
list-type="picture-card"
:http-request="requestUpload"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-change="handleChange"
:before-upload="beforeUpload"
:file-list="fileList"
:limit="4"
:on-exceed="exceedTips"
:multiple="true"
>
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
<script>
export default {
data() {
return {
dialogImageUrl: '',
dialogVisible: false
};
},
methods: {
handleRemove(file, fileList) {
console.log(file, fileList);
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url;
this.dialogVisible = true;
}
}
}
</script>
2. 常用钩子说明
来自官网!
3. 实战
3.1 需求
用户输入用户名和密码,并且上传多张个人图片。(瞎说)
要求:
用户信息和图片同时上传。
3.2 解决思路
构造form表单数据,将用户名,密码和图片同时发送。
代码:
<el-form ref="form" :model="form" label-width="80px" >
<el-form-item label="用户名">
<el-input v-model="form.name" ></el-input>
</el-form-item>
<el-form-item label="密码">
<el-input v-model="form.password" ></el-input>
</el-form-item>
<el-form-item label="头像">
<el-upload
action=""
list-type="picture-card"
:http-request="requestUpload"
:on-preview="handlePictureCardPreview"
:on-remove="handleRemove"
:on-change="handleChange"
:before-upload="beforeUpload"
:file-list="fileList"
:limit="4"
:on-exceed="exceedTips"
:multiple="true"
>
<i class="el-icon-plus"></i>
</el-upload>
<el-dialog :visible.sync="dialogVisible">
<img width="100%" :src="dialogImageUrl" alt="">
</el-dialog>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSubmit">提交</el-button>
<el-button>取消</el-button>
</el-form-item>
</el-form>
不用原生的action上传文件,我们需要自定义上传。
那何时触发上传图片操作呢?
点击提交,一起发送。
3.3 :file-list="fileList"说明
我这里的fileList相当于全局变量。
打印出来看看:
3.4 on-change 和 before-upload 钩子说明
on-change和before-upload 钩子经常会作为上传文件限制方式,例子:
handleChange(file,fileList){
console.log("handleChange执行");
console.log(file)
this.fileList = fileList;
},
// 上传预处理,不含fileList参数
beforeUpload(file) {
console.log("beforeUpload执行");
console.log(file)
//判断文件是否上传重复
let existFile = this.fileList.slice(0, this.fileList.length - 1).find(f => f.name === file.name);
//上传文件是不是图片
let fileImg = file.type.indexOf("image/") === -1;
if (existFile || fileImg) {
this.msgError("文件格式错误或文件重复,请上传图片类型,如:JPG,PNG后缀的文件。");
//不匹配就pop
this.fileList.pop();
}
},
测试:
- 两者执行顺序:
根据控制台输出我们可以看到是on-change比before-upload先执行。并且on-change钩子含有fileList参数。当我们想要在我们增添图片或者删除待上传图片实时更新全局fileList,那我们就需要设置on-change钩子并且添加语句:this.fileList = fileList;
我习惯在before-upload钩子中进行文件筛选,最为最后一步关卡。 - 两者参数说明
on-change钩子 ==》function(file, fileList)方法中的file对象
和
before-uploa钩子 ==》function(file)方法中的file对象其实是不一致的
而我们后台需要接受的其实是,后面那个file,也就是on-change 钩子中file对象的raw属性!!!
这点对于小白来说,经常会误用,导致后台接收不到文件!
3.5 构建form表单数据
文件数据以及准备好了fileList
,用户数据也是存在的。那如何将文件数据和用户数据一起发送给后端呢?
答案就是,构建FormData对象!
例子:
onSubmit() {
var formData = new FormData;
formData.append("username",this.form.name);
formData.append("password",this.form.password);
this.fileList.forEach(function (file) {
//fileList里的file对象就是on-change钩子中的对象。后台是接收不到的
//能接收的是file.raw对象
formData.append("file",file.raw);
})
axios.post("",formData).then(res=>{
console.log(res);
})
},
后台测试
@PostMapping("/test")
public AjaxResult test(String username,String password,MultipartFile[] file) throws IOException {
System.out.println("用户名"+username);
System.out.println("密码"+password);
System.out.println("文件个数"+file.length);
for (int i = 0; i < file.length; i++) {
File tempFile = new File("D:/"+i+""+".jpg");
file[i].transferTo(tempFile);
}
return AjaxResult.success();
}
输出:
测试成功了!
4. 常见问题
后台接收的文件格式
请求类型
模拟的是表单数据
spring是不能用@RequestBody
注解的接收含有文件数据的!!!