vue2上传大文件到minio分片上传

vue2上传大文件到minio分片上传_第1张图片

vue2上传大文件到minio分片上传_第2张图片

项目中使用到的类库:spark-md5axioselement-ui

npm install spark-md5 --S

npm install axios --S

页面

scirpt

css

upload.js

框架封装的请求,可以根据使用的框架自己改一下,就是请求后台接口

import request from '@/utils/request'
 
 
 
//上传信息
export function uploadFileInfo(data){
    return request({
        url:'upload/multipart/uploadFileInfo',
        method:'post',
        data
    })
}
 
// 上传校验
export function checkUpload(MD5) {
    return request({
        url: `upload/multipart/check?md5=${MD5}`,
        method: 'get',
    })
};
 
 
// 初始化上传
export function initUpload(data) {
    return request({
        url: `upload/multipart/init`,
        method: 'post',
        data
    })
};
 
 
// 文件合并
export function mergeUpload(data) {
    return request({
        url: `upload/multipart/merge`,
        method: 'post',
        data
    })
};
 
 
//判断文件是否存在
export function fileIsExits(data) {
    return request({
        url: `upload/multipart/fileIsExits`,
        method: 'post',
        data
    })
};
 
 

request.js

框架内容,自行修改

import axios from 'axios'
 
// 创建 axios 实例
const service = axios.create({
  baseURL: "/api", // 环境的不同,对应不同的baseURL
  // transformRequest: [function(data) {
  //   return Qs.stringify(data)
  // }],
  //timeout: 5000 // 请求超时时间
})
 
 
//request请求拦截
service.interceptors.request.use(
  config => {
    // var token=getToken()
    // if (token) {
    //     config.headers.token = token // 让每个请求携带自定义token 请根据实际情况自行修改
    //   }
    return config;
},
  error => {
    // do something with request error
    return Promise.reject(error)
  }
)
 
 
//响应拦截
service.interceptors.response.use(
  response => {
    const res = response
    return res
  },
  error => {
    
    //这里还可以根据实际情况增加一些功能
    return Promise.reject(error)
  }
)
 
export default service

后端代码

后端使用的是springboot ,使用之前要启动minio,redis,否则文件上传会出现异常。这里我都是使用windows版的

controller

package com.xy.fileservice.controller;
 
 
import com.xy.fileservice.entity.FileUploadInfo;
import com.xy.fileservice.service.UploadService;
import com.xy.fileservice.util.MinioUtils;
import com.xy.fileservice.util.ResponseResult;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
 
 
/**
 * minio上传流程
 *
 * 1.检查数据库中是否存在上传文件
 *
 * 2.根据文件信息初始化,获取分片预签名url地址,前端根据url地址上传文件
 *
 * 3.上传完成后,将分片上传的文件进行合并
 *
 * 4.保存文件信息到数据库
 */
@Slf4j
@RestController
@RequestMapping("/upload")
public class FileMinioController {
 
    @Resource
    private UploadService uploadService;
 
    @Resource
    private MinioUtils minioUtils;
 
    /**
     * 校验文件是否存在
     *
     * @param md5 String
     * @return ResponseResult
     */
    @GetMapping("/multipart/check")
    public ResponseResult checkFileUploadedByMd5(@RequestParam("md5") String md5) {
        log.info("REST: 通过查询 <{}> 文件是否存在、是否进行断点续传", md5);
        return uploadService.getByFileMd5(md5);
    }
 
    /**
     * 分片初始化
     *
     * @param fileUploadInfo 文件信息
     * @return ResponseResult
     */
    @PostMapping("/multipart/init")
    public ResponseResult initMultiPartUpload(@RequestBody FileUploadInfo fileUploadInfo) {
        log.info("REST: 通过 <{}> 初始化上传任务", fileUploadInfo);
        return uploadService.initMultiPartUpload(fileUploadInfo);
    }
 
    /**
     * 完成上传
     *
     * @param fileUploadInfo  文件信息
     * @return ResponseResult
     */
    @PostMapping("/multipart/merge")
    public ResponseResult completeMultiPartUpload(@RequestBody FileUploadInfo fileUploadInfo) {
        log.info("REST: 通过 <{}> 合并上传任务", fileUploadInfo);
        return uploadService.mergeMultipartUpload(fileUploadInfo);
    }
 
 
    @PostMapping("/multipart/fileIsExits")
    public ResponseResult fileIsExits(@RequestBody FileUploadInfo fileUploadInfo) {
        log.info("REST: 通过 <{}> 判断文件是否存在", fileUploadInfo);
        return uploadService.fileIsExits(fileUploadInfo);
    }
 
 
    @RequestMapping("/createBucket")
    public void createBucket(@RequestParam("bucketName")String bucketName){
        String bucket = minioUtils.createBucket(bucketName);
    }
 
 
 
 
}

UploadService

package com.xy.fileservice.service;
 
 
 
import com.xy.fileservice.entity.FileUploadInfo;
import com.xy.fileservice.util.ResponseResult;
import org.springframework.web.multipart.MultipartFile;
 
public interface UploadService {
    /**
     * 分片上传初始化
     *
     * @param fileUploadInfo
     * @return Map
     */
    ResponseResult initMultiPartUpload(FileUploadInfo fileUploadInfo);
 
    /**
     * 完成分片上传
     *
     * @param  fileUploadInfo
     * @return boolean
     */
    ResponseResult mergeMultipartUpload(FileUploadInfo fileUploadInfo);
 
    /**
     *  通过 sha256 获取已上传的数据
     * @param sha256 String
     * @return Mono>
     */
    ResponseResult getByFileMd5(String sha256);
 
    /**
     *  获取文件地址
     * @param bucketName
     * @param fileName
     *
     */
    String getFilePath(String bucketName, String fileName);
 
 
    /**
     * 单文件上传
     * @param file
     * @param bucketName
     * @return
     */
    String upload(MultipartFile file, String bucketName);
 
 
    /**
     * 判断文件是否存在
     * @param fileUploadInfo
     * @return
     */
    ResponseResult fileIsExits(FileUploadInfo fileUploadInfo);
 
}

UploadServiceImpl

package com.xy.fileservice.service.impl;
 
 
import com.alibaba.fastjson.JSONObject;
import com.xy.fileservice.entity.FileUploadInfo;
import com.xy.fileservice.service.UploadService;
import com.xy.fileservice.util.MinioUtils;
import com.xy.fileservice.util.RedisRepo;
import com.xy.fileservice.util.ResponseResult;
import com.xy.fileservice.util.ResultCode;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
 
import java.util.Objects;
 
import static com.xy.fileservice.util.ResultCode.ACCESS_PARAMETER_INVALID;
 
@Slf4j
@Service
public class UploadServiceImpl implements UploadService {
 
 
    @Resource
    private MinioUtils fileService;
 
    @Resource
    private RedisRepo redisRepo;
 
 
    /**
     * 通过 md5 获取已上传的数据(断点续传)
     *
     * @param md5 String
     * @return Mono>
     */
    @Override
    public ResponseResult getByFileMd5(String md5) {
 
        if (StringUtils.hasText(md5)) {
            log.error("查询文件是否存在、入参无效");
            return ResponseResult.error(ACCESS_PARAMETER_INVALID);
        }
 
        log.info("tip message: 通过 <{}> 查询数据是否存在", md5);
 
        // 获取文件名称和id
        String value = redisRepo.get(md5);
 
        FileUploadInfo fileUploadInfo = null;
 
        if (StringUtils.hasText(value)) {
            fileUploadInfo = JSONObject.parseObject(value, FileUploadInfo.class);
        }
 
        if (Objects.isNull(fileUploadInfo)) {
            // 返回数据不存在
            log.error("error message: 文件数据不存在");
            return ResponseResult.error(ResultCode.FOUND);
        }
 
        // 获取桶名称
        String bucketName = fileService.getBucketName(fileUploadInfo.getFileType());
 
        return fileService.getByFileMd5(fileUploadInfo.getFileName(), fileUploadInfo.getUploadId(), bucketName);
    }
 
 
    /**
     * 文件分片上传
     *
     * @param fileUploadInfo
     * @return Mono>
     */
    @Override
    public ResponseResult initMultiPartUpload(FileUploadInfo fileUploadInfo) {
 
        log.info("tip message: 通过 <{}> 开始初始化<分片上传>任务", fileUploadInfo);
 
        // 获取文件桶名
        String bucketName = fileService.getBucketName(fileUploadInfo.getFileType());
 
        // 单文件上传可拆分,可直接上传完成
        if (fileUploadInfo.getPartCount() == 1) {
 
            log.info("tip message: 当前分片数量 <{}> 进行单文件上传", fileUploadInfo.getPartCount());
 
            // 获取文件分片上传的url
            return fileService.getUploadObjectUrl(fileUploadInfo.getFileName(), bucketName);
 
        }else {
 
            log.info("tip message: 当前分片数量 <{}> 进行分片上传", fileUploadInfo.getPartCount());
 
            // 获取文件分片上传的url
            return fileService.initMultiPartUpload(fileUploadInfo, fileUploadInfo.getFileName(), fileUploadInfo.getPartCount(), fileUploadInfo.getContentType(), bucketName);
        }
 
    }
 
    /**
     * 文件合并
     *
     * @param
     * @return boolean
     */
    @Override
    public ResponseResult mergeMultipartUpload(FileUploadInfo fileUploadInfo) {
 
        log.info("tip message: 通过 <{}> 开始合并<分片上传>任务", fileUploadInfo);
 
        // 获取桶名称
        String bucketName = fileService.getBucketName(fileUploadInfo.getFileType());
 
        // 获取合并结果
        boolean result = fileService.mergeMultipartUpload(fileUploadInfo.getFileName(), fileUploadInfo.getUploadId(), bucketName);
 
        //获取上传文件地址
        if(result){
            String filePath = fileService.getFilePath(fileUploadInfo.getFileType().toLowerCase(), fileUploadInfo.getFileName());
            return ResponseResult.success(filePath);
        }
 
        log.error("error message: 文件合并异常");
 
        return  ResponseResult.error();
    }
 
 
 
 
    @Override
    public String getFilePath(String bucketName, String fileName) {
        return fileService.getFilePath(bucketName, fileName);
    }
 
 
    @Override
    public String upload(MultipartFile file, String bucketName) {
        fileService.upload(file, bucketName);
        return getFilePath(bucketName, file.getName());
    }
 
    public ResponseResult fileIsExits(FileUploadInfo fileUploadInfo){
        boolean b = fileService.doesObjectExist(fileUploadInfo.getFileType(), fileUploadInfo.getFileName());
 
        if(b){
            return ResponseResult.success();
        }
 
        return  ResponseResult.error();
    }
 
 
}

MinioUtils

package com.xy.fileservice.util;
 
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.HashMultimap;
import com.xy.fileservice.config.CustomMinioClient;
import com.xy.fileservice.entity.FileUploadInfo;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Part;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
 
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
 
import static com.xy.fileservice.util.ResultCode.DATA_NOT_EXISTS;
import static com.xy.fileservice.util.ResultCode.UPLOAD_FILE_FAILED;
 
 
@Slf4j
@Component
public class MinioUtils {
 
    @Value(value = "${minio.endpoint}")
    private String endpoint;
    @Value(value = "${minio.accesskey}")
    private String accesskey;
    @Value(value = "${minio.secretkey}")
    private String secretkey;
 
    @Resource
    private RedisRepo redisRepo;
 
    private CustomMinioClient customMinioClient;
 
 
    /**
     * 用spring的自动注入会注入失败
     */
    @PostConstruct
    public void init() {
        MinioClient minioClient = MinioClient.builder()
                .endpoint(endpoint)
                .credentials(accesskey, secretkey)
                .build();
        customMinioClient = new CustomMinioClient(minioClient);
    }
 
 
    /**
     * 单文件签名上传
     *
     * @param objectName 文件全路径名称
     * @param bucketName 桶名称
     * @return /
     */
    public ResponseResult getUploadObjectUrl(String objectName, String bucketName) {
 
        log.info("tip message: 通过 <{}-{}> 开始单文件上传", objectName, bucketName);
 
        try {
            String url = getPresidedObjectUrl(bucketName, objectName);
 
            Map resMap = new HashMap<>();
 
            resMap.put("uploadId", "SingleFileUpload");
 
            resMap.put("urlList", Collections.singletonList(url));
 
            return ResponseResult.success(resMap);
 
        } catch (Exception e) {
 
            log.error("error message: 初始化分片上传失败、原因:", e);
 
            // 返回 文件上传失败
            return ResponseResult.error(UPLOAD_FILE_FAILED);
        }
 
    }
 
 
 
    /**
     * 文件分片上传
     *
     * @param fileUploadInfo
     * @param objectName     文件全路径名称
     * @param partCount      分片数量
     * @param contentType    类型,如果类型使用默认流会导致无法预览
     * @param bucketName     桶名称
     * @return Mono>
     */
 
    public ResponseResult initMultiPartUpload(FileUploadInfo fileUploadInfo, String objectName, int partCount, String contentType, String bucketName) {
        log.info("tip message: 通过 <{}-{}-{}-{}> 开始初始化<分片上传>数据", objectName, partCount, contentType, bucketName);
 
        try {
            String uploadId = getUploadId(bucketName, objectName, contentType);
 
            fileUploadInfo.setUploadId(uploadId);
 
            //redis保存文件信息
            redisRepo.saveTimeout(fileUploadInfo.getFileMd5(), JSONObject.toJSONString(fileUploadInfo), 30, TimeUnit.MINUTES);
 
            List partList = getPartUploadUrls(uploadId, partCount, bucketName, objectName);
 
            Map resMap = new HashMap<>();
 
            resMap.put("uploadId", uploadId);
 
            resMap.put("urlList", partList);
 
            log.info("tip message: 文件初始化<分片上传>、成功");
 
            return ResponseResult.success(resMap);
 
        } catch (Exception e) {
 
            log.error("error message: 初始化分片上传失败、原因:", e);
 
            // 返回 文件上传失败
            return ResponseResult.error(UPLOAD_FILE_FAILED);
        }
    }
    
 
    /**
     * 分片上传完后合并
     *
     * @param objectName 文件全路径名称
     * @param uploadId   返回的uploadId
     * @param bucketName 桶名称
     * @return boolean
     */
    public boolean mergeMultipartUpload(String objectName, String uploadId, String bucketName) {
        try {
            log.info("tip message: 通过 <{}-{}-{}> 合并<分片上传>数据", objectName, uploadId, bucketName);
            //目前仅做了最大1000分片
            Part[] parts = new Part[1000];
            // 查询上传后的分片数据
            ListPartsResponse partResult = customMinioClient.listMultipart(bucketName, null, objectName, 1000, 0, uploadId, null, null);
            int partNumber = 1;
            for (Part part : partResult.result().partList()) {
                parts[partNumber - 1] = new Part(partNumber, part.etag());
                partNumber++;
            }
            // 合并分片
            customMinioClient.mergeMultipartUpload(bucketName, null, objectName, uploadId, parts, null, null);
 
        } catch (Exception e) {
            log.error("error message: 合并失败、原因:", e);
            return false;
        }
        return true;
    }
 
    /**
     * 通过 sha256 获取上传中的分片信息
     *
     * @param objectName 文件全路径名称
     * @param uploadId   返回的uploadId
     * @param bucketName 桶名称
     * @return Mono>
     */
    public ResponseResult getByFileMd5(String objectName, String uploadId, String bucketName) {
        log.info("通过 <{}-{}-{}> 查询上传分片数据", objectName, uploadId, bucketName);
        try {
            // 查询上传后的分片数据
            ListPartsResponse partResult = customMinioClient.listMultipart(bucketName, null, objectName, 1000, 0, uploadId, null, null);
            List collect = partResult.result().partList().stream().map(Part::partNumber).collect(Collectors.toList());
            return ResponseResult.uploading(collect);
        } catch (Exception e) {
            log.error("error message: 查询上传后的分片信息失败、原因:", e);
            return ResponseResult.error(DATA_NOT_EXISTS);
        }
    }
 
    /**
     * 获取文件下载地址
     *
     * @param bucketName 桶名称
     * @param fileName   文件名
     * @return
     */
    public String getFilePath(String bucketName, String fileName) {
        return StrUtil.format("{}/{}/{}", endpoint, bucketName, fileName);//文件访问路径
    }
 
    /**
     * 创建一个桶
     *
     * @return
     */
    public String createBucket(String bucketName) {
        try {
            BucketExistsArgs bucketExistsArgs = BucketExistsArgs.builder().bucket(bucketName).build();
 
            //如果桶存在
            if (customMinioClient.bucketExists(bucketExistsArgs)) {
                return bucketName;
            }
 
            // 如果不存在则创建新文件桶
            MakeBucketArgs makeBucketArgs = MakeBucketArgs.builder().bucket(bucketName).build();
 
            customMinioClient.makeBucket(makeBucketArgs);
 
            return bucketName;
 
        } catch (Exception e) {
            log.error("创建桶失败:{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }
 
 
    /**
     * 根据文件类型获取minio桶名称
     *
     * @param fileType
     * @return
     */
    public String getBucketName(String fileType) {
        try {
            if (StringUtils.isNotEmpty(fileType)) {
 
                //判断桶是否存在
                String bucketName = createBucket(fileType.toLowerCase());
 
                if (StringUtils.isNotEmpty(bucketName)) {
 
                    return bucketName;
                } else {
 
                    return fileType;
                }
            }
        } catch (Exception e) {
            log.error("Error reading bucket name ");
        }
        return fileType;
    }
 
 
    /**
     *  单文件获取上传url
     * @param bucketName
     * @param objectName
     * @return
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    private String getPresidedObjectUrl(String bucketName, String objectName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        return customMinioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.PUT)
                        .bucket(bucketName)
                        .object(objectName)
                        .expiry(1, TimeUnit.DAYS)
                        .build());
    }
 
 
    /**
     * 获取合并id
     * @param bucketName
     * @param objectName
     * @param contentType
     * @return
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws XmlParserException
     * @throws InvalidResponseException
     * @throws InternalException
     */
    private String getUploadId(String bucketName, String objectName, String contentType) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, XmlParserException, InvalidResponseException, InternalException {
 
        if (CharSequenceUtil.isBlank(contentType)) {
            contentType = "application/octet-stream";
        }
 
        HashMultimap headers = HashMultimap.create();
 
        headers.put("Content-Type", contentType);
 
        return customMinioClient.initMultiPartUpload(bucketName, null, objectName, headers, null);
    }
 
    /**
     * 获取文件分片urls
     * @param uploadId
     * @param partCount
     * @param bucketName
     * @param objectName
     * @return
     * @throws ServerException
     * @throws InsufficientDataException
     * @throws ErrorResponseException
     * @throws IOException
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws InvalidResponseException
     * @throws XmlParserException
     * @throws InternalException
     */
    private List getPartUploadUrls(String uploadId, int partCount, String bucketName, String objectName) throws ServerException, InsufficientDataException, ErrorResponseException, IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, InternalException {
        List partList = new ArrayList<>();
 
        for (int i = 1; i <= partCount; i++) {
 
            Map reqParams = new HashMap<>();
 
            reqParams.put("uploadId", uploadId);
 
            reqParams.put("partNumber", String.valueOf(i));
 
            String uploadUrl = customMinioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.PUT)
                            .bucket(bucketName)
                            .object(objectName)
                            .expiry(1, TimeUnit.DAYS)
                            .extraQueryParams(reqParams)
                            .build());
 
            partList.add(uploadUrl);
        }
        return partList;
    }
 
    /**
     * 判断文件是否存在
     *
     * @param bucketName 存储桶
     * @param objectName 对象
     * @return true:存在
     */
 
    public  boolean doesObjectExist(String bucketName, String objectName) {
        boolean exist = true;
        try {
            customMinioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Exception e) {
            exist = false;
        }
        return exist;
    }
 
 
    /**
     * 文件上传
     *
     * @param file 文件
     * @return Boolean
     */
    public String upload(MultipartFile file, String bucketName) {
        String originalFilename = file.getOriginalFilename();
        if (StringUtils.isBlank(originalFilename)) {
            throw new RuntimeException();
        }
        String objectName = file.getName();
        try {
            PutObjectArgs objectArgs = PutObjectArgs.builder().bucket(bucketName).object(objectName)
                    .stream(file.getInputStream(), file.getSize(), -1).contentType(file.getContentType()).build();
            //文件名称相同会覆盖
            customMinioClient.putObject(objectArgs);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        // 查看文件地址
        GetPresignedObjectUrlArgs build = new GetPresignedObjectUrlArgs().builder().bucket(bucketName).object(objectName).method(Method.GET).build();
        String url = null;
        try {
            url = customMinioClient.getPresignedObjectUrl(build);
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (InsufficientDataException e) {
            e.printStackTrace();
        } catch (InternalException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (InvalidResponseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (XmlParserException e) {
            e.printStackTrace();
        } catch (ServerException e) {
            e.printStackTrace();
        }
        return url;
    }
 
}

CustomMinioClient

package com.xy.config;
 
import com.google.common.collect.Multimap;
import io.minio.CreateMultipartUploadResponse;
import io.minio.ListPartsResponse;
import io.minio.MinioClient;
import io.minio.ObjectWriteResponse;
import io.minio.errors.*;
import io.minio.messages.Part;
 
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
 
 
public class CustomMinioClient extends MinioClient {
 
    /**
     * 继承父类
     * @param client
     */
    public CustomMinioClient(MinioClient client) {
        super(client);
    }
 
 
    /**
     * 初始化分片上传、获取 uploadId
     *
     * @param bucket           String  存储桶名称
     * @param region           String
     * @param object           String   文件名称
     * @param headers          Multimap 请求头
     * @param extraQueryParams Multimap
     * @return String
     */
    public String initMultiPartUpload(String bucket, String region, String object, Multimap headers, Multimap extraQueryParams) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, ServerException, InternalException, XmlParserException, InvalidResponseException, ErrorResponseException {
        CreateMultipartUploadResponse response = this.createMultipartUpload(bucket, region, object, headers, extraQueryParams);
        return response.result().uploadId();
    }
 
    /**
     * 合并分片
     *
     * @param bucketName       String   桶名称
     * @param region           String
     * @param objectName       String   文件名称
     * @param uploadId         String   上传的 uploadId
     * @param parts            Part[]   分片集合
     * @param extraHeaders     Multimap
     * @param extraQueryParams Multimap
     * @return ObjectWriteResponse
     */
    public ObjectWriteResponse mergeMultipartUpload(String bucketName, String region, String objectName, String uploadId, Part[] parts, Multimap extraHeaders, Multimap extraQueryParams) throws IOException, InvalidKeyException, NoSuchAlgorithmException, InsufficientDataException, ServerException, InternalException, XmlParserException, InvalidResponseException, ErrorResponseException {
        return this.completeMultipartUpload(bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams);
    }
 
    /**
     * 查询当前上传后的分片信息
     *
     * @param bucketName       String   桶名称
     * @param region           String
     * @param objectName       String   文件名称
     * @param maxParts         Integer  分片数量
     * @param partNumberMarker Integer  分片起始值
     * @param uploadId         String   上传的 uploadId
     * @param extraHeaders     Multimap
     * @param extraQueryParams Multimap
     * @return ListPartsResponse
     */
    public ListPartsResponse listMultipart(String bucketName, String region, String objectName, Integer maxParts, Integer partNumberMarker, String uploadId, Multimap extraHeaders, Multimap extraQueryParams) throws NoSuchAlgorithmException, InsufficientDataException, IOException, InvalidKeyException, ServerException, XmlParserException, ErrorResponseException, InternalException, InvalidResponseException {
        return this.listParts(bucketName, region, objectName, maxParts, partNumberMarker, uploadId, extraHeaders, extraQueryParams);
    }
 
 
}
 
 

corsConf

框架自带可不用

package com.xy.config;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
/**
 * 全局跨域处理
 * @author CV
 */
 
@Configuration
public class CorsConfig implements WebMvcConfigurer {
 
        private CorsConfiguration buildConfig() {
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            corsConfiguration.addAllowedOrigin("*");
            corsConfiguration.addAllowedHeader("*");
            corsConfiguration.addAllowedMethod("*");
            corsConfiguration.setMaxAge(3600L);
            corsConfiguration.setAllowCredentials(true);
            return corsConfiguration;
        }
 
        @Bean
        public CorsFilter corsFilter() {
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", buildConfig());
            return new CorsFilter(source);
        }
    }

 返回工具类

ResponseResult

package com.xy.util;
 
import lombok.Data;
 
@Data
public class ResponseResult {
    private int code;
    private String enMessage;
    private String zhMessage;
    private T data;
 
    public ResponseResult() {
    }
 
    public ResponseResult(int code, String enMessage, String zhMessage) {
        this.code = code;
        this.enMessage = enMessage;
        this.zhMessage = zhMessage;
    }
 
 
    /**
     * 成功
     */
    public static  ResponseResult success() {
        ResponseResult result = new ResponseResult();
        result.setCode(ResultCode.SUCCESS.getCode());
        result.setEnMessage(ResultCode.SUCCESS.getEnMessage());
        result.setZhMessage(ResultCode.SUCCESS.getZhMessage());
        return result;
    }
 
 
    /**
     * 成功
     */
    public static  ResponseResult success(T data) {
        ResponseResult result = new ResponseResult();
        result.setCode(ResultCode.SUCCESS.getCode());
        result.setEnMessage(ResultCode.SUCCESS.getEnMessage());
        result.setZhMessage(ResultCode.SUCCESS.getZhMessage());
        result.setData(data);
        return result;
    }
 
 
    /**
     * 失败
     */
    public static   ResponseResult  error() {
        ResponseResult result = new ResponseResult();
        result.setCode(ResultCode.FAIL.getCode());
        result.setEnMessage(ResultCode.FAIL.getEnMessage());
        result.setZhMessage(ResultCode.FAIL.getZhMessage());
        return result;
    }
 
    /**
     * 失败
     */
    public static  ResponseResult error(T data) {
        ResponseResult result = new ResponseResult();
        result.setCode(ResultCode.FAIL.getCode());
        result.setEnMessage(ResultCode.FAIL.getEnMessage());
        result.setZhMessage(ResultCode.FAIL.getZhMessage());
        result.setData(data);
        return result;
    }
 
 
    /**
     *
     * @param data 数据
     * @param 
     * @return
     */
    public static  ResponseResult uploading(T data) {
        ResponseResult result = new ResponseResult();
        result.setCode(ResultCode.UPLOADING.getCode());
        result.setEnMessage(ResultCode.UPLOADING.getEnMessage());
        result.setZhMessage(ResultCode.UPLOADING.getZhMessage());
        result.setData(data);
        return result;
    }
 
    /**
     * 成功
     */
    public static  ResponseResult success(int code, String enMessage, String zhMessage) {
        return new ResponseResult(code, enMessage, zhMessage);
    }
 
 
    /**
     * 失败
     */
    public static  ResponseResult error(int code, String enMessage, String zhMessage) {
        return new ResponseResult(code, enMessage, zhMessage);
    }
 
 
    public int getCode() {
        return code;
    }
 
    public void setCode(int code) {
        this.code = code;
    }
 
    public String getEnMessage() {
        return enMessage;
    }
 
    public void setEnMessage(String enMessage) {
        this.enMessage = enMessage;
    }
 
    public String getZhMessage() {
        return zhMessage;
    }
 
    public void setZhMessage(String zhMessage) {
        this.zhMessage = zhMessage;
    }
 
    public T getData() {
        return data;
    }
 
    public void setData(T data) {
        this.data = data;
    }
 
//    public static ResponseResult SUCCESS = new ResponseResult<>(200,"成功");
//    public static ResponseResult INTEVER_ERROR = new ResponseResult<>(500,"服务器错误");
//    public static ResponseResult NOT_FOUND = new ResponseResult<>(404,"未找到");
 
}

ResultCode

package com.xy.util;
 
 
 
/**
 * http状态码枚举类
 */
public enum ResultCode {
 
    SUCCESS(1, "Success", "成功"),
    UPLOADING(2, "Uploading", "上传中"),
    FAIL(-1, "Err", "失败"),
 
 
    DATABASE_OPERATION_FAILED(504, "数据库操作失败"),
    CONTINUE(100, "Continue", "请继续发送请求的剩余部分"),
    SWITCHING_PROTOCOLS(101, "Switching Protocols", "协议切换"),
    PROCESSING(102, "Processing", "请求将继续执行"),
    CHECKPOINT(103, "Checkpoint", "可以预加载"),
    OK(200, "OK", "请求已经成功处理"),
    CREATED(201, "Created", "请求已经成功处理,并创建了资源"),
    ACCEPTED(202, "Accepted", "请求已经接受,等待执行"),
    NON_AUTHORITATIVE_INFORMATION(203, "Non-Authoritative Information", "请求已经成功处理,但是信息不是原始的"),
    NO_CONTENT(204, "No Content", "请求已经成功处理,没有内容需要返回"),
    RESET_CONTENT(205, "Reset Content", "请求已经成功处理,请重置视图"),
    PARTIAL_CONTENT(206, "Partial Content", "部分Get请求已经成功处理"),
    MULTI_STATUS(207, "Multi-Status", "请求已经成功处理,将返回XML消息体"),
    ALREADY_REPORTED(208, "Already Reported", "请求已经成功处理,一个DAV的绑定成员被前一个请求枚举,并且没有被再一次包括"),
    IM_USED(226, "IM Used", "请求已经成功处理,将响应一个或者多个实例"),
    MULTIPLE_CHOICES(300, "Multiple Choices", "提供可供选择的回馈"),
    MOVED_PERMANENTLY(301, "Moved Permanently", "请求的资源已经永久转移"),
    FOUND(302, "Found", "请重新发送请求"),
    SEE_OTHER(303, "See Other", "请以Get方式请求另一个URI"),
    NOT_MODIFIED(304, "Not Modified", "资源未改变"),
    USE_PROXY(305, "Use Proxy", "请通过Location域中的代理进行访问"),
    TEMPORARY_REDIRECT(307, "Temporary Redirect", "请求的资源临时从不同的URI响应请求"),
    RESUME_INCOMPLETE(308, "Resume Incomplete", "请求的资源已经永久转移"),
    BAD_REQUEST(400, "Bad Request", "请求错误,请修正请求"),
    UNAUTHORIZED(401, "Unauthorized", "没有被授权或者授权已经失效"),
    PAYMENT_REQUIRED(402, "Payment Required", "预留状态"),
    FORBIDDEN(403, "Forbidden", "请求被理解,但是拒绝执行"),
    NOT_FOUND(404, "Not Found", "资源未找到"),
    METHOD_NOT_ALLOWED(405, "Method Not Allowed", "请求方法不允许被执行"),
    NOT_ACCEPTABLE(406, "Not Acceptable", "请求的资源不满足请求者要求"),
    PROXY_AUTHENTICATION_REQUIRED(407, "Proxy Authentication Required", "请通过代理进行身份验证"),
    REQUEST_TIMEOUT(408, "Request Timeout", "请求超时"),
    CONFLICT(409, "Conflict", "请求冲突"),
    GONE(410, "Gone", "请求的资源不可用"),
    LENGTH_REQUIRED(411, "Length Required", "Content-Length未定义"),
    PRECONDITION_FAILED(412, "Precondition Failed", "不满足请求的先决条件"),
    REQUEST_ENTITY_TOO_LARGE(413, "Request Entity Too Large", "请求发送的实体太大"),
    REQUEST_URI_TOO_LONG(414, "Request-URI Too Long", "请求的URI超长"),
    UNSUPPORTED_MEDIA_TYPE(415, "Unsupported Media Type", "请求发送的实体类型不受支持"),
    REQUESTED_RANGE_NOT_SATISFIABLE(416, "Requested range not satisfiable", "Range指定的范围与当前资源可用范围不一致"),
    EXPECTATION_FAILED(417, "Expectation Failed", "请求头Expect中指定的预期内容无法被服务器满足"),
    UNPROCESSABLE_ENTITY(422, "Unprocessable Entity", "请求格式正确,但是由于含有语义错误,无法响应"),
    LOCKED(423, "Locked", "当前资源被锁定"),
    FAILED_DEPENDENCY(424, "Failed Dependency", "由于之前的请求发生错误,导致当前请求失败"),
    UPGRADE_REQUIRED(426, "Upgrade Required", "客户端需要切换到TLS1.0"),
    PRECONDITION_REQUIRED(428, "Precondition Required", "请求需要提供前置条件"),
    TOO_MANY_REQUESTS(429, "Too Many Requests", "请求过多"),
    REQUEST_HEADER_FIELDS_TOO_LARGE(431, "Request Header Fields Too Large", "请求头超大,拒绝请求"),
    INTERNAL_SERVER_ERROR(500, "Internal Server Error", "服务器内部错误"),
    NOT_IMPLEMENTED(501, "Not Implemented", "服务器不支持当前请求的部分功能"),
    BAD_GATEWAY(502, "Bad Gateway", "响应无效"),
    SERVICE_UNAVAILABLE(503, "Service Unavailable", "服务器维护或者过载,拒绝服务"),
    GATEWAY_TIMEOUT(504, "Gateway Timeout", "上游服务器超时"),
    HTTP_VERSION_NOT_SUPPORTED(505, "HTTP Version not supported", "不支持的HTTP版本"),
    VARIANT_ALSO_NEGOTIATES(506, "Variant Also Negotiates", "服务器内部配置错误"),
    INSUFFICIENT_STORAGE(507, "Insufficient Storage", "服务器无法完成存储请求所需的内容"),
    LOOP_DETECTED(508, "Loop Detected", "服务器处理请求时发现死循环"),
    BANDWIDTH_LIMIT_EXCEEDED(509, "Bandwidth Limit Exceeded", "服务器达到带宽限制"),
    NOT_EXTENDED(510, "Not Extended", "获取资源所需的策略没有被满足"),
    NETWORK_AUTHENTICATION_REQUIRED(511, "Network Authentication Required", "需要进行网络授权"),
    ACCESS_PARAMETER_INVALID(1001,"Invalid access parameter","访问参数无效"),
    UPLOAD_FILE_FAILED(1002,"File upload failure","文件上传失败"),
    DATA_NOT_EXISTS(1003,"Data does not exist","数据不存在"),
 
    ;
 
 
 
    private int code;
    private String enMessage;
    private String zhMessage;
 
    ResultCode(int code, String enMessage, String zhMessage) {
        this.code = code;
        this.enMessage = enMessage;
        this.zhMessage = zhMessage;
    }
 
    ResultCode(int code, String message) {
 
    }
 
 
    public int getCode() {
        return code;
    }
 
    public void setCode(int code) {
        this.code = code;
    }
 
    public String getEnMessage() {
        return enMessage;
    }
 
    public void setEnMessage(String enMessage) {
        this.enMessage = enMessage;
    }
 
    public String getZhMessage() {
        return zhMessage;
    }
 
    public void setZhMessage(String zhMessage) {
        this.zhMessage = zhMessage;
    }
}

FileUploadInfo

package com.xy.entity;
 
import lombok.Data;
import lombok.experimental.Accessors;
 
 
@Data
@Accessors(chain = true)
public class FileUploadInfo {
 
    //@NotBlank(message = "文件名不能为空")
    private String fileName;
 
    // @NotNull(message = "文件大小不能为空")
    private Double fileSize;
 
    // @NotBlank(message = "Content-Type不能为空")
    private String contentType;
 
    //  @NotNull(message = "分片数量不能为空")
    private Integer partCount;
 
    // @NotBlank(message = "uploadId 不能为空")
    private String uploadId;
 
    // 桶名称
    //private String bucketName;
 
    //md5
    private String fileMd5;
 
    //文件类型
    private String fileType;
 
 
    public FileUploadInfo() {
    }
 
 
}
 
 

RedisRepo

package com.xy.util;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundValueOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
 
import java.util.concurrent.TimeUnit;
 
 
@Component
public class RedisRepo {
 
    @Autowired
    private StringRedisTemplate redisTemplate;
 
    public String get(String key) {
        BoundValueOperations ops = redisTemplate.boundValueOps(key);
        return ops.get();
    }
 
    public void save(String key,String str){
        BoundValueOperations ops = redisTemplate.boundValueOps(key);
        ops.set(str);
    }
 
    public void saveTimeout(String key, String value, long timeout, TimeUnit unit ){
        redisTemplate.boundValueOps(key).setIfAbsent(value,timeout,unit);
    }
 
    public void delete(String key){
        redisTemplate.delete(key);
    }
 
    public long expire(String key){
        return redisTemplate.opsForValue().getOperations().getExpire(key);
    }
}

.yaml配置

minio:
  endpoint: http://localhost:9000
  accesskey: minioadmin
  secretkey: minioadmin

spring:
  redis:
    host: localhost
    port: 6379

pom

      
            io.minio
            minio
            8.3.1
        
 
        
            com.squareup.okhttp3
            okhttp
            4.9.2
        

git地址: Study: study - Gitee.com

引用说明:

springboot整合Minio + vue 实现文件分片上传(完整代码已更新)_minioclient.putobject 方法如何获取上传进度-CSDN博客

你可能感兴趣的:(vue.js,javascript,ecmascript)