美文网首页
vue项目Minio上传附件记录

vue项目Minio上传附件记录

作者: vonson | 来源:发表于2021-07-23 15:04 被阅读0次

1.初始化Minio

创建minio.js文件

import { getOssSign } from '@/api/upload'

// 初始化minioClient
var Minio = require('minio')
export function initMinio () {
    return new Promise((resolve, reject) => {
        let localMinio = JSON.parse(localStorage.getItem('os'))
        if (localMinio) {
            let minioObj = {
                endPoint: 'oss.shlgbj.gov.cn',
                // port: 9200,
                useSSL: true,
                accessKey: localMinio.accessid,
                secretKey: localMinio.accesskey
            }
            var minioClient = newMinio(minioObj)
            resolve(minioClient)
        } else {
            let param = { ossType: 'minio' }
            getOssSign(param).then(response => {
                let minioDeploy = response.data
                let minioObj = {
                    endPoint: 'oss.shlgbj.gov.cn',
                    // endPoint: '10.0.51.96',
                    // port: 9200,
                    useSSL: true,
                    accessKey: minioDeploy.accessid,
                    secretKey: minioDeploy.accesskey
                    // accessKey: 'minioadmin',
                    // secretKey: 'minioadmin'
                }
                localStorage.setItem('os', JSON.stringify(minioDeploy))
                var minioClient = newMinio(minioObj)
                resolve(minioClient)
            }).catch(error => {
                console.log(error)
                reject()
            })
        }
    })
}

export const newMinio = (minioObj) => {
    return new Minio.Client(minioObj)
}

2.fileUpload组件使用Minio

<template>
  <div class="minioBox">
    <section class="uploadBar">
      <el-button
        class="btn_upload"
        icon="el-icon-plus"
        @click="getFileName"
        type="primary"
      >{{uploadText}}</el-button>
      <!-- <el-button v-if="fileList.length>0" style="marginRight:10px;" @click="upload" size="mini" type="success">上传</el-button> -->
      <input
        type="file"
        id="minIoFile"
        ref="minIoFile"
        :accept="allowType"
        v-show="false"
        @change="getFileObj"
      />
      <div class="attachmentsTips el-upload__tip" v-html="note"></div>
    </section>
    <section class="uploadFileList">
      <div v-for="(item, index) in fileList" :key="index" class="fileItem">
        <span class="name">{{item.name}}</span>
        <!-- <span>({{(item.size/1024/1024).toFixed(2)}}M)</span> -->
        <span class="progress_bar">
          <el-progress
            :percentage="item.uploadProgress"
            :format="setItemText(item)"
            v-if="item.showBar"
          />
        </span>
        <div class="btn_right">
          <i class="el-icon-circle-check el-icon-upload-success" v-if="!item.showBar"></i>
          <i class="el-icon-close" style="cursor: pointer;" @click="remove(item)"></i>
        </div>
      </div>
    </section>
  </div>
</template>
<script>
import { confirmOss, getFile } from '@/api/upload'
let stream = require('stream')
import { initMinio } from './minio'

export default {
  props: {
    uploadText: {
      type: String,
      default: '添加附件',
    },
    note: {
      type: String,
      default: () => ''
    },
    allowType: {
      type: String,
      default: () => ''
    },
    fileList: {
      type: Array,
      default: () => {
        return []
      }
    },
    fileSize: {
      type: Number,
      default: 20 // 0:表示没有限制
    },
    onSuccess: {
      type: Function,
      default: () => { }
    },
    onRemove: {
      type: Function,
      default: () => { }
    },
  },
  data () {
    return {
      //   fileList: [],
    }
  },
  methods: {
    setItemText (item) {
      return () => {
        return item.uploadProgress == 0 ? '解析中...' : item.uploadProgress + '%'
      }
    },
    upload () {
      this.fileList.map((item, index) => {
        this.uploadMinIo(item, index)
      })
    },
    remove (item) {
      this.onRemove(item)
    },
    getFileName () {
      let inputDOM = this.$refs.minIoFile
      inputDOM.click()
    },
    getFileObj (event) {
      let files = document.getElementById('minIoFile').files
      let fileSwitch = true
      if (files.length > 0) {
        for (let i = 0; i < files.length; i++) {
          const sizeLimit = this.fileSize !== 0 ? ((files[i].size / 1024 / 1024).toFixed(2) < this.fileSize) : true
          const nameLength = files[i].name.length <= 100
          if (!sizeLimit) {
            this.$message.error(`上传文件大小不能超过 ${this.fileSize}MB`)
            fileSwitch = false
            return
          }
          if (!nameLength) {
            this.$message.error(`附件名称过长,请重新上传`)
            fileSwitch = false
            return
          }
        }
        if (fileSwitch) {
          for (let i = 0; i < files.length; i++) {
            console.log(files[i][File])
            files[i].showBar = true
            files[i].uploadProgress = 0
            // this.$set(files[i], 'uploadProgress', 0)
            this.fileList.push(files[i])
          }
        }
        // this.upload()  //多选上传
        this.uploadMinIo(files[0])
      }
    },
    //上传文件
    async uploadMinIo (fileObj, index) {
      let minioClient = await initMinio()
      var localMinio = JSON.parse(localStorage.getItem('os'))
      let vm = this
      // 重置进度条
      // vm.uploadProgress = 0
      if (fileObj) {
        let file = fileObj
        //判断是否选择了文件
        if (file == undefined) {
          this.$message.error(`请上传文件`)
        } else {
          console.log(file)
          //获取文件类型及大小
          const filePath = file.name.split('.')
          const fileType = filePath[filePath.length - 1].toLowerCase()
          const fileNewName = `${filePath[0]}_${new Date().getTime()}.${fileType}`
          // const fileName = `${localMinio.bucketName}/${localMinio.dir}/${fileNewName}`
          const fileName = `${localMinio.dir}/${fileNewName}`
          const mineType = file.type
          const fileSize = file.size

          //参数
          let metadata = {
            "content-type": mineType,
            "content-length": fileSize
          }
          //判断储存桶是否存在
          minioClient.bucketExists(localMinio.bucketName, function (err) {
            if (err) {
              console.log(err)
              // if (err.code == 'NoSuchBucket') return console.log("bucket does not exist.")
              vm.$message.error(err)
              return
            }
            //存在
            console.log('Bucket exists.')
            //准备上传
            let reader = new FileReader()
            reader.readAsDataURL(file)
            reader.onloadend = function (e) {
              const dataurl = e.target.result
              //base64转blob
              const blob = vm.toBlob(dataurl)
              //blob转arrayBuffer
              let reader2 = new FileReader()
              reader2.readAsArrayBuffer(blob)
              reader2.onload = function (ex) {
                //定义流
                let bufferStream = new stream.PassThrough()
                //将buffer写入
                bufferStream.end(new Buffer(ex.target.result))
                // 单个上传对象进度条控制
                let newItem = vm.fileList[vm.fileList.length - 1]
                var timer = setInterval(() => {
                  if (newItem.uploadProgress <= 98) {
                    newItem.uploadProgress++
                    vm.$set(vm.fileList, vm.fileList.length - 1, newItem)
                  }
                }, 20)
                //上传
                minioClient.putObject(localMinio.bucketName, fileName, bufferStream, fileSize, metadata, function (err, etag) {
                  clearInterval(timer)
                  if (err == null) {
                    minioClient.presignedGetObject(localMinio.bucketName, fileName, 24 * 60 * 60, function (err, presignedUrl) {
                      if (err) {
                        this.$message.error(err)
                        return
                      }
                      //输出url
                      let curItem = vm.fileList[vm.fileList.length - 1]
                      curItem.showBar = false
                      curItem.uploadProgress = 100
                      vm.$set(vm.fileList, vm.fileList.length - 1, curItem)
                      vm.confirmOssUpload(fileObj, fileName)
                      console.log(presignedUrl)
                    })
                  }
                })
              }
            }
          })
        }

      }
    },
    //base64转blob
    toBlob (base64Data) {
      let byteString = base64Data
      if (base64Data.split(',')[0].indexOf('base64') >= 0) {
        byteString = atob(base64Data.split(',')[1]) // base64 解码
      } else {
        byteString = unescape(base64Data.split(',')[1])
      }
      // 获取文件类型
      let mimeString = base64Data.split(';')[0].split(":")[1] // mime类型

      // ArrayBuffer 对象用来表示通用的、固定长度的原始二进制数据缓冲区
      // let arrayBuffer = new ArrayBuffer(byteString.length) // 创建缓冲数组
      // let uintArr = new Uint8Array(arrayBuffer) // 创建视图

      let uintArr = new Uint8Array(byteString.length) // 创建视图

      for (let i = 0; i < byteString.length; i++) {
        uintArr[i] = byteString.charCodeAt(i)
      }
      // 生成blob
      const blob = new Blob([uintArr], {
        type: mimeString
      })
      // 使用 Blob 创建一个指向类型化数组的URL, URL.createObjectURL是new Blob文件的方法,可以生成一个普通的url,可以直接使用,比如用在img.src上
      return blob
    },
    confirmOssUpload (file, fileName) {
      const paramsObj = [{
        // moduleId: getMid(),
        moduleId: '10102',
        orgFileName: file.name,
        postName: fileName,
        size: file.size + '',
        needTransferFormat: 'Y',
        disableIdentify: 'N'
      }]
      confirmOss(paramsObj).then(res => {
        res = res.data
        getFile({ 'fileId': res[0].fileId }).then(res => {
          this.fileList.pop()   //删除上传时放入数组的file对象
          this.onSuccess(res.data, file)
          // this.onSuccess(res.data, file, fileList)
        }).catch(error => {
          console.log(error)
        })
      })
    }
  }
}
</script>
<style lang="scss" scoped>
.minioBox {
  color: #000000;
  // padding: 10px;
  .uploadBar {
    display: flex;
    .attachmentsTips {
      margin-top: 0;
      padding-left: 10px;
      font-size: 12px;
      display: inline-block;
      height: 30px;
      vertical-align: middle;
      line-height: 30px;
      color: #aaa;
      text-align: left;
    }
  }
  .uploadFileList {
    margin-top: 10px;
    .fileItem {
      display: flex;
      align-items: center;
      width: 100%;
      height: 30px;
      .name {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
      .progress_bar {
        flex: 1;
        margin: 0 20px;
        /deep/ .el-progress {
          display: flex;
          align-items: center;
          .el-progress__text {
            width: 80px;
          }
        }
      }
      .btn_right {
        .el-icon-close {
          display: none;
        }
      }
      &:hover {
        cursor: pointer;
        background-color: #f5f7fa;
        .el-icon-close {
          display: block;
        }
        .el-icon-upload-success {
          display: none;
        }
      }
      i {
        margin: 0 5px 0 0;
      }
      .el-icon-upload-success {
        color: #67c23a;
      }
      .upload-fail {
        color: red;
      }
    }
  }
}
</style>

一些坑:

  1. 使用node的stream模块将file进行了可读流的转化,至今不知为啥可以用;
  2. 给每个上传附件自定义进度条的时候,set的更新数据问题; 需要改变单个item,更新整个fileList:vm.set(vm.fileList, vm.fileList.length - 1, curItem)
  3. 上传中fileList展示区域,本质上是本地文件的进度状态,
    成功之后展示已上传的文件信息,此处需要删除上传时放入数组的file对象 this.fileList.pop()

相关文章

  • vue项目Minio上传附件记录

    1.初始化Minio 2.fileUpload组件使用Minio 一些坑: 使用node的stream模块将fil...

  • vue中实现附件上传

    前言 本篇主要记录在 Vue项目中 实现附件上传功能,可实现单/多附件上传,识别文件格式并用不同图标展示功能,及控...

  • 利用U标将文件夹的文件名更新到数据库中

    问题背景: 做项目时,用户上传附件,由于数据库字段设置太小,用户上传附件名称太长时,存储附件路径的自动只能...

  • vue中图片、文件上传

    记录下项目中遇到的图片上传,亦或者文件上传的方式,总是遗忘,查资料好慢 项目采用的vue-element-admi...

  • 使用iView的Upload组件实现将文件上传至OSS文件服务器

    一、情景摘要 在项目开发中,我们经常会遇到需要上传附件的需求,如果实际业务场景下只需要上传少量附件的,上传到代码部...

  • 上传附件

    使用vant实现上传附件功能1.选择附件 2.上传附件到附件服务器 3.获取附件信息 上传附件一共需要三个步骤,首...

  • vue + element Upload + axios文件上传

    项目开发采用前后端分离,在开发中发现需要开发附件上传功能,遇到的一些问题,做一些总结和记录整个文件上传逻辑是:1 ...

  • T100附件问题处理

    一、BPM对接传递附件的需求。 附件传递目前有几个问题点需要解决 1、T100上传附件的方式 通过附件上传、上传到...

  • url 中包含中文AFN 会下载失败

    项目中涉及附件上传管理当遇见附件下载时,本地做了缓存处理,节约流量例如:选取的文件名为:项目开发和对接状态_201...

  • tomcat访问软链接

    问题: tomcat的webapps目录下,是项目相关文件,有时需要访问软链接,(比如上传附件功能,需要把附件保存...

网友评论

      本文标题:vue项目Minio上传附件记录

      本文链接:https://www.haomeiwen.com/subject/xpfpmltx.html