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

发布时间:2024年01月13日

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-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、数据和数据校验部分
 <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、方法部分
<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用来重新命名文件和做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)
//上传资源方法
    @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)

效果图如下:

在这里插入图片描述

<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>
文章来源:https://blog.csdn.net/qq_57340195/article/details/135564355
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。