Vue+ElementUI+Axios实现携带参数的文件上传(数据校验+进度条)
可以实现对上传文件的类型,大小进行数据校验,以及对上传文件所要携带的数据也进行的校验,也有文件上传进度的进度条。
一、Vue 结构部分
弹窗显示(文件上传框+文本框+单选按钮)
<template><!-- 控制子组件显示还是隐藏: :visible.sync="isShow" --><div><!-- 弹窗 --><el-dialog width="30%" :modal="true" title="新增资源" :modal-append-to-body="true" :visible.sync="isShowAdd":close-on-click-modal="false" :close-on-press-escape='false' :show-close="false" center><!-- 需要上传的表单::model 和 ref 的值尽量保持一致,ref在的值在提交数据时进行对提交的数据进行校验 --><el-form :model="ResourceInfo" ref="ResourceInfo" :rules="rules" size="small" label-width="120px" label-position="right" key="1" :hide-required-asterisk="true"><el-form-item label="资源" ><!-- 文件上传:http-request这里用来获取到要上传的文件。limit限制文件个数。on-exceed:用来校验文件个数 ,before-remove:删除上传列表时提示用户--><el-uploadclass="upload-demo" action="" ref="upload" :http-request="httprequest" :limit=1 :drag="true" :on-exceed="handleExceed" :before-remove="beforeRemove"><i class="el-icon-upload"></i><div class="el-upload__text">将文件拖到此处,或<em>点击选择文件</em></div></el-upload></el-form-item><!-- 文本框用来填写要上传一个参数,这里是为了给文件打标签 --><el-form-item prop="tag" label="标签"><el-input v-model="ResourceInfo.tag" ref="tag" maxlength="30" autocomplete="off" placeholder="如:风景/天空"></el-input></el-form-item><!-- 单选框,也是文件的一个参数 --><el-form-item prop="type" label="类型" ><el-radio-group v-model="ResourceInfo.type" ref="type"><el-radio border label="静态"></el-radio><el-radio border label="动态"></el-radio></el-radio-group></el-form-item></el-form><!--进度条:只有上传时才显示--><div v-if="loading" ><el-progress type="line" :percentage="percentage" class="progress" :show-text="true"></el-progress></div><!-- 上传和取消按钮 --><div slot="footer" class="dialog-footer"><el-button @click="quxiao()">取 消</el-button><!-- 调用上传文件方法,将填写的表单数据做为参数 --><el-button type="primary" @click="submitFileInfo(ResourceInfo)">确 定</el-button></div></el-dialog></div></template>
二、JS部分
1、数据和数据校验部分
<script>
export default {name:"ResourceAdd",//组件是否显示(父组件传过来的)props: {isShowAdd: {type: Boolean,default: false},},data() {//数据校验var Type = (rule, value, callback) => {if (value === '') {callback(new Error('请选择壁纸类型'));this.islose = true;} else {this.islose = falsecallback();}};//数据校验var Tag = (rule, value, callback) => {if (value === '') {callback(new Error('请添加标签'));this.islose = true;} else if (value.length < 4) {callback(new Error('最少输入4个字'));this.islose = true;} else {this.islose = false;callback();}};return {resouceFileImg:null,loading:false, //进度条是否隐藏percentage:0, //进度条数值dialogVisible:false, //是否上传完备//要上传文件的信息ResourceInfo: {"file":"","tag":"","type":""},//要校验的表单信息rules: { type: [{ validator: Type, trigger: 'blur'}],tag: [{ validator: Tag, trigger: 'blur' }],},};},</script>
2、方法部分
<script>export default {methods: {submitFileInfo(resourceInfo){//调用文件类型判断方法,检查上传文件类型是否合法(返回Boolean类型)let fileTypeCheck=this.fileTypeCheck(resourceInfo.file)// 判断文件是否合法if(fileTypeCheck){//文件通过校验,校验其它要上传里其它参数是否合法this.$refs.ResourceInfo.validate((valid) => {if(valid){//如果都合法// 直接通过new来创建FormData对象,用来装文件对象和其它参数()let UpResourceInfo = new FormData();//通过append将数据添加到FormData中(数据是键值对类型)//注意:键要和后端接收的参数列表一一对应。UpResourceInfo.append('file', resourceInfo.file);UpResourceInfo.append("email",window.sessionStorage.getItem("Account"));UpResourceInfo.append("tag",resourceInfo.tag);UpResourceInfo.append("type",resourceInfo.type);//计算过上传进度// 进度条的实现主要依靠axios中提供的onUploadProgress函数//该函数提供了文件已上传部分的大小progressEvent.loaded和文件总大小progressEvent.total,利用这两个数据我们就可以计算出已经上传文件的进度。let config = {onUploadProgress: progressEvent => {//progressEvent.loaded:已上传文件大小//progressEvent.total:被上传文件的总大小let complete = (progressEvent.loaded / progressEvent.total ).toFixed(2) * 100 ;this.percentage = complete; //上传进度if (this.percentage >= 100){this.dialogVisible = true //上传完毕}} };//显示进度条this.loading = true;//通过axios对后端接口发起请求,并将上面的FormData对象参数发送过去,已经。axios.post("http://localhost:8888/resources/uploadResource",UpResourceInfo,config).then((res)=>{if(res.data.flag==true){ //清空表单信息this.ResourceInfo={"file":"","tag":"","type":""}//清除上传文件列表this.$refs.upload.clearFiles();this.loading=false; //隐藏进度条this.$message.success("添加成功!")//调用父组件的方法隐藏弹窗// this.$parent.AddSuccessColse(); }}).catch((err)=>{this.$message.error(err)//清空表单信息this.ResourceInfo={};//清除上传文件列表this.$refs.upload.clearFiles();//调用父组件的方法隐藏弹窗//this.$parent.AddSuccessColse(); })}});}},// 文件类型、大小数据校验fileTypeCheck(file) {const isJPG = file.type === 'image/jpg';const isJPEG = file.type === 'image/jpeg';const isPNG = file.type === 'image/png';const isMP4 = file.type === 'video/mp4';const isLt30M = file.size / 1024 / 1024 < 30;if (!isJPG && !isJPEG && !isPNG && !isMP4) {this.$message.error('请上传 JPG、PNG、MP4格式文件!');} else if (!isLt30M) {this.$message.error('大小不能超过 30MB!');}return (isJPG || isPNG || isMP4 || isJPEG) && isLt30M;},//将上传的文件对象赋值到要上传的键值对中httprequest(param) {//将通过钩子函数函数,传过来的文件上传信息,中的文件赋值到要上传的键值对中this.ResourceInfo.file = param.file;},//取消时调用的方法quxiao() {this.$message.info("取消添加!");//清空表单信息this.ResourceInfo={"file":"","tag": "","type":""}this.$refs.upload.clearFiles();//通过调用父组件的方法来隐藏子组件(子组件无法修改父组件的值)this.$parent.AddQuXiaoColse();},//文件数量超过1个时自动调用的handleExceed(files, fileList) {this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);},//是否删除文件列表中的文件(删除时自动调用)beforeRemove(file) {let isDel=this.$confirm(`确定移除 ${ file.name }?`);console.log(isDel)return isDel;}},}</script>
三、后端代码(Springboot)
1、接口层方法(Controller)
//资源上传接口@PostMapping("/uploadResource")public Result uploadResource(MultipartFile file,String email,String tag,String type){//生成UUID用来重新命名文件和做ridString uuid= UUID.randomUUID().toString().replaceAll("-","");Resource resource =new Resource();resource.setRid(uuid);resource.setEmail(email);resource.setTag(tag);resource.setType(type);return new Result(iResourceService.uploadResource(file,resource));}
2、服务层方法(Service)
//上传资源方法@Overridepublic Boolean uploadResource(MultipartFile file, Resource resource) {if(!file.isEmpty()){String fullName = file.getOriginalFilename(); //获取全文件名String type = fullName.substring(file.getOriginalFilename().lastIndexOf(".")); //获取文件后缀String fileName=resource.getRid()+type; //拼接新文件名//获取上传目录路径ApplicationHome applicationHome=new ApplicationHome(this.getClass());String pre=applicationHome.getDir().getParentFile().getParentFile()+"\\src\\main\\resources\\static\\wallpaper\\";//拼接上传路径String path=pre+fileName;try {//将文件上传到指定目录file.transferTo(new File(path));//将文件拼接成可访问的在线链接,并赋值到对象的setRUrl属性中resource.setRUrl("http://localhost:8888/static/wallpaper/"+fileName);}catch (IOException e){e.printStackTrace();}}//将图像信息插入到数据库中return resourceDao.insert(resource)==1;}
3、数据库数据
四、前端组件全部代码(ResourceAdd.vue)
效果图如下:
<template><!-- 控制子组件显示还是隐藏: :visible.sync="isShow" --><div><!-- 弹窗 --><el-dialog width="30%" :modal="true" title="新增资源" :modal-append-to-body="true" :visible.sync="isShowAdd":close-on-click-modal="false" :close-on-press-escape='false' :show-close="false" center><!-- 需要上传的表单::model 和 ref 的值尽量保持一致,ref在的值在提交数据时进行对提交的数据进行校验 --><el-form :model="ResourceInfo" ref="ResourceInfo" :rules="rules" size="small" label-width="120px" label-position="right" key="1" :hide-required-asterisk="true"><el-form-item label="资源" ><!-- 文件上传:http-request这里用来获取到要上传的文件。limit限制文件个数。on-exceed:用来校验文件个数 ,before-remove:删除上传列表时提示用户--><el-uploadclass="upload-demo" action="" ref="upload" :http-request="httprequest" :limit=1 :drag="true" :on-exceed="handleExceed" :before-remove="beforeRemove"><i class="el-icon-upload"></i><div class="el-upload__text">将文件拖到此处,或<em>点击选择文件</em></div></el-upload></el-form-item><!-- 文本框用来填写要上传一个参数,这里是为了给文件打标签 --><el-form-item prop="tag" label="标签"><el-input v-model="ResourceInfo.tag" ref="tag" maxlength="30" autocomplete="off" placeholder="如:风景/天空"></el-input></el-form-item><!-- 单选框,也是文件的一个参数 --><el-form-item prop="type" label="类型" ><el-radio-group v-model="ResourceInfo.type" ref="type"><el-radio border label="静态"></el-radio><el-radio border label="动态"></el-radio></el-radio-group></el-form-item></el-form><!--进度条:只有上传时才显示--><div v-if="loading" ><el-progress type="line" :percentage="percentage" class="progress" :show-text="true"></el-progress></div><!-- 上传和取消按钮 --><div slot="footer" class="dialog-footer"><el-button @click="quxiao()">取 消</el-button><!-- 调用上传文件方法,将填写的表单数据做为参数 --><el-button type="primary" @click="submitFileInfo(ResourceInfo)">确 定</el-button></div></el-dialog></div></template><script>export default {name:"ResourceAdd",//组件是否显示(父组件传过来的)props: {isShowAdd: {type: Boolean,default: false},},data() {//数据校验var Type = (rule, value, callback) => {if (value === '') {callback(new Error('请选择壁纸类型'));this.islose = true;} else {this.islose = falsecallback();}};//数据校验var Tag = (rule, value, callback) => {if (value === '') {callback(new Error('请添加标签'));this.islose = true;} else if (value.length < 4) {callback(new Error('最少输入4个字'));this.islose = true;} else {this.islose = false;callback();}};return {resouceFileImg:null,loading:false, //进度条是否隐藏percentage:0, //进度条数值dialogVisible:false, //是否上传完备//要上传文件的信息ResourceInfo: {"file":"","tag":"","type":""},//要校验的表单信息rules: { type: [{ validator: Type, trigger: 'blur'}],tag: [{ validator: Tag, trigger: 'blur' }],},};},methods: {submitFileInfo(resourceInfo){//调用文件类型判断方法,检查上传文件类型是否合法(返回Boolean类型)let fileTypeCheck=this.fileTypeCheck(resourceInfo.file)// 判断文件是否合法if(fileTypeCheck){//文件通过校验,校验其它要上传里其它参数是否合法this.$refs.ResourceInfo.validate((valid) => {if(valid){//如果都合法// 直接通过new来创建FormData对象,用来装文件对象和其它参数()let UpResourceInfo = new FormData();//通过append将数据添加到FormData中(数据是键值对类型)//注意:键要和后端接收的参数列表一一对应。UpResourceInfo.append('file', resourceInfo.file);UpResourceInfo.append("email",window.sessionStorage.getItem("Account"));UpResourceInfo.append("tag",resourceInfo.tag);UpResourceInfo.append("type",resourceInfo.type);//计算过上传进度// 进度条的实现主要依靠axios中提供的onUploadProgress函数//该函数提供了文件已上传部分的大小progressEvent.loaded和文件总大小progressEvent.total,利用这两个数据我们就可以计算出已经上传文件的进度。let config = {onUploadProgress: progressEvent => {//progressEvent.loaded:已上传文件大小//progressEvent.total:被上传文件的总大小let complete = (progressEvent.loaded / progressEvent.total ).toFixed(2) * 100 ;this.percentage = complete; //上传进度if (this.percentage >= 100){this.dialogVisible = true //上传完毕}} };//显示进度条this.loading = true;//通过axios对后端接口发起请求,并将上面的FormData对象参数发送过去,已经。axios.post("http://localhost:8888/resources/uploadResource",UpResourceInfo,config).then((res)=>{if(res.data.flag==true){ //清空表单信息this.ResourceInfo={"file":"","tag":"","type":""}//清除上传文件列表this.$refs.upload.clearFiles();this.loading=false; //隐藏进度条this.$message.success("添加成功!")//调用父组件的方法隐藏弹窗// this.$parent.AddSuccessColse(); }}).catch((err)=>{this.$message.error(err)//清空表单信息this.ResourceInfo={};//清除上传文件列表this.$refs.upload.clearFiles();//调用父组件的方法隐藏弹窗//this.$parent.AddSuccessColse(); })}});}},// 文件类型、大小数据校验fileTypeCheck(file) {const isJPG = file.type === 'image/jpg';const isJPEG = file.type === 'image/jpeg';const isPNG = file.type === 'image/png';const isMP4 = file.type === 'video/mp4';const isLt30M = file.size / 1024 / 1024 < 30;if (!isJPG && !isJPEG && !isPNG && !isMP4) {this.$message.error('请上传 JPG、PNG、MP4格式文件!');} else if (!isLt30M) {this.$message.error('大小不能超过 30MB!');}return (isJPG || isPNG || isMP4 || isJPEG) && isLt30M;},//将上传的文件对象赋值到要上传的键值对中httprequest(param) {//将通过钩子函数函数,传过来的文件上传信息,中的文件赋值到要上传的键值对中this.ResourceInfo.file = param.file;},//取消时调用的方法quxiao() {this.$message.info("取消添加!");//清空表单信息this.ResourceInfo={"file":"","tag": "","type":""}this.$refs.upload.clearFiles();//通过调用父组件的方法来隐藏子组件(子组件无法修改父组件的值)this.$parent.AddQuXiaoColse();},//文件数量超过1个时自动调用的handleExceed(files, fileList) {this.$message.warning(`当前限制选择 1 个文件,本次选择了 ${files.length} 个文件,共选择了 ${files.length + fileList.length} 个文件`);},//是否删除文件列表中的文件(删除时自动调用)beforeRemove(file) {let isDel=this.$confirm(`确定移除 ${ file.name }?`);console.log(isDel)return isDel;}},}</script>