iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >Java怎么将大文件分片上传
  • 632
分享到

Java怎么将大文件分片上传

2023-07-02 00:07:22 632人浏览 八月长安
摘要

这篇文章主要介绍“Java怎么将大文件分片上传”,在日常操作中,相信很多人在Java怎么将大文件分片上传问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java怎么将大文件分片上传”的疑惑有所帮助!接下来,请跟

这篇文章主要介绍“Java怎么将大文件分片上传”,在日常操作中,相信很多人在Java怎么将大文件分片上传问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java怎么将大文件分片上传”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

Java 大文件分片上传

原理:前端通过js读取文件,并将大文件按照指定大小拆分成多个分片,并且计算每个分片的MD5值。前端将每个分片分别上传到后端,后端在接收到文件之后验证当前分片的MD5值是否与上传的MD5一致,待所有分片上传完成之后后端将多个分片合并成一个大文件,并校验该文件的MD5值是否与上传时传入的MD5值一致;

首先是交互的控制器

支持文件分片上传,查询当前已经上传的分片信息,取消文件上传

package com.aimilin.component.system.service.modular.file.controller;import com.aimilin.common.core.pojo.base.param.BaseParam;import com.aimilin.common.core.pojo.response.ResponseData;import com.aimilin.common.log.annotation.BusinessLog;import com.aimilin.common.log.enums.LoGopTypeEnum;import com.aimilin.common.security.annotation.Permission;import com.aimilin.component.system.service.modular.file.param.SysPartFileParam;import com.aimilin.component.system.service.modular.file.result.SysPartFileResult;import com.aimilin.component.system.service.modular.file.service.SysPartFileService;import lombok.extern.slf4j.Slf4j;import org.springframework.validation.annotation.Validated;import org.springframework.WEB.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.PostMapping;import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@Slf4j@RestControllerpublic class SysPartFileController {    @Resource    private SysPartFileService sysPartFileService;        @Permission    @PostMapping("/sysFileInfo/partUpload")    public ResponseData<SysPartFileResult> partUpload(@Validated(BaseParam.add.class) SysPartFileParam partFile) {        return ResponseData.success(sysPartFileService.partUpload(partFile));    }        @Permission    @GetMapping("/sysFileInfo/partUpload/status")    public ResponseData<SysPartFileResult> getPartUploadStatus(@Validated(BaseParam.detail.class) SysPartFileParam partFile) {        return ResponseData.success(sysPartFileService.getPartUploadStatus(partFile));    }        @Permission    @GetMapping("/sysFileInfo/partUpload/cancel")    @BusinessLog(title = "文件_上传大文件_取消", opType = LogOpTypeEnum.OTHER)    public ResponseData<SysPartFileResult> cancelUpload(@Validated(BaseParam.detail.class) SysPartFileParam partFile) {        return ResponseData.success(sysPartFileService.cancelUpload(partFile));    }}

上传文件分片参数接收

如果按照分片方式上传文件需要指定当前大文件的MD5、分片MD5、分片内容、分片大小、当前文件名称、文件总大小等信息;另外对于每个文件前端都需要生成一个唯一编码用于确定当前上传的分片属于统一文件。

package com.aimilin.component.system.service.modular.file.param;import java.io.Serializable;import java.util.Objects;import com.baomidou.mybatisplus.core.toolkit.StringUtils;import com.aimilin.common.core.pojo.base.param.BaseParam;import lombok.Getter;import lombok.Setter;import lombok.ToString;import org.springframework.web.multipart.MultipartFile;import javax.validation.constraints.NotNull;@Getter@Setter@ToStringpublic class SysPartFileParam extends BaseParam implements Serializable {        @NotNull(message = "uid不能为空", groups = {BaseParam.detail.class, BaseParam.add.class})    private String uid;        private String filename;        @NotNull(message = "partNumber不能为空", groups = {BaseParam.add.class})    private Integer partNumber;        @NotNull(message = "partMd5不能为空", groups = {BaseParam.add.class})    private String partMd5;        @NotNull(message = "partSize不能为空", groups = {BaseParam.add.class})    private Long partSize;        @NotNull(message = "totalSize不能为空", groups = {BaseParam.add.class})    private Long totalSize;        @NotNull(message = "fileMd5不能为空", groups = {BaseParam.add.class})    private String fileMd5;        @NotNull(message = "file不能为空", groups = {BaseParam.add.class})    private MultipartFile file;        public Integer getTotalParts() {        if (Objects.isNull(totalSize) || Objects.isNull(partSize)) {            return 0;        }        return new Double(Math.ceil(totalSize * 1.0 / partSize)).intValue();    }    public String getFilename() {        if (StringUtils.isBlank(this.filename) && Objects.isNull(this.file)) {            return null;        }        return StringUtils.isBlank(this.filename) ? this.file.getOriginalFilename() : this.filename;    }}

至于代码中的 BaseParam 类,只是定义了一些验证的分组,类似以下代码:

        public @interface page {    }        public @interface list {    }        public @interface dropDown {    }        public @interface add {    }

大文件分片上传服务类实现

也是定义了三个接口,分片上传、查询当前已上传的分片、取消文件上传

package com.aimilin.component.system.service.modular.file.service;import com.aimilin.component.system.service.modular.file.param.SysPartFileParam;import com.aimilin.component.system.service.modular.file.result.SysPartFileResult;public interface SysPartFileService {        public static final String PART_FILE_KEY = "PART_FILE";        public SysPartFileResult partUpload(SysPartFileParam partFile);        public SysPartFileResult getPartUploadStatus(SysPartFileParam partFile);        public SysPartFileResult cancelUpload(SysPartFileParam partFile);}

服务实现类:

package com.aimilin.component.system.service.modular.file.service.impl;import cn.hutool.core.io.FileUtil;import com.baomidou.mybatisplus.core.toolkit.IdWorker;import com.aimilin.common.base.file.FilePartOperator;import com.aimilin.common.base.file.param.AbortMultipartUploadResult;import com.aimilin.common.base.file.param.CompleteFileUploadPart;import com.aimilin.common.base.file.param.FileUploadPart;import com.aimilin.common.base.file.param.FileUploadPartResult;import com.aimilin.common.cache.RedisService;import com.aimilin.common.core.consts.CommonConstant;import com.aimilin.common.core.context.login.LoginContextHolder;import com.aimilin.common.core.exception.ServiceException;import com.aimilin.component.system.service.modular.file.convert.SysPartFileConvert;import com.aimilin.component.system.service.modular.file.entity.SysFileInfo;import com.aimilin.component.system.service.modular.file.enums.SysFileInfoExceptionEnum;import com.aimilin.component.system.service.modular.file.enums.SysPartFileEnum;import com.aimilin.component.system.service.modular.file.param.SysPartFileParam;import com.aimilin.component.system.service.modular.file.result.SysPartFileCache;import com.aimilin.component.system.service.modular.file.result.SysPartFileCache.FileInfo;import com.aimilin.component.system.service.modular.file.result.SysPartFileCache.SysFilePart;import com.aimilin.component.system.service.modular.file.result.SysPartFileResult;import com.aimilin.component.system.service.modular.file.service.SysFileInfoService;import com.aimilin.component.system.service.modular.file.service.SysPartFileService;import lombok.extern.slf4j.Slf4j;import org.apache.commons.io.FilenameUtils;import org.Redisson.api.RLock;import org.redisson.api.RedissonClient;import org.springframework.stereotype.Service;import org.springframework.web.multipart.MultipartFile;import javax.annotation.Resource;import java.io.IOException;import java.util.*;import java.util.concurrent.TimeUnit;import static com.aimilin.component.system.service.config.FileConfig.DEFAULT_BUCKET;@Slf4j@Servicepublic class SysPartFileServiceImpl implements SysPartFileService {    @Resource    private FilePartOperator fileOperator;    @Resource    private RedisService redisService;    @Resource    private SysFileInfoService sysFileInfoService;    @Resource    private RedissonClient redisson;        @Override    public SysPartFileResult partUpload(SysPartFileParam partFile) {        MultipartFile file = partFile.getFile();        log.info("分块上传文件:{}, partNumber:{}/{}, partSize:{}/{}",                partFile.getFilename(), partFile.getPartNumber(), partFile.getTotalParts(), file.getSize(), partFile.getPartSize());        SysPartFileResult partUploadStatus = this.getPartUploadStatus(partFile);        // 已经上传该部分则直接返回当前文件状态        if (SysPartFileEnum.SUCCESS.getCode().equals(partUploadStatus.getPartState())) {            return partUploadStatus;        }        // 上传分片文件        FileUploadPart fileUploadPart = this.getFileUploadPart(partFile);        try {            FileUploadPartResult uploadPartResult = fileOperator.uploadPart(fileUploadPart);            this.setPartUploadStatus(partFile, uploadPartResult);        } catch (Exception e) {            log.error("文件分片上传失败,请求:{}:{}", partFile, e.getMessage(), e);            throw new ServiceException(SysFileInfoExceptionEnum.FILE_OSS_ERROR);        }        return this.getPartUploadStatus(partFile);    }        @Override    public SysPartFileResult getPartUploadStatus(SysPartFileParam partFile) {        SysPartFileCache fileCache = redisService.getCacheObject(getPartFileKey(partFile.getUid()));        SysPartFileResult result;        // 如果没有上传过则返回默认值        if (Objects.isNull(fileCache)) {            result = SysPartFileConvert.INSTANCE.toSysPartFileResult(partFile);            result.setFileState(SysPartFileEnum.NOT_EXISTS.getCode());            result.setPartState(SysPartFileEnum.NOT_EXISTS.getCode());        } else {            result = SysPartFileConvert.INSTANCE.toSysPartFileResult(fileCache, fileCache.getFilePart(partFile.getPartNumber()));        }        return result;    }        @Override    public SysPartFileResult cancelUpload(SysPartFileParam partFile) {        String cacheKey = getPartFileKey(partFile.getUid());        SysPartFileCache fileCache = redisService.getCacheObject(cacheKey);        if (Objects.isNull(fileCache)) {            throw new ServiceException(SysFileInfoExceptionEnum.NOT_EXISTED_FILE);        }        SysPartFileCache.FileInfo fileInfo = fileCache.getFileInfo();        fileOperator.abortMultipartUpload(fileInfo.getBucketName(), fileInfo.getObjectName(), fileInfo.getUploadId());        log.info("取消文件上传:{}", partFile.getUid());        SysPartFileResult sysPartFileResult = SysPartFileConvert.INSTANCE.toSysPartFileResult(partFile);        sysPartFileResult.setFileState(SysPartFileEnum.CANCELED.getCode());        redisService.deleteObject(cacheKey);        return sysPartFileResult;    }        private void setPartUploadStatus(SysPartFileParam partFile, FileUploadPartResult uploadPartResult) {        String redisKey = getPartFileKey(partFile.getUid());        if (!redisService.hasKey(redisKey)) {            throw new ServiceException(SysFileInfoExceptionEnum.FILE_CACHE_ERROR);        }        RLock lock = redisson.getLock(CommonConstant.getLockKey(redisKey));        try {            lock.lock();            SysPartFileCache fileCache = redisService.getCacheObject(redisKey);            Set<SysFilePart> filePartList = fileCache.getFilePartList();            if (Objects.isNull(filePartList)) {                filePartList = new HashSet<>();                fileCache.setFilePartList(filePartList);            }            SysFilePart sysFilePart = new SysFilePart();            sysFilePart.setPartNumber(partFile.getPartNumber());            sysFilePart.setPartState(SysPartFileEnum.SUCCESS.getCode());            sysFilePart.setPartMd5(partFile.getPartMd5());            sysFilePart.setPartSize(partFile.getFile().getSize());            sysFilePart.setFileUploadPartResult(uploadPartResult);            filePartList.add(sysFilePart);            fileCache.setFileState(SysPartFileEnum.UPLOADING.getCode());            // 所有文本块都已经上传完成            if (new HashSet<>(fileCache.getUploadedParts()).size() == fileCache.getTotalParts()) {                CompleteFileUploadPart completeFileUploadPart = SysPartFileConvert.INSTANCE.toCompleteFileUploadPart(fileCache);                fileOperator.completeMultipartUpload(completeFileUploadPart);                log.info("文件合并完成:{},part: {}/{}", partFile.getFilename(), partFile.getPartNumber(), partFile.getTotalParts());                this.saveFileInfo(partFile, fileCache);                fileCache.setFileState(SysPartFileEnum.SUCCESS.getCode());                redisService.setCacheObject(redisKey, fileCache, 1L, TimeUnit.DAYS);            } else {                redisService.setCacheObject(redisKey, fileCache);            }        } catch (Exception e) {            log.error("设置文件分片上传状态异常,{},上传结果:{}", partFile, uploadPartResult, e);            throw new ServiceException(SysFileInfoExceptionEnum.PART_FILE_SET_STATE_ERROR);        }finally {            lock.unlock();        }    }        private void saveFileInfo(SysPartFileParam partFile, SysPartFileCache fileCache) {        SysFileInfo sysFileInfo = new SysFileInfo();        sysFileInfo.setId(Objects.isNull(fileCache.getFileId()) ? IdWorker.getId() : fileCache.getFileId());        sysFileInfo.setFileLocation(fileOperator.getFileLocation().getCode());        sysFileInfo.setFileBucket(fileCache.getFileInfo().getBucketName());        sysFileInfo.setFileOriginName(fileCache.getFilename());        sysFileInfo.setFileSuffix(FilenameUtils.getExtension(fileCache.getFileInfo().getObjectName()));        sysFileInfo.setFileSizeKb(SysFileUtils.getFileSizeKb(fileCache.getTotalSize()));        sysFileInfo.setFileSizeInfo(FileUtil.readableFileSize(fileCache.getTotalSize()));        sysFileInfo.setFileObjectName(fileCache.getFileInfo().getObjectName());        boolean save = sysFileInfoService.save(sysFileInfo);        log.info("保存文件信息完成:{},结果:{}", partFile.getFilename(), save);    }        private FileUploadPart getFileUploadPart(SysPartFileParam partFile) {        try {            SysPartFileCache fileCache = redisService.getCacheObject(getPartFileKey(partFile.getUid()));            if (Objects.isNull(fileCache)) {                fileCache = this.initSysPartFileCache(partFile);            }            return SysPartFileConvert.INSTANCE.toFileUploadPart(fileCache.getFileInfo(), partFile);        } catch (IOException e) {            log.error("获取文件分片对象异常:{}", e.getMessage(), e);            throw new ServiceException(SysFileInfoExceptionEnum.FILE_STREAM_ERROR);        }    }        private SysPartFileCache initSysPartFileCache(SysPartFileParam partFile) {        String key  =  getPartFileKey(partFile.getUid());        RLock lock = redisson.getLock(CommonConstant.getLockKey(key));        try {            lock.lock();            SysPartFileCache fileCache = redisService.getCacheObject(key);            if(Objects.isNull(fileCache)){                Long fileId = IdWorker.getId();                String objectName = SysFileUtils.getFileObjectName(partFile.getFilename(), fileId);                String uploadId = fileOperator.initiateMultipartUpload(DEFAULT_BUCKET, objectName);                fileCache = SysPartFileConvert.INSTANCE.toSysPartFileCache(partFile);                fileCache.setFileState(SysPartFileEnum.UPLOADING.getCode());                fileCache.setFileInfo(new FileInfo(DEFAULT_BUCKET, objectName, uploadId));                fileCache.setFileId(fileId);                redisService.setCacheObject(getPartFileKey(partFile.getUid()), fileCache);            }            return fileCache;        } catch (Exception e) {            log.error("文件缓存初始化异常:{}", partFile, e);            throw new ServiceException(SysFileInfoExceptionEnum.PART_FILE_INIT_CACHE_ERROR);        }finally {            lock.unlock();        }    }        private String getPartFileKey(String fileId) {        return String.fORMat("%s:%s:%s", PART_FILE_KEY, LoginContextHolder.me().getSysLoginUserId(), fileId);    }}

文件分片上传定义公共服务类接口

package com.aimilin.common.base.file;import com.aimilin.common.base.file.param.*;public interface FilePartOperator extends FileOperator {        String initiateMultipartUpload(String bucketName, String key);        FileUploadPartResult uploadPart(FileUploadPart fileUploadPart);        CompleteFileUploadPartResult completeMultipartUpload(CompleteFileUploadPart completeFileUploadPart);        void abortMultipartUpload(String bucketName, String objectName, String uploadId);}public class AbortMultipartUploadResult {}@Getter@Setter@ToStringpublic class CompleteFileUploadPart implements Serializable {    private String bucketName;    private String objectName;    private String uploadId;    private List<FileUploadPartResult> partETags;}@Getter@Setter@ToStringpublic class CompleteFileUploadPartResult implements Serializable {    private String bucketName;    private String objectName;    private String location;    private String eTag;}@Getter@Setter@ToStringpublic class FileUploadPart implements Serializable {        private String bucketName;        private String objectName;        private String uploadId;        private Long partSize;        private Integer partNumber;        private String partMd5;        @JSONIgnore    @JSONField(deserialize = false, serialize = false)    private InputStream partContent;}@Getter@Setter@ToStringpublic class FileUploadPartResult implements Serializable {        private Integer partNumber;        private Long partSize;        private String partETag;}

文件分片上传文件操作接口实现类

这里风两种实现,1:本地文件上传,2:oss对象存储方式分片上传

@Slf4jpublic class LocalFileOperator implements FilePartOperator {    @Override    public FileLocationEnum getFileLocation() {        return FileLocationEnum.LOCAL;    }    private final LocalFileProperties localFileProperties;    private String currentSavePath = "";    private Dict localClient;    public LocalFileOperator(LocalFileProperties localFileProperties) {        this.localFileProperties = localFileProperties;        initClient();    }    @Override    public void initClient() {        if (SystemUtil.getOsInfo().iswindows()) {            String savePathWindows = localFileProperties.getLocalFileSavePathWin();            if (!FileUtil.exist(savePathWindows)) {                FileUtil.mkdir(savePathWindows);            }            currentSavePath = savePathWindows;        } else {            String savePathlinux = localFileProperties.getLocalFileSavePathLinux();            if (!FileUtil.exist(savePathLinux)) {                FileUtil.mkdir(savePathLinux);            }            currentSavePath = savePathLinux;        }        localClient = Dict.create();        localClient.put("currentSavePath", currentSavePath);        localClient.put("localFileProperties", localFileProperties);    }    @Override    public void destroyClient() {        // empty    }    @Override    public Object getClient() {        // empty        return localClient;    }    @Override    public boolean doesBucketExist(String bucketName) {        String absolutePath = currentSavePath + File.separator + bucketName;        return FileUtil.exist(absolutePath);    }    @Override    public void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum) {        // empty    }    @Override    public boolean isExistingFile(String bucketName, String key) {        return FileUtil.exist(this.getAbsolutePath(bucketName, key));    }    @Override    public void storageFile(String bucketName, String key, byte[] bytes) {        // 判断bucket存在不存在        String bucketPath = currentSavePath + File.separator + bucketName;        if (!FileUtil.exist(bucketPath)) {            FileUtil.mkdir(bucketPath);        }        // 存储文件        FileUtil.writeBytes(bytes, this.getAbsolutePath(bucketName, key));    }    @Override    public void storageFile(String bucketName, String key, InputStream inputStream, long fileSize) {        // 判断bucket存在不存在        String bucketPath = currentSavePath + File.separator + bucketName;        if (!FileUtil.exist(bucketPath)) {            FileUtil.mkdir(bucketPath);        }        // 存储文件        FileUtil.writeFromStream(inputStream, this.getAbsolutePath(bucketName, key));    }    @Override    public byte[] getFileBytes(String bucketName, String key) {        // 判断文件存在不存在        String absoluteFile = this.getAbsolutePath(bucketName, key);        if (!FileUtil.exist(absoluteFile)) {            String message = StrUtil.format("文件不存在,bucket={},key={}", bucketName, key);            throw new FileServiceException(message);        } else {            return FileUtil.readBytes(absoluteFile);        }    }    @Override    public void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {        // empty    }    @Override    public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {        // 判断文件存在不存在        String originFile = this.getAbsolutePath(originBucketName, originFileKey);        if (!FileUtil.exist(originFile)) {            String message = StrUtil.format("源文件不存在,bucket={},key={}", originBucketName, originFileKey);            throw new FileServiceException(message);        } else {            // 拷贝文件            String destFile = this.getAbsolutePath(newBucketName, newFileKey);            FileUtil.copy(originFile, destFile, true);        }    }    @Override    public String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {        // empty        return null;    }    @Override    public void deleteFile(String bucketName, String key) {        // 判断文件存在不存在        String file = this.getAbsolutePath(bucketName, key);        if (!FileUtil.exist(file)) {            return;        }        // 删除文件        FileUtil.del(file);    }        @Override    public String initiateMultipartUpload(String bucketName, String key) {        return FileNameUtil.getName(key);    }        @Override    public FileUploadPartResult uploadPart(FileUploadPart fileUploadPart) {        String partName = fileUploadPart.getObjectName() + "." + fileUploadPart.getPartNumber();        this.storageFile(fileUploadPart.getBucketName(), partName, fileUploadPart.getPartContent(), fileUploadPart.getPartSize());        FileUploadPartResult result = new FileUploadPartResult();        result.setPartNumber(fileUploadPart.getPartNumber());        result.setPartSize(fileUploadPart.getPartSize());        result.setPartETag(partName);        // TODO 正常文件上传完成之后需要验证文件的分片的MD5值是否与前端传入的值一样        return result;    }        @Override    public CompleteFileUploadPartResult completeMultipartUpload(CompleteFileUploadPart completeFileUploadPart) {        try {            List<FileUploadPartResult> partETags = completeFileUploadPart.getPartETags();            String path = this.getAbsolutePath(completeFileUploadPart.getBucketName(), completeFileUploadPart.getObjectName());            partETags.sort((o1, o2) -> {                String p1 = FileNameUtil.extName(o1.getPartETag());                String p2 = FileNameUtil.extName(o2.getPartETag());                return Integer.valueOf(p1).compareTo(Integer.valueOf(p2));            });            Files.createFile(Paths.get(path));            partETags.forEach(c -> {                try {                    Path partPath = Paths.get(this.getAbsolutePath(completeFileUploadPart.getBucketName(), c.getPartETag()));                    Files.write(Paths.get(path), Files.readAllBytes(partPath), StandardOpenOption.APPEND);                    Files.delete(partPath);                } catch (IOException e) {                    log.error("合并文件失败:{}", e.getMessage(), e);                    throw new FileServiceException(e.getMessage());                }            });            // 文件合并完成之后需要校验文件的MD5值是否与前端传入的一致            return new CompleteFileUploadPartResult();        } catch (IOException e) {            log.error("合并文件失败:{}", e.getMessage(), e);            throw new FileServiceException(e.getMessage());        }    }        @Override    public void abortMultipartUpload(String bucketName, String objectName, String uploadId) {        try {            Path folder = Paths.get(this.getAbsolutePath(bucketName, objectName)).getParent();            String partName = objectName + ".";            Files.list(folder)                    .filter(path -> StrUtil.contains(path.toString(), partName))                    .forEach(path -> {                        try {                            Files.delete(path);                        } catch (IOException e) {                            log.warn("删除分片文件失败:{}", path);                        }                    });        } catch (IOException e) {            log.error("取消文件分片上传异常:{}", e.getMessage(), e);            throw new FileServiceException(e.getMessage());        }    }        private String getAbsolutePath(String bucketName, String key) {        return currentSavePath + File.separator + bucketName + File.separator + key;    }}

OSS阿里云对象存储分片上传实现

@Slf4jpublic class AliyunFileOperator implements FilePartOperator {    @Override    public FileLocationEnum getFileLocation() {        return FileLocationEnum.ALIYUN;    }        private OSS ossClient;        private final AliyunOssProperties aliyunOssProperties;    public AliyunFileOperator(AliyunOssProperties aliyunOssProperties) {        this.aliyunOssProperties = aliyunOssProperties;        this.initClient();    }    @Override    public void initClient() {        String endpoint = aliyunOssProperties.getEndPoint();        String accessKeyId = aliyunOssProperties.getAccessKeyId();        String accessKeySecret = aliyunOssProperties.getAccessKeySecret();        // 创建OSSClient实例。        ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);    }    @Override    public void destroyClient() {        ossClient.shutdown();    }    @Override    public Object getClient() {        return ossClient;    }    @Override    public boolean doesBucketExist(String bucketName) {        try {            return ossClient.doesBucketExist(bucketName);        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        }    }    @Override    public void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum) {        try {            if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {                ossClient.setBucketAcl(bucketName, CannedAccessControlList.Private);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {                ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {                ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);            }        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        }    }    @Override    public boolean isExistingFile(String bucketName, String key) {        try {            return ossClient.doesObjectExist(bucketName, key);        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        }    }    @Override    public void storageFile(String bucketName, String key, byte[] bytes) {        try {            ossClient.putObject(bucketName, key, new ByteArrayInputStream(bytes));        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        }    }    @Override    public void storageFile(String bucketName, String key, InputStream inputStream, long fileSize) {        try {            String contentType = "application/octet-stream";            if (key.contains(".")) {                contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);            }            ObjectMetadata metadata = new ObjectMetadata();            metadata.setContentType(contentType);            metadata.setContentLength(fileSize);            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, inputStream, metadata);            ossClient.putObject(putObjectRequest);        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        }    }    @Override    public byte[] getFileBytes(String bucketName, String key) {        InputStream objectContent = null;        try {            OSSObject ossObject = ossClient.getObject(bucketName, key);            objectContent = ossObject.getObjectContent();            return IoUtil.readBytes(objectContent);        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        } finally {            IoUtil.close(objectContent);        }    }    @Override    public void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {        try {            if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {                ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.Private);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {                ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {                ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicReadWrite);            }        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        }    }    @Override    public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {        try {            ossClient.copyObject(originBucketName, originFileKey, newBucketName, newFileKey);        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        }    }    @Override    public String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {        try {            Date expiration = new Date(new Date().getTime() + timeoutMillis);            URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);            return url.toString();        } catch (OSSException e) {            throw new AliyunFileServiceException(e);        } catch (ClientException e) {            throw new AliyunFileServiceException(e);        }    }    @Override    public void deleteFile(String bucketName, String key) {        ossClient.deleteObject(bucketName, key);    }        @Override    public String initiateMultipartUpload(String bucketName, String key) {        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, key);        InitiateMultipartUploadResult result = ossClient.initiateMultipartUpload(request);        log.info("阿里云 初始化分片文件上传:{}", key);        return result.getUploadId();    }        @Override    public FileUploadPartResult uploadPart(FileUploadPart fileUploadPart) {        UploadPartRequest request = AliyunConvert.INSTANCE.convert(fileUploadPart);        UploadPartResult result = ossClient.uploadPart(request);        FileUploadPartResult convert = AliyunConvert.INSTANCE.convert(result);        convert.setPartSize(fileUploadPart.getPartSize());        log.info("阿里云 分片文件上传:{},结果:{}", fileUploadPart, request);        return convert;    }        @Override    public CompleteFileUploadPartResult completeMultipartUpload(CompleteFileUploadPart completeFileUploadPart) {        List<PartETag> tags = new ArrayList<>();        for (FileUploadPartResult partETag : completeFileUploadPart.getPartETags()) {            tags.add(new PartETag(partETag.getPartNumber(), partETag.getPartETag()));        }        CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(                completeFileUploadPart.getBucketName(),                completeFileUploadPart.getObjectName(),                completeFileUploadPart.getUploadId(),                tags        );        CompleteMultipartUploadResult result = ossClient.completeMultipartUpload(request);        log.info("京东云合并文件:{},结果:{}", completeFileUploadPart, result);        return AliyunConvert.INSTANCE.convert(result);    }        @Override    public void abortMultipartUpload(String bucketName, String objectName, String uploadId) {        AbortMultipartUploadRequest request = new AbortMultipartUploadRequest(bucketName, objectName, uploadId);        ossClient.abortMultipartUpload(request);    }}

京东云对象存储实现

package com.aimilin.common.base.file.modular.jdcloud;import cn.hutool.core.io.IoUtil;import com.amazonaws.SdkClientException;import com.amazonaws.services.s3.model.*;import com.aimilin.common.base.file.FileOperator;import com.aimilin.common.base.file.FilePartOperator;import com.aimilin.common.base.file.common.enums.BucketAuthEnum;import com.aimilin.common.base.file.common.enums.FileLocationEnum;import com.aimilin.common.base.file.modular.jdcloud.exp.JdCloudFileServiceException;import com.aimilin.common.base.file.modular.jdcloud.prop.JdCloudConvert;import com.aimilin.common.base.file.modular.jdcloud.prop.JdCloudOssProperties;import com.amazonaws.auth.AWSCredentialsProvider;import com.amazonaws.auth.AWSStaticCredentialsProvider;import com.amazonaws.client.builder.AwsClientBuilder;import com.amazonaws.services.s3.AmazonS3;import com.amazonaws.services.s3.AmazonS3Client;import com.amazonaws.auth.AWSCredentials;import com.amazonaws.auth.BasicAWSCredentials;import com.amazonaws.ClientConfiguration;import com.aimilin.common.base.file.param.*;import lombok.extern.slf4j.Slf4j;import javax.activation.MimetypesFileTypeMap;import java.io.ByteArrayInputStream;import java.io.InputStream;import java.net.URL;import java.util.ArrayList;import java.util.Date;import java.util.List;@Slf4jpublic class JdCloudFileOperator implements FilePartOperator {    @Override    public FileLocationEnum getFileLocation() {        return FileLocationEnum.JDCLOUD;    }        private AmazonS3 ossClient;        private final JdCloudOssProperties jdCloudOssProperties;        public JdCloudFileOperator(JdCloudOssProperties jdCloudOssProperties) {        this.jdCloudOssProperties = jdCloudOssProperties;        this.initClient();    }    @Override    public void initClient() {        ClientConfiguration config = new ClientConfiguration();        AwsClientBuilder.EndpointConfiguration endpointConfig =                new AwsClientBuilder.EndpointConfiguration(jdCloudOssProperties.getEndPoint(), jdCloudOssProperties.getSigningRegion());        AWSCredentials awsCredentials = new BasicAWSCredentials(jdCloudOssProperties.getAccessKeyID(),jdCloudOssProperties.getAccessKeySecret());        AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials);        ossClient = AmazonS3Client.builder()                .withEndpointConfiguration(endpointConfig)                .withClientConfiguration(config)                .withCredentials(awsCredentialsProvider)                .disableChunkedEncoding()                .build();    }    @Override    public void destroyClient() {        ossClient.shutdown();    }    @Override    public Object getClient() {        return ossClient;    }    @Override    public boolean doesBucketExist(String bucketName) {        return ossClient.doesBucketExistV2(bucketName);    }    @Override    public void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum) {        try {            if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {                ossClient.setBucketAcl(bucketName, CannedAccessControlList.Private);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {                ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {                ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);            }        } catch (Exception e) {            log.error("JdCloud-oss-设置预定义策略异常",e);            throw new JdCloudFileServiceException(e);        }    }    @Override    public boolean isExistingFile(String bucketName, String key) {        try {            return ossClient.doesObjectExist(bucketName, key);        } catch (Exception e) {            log.error("JdCloud-oss-判断是否存在文件异常",e);            throw new JdCloudFileServiceException(e);        }    }    @Override    public void storageFile(String bucketName, String key, byte[] bytes) {        try {            InputStream is = new ByteArrayInputStream(bytes);            ObjectMetadata metadata = new ObjectMetadata();            metadata.setContentType("text/plain");            metadata.setContentLength((long)bytes.length);            ossClient.putObject(bucketName, key, is, metadata);        } catch (Exception e) {            log.error("JdCloud-oss-存储文件异常",e);            throw new JdCloudFileServiceException(e);        }    }    @Override    public void storageFile(String bucketName, String key, InputStream inputStream, long fileSize) {        try {            String contentType = "application/octet-stream";            if (key.contains(".")) {                contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);            }            ObjectMetadata metadata = new ObjectMetadata();            metadata.setContentType(contentType);            metadata.setContentLength(fileSize);            ossClient.putObject(bucketName, key, inputStream, metadata);        } catch (Exception e) {            log.error("JdCloud-oss-存储文件异常",e);            throw new JdCloudFileServiceException(e);        }    }    @Override    public byte[] getFileBytes(String bucketName, String key) {        InputStream objectContent = null;        try {            S3Object s3Object = ossClient.getObject(bucketName, key);            objectContent = s3Object.getObjectContent();            return IoUtil.readBytes(objectContent);        } catch (Exception e) {            log.error("JdCloud-oss-获取某个bucket下的文件字节异常",e);            throw new JdCloudFileServiceException(e);        }finally {            IoUtil.close(objectContent);        }    }    @Override    public void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {        try {            if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {                ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.Private);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {                ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {                ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicReadWrite);            }        } catch (Exception e) {            log.error("JdCloud-oss-文件访问权限管理异常",e);            throw new JdCloudFileServiceException(e);        }    }    @Override    public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {        try {            ossClient.copyObject(originBucketName, originFileKey, newBucketName, newFileKey);        } catch (Exception e) {            log.error("JdCloud-oss-拷贝文件异常",e);            throw new JdCloudFileServiceException(e);        }    }    @Override    public String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {        try {            Date expiration = new Date(System.currentTimeMillis() + timeoutMillis);            URL url = ossClient.generatePresignedUrl(bucketName, key, expiration);            return url.toString();        } catch (Exception e) {            log.error("JdCloud-oss-获取文件的下载地址异常",e);            throw new JdCloudFileServiceException(e);        }    }    @Override    public void deleteFile(String bucketName, String key) {        try {            ossClient.deleteObject(bucketName, key);        } catch (Exception e) {            log.error("JdCloud-oss-删除文件异常", e);            throw new JdCloudFileServiceException(e);        }    }        @Override    public String initiateMultipartUpload(String bucketName, String key) {        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, key);        InitiateMultipartUploadResult initiateMultipartUploadResult = ossClient.initiateMultipartUpload(request);        log.info("京东云 初始化分片文件上传:{}", key);        return initiateMultipartUploadResult.getUploadId();    }        @Override    public FileUploadPartResult uploadPart(FileUploadPart fileUploadPart) {        UploadPartRequest request = JdCloudConvert.INSTANCE.convert(fileUploadPart);        UploadPartResult uploadPartResult = ossClient.uploadPart(request);        FileUploadPartResult result = JdCloudConvert.INSTANCE.convert(uploadPartResult.getPartETag());        result.setPartSize(fileUploadPart.getPartSize());        log.info("京东云 分片文件上传:{},结果:{}", fileUploadPart, request);        return result;    }        @Override    public CompleteFileUploadPartResult completeMultipartUpload(CompleteFileUploadPart completeFileUploadPart) {        CompleteMultipartUploadRequest request = JdCloudConvert.INSTANCE.convert(completeFileUploadPart);        CompleteMultipartUploadResult result = ossClient.completeMultipartUpload(request);        log.info("京东云合并文件:{},结果:{}", completeFileUploadPart, result);        return JdCloudConvert.INSTANCE.convert(result);    }        @Override    public void abortMultipartUpload(String bucketName, String objectName, String uploadId) {        ossClient.abortMultipartUpload(new AbortMultipartUploadRequest(bucketName, objectName, uploadId));    }}

腾讯云对象存储分片上传

package com.aimilin.common.base.file.modular.tencent;import cn.hutool.core.io.IoUtil;import com.aimilin.common.base.file.FilePartOperator;import com.aimilin.common.base.file.common.enums.FileLocationEnum;import com.aimilin.common.base.file.modular.aliyun.prop.AliyunConvert;import com.aimilin.common.base.file.modular.tencent.prop.TenConvert;import com.aimilin.common.base.file.param.CompleteFileUploadPart;import com.aimilin.common.base.file.param.CompleteFileUploadPartResult;import com.aimilin.common.base.file.param.FileUploadPart;import com.aimilin.common.base.file.param.FileUploadPartResult;import com.qcloud.cos.COSClient;import com.qcloud.cos.ClientConfig;import com.qcloud.cos.auth.BasicCOSCredentials;import com.qcloud.cos.auth.COSCredentials;import com.qcloud.cos.exception.CosClientException;import com.qcloud.cos.exception.CosServiceException;import com.qcloud.cos.Http.HttpMethodName;import com.qcloud.cos.model.*;import com.qcloud.cos.region.Region;import com.qcloud.cos.transfer.TransferManager;import com.qcloud.cos.transfer.TransferManagerConfiguration;import com.aimilin.common.base.file.FileOperator;import com.aimilin.common.base.file.common.enums.BucketAuthEnum;import com.aimilin.common.base.file.modular.tencent.exp.TencentFileServiceException;import com.aimilin.common.base.file.modular.tencent.prop.TenCosProperties;import lombok.extern.slf4j.Slf4j;import javax.activation.MimetypesFileTypeMap;import java.io.ByteArrayInputStream;import java.io.InputStream;import java.net.URL;import java.util.ArrayList;import java.util.Date;import java.util.List;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;@Slf4jpublic class TenFileOperator implements FilePartOperator {    @Override    public FileLocationEnum getFileLocation() {        return FileLocationEnum.TENCENT;    }    private final TenCosProperties tenCosProperties;    private COSClient cosClient;    private TransferManager transferManager;    public TenFileOperator(TenCosProperties tenCosProperties) {        this.tenCosProperties = tenCosProperties;        initClient();    }    @Override    public void initClient() {        // 1.初始化用户身份信息        String secretId = tenCosProperties.getSecretId();        String secreTKEy = tenCosProperties.getSecretKey();        COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);        // 2.设置 bucket 的区域, COS 地域的简称请参照 https://cloud.tencent.com/document/product/436/6224        Region region = new Region(tenCosProperties.getRegionId());        ClientConfig clientConfig = new ClientConfig(region);        // 3.生成 cos 客户端。        cosClient = new COSClient(cred, clientConfig);        // 4.线程池大小,建议在客户端与 COS 网络充足(例如使用腾讯云的 CVM,同地域上传 COS)的情况下,设置成16或32即可,可较充分的利用网络资源        // 对于使用公网传输且网络带宽质量不高的情况,建议减小该值,避免因网速过慢,造成请求超时。        ExecutorService threadPool = Executors.newFixedThreadPool(32);        // 5.传入一个 threadpool, 若不传入线程池,默认 TransferManager 中会生成一个单线程的线程池。        transferManager = new TransferManager(cosClient, threadPool);        // 6.设置高级接口的分块上传阈值和分块大小为10MB        TransferManagerConfiguration transferManagerConfiguration = new TransferManagerConfiguration();        transferManagerConfiguration.setMultipartUploadThreshold(10 * 1024 * 1024);        transferManagerConfiguration.setMinimumUploadPartSize(10 * 1024 * 1024);        transferManager.setConfiguration(transferManagerConfiguration);    }    @Override    public void destroyClient() {        cosClient.shutdown();    }    @Override    public Object getClient() {        return cosClient;    }    @Override    public boolean doesBucketExist(String bucketName) {        try {            return cosClient.doesBucketExist(bucketName);        } catch (CosServiceException e) {            throw new TencentFileServiceException(e);        } catch (CosClientException e) {            throw new TencentFileServiceException(e);        }    }    @Override    public void setBucketAcl(String bucketName, BucketAuthEnum bucketAuthEnum) {        try {            if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {                cosClient.setBucketAcl(bucketName, CannedAccessControlList.Private);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {                cosClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);            } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {                cosClient.setBucketAcl(bucketName, CannedAccessControlList.PublicReadWrite);            }        } catch (CosServiceException e) {            throw new TencentFileServiceException(e);        } catch (CosClientException e) {            throw new TencentFileServiceException(e);        }    }    @Override    public boolean isExistingFile(String bucketName, String key) {        try {            cosClient.getObjectMetadata(bucketName, key);            return true;        } catch (CosServiceException e) {            return false;        }    }    @Override    public void storageFile(String bucketName, String key, byte[] bytes) {        // 根据文件名获取contentType        String contentType = "application/octet-stream";        if (key.contains(".")) {            contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);        }        // 上传文件        ByteArrayInputStream byteArrayInputStream = null;        try {            byteArrayInputStream = new ByteArrayInputStream(bytes);            ObjectMetadata objectMetadata = new ObjectMetadata();            objectMetadata.setContentType(contentType);            cosClient.putObject(bucketName, key, new ByteArrayInputStream(bytes), objectMetadata);        } catch (CosServiceException e) {            throw new TencentFileServiceException(e);        } catch (CosClientException e) {            throw new TencentFileServiceException(e);        } finally {            IoUtil.close(byteArrayInputStream);        }    }    @Override    public void storageFile(String bucketName, String key, InputStream inputStream, long fileSize) {        // 根据文件名获取contentType        String contentType = "application/octet-stream";        if (key.contains(".")) {            contentType = MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(key);        }        // 上传文件        try {            ObjectMetadata objectMetadata = new ObjectMetadata();            objectMetadata.setContentType(contentType);            objectMetadata.setContentLength(fileSize);            cosClient.putObject(bucketName, key, inputStream, objectMetadata);        } catch (CosServiceException e) {            throw new TencentFileServiceException(e);        } catch (CosClientException e) {            throw new TencentFileServiceException(e);        } finally {            IoUtil.close(inputStream);        }    }    @Override    public byte[] getFileBytes(String bucketName, String key) {        COSObjectInputStream cosObjectInput = null;        try {            GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);            COSObject cosObject = cosClient.getObject(getObjectRequest);            cosObjectInput = cosObject.getObjectContent();            return IoUtil.readBytes(cosObjectInput);        } catch (CosServiceException e) {            throw new TencentFileServiceException(e);        } catch (CosClientException e) {            throw new TencentFileServiceException(e);        } finally {            IoUtil.close(cosObjectInput);        }    }    @Override    public void setFileAcl(String bucketName, String key, BucketAuthEnum bucketAuthEnum) {        if (bucketAuthEnum.equals(BucketAuthEnum.PRIVATE)) {            cosClient.setObjectAcl(bucketName, key, CannedAccessControlList.Private);        } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ)) {            cosClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);        } else if (bucketAuthEnum.equals(BucketAuthEnum.PUBLIC_READ_WRITE)) {            cosClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicReadWrite);        }    }    @Override    public void copyFile(String originBucketName, String originFileKey, String newBucketName, String newFileKey) {        // 初始化拷贝参数        Region srcBucketRegion = new Region(tenCosProperties.getRegionId());        CopyObjectRequest copyObjectRequest = new CopyObjectRequest(                srcBucketRegion, originBucketName, originFileKey, newBucketName, newFileKey);        // 拷贝对象        try {            transferManager.copy(copyObjectRequest, cosClient, null);        } catch (CosServiceException e) {            throw new TencentFileServiceException(e);        } catch (CosClientException e) {            throw new TencentFileServiceException(e);        }    }    @Override    public String getFileAuthUrl(String bucketName, String key, Long timeoutMillis) {        GeneratePresignedUrlRequest presignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);        Date expirationDate = new Date(System.currentTimeMillis() + timeoutMillis);        presignedUrlRequest.setExpiration(expirationDate);        URL url = null;        try {            url = cosClient.generatePresignedUrl(presignedUrlRequest);        } catch (CosServiceException e) {            throw new TencentFileServiceException(e);        } catch (CosClientException e) {            throw new TencentFileServiceException(e);        }        return url.toString();    }    @Override    public void deleteFile(String bucketName, String key) {        cosClient.deleteObject(bucketName, key);    }        @Override    public String initiateMultipartUpload(String bucketName, String key) {        InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, key);        InitiateMultipartUploadResult result = cosClient.initiateMultipartUpload(request);        log.info("腾讯云 初始化分片文件上传:{}", key);        return result.getUploadId();    }        @Override    public FileUploadPartResult uploadPart(FileUploadPart fileUploadPart) {        UploadPartRequest request = TenConvert.INSTANCE.convert(fileUploadPart);        UploadPartResult result = cosClient.uploadPart(request);        FileUploadPartResult convert = TenConvert.INSTANCE.convert(result);        convert.setPartSize(fileUploadPart.getPartSize());        log.info("腾讯云 分片文件上传:{},结果:{}", fileUploadPart, request);        return convert;    }        @Override    public CompleteFileUploadPartResult completeMultipartUpload(CompleteFileUploadPart completeFileUploadPart) {        List<PartETag> tags = new ArrayList<>();        for (FileUploadPartResult partETag : completeFileUploadPart.getPartETags()) {            tags.add(new PartETag(partETag.getPartNumber(), partETag.getPartETag()));        }        CompleteMultipartUploadRequest request = new CompleteMultipartUploadRequest(                completeFileUploadPart.getBucketName(),                completeFileUploadPart.getObjectName(),                completeFileUploadPart.getUploadId(),                tags);        CompleteMultipartUploadResult result = cosClient.completeMultipartUpload(request);        log.info("京东云合并文件:{},结果:{}", completeFileUploadPart, result);        return TenConvert.INSTANCE.convert(result);    }        @Override    public void abortMultipartUpload(String bucketName, String objectName, String uploadId) {        AbortMultipartUploadRequest request = new AbortMultipartUploadRequest(bucketName, objectName, uploadId);        cosClient.abortMultipartUpload(request);    }}

分片上传前端代码实现

<template>  <div class="upload__wrap" :class="`upload__wrap--${size}`">    <div class="files" v-for="img in existsImgs" :key="img.id">      <template v-if="pictureType.includes(handleType(img.fileSuffix))">        <!-- 图片类型 -->        <img  width="104" height="104" :src="handleImg(img.id, 208, 208)" />        <div class="btn__wraps">          <div class="btn__innerwraps">            <a-icon class="icon__btn" type="eye" @click="$refs.previewForm.preview({ id: img.id })" />            <a-popconfirm placement="topRight" title="确认删除?" @confirm="() => deleteImg(img.id)">              <a-icon class="icon__btn" type="delete" />            </a-popconfirm>          </div>        </div>      </template>      <template v-else-if="threedType.includes(handleType(img.fileSuffix))">        <img                    width="104"          height="104"          src="https://file.lsjlt.com/upload/202306/28/p5vm5e4cm5j.png"        />        <div class="btn__wraps">          <div class="btn__innerwraps">            <a-icon class="icon__btn" type="eye" @click="show3DModal(img)" />            <a-popconfirm placement="topRight" title="确认删除?" @confirm="() => deleteImg(img.id)">              <a-icon class="icon__btn" type="delete" />            </a-popconfirm>          </div>        </div>      </template>      <template v-else>        当前类型文件暂不支持预览      </template>    </div>    <div class="tempimg__placeholder" v-for="temp in tempImgArr" :key="temp.uid">上传中…</div>    <a-upload      name="upload"      :list-type="listType"      :file-list="fileList"      :accept="format"      :multiple="multiple"      :before-upload="beforeUpload"      :customRequest="customRequest"    >      <div v-if="existsImgs.length + tempImgArr.length < maxPicsLength">        <a-icon type="plus" />        <div class="ant-upload-text">          上传        </div>      </div>    </a-upload>    <preview-form ref="previewForm"></preview-form>    <preview3d-model :is3dModelShow="is3dModelShow" :carousel-lists="preview3dModel" title="3D模型预览" @closeModal="closeModal"></preview3d-model>    <!-- :carousel-lists="" -->  </div></template><script>  // import { sysFileInfoPage, sysFileInfoDelete, sysFileInfoPartUpload, sysFileInfoDownload } from '@/api/modular/system/fileManage'import { sysFileInfoPartUpload } from '@/api/modular/system/fileManage'import previewForm from '@/views/system/file/previewForm.Vue'import Preview3dModel from '@/views/system/file/preview3dmodel.vue'import { handleImg } from '@/utils/util'import sparkMD5 from 'spark-md5'import { SUCCESS, SERVICE_ERROR, UPLOADING } from '@/assets/js/responseCode'const SIZEUNIT = 1 * 1024 * 1024export default {  components: {    previewForm,    Preview3dModel  },  props: {    isCloseUpload: {      type: Boolean,      default: false    },    size: {      type: String,      default: 'default'    },    format: {      type: String,      default: 'image/gif, image/jpeg, image/png, image/jpg'    },    listType: {      type: String,      default: 'picture-card'    },    maxPicsLength: {      type: Number,      default: 9    },    uploadText: {      type: String,      default: '上传'    },    existsImgs: {      type: Array,      default () {        return []      }    },    maxSize: {      type: Number,      default: 20    },    multiple: {      type: Boolean,      default: false    }  },  data() {    return {      pictureType: ['.gif', '.jpeg', '.png', '.jpg'],      threedType: ['.json', '.obj', '.dae', '.ply', '.gltf', '.stl', '.fbx'],      previewVisible: false,      previewImage: '',      fileList: [],      // loading: false,      is3dModelShow: false,      preview3dModel: [],      tempImgArr: [],      isStopUpload: false    }  },  create() {    this.timer = null    console.log('this', this)  },  watch: {    isCloseUpload: {      handler (newval) {        if (newval) {          this.$set(this, 'tempImgArr', [])          this.$emit('imgUploadingStatus', 0)        }      },      immediate: true    }  },  methods: {    handleImg,    show3dModal (obj) {      this.preview3dModel = [obj]      this.is3dModelShow = true    },    closeModal () {      this.is3dModelShow = false    },    handleType (filetType) {      return filetType.indexOf('.') > -1 ? filetType : '.' + filetType    },    beforeUpload(file, fileList) {      console.log('this', this)      return new Promise((resolve, reject) => {        let type = file.type        if (!type) {          type = '.' + file.name.split('.').pop()        }        const isFormatFiles = this.format.replace(/\s*/g, '').split(',').includes(type)        if (!isFormatFiles) {          this.$message.error(`只支持以下${this.format}格式!`)          return reject(new Error(`只支持以下${this.format}格式!`))        }        const maxSizeLimit = this.threedType.includes(type) ? 100 : 20        const isLtMaxSize = file.size / SIZEUNIT < maxSizeLimit        if (!isLtMaxSize) {          this.$message.error(`图片须小于${maxSizeLimit}MB!`)          return reject(new Error(`图片须小于${maxSizeLimit}MB!`))        }        // 是否上传图片超过最大限度        if (this.existsImgs.length + this.tempImgArr.length >= this.maxPicsLength) {          if (this.timer) {            clearTimeout(this.timer)          }          this.timer = setTimeout(() => {            this.$message.error(`最多只能上传${this.maxPicsLength}张!`)          }, 300)          return reject(new Error(`最多只能上传${this.maxPicsLength}张!`))        }        this.isStopUpload = false        // this.loading = true        this.$set(this, 'tempImgArr', [...this.tempImgArr, file.uid])        this.$emit('imgUploadingStatus', [...this.tempImgArr, file.uid].length)        this.$emit('resetUploadStatus')        resolve(true)      })      // return isFormatFiles && isLt2M    },    preview (id) {      this.$refs.previewForm.preview({ id })    },    deleteImg (id) {      this.$emit('deletePic', id)    },        customRequest (data) {        const fileType = '.' + data.file.name.split('.').pop()        const fileReader = new FileReader()        const blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice        let currentChunk = 0        const chunkSize = 4 * 1024 * 1024        const chunks = Math.ceil(data.file.size / chunkSize)        const spark = new SparkMD5.ArrayBuffer()        const partChunksArr = []        const fileData = {}        loadNext()        fileReader.onload = e => {          spark.append(e.target.result)          const sparkChunk = new SparkMD5.ArrayBuffer()          sparkChunk.append(e.target.result)          const partMd5 = sparkChunk.end()          partChunksArr.push({            file: fileData[currentChunk],            partNumber: currentChunk + 1,            partMd5,            partSize: chunkSize,            totalSize: data.file.size          })          currentChunk++          if (currentChunk < chunks) {            loadNext()          } else {            const md5 = spark.end()            this.finalUploadFn(partChunksArr, fileType, data, md5)          }        }        fileReader.onerror = function () {          this.$message.error(`文件${data.file.name}读取出错,请检查该文件`)          // data.cancel()        }        function loadNext() {          const start = currentChunk * chunkSize          const end = ((start + chunkSize) >= data.file.size) ? data.file.size : start + chunkSize          const currentChunkData = blobSlice.call(data.file, start, end)          fileReader.readAsArrayBuffer(currentChunkData)          fileData[currentChunk] = currentChunkData        }    },    finalUploadFn (formData, fileType, data, wholeFileMd5) {      formData.forEach(item => {        const newFormData = new FormData()        // newFormData.set('file', data.file)        newFormData.set('uid', data.file.uid)        newFormData.set('filename', data.file.name)        Object.keys(item).forEach(key => {          newFormData.set(            key, item[key]          )          newFormData.set('fileMd5', wholeFileMd5)        })        if (this.isStopUpload) {          return        }        sysFileInfoPartUpload(newFormData).then((res) => {        // this.loading = false        if (res.code === SUCCESS && res.data?.fileState === SUCCESS) {          this.$emit('getNewPics', {            id: res.data.fileId,            fileSuffix: fileType          })          const newTempImgArr = this.tempImgArr.filter(item => item !== res.data?.uid)          this.$set(this, 'tempImgArr', newTempImgArr)          this.$emit('imgUploadingStatus', newTempImgArr.length)          // this.$refs.table.refresh()        } else if (res.code === SUCCESS && res.data?.fileState === UPLOADING) {        } else if (res.code === SUCCESS && res.data?.fileState === SERVICE_ERROR) {          if (!this.failupload) {            this.failupload = {}            this.failupload[data.file.uid] = data.file.uid            sysFileInfoPartUpload(newFormData)          } else {            if (!this.failupload[data.file.uid]) {                sysFileInfoPartUpload(newFormData)                this.failupload[data.file.uid] = data.file.uid            }          }        } else if (res.code !== SUCCESS) {          // 上传失败,从占位图中移除一个          const newTempImgArr = this.tempImgArr          newTempImgArr.pop()          this.$set(this, 'tempImgArr', newTempImgArr)          this.$emit('imgUploadingStatus', newTempImgArr.length)          if (this.timer) {            clearTimeout(this.timer)          }          this.timer = setTimeout(() => {            this.$message.error('上传失败!' + res.message)          }, 300)        }      }).catch(e => {        const newTempImgArr = this.tempImgArr        newTempImgArr.pop()        this.$set(this, 'tempImgArr', newTempImgArr)        this.$emit('imgUploadingStatus', newTempImgArr.length)        console.log('error', e)        // this.loading = false        // this.tempImgArr.length && this.$message.error('上传失败,请重新上传')      }).finally((p) => {        console.log('sysFileInfoPartUpload', p)        // this.loading = false      })      })    },    clearTimer() {      clearTimeout(this.timer)      this.$set(this, 'tempImgArr', [])      this.$emit('imgUploadingStatus', 0)      this.isStopUpload = true    }  },  beforeDestoryed() {    this.clearTimer()  }}</script><style>.ant-upload-select-picture-card i {  font-size: 32px;  color: #999;}.ant-upload-select-picture-card .ant-upload-text {  margin-top: 8px;  color: #666;}</style><style lang="less" scoped>.upload__wrap{  display: -webkit-inline-box;  display: -moz-inline-box;  display: inline-box;  flex-wrap: wrap;  .files{      position: relative;      width:104px;      height: 104px;      margin-right: 10px;      margin-bottom: 10px;    .btn__wraps{      position: absolute;      left: 0;      top: 0;      width: 100%;      height: 100%;      background: rgba(0,0,0,0);      display: flex;      align-items: center;      justify-content: center;      transition: all 0.3s linear;      z-index: -1;      .btn__innerwraps{        display: flex;        .icon__btn{          margin-right: 10px;          font-size: 16px;          color: rgba(255,255,255, 0);          cursor: pointer;          &:last-child{            margin-right: 0;          }        }      }    }    &:hover{      .btn__wraps{        background: rgba(0,0,0,0.5);        transition: all 0.3s linear;        z-index: 1;        .btn__innerwraps{          .icon__btn{            color: rgba(255,255,255, 0.8);          }        }      }    }  }  .tempimg__placeholder{    width: 104px;    height: 104px;    display: flex;    justify-content: center;    align-items: center;    border: 1px solid #d9d9d9;    margin-right: 10px;    margin-bottom: 10px;  }}</style>

到此,关于“Java怎么将大文件分片上传”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: Java怎么将大文件分片上传

本文链接: https://www.lsjlt.com/news/338728.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java怎么将大文件分片上传
    这篇文章主要介绍“Java怎么将大文件分片上传”,在日常操作中,相信很多人在Java怎么将大文件分片上传问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java怎么将大文件分片上传”的疑惑有所帮助!接下来,请跟...
    99+
    2023-07-02
  • Java超详细大文件分片上传代码
    目录Java 大文件分片上传首先是交互的控制器上传文件分片参数接收大文件分片上传服务类实现文件分片上传定义公共服务类接口文件分片上传文件操作接口实现类OSS阿里云对象存储分片上传实现...
    99+
    2024-04-02
  • Java实现文件分片上传
    起因:最近在工作中接到了一个大文件上传下载的需求,要求将文件上传到share盘中,下载的时候根据前端传的不同条件对单个或多个文件进行打包并设置目录下载。 一开始我想着就还是用老办法直接file.transferTo(newFile)就算是大...
    99+
    2023-08-18
    Java 分片上传 文件
  • Java实现浏览器端大文件分片上传
    目录背景介绍 项目介绍 需要知识点 启动项目 项目示范 核心讲解核心原理 功能分析分块上传 秒传功能 断点续传 总结 参考文献 背景介绍   Breakpo...
    99+
    2024-04-02
  • JavaScript怎么实现大文件分片上传处理
    这篇文章主要介绍“JavaScript怎么实现大文件分片上传处理”,在日常操作中,相信很多人在JavaScript怎么实现大文件分片上传处理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JavaScript怎...
    99+
    2023-06-20
  • vue 大文件分片上传(断点续传、并发上传、秒传)
    对于大文件的处理,无论是用户端还是服务端,如果一次性进行读取发送、接收都是不可取,很容易导致内存问题。所以对于大文件上传,采用切块分段上传,从上传的效率来看,利用多线程并发上传能够达...
    99+
    2024-04-02
  • 【java】java实现大文件的分片上传与下载(springboot+vue3)
    文章目录 1.1 项目背景1.2 项目目标2.1 业务流程2.2 系统用例2.3 系统总体功能3.1 技术选型4.1 文件上传模块4.2 文件下载模块4.3 数据库设计5.1 大文件上传实现5.2 大文件下载实现 源码: htt...
    99+
    2023-08-16
    java spring boot spring vue
  • JavaScript实现大文件分片上传处理
    很多时候我们在处理文件上传时,如视频文件,小则几十M,大则 1G+,以一般的HTTP请求发送数据的方式的话,会遇到的问题: 1、文件过大,超出服务端的请求大小限制; 2、请求时间过长...
    99+
    2024-04-02
  • vue怎么实现大文件分片上传与断点续传送
    本文小编为大家详细介绍“vue怎么实现大文件分片上传与断点续传送”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue怎么实现大文件分片上传与断点续传送”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。问题:前段时间...
    99+
    2023-07-02
  • springboot大文件上传、分片上传、断点续传、秒传的实现
    对于大文件的处理,无论是用户端还是服务端,如果一次性进行读取发送、接收都是不可取,很容易导致内存问题。所以对于大文件上传,采用切块分段上传,从上传的效率来看,利用多线程并发上传能够达...
    99+
    2024-04-02
  • Java如何实现浏览器端大文件分片上传
    小编给大家分享一下Java如何实现浏览器端大文件分片上传,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!背景介绍  Breakpoint-http,是不是觉得这个名...
    99+
    2023-06-20
  • 怎么使用php解决大文件分片上传问题
    小编给大家分享一下怎么使用php解决大文件分片上传问题,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!前提首先, 上传超大的文件, 前端要和后端相互配合文件上传要使...
    99+
    2023-06-20
  • el-upload大文件切片上传怎么实现
    这篇文章主要介绍“el-upload大文件切片上传怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“el-upload大文件切片上传怎么实现”文章能帮助大家解决问题。html<el-upl...
    99+
    2023-07-05
  • 如何使用大文件上传:秒传、断点续传、分片上传方法
    本篇内容介绍了“如何使用大文件上传:秒传、断点续传、分片上传方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!秒传1、什么是秒传通俗的说,你...
    99+
    2023-06-15
  • 前端使用koa实现大文件分片上传
    目录引言前端拆分上传的文件流后端接收文件片段合并文件片段总结引言 一个文件资源服务器,很多时候需要保存的不只是图片,文本之类的体积相对较小的文件,有时候,也会需要保存音视频之类的大文...
    99+
    2024-04-02
  • Go实现文件分片上传
    Go语言在写HTTP服务程序时,会经常用到文件上传和文件下载,文件上传和文件下载都可以用http包,默认的功能基本上够用了。http包支持文件下载的断点续传和进度显示,文件上传貌似不...
    99+
    2024-04-02
  • 前端大文件上传与下载(分片上传)的详细过程
    目录一、问题二、解决1.第一步选择文件2.校验文件是否符合规范3.文件切片上传4.分片上传注意点5.大文件下载总结一、问题 日常业务中难免出现前端需要向后端传输大型文件的情况,这时单...
    99+
    2022-11-13
    前端文件上传和下载 前端上传文件 前端大文件上传
  • Java实现图片文件上传
    Java实现后台图片上传,将上传图片的接口进行分层,便于维护接口。 接口部分(interface) 将接口分为单图片上传以及多图片上传 public interface FileUp...
    99+
    2024-04-02
  • 利用Vue3+Element-plus实现大文件分片上传组件
    目录一、背景二、技术栈三、核心代码实现四、总结一、背景 实际项目中遇到需要上传几十个G的3d模型文件,传统上传就不适用了。 结合element提供的上传组件自己封装了文件分片上传的组...
    99+
    2023-01-28
    elementui分片上传 vue element ui教程 element ui 上传文件组件
  • java怎么限制上传图片大小
    在Java中,可以通过以下步骤限制上传图片的大小: 获取上传图片的文件大小。可以使用`file.length()`方法获取文件的...
    99+
    2023-10-24
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作