Vue+ElementUI+Axios实现携带参数的文件上传(数据校验+进度条)

Vue+ElementUI+Axios实现携带参数的文件上传(数据校验+进度条)

可以实现对上传文件的类型,大小进行数据校验,以及对上传文件所要携带的数据也进行的校验,也有文件上传进度的进度条。

一、Vue 结构部分

弹窗显示(文件上传框+文本框+单选按钮)

html 复制代码
<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-upload
            class="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、数据和数据校验部分
js 复制代码
 <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 = false
                  callback();
              }
          };
     //数据校验
      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、方法部分
js 复制代码
<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)
java 复制代码
 //资源上传接口
    @PostMapping("/uploadResource")
    public Result uploadResource(MultipartFile file,String email,String tag,String type){
        //生成UUID用来重新命名文件和做rid
        String 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)
java 复制代码
//上传资源方法
    @Override
    public 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)

效果图如下:

html 复制代码
<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-upload
            class="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 = false
                  callback();
              }
          };
     //数据校验
      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>
相关推荐
李白的粉2 分钟前
基于springboot的在线教育系统
java·spring boot·毕业设计·课程设计·在线教育系统·源代码
亭台烟雨中5 分钟前
【前端记事】关于electron的入门使用
前端·javascript·electron
码农10087号15 分钟前
Hot100方法及易错点总结2
java
泯泷19 分钟前
「译」解析 JavaScript 中的循环依赖
前端·javascript·架构
Senar1 小时前
Web端选择本地文件的几种方式
前端·javascript·html
iuyou️1 小时前
Spring Boot知识点详解
java·spring boot·后端
北辰浮光1 小时前
[Mybatis-plus]
java·开发语言·mybatis
一弓虽1 小时前
SpringBoot 学习
java·spring boot·后端·学习