MinIo前端Vue后端Springboot实现大文件上传

大文件上传主要功能:上传进度,md5文件计算,重复上传实现秒传功能。
主要实现思路
1.前端使用FileReader对文件进行分片。
2.后台调用Minio接口进行分片上传。
3.上传完成后,调用compose方法进行组合。
4.业务表存的是文件的ID,多个文件用“,”隔开。

组件的使用

 <el-form-item>
          <upload-file ref="uploadFile" :limit-size="1024" :limit="8" :ids.sync="form.attribute1" />
   </el-form-item>
 
  注意 在表单提交或关闭弹出框是一定要清除件内的数据;如在弹出对话框内新增数据关闭时调用组件内的clear方法:
 
<el-dialog
     
      :visible.sync="dialogFormVisible"
      fullscreen
      :modal="false"
      @close="handleCloseDialog"
      show-close
    >
     ...表单...
    </el-dialog>
 
    handleCloseDialog(){
      this.$refs.uploadFile.clear();
    }

实现效果

在这里插入图片描述

前端实现

依赖包 spark-md5 前端进行文件md5计算使用。 安装 npm install spark-md5 --save

BigFileUpload.vue 组件

主要功能:上传、展示文件列表,文件删除更新操作。

<template>
  <div
    v-loading="loading"
    style="width: 100%;overflow: hidden;padding-bottom:20px"
    class="file-wrapper"
    :element-loading-text="loadingText"
    element-loading-spinner="el-icon-loading"
    element-loading-background="rgba(0, 0, 0, 0.3)"
  >
    <h3> <span v-show="required" style="color:#F56C6C;font-weight: bolder;font-size: 16px;margin-right: 5px ">*</span>{{label}}</h3>
    <div v-show="clearable" style="width: 300px;height: 40px;position: relative">
      <input ref="fileUpload" type="file" multiple style="width: 300px;height: 40px;position: absolute;left: 0;opacity: 0;z-index: 10;cursor: pointer" @change="handleFileChange" >
      <el-button type="primary" size="mini" style="margin-left: 20px;width: 200px" >选取文件</el-button>
    </div>
  <div>
    <el-table
      border
      ref="table"
      :data="fileList"
    >
      <el-table-column
        type="index"
        min-width="50"
      />
      <el-table-column
        prop="fileName"
        label="文件名"
        min-width="150"
      />
      <el-table-column
        prop="fileSize"
        label="大小(M)"
        min-width="80"
        :formatter="(row, column, cellValue, index) => cellValue ? (cellValue/1024/1024).toFixed(3) : 0 "
      />
      <el-table-column
        prop="fileSize"
        label="md5"
        min-width="80"
      >
        <template slot-scope="{row}">
          {{ row.md5 ? 'md5计算完成': 'md5未计算' }}
        </template>
      </el-table-column>
      <el-table-column
        prop="percent"
        label="上传进度(%)"
        min-width="100"
      >
        <template slot-scope="{row}">
          {{ row.percent  }}
        </template>
      </el-table-column>
 
      <el-table-column
        align="center"
        :label="$t( $constant.TRANSLATION_SYSTEM+ '.'+'table_column_operate' )"
        min-width="150"
      >
        <template slot-scope="scope">
          <el-link icon="el-icon-download" v-show="scope.row.status" @click="handleDownload(scope.row)">下载</el-link>
          <el-button v-show="clearable" type="text" size="medium" @click="handleDeleteFile(scope.row)" style="margin-left: 5px;position: relative;top:2px">{{ $t( $constant.TRANSLATION_SYSTEM +'.btn_del') }}</el-button>
          <el-button v-show="!scope.row.status" type="text" size="medium" @click="handleUploadFile(scope.row)" style="margin-left: 5px;position: relative;top:2px">{{ $t( $constant.TRANSLATION_SYSTEM +'.upload','上传') }}</el-button>
        </template>
      </el-table-column>
    </el-table>
 
  </div>
 
  </div>
</template>
<script>
import { getToken } from '@/utils/auth'
import axios from 'axios'
import { mapGetters } from 'vuex';
import { downloadFile, deleteFile } from '@/api/file';
import FileUpload from "@/utils/fileUpload";
export default {
  name:"UploadBigFile",
  props: {
    limit: {
      type: Number,
      default: 10
    },
    ids: {
      type: String,
      default: ''
    },
    clearable: {
      type: Boolean,
      default: true
    },
    disabled: {
      type: Boolean,
      default: true
    },
    limitSize:{
      type:Number,
      default:10 // unit M
    },
    label:{
      type: String,
      default:'附件'
    },
    required:{
      default: false
    }
  },
  data() {
    return {
      fileList: [],
      originFileList:[],
      action: process.env.VUE_APP_BASE_API,
      loading: false,
      loadingText:''
    }
  },
  computed: {
    ...mapGetters(['user']),
 
    headers() {
      return {
        Authorization: 'Bearer ' + getToken(),
        TENANTID: this.user.tenantId
      }
    }
  },
  watch: {
    ids: {
      immediate: true,
      handler(val) {
        if (val) {
          axios.get(this.action + '/tccloud-mdm/file/getFiles?ids=' + val, {
            headers: {
              ...this.headers
            }
          }).then(res => {
            if (res.status === 200) {
              res.data.forEach(item=>{
                const file = this.fileList.find(file => file.fileName === item.fileName)
                if(file){
                  Object.assign(file,item,{status:true,md5:'ok',percent:100})
                  console.log("update===>",file);
                }
                else{
                  console.log("unshift===>",item);
                  this.fileList.unshift( Object.assign(item,{status:true,md5:'ok',percent:100}));
                }
              })
              this.$refs.table.doLayout()
            }
          })
        }
      }
    }
  },
  mounted() {
    this.$refs.table.doLayout()
  },
  methods: {
    handleFileChange(e){
      const files = e.target.files
      console.log(files);
 
      for(let i = 0; i < files.length; i++){
        const file= files[i]
        const f = this.originFileList.findIndex(item=> file.name ===item.name )
        if(f > -1){
          this.msgError(file.name + "文件重名或已经存在")
          continue;
        }
        this.originFileList.push(file);
        this.fileList.push( {
          id: -new Date().getTime(),
          fileName:file.name,
          fileSize:file.size,
          type:file.type,
          md5:'',
          status:false,
          percent:0,
          fileUrl:'',
        })
      }
      e.target.value=null
    },
    handleDeleteFile(file) {
      let index= this.fileList.findIndex(item=> item.id === file.id)
      this.fileList.splice(index,1);
      index = this.originFileList.findIndex(item=> item.name === file.fileName)
      this.originFileList.splice(index,1);
      if(file.id < 0){
        return;
      }
      this.loading = true;
      deleteFile(file.id).then(res => {
        this.loading = false;
        this.updateFileId()
        this.msgSuccess('删除成功')
      }).catch(e => {
        this.loading = false;
        this.msgError('删除文件失败')
      })
    },
    updateFileId() {
      console.log('==========updateFileId============>',this.fileList)
      const ids = this.getFileIds(this.fileList)
      this.$emit('update:ids', ids)
    },
    getFileIds(fileList) {
      if (!fileList || fileList.length === 0) return ''
      let ids = ''
      fileList.forEach((item, index) => {
        if(item.id < 0) return;
        if (!ids) {
          ids += item.id
        } else {
          ids = ids + ',' + item.id
        }
      })
      return ids
    },
    handleDownload(row) {
      console.log(row)
      this.loadingText = "";
      this.loading = true
      downloadFile(row.id).then(res => {
        const a = document.createElement('a')
        a.style.display = 'none'
        a.download = row.fileName
        a.href = window.URL.createObjectURL(res)
        a.click()
        a.remove()
        this.loading = false
      })
    },
   async handleUploadFile(row){
      this.loading = true
      const file =  this.originFileList.find(file=> file.name === row.fileName);
      const fileShadow = this.fileList.find(file=> file.fileName === row.fileName);
      // 文件小于4M直接上传
      if(file.size < 4 * 1024 * 1024){
       const res = await this.uploadSmallFile(file);
        Object.assign(fileShadow,res,{status:true,md5:'ok',percent:100})
        console.log('==========>',fileShadow);
        this.loading = false;
        this.updateFileId();
        return;
      }
     this.loadingText='md5计算 0%'
      const upload = new FileUpload(file);
      row.md5 = await upload.calculateMD5(info=>{
        this.loadingText= 'md5计算:'+ info + '%';
      });
      upload.startUpload(this.headers,this.action + '/tccloud-mdm/file/uploadBigFile',info=>{
        fileShadow.percent = info;
        this.loadingText="文件上传:" +info + '%';
      },res=>{
        console.log("complete")
        console.log(res)
        Object.assign(fileShadow,res,{status:true,md5:'ok',percent:100})
        this.updateFileId();
        this.loading = false;
 
      })
 
    },
    async uploadSmallFile(file){
      const formData = new FormData();
      formData.append('file', file);
      const res = await axios.post(this.action + '/tccloud-mdm/file/upload',formData,{
        headers:this.headers
      })
      return res.data
    },
    clear(){
      this.fileList = [];
      this.originFileList =[]
    }
 
 
  }
}
</script>
<style lang="scss" scoped>
.file-wrapper {
  a:hover{
    color: #52de38;
  }
}
 
</style>

FileUpload工具类

主要功能,文件分片,文件上传。

import SparkMD5 from 'spark-md5';
import axios from "axios";
export default class FileUpload {
  constructor(file) {
    this.file= file;
    this.chunkSize = 1024*6*1024; // 6MB per chunk
    this.totalChunks = Math.ceil(file.size / this.chunkSize);
    this.spark = new SparkMD5.ArrayBuffer();
    this.fileReader = new FileReader();
    this.chunkIndex = 0;
    this.md5 = '';
  }
  calculateMD5(onProcess) {
    return new Promise((resolve, reject) => {
      this.fileReader.onload =  (e) =>{
        this.spark.append(e.target.result); // Append array buffer
        this.chunkIndex++;
        if (this.chunkIndex < this.totalChunks) {
          this.loadNext();
         onProcess && onProcess((this.chunkIndex / this.totalChunks * 100).toFixed(2))
        } else {
          this.md5 = this.spark.end(); // Compute MD5 hash
          resolve(this.md5)
        }
      };
 
      this.fileReader.onerror = function () {
        reject("File read error")
      };
      this.loadNext();
    })
  }
  loadNext() {
    const start = this.chunkIndex * this.chunkSize;
    const end = Math.min(this.file.size, start + this.chunkSize);
    this.fileReader.readAsArrayBuffer(this.file.slice(start, end));
  }
  startUpload(headers,path,onProcess,onComplete){
    this.fileReader = new FileReader();
    this.chunkIndex = 0;
    this.fileReader.onload =  (e) =>{
      const formData = new FormData();
      formData.append('chunk', new Blob([e.target.result], { type: this.file.type }));
      formData.append('chunkIndex', this.chunkIndex);
      formData.append('totalChunks', this.totalChunks);
      formData.append('fileName', this.file.name);
      formData.append('totalSize', this.file.size);
      formData.append("md5",this.md5)
      onProcess((this.chunkIndex / this.totalChunks * 100).toFixed(2) );
 
       axios.post(path,formData,{
        headers:headers
      }).then(res=>{
        // 秒传
        if(res&& res.data){
          console.log("-------------秒传------------>",res)
          onProcess &&  onProcess("100%");
          onComplete &&  onComplete(res.data);
          return
        }
         this.chunkIndex++;
         if (this.chunkIndex < this.totalChunks) {
           this.loadNext();
         } else {
           onProcess &&  onProcess("100%");
           onComplete &&  onComplete(res.data);
         }
       }).catch(e =>{
         onProcess &&  onProcess("文件上传失败");
       })
    };
 
    this.fileReader.onerror =e => {
      onProcess &&  onProcess("文件上传失败");
    };
    this.loadNext();
  }
}

后端代码

表结构

做文件的存储,实际文件存储到Minio中,这里是存储下文件的信息。

CREATE TABLE `MDM_FILE` (
  `ID` bigint(65) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `FILE_NAME` varchar(128) DEFAULT NULL COMMENT '文件名称',
  `FILE_URL` varchar(512) NOT NULL COMMENT '文件地址',
  `FILE_ID` bigint(65) DEFAULT NULL COMMENT '文件id',
  `FILE_SIZE` bigint(20) DEFAULT NULL COMMENT '文件大小',
  `CREATE_BY` varchar(128) DEFAULT NULL COMMENT '创建者',
  `CREATE_TIME` datetime DEFAULT NULL COMMENT '创建时间',
  `UPDATE_BY` varchar(128) DEFAULT NULL COMMENT '更新者',
  `UPDATE_TIME` datetime DEFAULT NULL COMMENT '更新时间',
  `REMARK` varchar(128) DEFAULT NULL COMMENT '备注',
  `create_name` varchar(64) DEFAULT NULL COMMENT '创建人',
  `UPDATE_NAME` varchar(64) DEFAULT NULL COMMENT '修改人',
  PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=80 DEFAULT CHARSET=utf8 COMMENT='附件表';

实体类

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Getter;
import lombok.Setter;
 
/**
 * <p>
 * 附件表
 * </p>
 *
 * @author zyl
 * @since 2023-12-21
 */
@Getter
@Setter
@TableName("MDM_FILE")
public class MdmFile implements Serializable {
 
    private static final long serialVersionUID = 1L;
 
    /**
     * 主键ID
     */
    @TableId(value = "ID", type = IdType.AUTO)
    private Long id;
 
    /**
     * 文件名称
     */
    private String fileName;
 
    /**
     * 文件地址
     */
    private String fileUrl;
 
    /**
     * 文件id
     */
    private Long fileId;
 
    /**
     * 文件大小
     */
    private Long fileSize;
 
    /**
     * 创建者
     */
    private String createBy;
 
    /**
     * 创建时间
     */
    private Date createTime;
    private String createName;
    private String updateName;
 
    /**
     * 更新者
     */
    private String updateBy;
 
    /**
     * 更新时间
     */
    private Date updateTime;
 
    /**
     * 备注
     */
    private String remark;
}

FileService 接口类

import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.http.HttpServletResponse;
 
/**
 * <p>
 * 附件表 服务类
 * </p>
 *
 * @author zyl
 * @since 2023-12-21
 */
public interface FileService extends IService<MdmFile> {
 
    MdmFile uploadFile(MultipartFile file);
 
    void download(Long id, HttpServletResponse response);
 
    void deleteFile(Long id);
 
    MdmFile uploadBigFile(MultipartFile file, BigFile bigFile);
}

FileServiceImpl

实现本地文件表操作及远程Minio操作。
整体思路,文件表里存的是文件的基础信息。当我们使用附件时,我们业务表存的是这个表的ID,根据这个ID我们可以拿到文件信息,实现文件信息展示,或预览。

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.HashMultimap;
import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Part;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
 
/**
 * <p>
 * 附件表 服务实现类
 * </p>
 *
 * @author zyl
 * @since 2023-12-21
 */
@Service
public class FileServiceImpl extends ServiceImpl<FileMapper, MdmFile> implements FileService {
    @Value("${spring.application.name}")
    private String applicationName;
    @Autowired
    private  MinioKit minioKit;
    @Autowired
    private RedisService redisService;
 
    @Override
    public MdmFile uploadFile(MultipartFile file) {
 
        boolean b = minioKit.bucketExists(applicationName);
        if(!b){
            minioKit.bucketAdd(applicationName);
        }
        String fileName = file.getOriginalFilename();
        long dateTimestamp = System.currentTimeMillis();
        String fileNameUpload = fileName+"_"+dateTimestamp;
        long size = file.getSize();
        try {
            String url = minioKit.putObjectUrl(applicationName, fileNameUpload, file);
            MdmFile mdmFileEntity = new MdmFile();
            mdmFileEntity.setFileUrl(url);
            mdmFileEntity.setFileSize(size);
            SetEntityUtil.setCreateTimeAndUser(mdmFileEntity);
            mdmFileEntity.setFileName(fileName);
            mdmFileEntity.setRemark(fileNameUpload);
            this.baseMapper.insert(mdmFileEntity);
            return mdmFileEntity;
 
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        }
        return null;
    }
 
    @Override
    public void download(Long id, HttpServletResponse response) {
        MdmFile mdmFile = this.baseMapper.selectById(id);
 
        String fileName = mdmFile.getRemark();
        if(StringUtils.isEmpty(fileName)){
            fileName = mdmFile.getFileName();
        }
 
        minioKit.downloadFile(applicationName,fileName,response);
    }
 
    @Override
    public void deleteFile(Long id) {
        MdmFile mdmFile = this.baseMapper.selectById(id);
        String fileName = mdmFile.getRemark();
        if(StringUtils.isEmpty(fileName)){
            fileName = mdmFile.getFileName();
        }
        try {
 
            String md5Id = fileName.replace(mdmFile.getFileName(), "");
            if(StringUtils.isNotEmpty(md5Id) && md5Id.substring(0,1).equals("-")){
                md5Id = md5Id.substring(1);
                List<MdmFile> mdmFileList = this.getMdmFile(md5Id);
                // 如果有多条数据引用源文件,不删除源文件,只删除关联
                if(mdmFileList.size() > 1){
                    this.baseMapper.deleteById(id);
                    return;
                }
//                if(md5Id.length() == 32){
//                    Long totalChunks = mdmFile.getFileSize() / (1024 * 6 * 1024) + 1;
//                    removeFile(applicationName, totalChunks.intValue() ,md5Id);
//                }
            }
            removeFile(applicationName,50,"ff9db477d61377e100c334bbf310bf2e");
            minioKit.removeObject(applicationName,fileName);
            this.baseMapper.deleteById(id);
        } catch (Exception e) {
            throw new BadRequestException("删除文件失败:"+e.getMessage());
        }
    }
 
    @Override
    public MdmFile uploadBigFile(MultipartFile file, BigFile bigFile) {
        MinioClient minioClient = minioKit.getMinioClient();
        try {
            // 确保 bucket 存在
            boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(applicationName).build());
            if (!isExist) {
                minioClient.makeBucket(MakeBucketArgs.builder().bucket(applicationName).build());
            }
            Integer chunkIndex = bigFile.getChunkIndex();
            String md5 = bigFile.getMd5();
 
 
            if(chunkIndex == 0){
                // 校验md5文件是否存在
                List<MdmFile> existMd5FileList = this.getMdmFile(md5);
                if(!existMd5FileList.isEmpty()){
                    MdmFile  existMd5File = existMd5FileList.get(0);
                    MdmFile mdmFile = new MdmFile();
                    mdmFile.setFileUrl(existMd5File.getFileUrl());
                    mdmFile.setFileSize(existMd5File.getFileSize());
                    mdmFile.setFileName(existMd5File.getFileName());
                    mdmFile.setRemark(existMd5File.getRemark());
                    this.baseMapper.insert(mdmFile);
                    return mdmFile;
                }
            }
            String fileMd5Name =md5;
            String fileName = bigFile.getFileName()+"-"+md5;
            Integer totalChunk = bigFile.getTotalChunks();
            minioKit.uploadFile(applicationName,fileMd5Name,chunkIndex,file);
            if(chunkIndex == totalChunk-1){
                List<ComposeSource> sourceObjectList = Stream.iterate(0, i -> ++i)
                        .limit(bigFile.getTotalChunks())
                        .map(i -> ComposeSource.builder()
                                .bucket(applicationName)
                                .object(fileMd5Name.concat("/").concat(Integer.toString(i)))
                                .build())
                        .collect(Collectors.toList());
                minioKit.composeFile(applicationName, fileName, sourceObjectList);
                // 删除分片文件
                removeFile(applicationName,totalChunk,fileName);
                MdmFile mdmFile = new MdmFile();
                String objectUrl = minioKit.getObjectUrl(applicationName, fileName);
                mdmFile.setFileUrl(objectUrl);
                mdmFile.setFileSize(bigFile.getTotalSize());
                mdmFile.setFileName(bigFile.getFileName());
                mdmFile.setRemark(fileName);
                this.baseMapper.insert(mdmFile);
                return mdmFile;
            }
 
 
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("Big File Upload Error occurred: " + e.getMessage());
        }
        return null;
    }
 
    private void removeFile(String applicationName,Integer totalChunk, String fileName ) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, XmlParserException, InvalidResponseException, InternalException {
        for(int i = 0 ; i < totalChunk; i++){
            String objectName =fileName.concat("/").concat(Integer.toString(i));
            minioKit.removeObject(applicationName,objectName);
        }
       // minioKit.removeObject(applicationName,fileName);
    }
    private List<MdmFile> getMdmFile(String md5){
        QueryWrapper<MdmFile> queryWrapper = new QueryWrapper<>();
        queryWrapper.like("remark",md5);
        return this.baseMapper.selectList(queryWrapper);
    }
}

FileMapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 
/**
 * <p>
 * 附件表 Mapper 接口
 * </p>
 *
 * @author zyl
 * @since 2023-12-21
 */
public interface FileMapper extends BaseMapper<MdmFile> {
 
}

FileUploadController

import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
import io.minio.MinioClient;
import io.minio.UploadPartResponse;
import io.minio.errors.MinioException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
 
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
 
/**
 * <p>
 * 附件表 前端控制器
 * </p>
 *
 * @author zyl
 * @since 2023-12-21
 */
@RestController
@RequestMapping(value = "/file", name = "文件附件")
public class FileController extends BaseController<MdmFile> {
    private FileService fileService;
    @Autowired
    private RedisService redisCache;
 
 
    @Autowired
    public FileController(FileService fileService){
        this.baseService =fileService;
        this.fileService=fileService;
    }
 
    @PostMapping("/upload")
    @AuditBizLog(desc = "附件上传", businessType = BusinessType.INSERT)
    public ResponseEntity<MdmFile> uploadFile(@RequestParam("file") MultipartFile file){
        MdmFile mdmFileEntity = this.fileService.uploadFile(file);
        return new ResponseEntity<>(mdmFileEntity, HttpStatus.OK);
    }
 
    @PostMapping("/uploadBigFile")
    public ResponseEntity<MdmFile> uploadBigFile(@RequestParam("chunk") MultipartFile file,  @ModelAttribute BigFile bigFile){
        MdmFile mdmFileEntity = this.fileService.uploadBigFile(file,bigFile);
        return new ResponseEntity<>(mdmFileEntity, HttpStatus.OK);
    }
 
    @GetMapping("/getFiles")
    public ResponseEntity<List<MdmFile>> getFiles(String ids){
        List<MdmFile> mdmFiles = new ArrayList<>();
        if(StringUtils.isEmpty(ids)) {
            return new ResponseEntity<>(mdmFiles,HttpStatus.OK);
        }
        String[] idArr = ids.split(",");
        for(String id : idArr){
            mdmFiles.add(this.fileService.getById(id));
        }
        return new ResponseEntity<>(mdmFiles,HttpStatus.OK);
    }
    @GetMapping("/download")
    public void download( Long id, HttpServletResponse response) {
        this.fileService.download(id,response);
    }
    @DeleteMapping("/deleteFile")
    @AuditBizLog(desc = "附件删除", businessType = BusinessType.DELETE)
    public void deleteFile(Long id){
        this.fileService.deleteFile(id);
    }
 
    @GetMapping("/getUploadInfo")
    public ResponseEntity<String> getUploadInfo(Long timestamp){
        Object msg = redisCache.getCacheObject(RedisConstant.UPLOAD_EXCEL_FILE + timestamp);
        if(msg==null){
            return new ResponseEntity<>("",HttpStatus.OK);
        }
        return new ResponseEntity<>(msg.toString(),HttpStatus.OK);
    }
}

Minio工具类增加方法

/**
     * 文件上传/文件分块上传
     *
     * @param bucketName 桶名称
     * @param objectName 对象名称
     * @param sliceIndex 分片索引
     * @param file       文件
     */
    public Boolean uploadFile(String bucketName, String objectName, Integer sliceIndex, MultipartFile file) {
        try {
            if (sliceIndex != null) {
                objectName = objectName.concat("/").concat(Integer.toString(sliceIndex));
            }
            // 写入文件
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .contentType(file.getContentType())
                    .build());
            log.debug("上传到minio文件|uploadFile|参数:bucketName:{},objectName:{},sliceIndex:{}"
                    , bucketName, objectName, sliceIndex);
            return true;
        } catch (Exception e) {
            log.error("文件上传到Minio异常|参数:bucketName:{},objectName:{},sliceIndex:{}|异常:{}", bucketName, objectName, sliceIndex, e);
            return false;
        }
    }
 
    /**
     * 文件合并
     *
     * @param bucketName       桶名称
     * @param objectName       对象名称
     * @param sourceObjectList 源文件分片数据
     */
    public Boolean composeFile(String bucketName, String objectName, List<ComposeSource> sourceObjectList) {
        // 合并操作
        try {
            ObjectWriteResponse response = minioClient.composeObject(
                    ComposeObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .sources(sourceObjectList)
                            .build());
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("组合文件失败:"+objectName);
            return false;
        }
    }
以下是一个简单的示例代码,可以使用新版的Minio SDK在Spring Boot应用程序中上传文件: 首先,你需要在你的pom.xml文件中添加以下依赖项: ```xml <dependency> <groupId>io.minio</groupId> <artifactId>minio</artifactId> <version>RELEASE.2021-07-28T23-58-54Z</version> </dependency> ``` 接下来,你需要在应用程序的配置文件中设置Minio服务器的访问密钥和地址: ``` minio: endpoint: <minio服务器地址> accessKey: <访问密钥> secretKey: <秘密密钥> ``` 然后,你可以创建一个MinioConfig类,用于配置MinioClient: ```java @Configuration public class MinioConfig { @Value("${minio.endpoint}") private String endpoint; @Value("${minio.accessKey}") private String accessKey; @Value("${minio.secretKey}") private String secretKey; @Bean public MinioClient minioClient() throws Exception { return MinioClient.builder() .endpoint(endpoint) .credentials(accessKey, secretKey) .build(); } } ``` 最后,你可以编写一个UploadService类,用于将文件上传Minio服务器: ```java @Service public class UploadService { @Autowired private MinioClient minioClient; public void upload(String bucketName, String fileName, InputStream inputStream) throws Exception { boolean isExist = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); if(!isExist) minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(inputStream, -1, 10485760).build()); } } ``` 现在,你可以在你的控制器中使用UploadService类来上传文件。例如: ```java @RestController @RequestMapping("/api/upload") public class UploadController { @Autowired private UploadService uploadService; @PostMapping public ResponseEntity<?> uploadFile(@RequestParam("file") MultipartFile file) throws Exception { InputStream inputStream = file.getInputStream(); String fileName = file.getOriginalFilename(); uploadService.upload("my-bucket", fileName, inputStream); return ResponseEntity.ok("File uploaded successfully"); } } ``` 以上代码示例演示了如何使用Minio SDK在Spring Boot应用程序中上传文件。你可以根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值