element-ui上传组件多个文件同时上传请求一次后台接口(前后端代码版)

前言

在使用element-ui上传组件上传多个文件时,出现多个文件对应着多个请求,比如你要上传3个文件,那么将请求3个后台接口,这样会无形之中增加了后台系统的服务器压力,因此只能前端代码做修改,使得多个文件上传只请求1次后台接口。而搜索了相关文章,大部分都是讲解了前端的代码,而没有添上后台的代码,因此本作者借此将我完善的前后端代码添出来供大家参考。

前端代码

<template>
  <div>
    <el-upload
      class="upload-demo"
      drag
      ref="upload"
      :action="uploadAction"
      :auto-upload="autoUpload"
      :on-remove="handleRemove"
      :before-remove="beforeRemove"
      :on-change="beforeUpload"
      :on-success="handleUploadSuccess"
      :on-error="handleUploadError"
      :data="extraParam"
      :headers="headers"
      :limit="fileSizeLimit"
      :file-list="fileList"
      :on-exceed="handleExceed"
      :accept="fileType"
      multiple>
      <i class="el-icon-upload"></i>
      <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
      <div class="el-upload__tip" slot="tip">
        <span style="color: #FE6D68;">*</span>
        {{promptMessage}}
      </div>
    </el-upload>
  </div>
</template>
<script>
  import {upload} from '@/utils/upload'
  import {getToken} from '@/utils/tokenOperation'
  export default{
    name: 'FileUpload',
    props: {
      /* 上传框提示 */
      promptMessage: {
        default: '只能上传xls/xlsx文件',
        type: String
      },
      /* 文件上传路径 */
      uploadAction: {
        default: '',
        type: String
      },
      /* 文件类型 */
      fileType: {
        default: '.xlsx,.xls',
        type: String
      },
      /* 限制最大文件上传数 */
      fileSizeLimit: {
        default: 2,
        type: Number
      }
    },
    data() {
      return {
        /* 上传时附带的额外参数,返回是一个对象 */
        extraParam: {},
        /* 已上传的文件列表 */
        fileList: [],
        /* 请求头 */
        headers: {
          'strainpreservation': getToken()
        },
        /* 是否在选取文件后立即进行上传 */
        autoUpload: false,
      }
    },
    methods:{
      /* 文件列表移除文件成功时的钩子 */
      handleRemove(file, fileList) {
        return this.successNotify(`已成功移除"${file.name}"文件`)
      },
      /* 处理上传失败时的勾子 */
      handleUploadError(err, file, fileList) {
        this.errorNotify(`文件上传失败`)
      },
      /* 文件删除前的勾子 */
      beforeRemove(file, fileList) {
        return this.$confirm(`确定移除"${file.name}"文件吗?`)
      },
      /* 上传文件之前的钩子 因设置了auto-upload为false,如果使用before-upload,虽有提示,但是还是会请求服务器*/
      beforeUpload(file,fileList) {
        // 1、判断文件名是否重复,不允许上传相同文件
        let existFile = fileList.slice(0, fileList.length - 1).find(f => f.name === file.name)
        if(existFile){
          fileList.pop()
          this.warningNotify(file.name+" 文件已存在!")
        }
        // 2、获取文件后缀
        fileList.forEach(everyFile => {
          const fileType = everyFile.name.substring(everyFile.name.lastIndexOf('.'))
          if(this.fileType.search(fileType) === -1){
             fileList.pop()
             this.warningNotify("上传文件的类型不正确"+"文件类型必须为" + this.fileType + '')
          }
        })
        this.fileList = fileList;
      },
      /* 文件超出个数限制时的钩子 */
      handleExceed(files, fileList) {
        this.warningNotify(`当前限制选择`+ this.fileSizeLimit +`个文件,本次选择了 ${files.length} 个文件,已超出了文件最大上传个数`)
      },
      /* 文件上传成功时的钩子 */
      handleUploadSuccess(res, file, fileList) {
        console.info(JSON.stringify(res))
      },
      /* 确定上传 */
      submitUpload() {
        upload(this.uploadAction,this.fileList).then(res => {
          this.fileList = []
        });
      }
    }
  }
</script>
<style rel="stylesheet/scss" lang="scss" scoped>
  .el-upload__tip{
    font-weight: bold;
    font-size: 14px;
  }
  .upload_div{
    padding: 10px 0px 20px 20px;
    text-align: right;
    box-sizing: border-box;
  }
</style>
import axios from 'axios'
import { getToken } from '@/utils/tokenOperation'

export function upload(api, file) {
  var data = new FormData()
  file.forEach(everyFile => {
    data.append("file",everyFile.raw)
  })
  const config = {
    headers: {
      'strainpreservation': getToken()
       }
  }
  return axios.post(api, data, config)
}

将选中的文件提交到服务器
/**
 * @Date: 2021-03-15 16:43:49
 * @description: 上传文件
 * @param {*}
 * @return {*}
 */
upDataFile() {
  // 创建FormData对象
  var data = new FormData()
  // 获取将fileList数组中的file对象插入到FormData对象中
  this.$refs.upload.fileList.forEach((everyFile, index) => {
    data.append("file"+index, everyFile.raw)
  })
  // 将额外的参数插入到formdata对象中
  data.append('isUpdateSupport', this.$refs.upload.tipsChecked)
  let self = this
  // 调用上传文件api发送上传文件请求
  inputImport(data).then((res)=>{
    self.msgSuccess(res.msg)
  }, (err)=> {
    self.msgInfo(err.msg)
  })
}

1、getToken是自己封装的从cookie中获取token的方法
2、everyFile.raw就是File数据,大伙可以debug看看,或者使用console.info(everyFile)看看里面的内容

  • 结合前端的代码做一些讲解:
    1、upload上传组件的action属性一定要写
    这是upload组件约定的,无论是否使用upload内部实现的上传方式,这个action属性是一定要写的,要不然会报"没有action属性"的错误。

2、action-upload设置为false,file-list属性也一定要写
action-upload设置为false,是因为不让它自动上传,因为我们的页面,很多时候都是当选择完文件后,点击按钮才允许上传的,而file-list属性是存储上传的文件的信息。

3、当action-upload属性设置为false时,before-upload方法是失效的
当action-upload属性设置为false时,before-upload如果做文件大小、文件类型、文件重复等逻辑的判断,假如文件类型错误,return false或者Promise. reject ()方法想终止上传时,是终止不了的,还是会请求到服务器。因此需要使用on-onchange属性来替换

后台代码

 /**
    * 导入培养基信息
    * @param file
    * @return
    */
    @ApiOperation(value = "导入培养基信息",notes = "点击页面上的导入按钮时请求的接口")
    @PostMapping(value = "/importMediumInfo")
    @PreAuthorize("@el.check('sys:medium:import')")
    public BaseResultVO importMediumInfo(@RequestParam("file") MultipartFile[] file){
      return iMediumInfoService.mediumFileUpload(file);
    }
  • 后台我使用MultipartFile数组来接收前端FormData传来的数据。业务层的逻辑我就不添出来了,因为后台我是使用的EasyExcel来实现的。

转载地址

GitHub 加速计划 / eleme / element
54.06 K
14.63 K
下载
A Vue.js 2.0 UI Toolkit for Web
最近提交(Master分支:3 个月前 )
c345bb45 7 个月前
a07f3a59 * Update transition.md * Update table.md * Update transition.md * Update table.md * Update transition.md * Update table.md * Update table.md * Update transition.md * Update popover.md 7 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐