SpringBoot集成minio分片上传合并(前端直传minio)

打印 上一主题 下一主题

主题 1940|帖子 1940|积分 5820

 数据库效果图:
 

代码部门:本身搭建minio测试  Result和配置文件可以本身编写 不必要和我一样

  1. my.storage.minio.protocol                   = http
  2. my.storage.minio.endPoint                   = 192.168.3.115:9000
  3. my.storage.minio.stsEndPoint                = 192.168.3.115:9000
  4. my.storage.minio.accessKey                  = ZCEqAP5ECpdyt4pg9VIx
  5. my.storage.minio.secretKey                  = dAlXmXdHWjYOZb8IWBowJGnGZzeKL9OC3TmYR8uO
  6. my.storage.minio.internetProtocol           = http
  7. my.storage.minio.internetEndPoint           = 192.168.3.115:9000
  8. my.storage.minio.intranetProtocol           = http
  9. my.storage.minio.intranetEndPoint           = 192.168.3.115:9000
复制代码

  1.     public Result checkFileByMd5(FileCheckAndMergeForm fileCheckAndMergeForm) {
  2.         String md5 = fileCheckAndMergeForm.getMd5();
  3.         String bucket = fileCheckAndMergeForm.getBucket();
  4.         FileUploadInfo fileUploadInfo = (FileUploadInfo)redisUtil.get(md5);
  5.         if (fileUploadInfo != null) {
  6.             List<Integer> listParts = minioUtil.getListParts(fileUploadInfo.getObject(), fileUploadInfo.getUploadId(),bucket);
  7.             fileUploadInfo.setListParts(listParts);
  8.             return Result.ok("上传中")
  9.                     .build("fileUploadInfo", fileUploadInfo);
  10.         }
  11.         ShardFilesUpload shardFilesUpload = shardFilesUploadMapper.selectShardFilesUploadByMd5(md5,bucket);
  12.         if (shardFilesUpload != null) {
  13.             FileUploadInfo dbFileInfo = BeanUtil.copyFrom(shardFilesUpload, FileUploadInfo.class);
  14.             return Result.ok("上传成功")
  15.                     .build("fileUploadInfo", dbFileInfo);
  16.         }
  17.         return Result.ok("未上传");
  18.     }
  19.     @SneakyThrows
  20.     public Result initMultipartUpload(FileUploadInfo fileUploadInfo) {
  21.         FileUploadInfo redisFileUploadInfo = (FileUploadInfo)redisUtil.get(fileUploadInfo.getMd5());
  22.         String bucket = fileUploadInfo.getBucket();
  23.         // 若 redis 中有该 md5 的记录,以 redis 中为主
  24.         String object;
  25.         if (redisFileUploadInfo != null) {
  26.             fileUploadInfo = redisFileUploadInfo;
  27.             object = redisFileUploadInfo.getObject();
  28.         } else {
  29.             String originFileName = fileUploadInfo.getOriginFileName();
  30.             String suffix = FileUtil.extName(originFileName);
  31.             String fileName = FileUtil.mainName(originFileName);
  32.             // 对文件重命名,并以年月日文件夹格式存储
  33.             String nestFile = DateUtil.format(LocalDateTime.now(), "yyyy/MM/dd");
  34.             object = nestFile + "/" + fileName + "_" + fileUploadInfo.getMd5() + "." + suffix;
  35.             fileUploadInfo.setObject(object).setType(suffix);
  36.         }
  37.         UploadUrlsVO urlsVO;
  38.         // 单文件上传
  39.         if (fileUploadInfo.getChunkCount() == 1) {
  40.             urlsVO = minioUtil.getUploadObjectUrl(fileUploadInfo.getContentType(), object,bucket);
  41.         } else {
  42.             // 分片上传
  43.             urlsVO = minioUtil.initMultiPartUpload(fileUploadInfo, object,bucket);
  44.         }
  45.         fileUploadInfo.setUploadId(urlsVO.getUploadId());
  46.         // 存入 redis
  47.         redisUtil.set(fileUploadInfo.getMd5(), fileUploadInfo, 1, TimeUnit.DAYS);
  48.         return Result.ok()
  49.                 .build("urlsVO", urlsVO);
  50.     }
  51.     public Result mergeMultipartUpload(FileCheckAndMergeForm fileCheckAndMergeForm){
  52.         String md5 = fileCheckAndMergeForm.getMd5();
  53.         String bucket = fileCheckAndMergeForm.getBucket();
  54.         FileUploadInfo redisFileUploadInfo = (FileUploadInfo)redisUtil.get(md5);
  55.         if (redisFileUploadInfo==null){
  56.             return Result.error("文件处理失败");
  57.         }
  58.         MyProperties.Minio minio = myProperties.getStorage().getMinio();
  59.         String url = String.format("%s://%s/%s/%s", minio.getProtocol(), minio.getEndPoint(), bucket, redisFileUploadInfo.getObject());
  60.           //获取真实的请求IP  如果是互联网地址,则将minio 地址替换
  61.         if (getRequest() != null) {
  62.             String ipAddr = IpUtil.getIpAddr(getRequest());
  63.             if (IpUtil.isExternalIP(ipAddr)) {
  64.                 url = url.replaceFirst(minio.getProtocol(), minio.getInternetProtocol());
  65.                 url = url.replaceFirst(minio.getEndPoint(), minio.getInternetEndPoint());
  66.             } else {
  67.                 url = url.replaceFirst(minio.getProtocol(), minio.getIntranetProtocol());
  68.                 url = url.replaceFirst(minio.getEndPoint(), minio.getIntranetEndPoint());
  69.             }
  70.         }
  71.         // 更新数据库
  72.         ShardFilesUpload shardFilesUpload = BeanUtil.copyFrom(redisFileUploadInfo, ShardFilesUpload.class);
  73.         shardFilesUpload.setId(UUID.randomUUID().toString());
  74.         shardFilesUpload.setUrl(url);
  75.         shardFilesUpload.setIsDelete(0);
  76.         shardFilesUpload.setBucket(bucket);
  77.         shardFilesUpload.setCreateTime(System.currentTimeMillis());
  78.         Integer chunkCount = redisFileUploadInfo.getChunkCount();
  79.         // 分片为 1 ,不需要合并,否则合并后看返回的是 true 还是 false
  80.         boolean isSuccess = chunkCount == 1 || minioUtil.mergeMultipartUpload(redisFileUploadInfo.getObject(), redisFileUploadInfo.getUploadId(),bucket);
  81.         if (isSuccess) {
  82.             shardFilesUploadMapper.insert(shardFilesUpload);
  83.             redisUtil.del(md5);
  84.             return Result.ok()
  85.                     .build("storage", "minio")
  86.                     .build("url", url);
  87.         }
  88.         return Result.error("文件处理失败");
  89.     }
复制代码
  1.     /**
  2.      * 检查文件是否存在
  3.      */
  4.     @RequestMapping (value = "/multipart/check", method = RequestMethod.POST)
  5.     public Result checkFileByMd5(@RequestBody @Valid FileCheckAndMergeForm fileCheckAndMergeForm) {
  6.         return sdkService.checkFileByMd5(fileCheckAndMergeForm);
  7.     }
  8.     /**
  9.      * 初始化文件分片地址及相关数据
  10.      */
  11.     @RequestMapping (value = "/multipart/init", method = RequestMethod.POST)
  12.     public Result initMultiPartUpload(@RequestBody @Valid FileUploadInfo fileUploadInfo) {
  13.         return sdkService.initMultipartUpload(fileUploadInfo);
  14.     }
  15.     /**
  16.      * 文件合并(单文件不会合并,仅信息入库)
  17.      */
  18.     @RequestMapping (value = "/multipart/merge", method = RequestMethod.POST)
  19.     public Result mergeMultipartUpload(@RequestBody @Valid FileCheckAndMergeForm fileCheckAndMergeForm) {
  20.         return sdkService.mergeMultipartUpload(fileCheckAndMergeForm);
  21.     }
复制代码
  1.   Result checkFileByMd5(FileCheckAndMergeForm fileCheckAndMergeForm) ;
  2.     Result initMultipartUpload(FileUploadInfo fileUploadInfo) ;
  3.     Result mergeMultipartUpload(FileCheckAndMergeForm fileCheckAndMergeForm);
复制代码
 数据库是postgresSQL
  1. DROP TABLE IF EXISTS religious.shard_files_upload;
  2. CREATE TABLE religious.shard_files_upload
  3. (
  4.     id               VARCHAR(255) NOT NULL,
  5.     upload_id        VARCHAR(255),
  6.     md5              VARCHAR(255),
  7.     url              VARCHAR(255),
  8.     bucket           VARCHAR(64),
  9.     object           VARCHAR(255),
  10.     origin_file_name VARCHAR(255),
  11.     size             BIGINT,
  12.     type             VARCHAR(64),
  13.     chunk_size       BIGINT,
  14.     chunk_count      INTEGER,
  15.     is_delete        INTEGER,
  16.     create_time      BIGINT,
  17.     PRIMARY KEY (id)
  18. );
  19. COMMENT ON TABLE religious.shard_files_upload IS '分片上传记录明细表';
  20. COMMENT ON COLUMN religious.shard_files_upload.upload_id IS '文件上传id';
  21. COMMENT ON COLUMN religious.shard_files_upload.md5 IS '文件计算md5';
  22. COMMENT ON COLUMN religious.shard_files_upload.url IS '文件访问地址';
  23. COMMENT ON COLUMN religious.shard_files_upload.bucket IS '存储桶';
  24. COMMENT ON COLUMN religious.shard_files_upload.object IS 'minio中文件名';
  25. COMMENT ON COLUMN religious.shard_files_upload.origin_file_name IS '原始文件名';
  26. COMMENT ON COLUMN religious.shard_files_upload.size IS '文件大小';
  27. COMMENT ON COLUMN religious.shard_files_upload.type IS '文件类型';
  28. COMMENT ON COLUMN religious.shard_files_upload.chunk_size IS '分片大小';
  29. COMMENT ON COLUMN religious.shard_files_upload.chunk_count IS '分片数量';
  30. COMMENT ON COLUMN religious.shard_files_upload.is_delete IS '是否删除';
  31. COMMENT ON COLUMN religious.shard_files_upload.create_time IS '创建时间';
复制代码
  1. package net.junnan.religious.base.api.config;
  2. import com.google.common.collect.Multimap;
  3. import io.minio.CreateMultipartUploadResponse;
  4. import io.minio.ListPartsResponse;
  5. import io.minio.MinioAsyncClient;
  6. import io.minio.ObjectWriteResponse;
  7. import io.minio.messages.Part;
  8. public class CustomMinioClient extends MinioAsyncClient {
  9.     /**
  10.      * 继承父类
  11.      * @param client
  12.      */
  13.     public CustomMinioClient(MinioAsyncClient client) {
  14.         super(client);
  15.     }
  16.     /**
  17.      * 初始化分片上传、获取 uploadId
  18.      * @param bucket String  存储桶名称
  19.      * @param region String
  20.      * @param object String   文件名称
  21.      * @param headers Multimap<String, String> 请求头
  22.      * @param extraQueryParams Multimap<String, String>
  23.      * @return String
  24.      */
  25.     public String initMultiPartUpload(String bucket, String region, String object, Multimap<String, String> headers, Multimap<String, String> extraQueryParams) throws Exception {
  26.         CreateMultipartUploadResponse response = super.createMultipartUploadAsync(bucket, region, object, headers, extraQueryParams).get();
  27.         return response.result().uploadId();
  28.     }
  29.     /**
  30.      * 合并分片
  31.      * @param bucketName String   桶名称
  32.      * @param region String
  33.      * @param objectName String   文件名称
  34.      * @param uploadId String   上传的 uploadId
  35.      * @param parts Part[]   分片集合
  36.      * @param extraHeaders Multimap<String, String>
  37.      * @param extraQueryParams Multimap<String, String>
  38.      * @return ObjectWriteResponse
  39.      */
  40.     public ObjectWriteResponse mergeMultipartUpload(String bucketName, String region, String objectName, String uploadId, Part[] parts, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws Exception {
  41.         return super.completeMultipartUploadAsync(bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams).get();
  42.     }
  43.     /**
  44.      * 查询当前上传后的分片信息
  45.      * @param bucketName String   桶名称
  46.      * @param region String
  47.      * @param objectName String   文件名称
  48.      * @param maxParts Integer  分片数量
  49.      * @param partNumberMarker Integer  分片起始值
  50.      * @param uploadId String   上传的 uploadId
  51.      * @param extraHeaders Multimap<String, String>
  52.      * @param extraQueryParams Multimap<String, String>
  53.      * @return ListPartsResponse
  54.      */
  55.     public ListPartsResponse listMultipart(String bucketName, String region, String objectName, Integer maxParts, Integer partNumberMarker, String uploadId, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws Exception {
  56.         return super.listPartsAsync(bucketName, region, objectName, maxParts, partNumberMarker, uploadId, extraHeaders, extraQueryParams).get();
  57.     }
  58. }
复制代码
  1. package net.junnan.religious.base.api.form.common.Sdk;
  2. import lombok.Data;
  3. import javax.validation.constraints.NotBlank;
  4. /**
  5. * @title: FileCheckAndMergeForm
  6. * @Author CaoJun
  7. * @Date: 2025/5/7 上午11:27
  8. * @Version 1.0
  9. */
  10. @Data
  11. public class FileCheckAndMergeForm {
  12.     @NotBlank(message = "bucket 不可为空")
  13.     private String bucket;
  14.     @NotBlank(message = "文件的MD5值不可为空")
  15.     private String md5;
  16. }
复制代码
  1. package net.junnan.religious.base.api.form.religious.ShardFilesUpload;
  2. import lombok.Data;
  3. import lombok.experimental.Accessors;
  4. import javax.validation.constraints.NotBlank;
  5. import javax.validation.constraints.NotNull;
  6. import java.util.List;
  7. /**
  8. * 文件上传信息,查询 redis 后的返回信息
  9. */
  10. @Data
  11. @Accessors(chain = true)
  12. public class FileUploadInfo {
  13.     @NotBlank(message = "md5 不能为空")
  14.     private String md5;
  15.     private String uploadId;
  16.     @NotBlank(message = "文件名不能为空")
  17.     private String originFileName;
  18.     // 仅秒传会有值
  19.     private String url;
  20.     // 后端使用
  21.     private String object;
  22.     private String type;
  23.     @NotNull(message = "文件大小不能为空")
  24.     private Long size;
  25.     @NotNull(message = "分片数量不能为空")
  26.     private Integer chunkCount;
  27.     @NotNull(message = "分片大小不能为空")
  28.     private Long chunkSize;
  29.     private String contentType;
  30.     // listParts 从 1 开始,前端需要上传的分片索引+1
  31.     private List<Integer> listParts;
  32.     @NotBlank(message = "bucket 不可为空")
  33.     private String bucket;
  34. }
复制代码
  1. package net.junnan.religious.base.api.util;
  2. import cn.hutool.core.util.IdUtil;
  3. import com.google.common.collect.HashMultimap;
  4. import io.minio.*;
  5. import io.minio.http.Method;
  6. import io.minio.messages.Part;
  7. import lombok.SneakyThrows;
  8. import lombok.extern.slf4j.Slf4j;
  9. import net.junnan.religious.base.api.config.CustomMinioClient;
  10. import net.junnan.religious.base.api.form.religious.ShardFilesUpload.FileUploadInfo;
  11. import net.junnan.religious.base.api.form.religious.ShardFilesUpload.UploadUrlsVO;
  12. import net.junnan.religious.base.api.properties.MyProperties;
  13. import org.springframework.stereotype.Component;
  14. import javax.annotation.PostConstruct;
  15. import javax.annotation.Resource;
  16. import javax.validation.constraints.NotNull;
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.concurrent.TimeUnit;
  22. import java.util.stream.Collectors;
  23. @Slf4j
  24. @Component
  25. public class MinioUtil {
  26.     private CustomMinioClient customMinioClient;
  27.     @Resource
  28.     MyProperties myProperties;
  29.     // spring自动注入会失败
  30.     @PostConstruct
  31.     public void init() {
  32.         MyProperties.Minio minio = myProperties.getStorage().getMinio();
  33.         MinioAsyncClient minioClient = MinioAsyncClient.builder()
  34.                 .endpoint(String.format("%s://%s", minio.getProtocol(), minio.getEndPoint()))
  35.                 .credentials(minio.getAccessKey(), minio.getSecretKey())
  36.                 .build();
  37.         customMinioClient = new CustomMinioClient(minioClient);
  38.     }
  39.     /**
  40.      * 获取 Minio 中已经上传的分片文件
  41.      * @param object 文件名称
  42.      * @param uploadId 上传的文件id(由 minio 生成)
  43.      * @return List<Integer>
  44.      */
  45.     @SneakyThrows
  46.     public List<Integer> getListParts(String object, String uploadId,String bucketName) {
  47.         List<Part> parts = getParts(object, uploadId,bucketName);
  48.         return parts.stream()
  49.                 .map(Part::partNumber)
  50.                 .collect(Collectors.toList());
  51.     }
  52.     /**
  53.      * 单文件签名上传
  54.      * @param object 文件名称(uuid 格式)
  55.      * @return UploadUrlsVO
  56.      */
  57.     public UploadUrlsVO getUploadObjectUrl(String contentType, String object,String bucketName) throws Exception {
  58.         try {
  59.             UploadUrlsVO urlsVO = new UploadUrlsVO();
  60.             List<String> urlList = new ArrayList<>();
  61.             // 主要是针对图片,若需要通过浏览器直接查看,而不是下载,需要指定对应的 content-type
  62.             HashMultimap<String, String> headers = HashMultimap.create();
  63.             if (contentType == null || contentType.equals("")) {
  64.                 contentType = "application/octet-stream";
  65.             }
  66.             headers.put("Content-Type", contentType);
  67.             String uploadId = IdUtil.simpleUUID();
  68.             Map<String, String> reqParams = new HashMap<>();
  69.             reqParams.put("uploadId", uploadId);
  70.             String url = customMinioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
  71.                     .method(Method.PUT)
  72.                     .bucket(bucketName)
  73.                     .object(object)
  74.                     .extraHeaders(headers)
  75.                     .extraQueryParams(reqParams)
  76.                     .expiry(1, TimeUnit.DAYS)
  77.                     .build());
  78.             urlList.add(url);
  79.             urlsVO.setUploadId(uploadId).setUrls(urlList);
  80.             return urlsVO;
  81.         } catch (Exception e) {
  82.             throw new Exception(e);
  83.         }
  84.     }
  85.     /**
  86.      * 初始化分片上传
  87.      * @param fileUploadInfo 前端传入的文件信息
  88.      * @param object object
  89.      * @return UploadUrlsVO
  90.      */
  91.     public UploadUrlsVO initMultiPartUpload(FileUploadInfo fileUploadInfo, String object,String bucketName) throws Exception {
  92.         Integer chunkCount = fileUploadInfo.getChunkCount();
  93.         String contentType = fileUploadInfo.getContentType();
  94.         String uploadId = fileUploadInfo.getUploadId();
  95.         UploadUrlsVO urlsVO = new UploadUrlsVO();
  96.         try {
  97.             HashMultimap<String, String> headers = HashMultimap.create();
  98.             if (contentType == null || contentType.equals("")) {
  99.                 contentType = "application/octet-stream";
  100.             }
  101.             headers.put("Content-Type", contentType);
  102.             // 如果初始化时有 uploadId,说明是断点续传,不能重新生成 uploadId
  103.             if (fileUploadInfo.getUploadId() == null || fileUploadInfo.getUploadId().equals("")) {
  104.                 uploadId = customMinioClient.initMultiPartUpload(bucketName, null, object, headers, null);
  105.             }
  106.             urlsVO.setUploadId(uploadId);
  107.             List<String> partList = new ArrayList<>();
  108.             Map<String, String> reqParams = new HashMap<>();
  109.             reqParams.put("uploadId", uploadId);
  110.             for (int i = 1; i <= chunkCount; i++) {
  111.                 reqParams.put("partNumber", String.valueOf(i));
  112.                 String uploadUrl = customMinioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
  113.                         .method(Method.PUT)
  114.                         .bucket(bucketName)
  115.                         .object(object)
  116.                         .expiry(1, TimeUnit.DAYS)
  117.                         .extraQueryParams(reqParams)
  118.                         .build());
  119.                 partList.add(uploadUrl);
  120.             }
  121.             urlsVO.setUrls(partList);
  122.             return urlsVO;
  123.         } catch (Exception e) {
  124.             throw new Exception(e);
  125.         }
  126.     }
  127.     /**
  128.      * 合并文件
  129.      * @param object object
  130.      * @param uploadId uploadUd
  131.      */
  132.     @SneakyThrows
  133.     public boolean mergeMultipartUpload(String object, String uploadId,String bucketName) {
  134.         // 获取所有分片
  135.         List<Part> partsList = getParts(object, uploadId,bucketName);
  136.         Part[] parts = new Part[partsList.size()];
  137.         int partNumber = 1;
  138.         for (Part part : partsList) {
  139.             parts[partNumber - 1] = new Part(partNumber, part.etag());
  140.             partNumber++;
  141.         }
  142.         // 合并分片
  143.         customMinioClient.mergeMultipartUpload(bucketName, null, object, uploadId, parts, null, null);
  144.         return true;
  145.     }
  146.     @NotNull
  147.     private  List<Part> getParts(String object, String uploadId,String bucketName) throws Exception {
  148.         int partNumberMarker = 0;
  149.         boolean isTruncated = true;
  150.         List<Part> parts = new ArrayList<>();
  151.         while(isTruncated){
  152.             ListPartsResponse partResult = customMinioClient.listMultipart(bucketName, null, object, 1000, partNumberMarker, uploadId, null, null);
  153.             parts.addAll(partResult.result().partList());
  154.             // 检查是否还有更多分片
  155.             isTruncated = partResult.result().isTruncated();
  156.             if (isTruncated) {
  157.                 // 更新partNumberMarker以获取下一页的分片数据
  158.                 partNumberMarker = partResult.result().nextPartNumberMarker();
  159.             }
  160.         }
  161.         return parts;
  162.     }
  163. }
复制代码
  1. package net.junnan.religious.base.api.util;
  2. import org.springframework.data.redis.core.RedisTemplate;
  3. import org.springframework.data.redis.core.ZSetOperations;
  4. import org.springframework.stereotype.Component;
  5. import org.springframework.util.CollectionUtils;
  6. import javax.annotation.Resource;
  7. import java.util.Collection;
  8. import java.util.List;
  9. import java.util.Map;
  10. import java.util.Set;
  11. import java.util.concurrent.TimeUnit;
  12. @Component
  13. public class RedisUtil {
  14.     @Resource
  15.     private RedisTemplate redisTemplate;
  16.     /**
  17.      * 指定缓存失效时间
  18.      * @param key 键
  19.      * @param time 时间(秒)
  20.      * @return
  21.      */
  22.     public boolean expire(String key, long time) {
  23.         try {
  24.             if (time > 0) {
  25.                 redisTemplate.expire(key, time, TimeUnit.SECONDS);
  26.             }
  27.             return true;
  28.         } catch (Exception e) {
  29.             e.printStackTrace();
  30.             return false;
  31.         }
  32.     }
  33.     /**
  34.      * 根据key 获取过期时间
  35.      * @param key 键 不能为null
  36.      * @return 时间(秒) 返回0代表为永久有效
  37.      */
  38.     public long getExpire(String key) {
  39.         return redisTemplate.getExpire(key, TimeUnit.SECONDS);
  40.     }
  41.     /**
  42.      * 判断key是否存在
  43.      * @param key 键
  44.      * @return true 存在 false不存在
  45.      */
  46.     public boolean hasKey(String key) {
  47.         try {
  48.             return redisTemplate.hasKey(key);
  49.         } catch (Exception e) {
  50.             e.printStackTrace();
  51.             return false;
  52.         }
  53.     }
  54.     /**
  55.      * 删除缓存
  56.      * @param key 可以传一个值 或多个
  57.      */
  58.     @SuppressWarnings("unchecked")
  59.     public void del(String... key) {
  60.         if (key != null && key.length > 0) {
  61.             if (key.length == 1) {
  62.                 redisTemplate.delete(key[0]);
  63.             } else {
  64.                 redisTemplate.delete(CollectionUtils.arrayToList(key));
  65.             }
  66.         }
  67.     }
  68.     //============================String=============================
  69.     /**
  70.      * 普通缓存获取
  71.      * @param key 键
  72.      * @return 值
  73.      */
  74.     public Object get(String key) {
  75.         return key == null ? null : redisTemplate.opsForValue().get(key);
  76.     }
  77.     /**
  78.      * 普通缓存放入
  79.      * @param key 键
  80.      * @param value 值
  81.      * @return true成功 false失败
  82.      */
  83.     public boolean set(String key, Object value) {
  84.         try {
  85.             redisTemplate.opsForValue().set(key, value);
  86.             return true;
  87.         } catch (Exception e) {
  88.             e.printStackTrace();
  89.             return false;
  90.         }
  91.     }
  92.     /**
  93.      * 普通缓存放入并设置时间
  94.      * @param key 键
  95.      * @param value 值
  96.      * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
  97.      * @return true成功 false 失败
  98.      */
  99.     public boolean set(String key, Object value, long time) {
  100.         try {
  101.             if (time > 0) {
  102.                 redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
  103.             } else {
  104.                 set(key, value);
  105.             }
  106.             return true;
  107.         } catch (Exception e) {
  108.             e.printStackTrace();
  109.             return false;
  110.         }
  111.     }
  112.     /**
  113.      * 普通缓存放入并设置时间和单位
  114.      * @param key 键
  115.      * @param value 值
  116.      * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
  117.      * @param unit 单位
  118.      * @return true成功 false 失败
  119.      */
  120.     public boolean set(String key, Object value, long time, TimeUnit unit) {
  121.         try {
  122.             if (time > 0) {
  123.                 redisTemplate.opsForValue().set(key, value, time, unit);
  124.             } else {
  125.                 set(key, value);
  126.             }
  127.             return true;
  128.         } catch (Exception e) {
  129.             e.printStackTrace();
  130.             return false;
  131.         }
  132.     }
  133.     /**
  134.      * 递增
  135.      * @param key 键
  136.      * @param delta 要增加几(大于0)
  137.      * @return
  138.      */
  139.     public long incr(String key, long delta) {
  140.         if (delta < 0) {
  141.             throw new RuntimeException("递增因子必须大于0");
  142.         }
  143.         return redisTemplate.opsForValue().increment(key, delta);
  144.     }
  145.     /**
  146.      * 递减
  147.      * @param key 键
  148.      * @param delta 要减少几(小于0)
  149.      * @return
  150.      */
  151.     public long decr(String key, long delta) {
  152.         if (delta < 0) {
  153.             throw new RuntimeException("递减因子必须大于0");
  154.         }
  155.         return redisTemplate.opsForValue().increment(key, -delta);
  156.     }
  157.     //================================Map=================================
  158.     /**
  159.      * HashGet
  160.      * @param key 键 不能为null
  161.      * @param item 项 不能为null
  162.      * @return 值
  163.      */
  164.     public Object hget(String key, String item) {
  165.         return redisTemplate.opsForHash().get(key, item);
  166.     }
  167.     /**
  168.      * 获取hashKey对应的所有键值
  169.      * @param key 键
  170.      * @return 对应的多个键值
  171.      */
  172.     public Map<Object, Object> hmget(String key) {
  173.         return redisTemplate.opsForHash().entries(key);
  174.     }
  175.     /**
  176.      * HashSet
  177.      * @param key 键
  178.      * @param map 对应多个键值
  179.      * @return true 成功 false 失败
  180.      */
  181.     public boolean hmset(String key, Map<String, Object> map) {
  182.         try {
  183.             redisTemplate.opsForHash().putAll(key, map);
  184.             return true;
  185.         } catch (Exception e) {
  186.             e.printStackTrace();
  187.             return false;
  188.         }
  189.     }
  190.     /**
  191.      * HashSet 并设置时间
  192.      * @param key 键
  193.      * @param map 对应多个键值
  194.      * @param time 时间(秒)
  195.      * @return true成功 false失败
  196.      */
  197.     public boolean hmset(String key, Map<String, Object> map, long time) {
  198.         try {
  199.             redisTemplate.opsForHash().putAll(key, map);
  200.             if (time > 0) {
  201.                 expire(key, time);
  202.             }
  203.             return true;
  204.         } catch (Exception e) {
  205.             e.printStackTrace();
  206.             return false;
  207.         }
  208.     }
  209.     /**
  210.      * 向一张hash表中放入数据,如果不存在将创建
  211.      * @param key 键
  212.      * @param item 项
  213.      * @param value 值
  214.      * @return true 成功 false失败
  215.      */
  216.     public boolean hset(String key, String item, Object value) {
  217.         try {
  218.             redisTemplate.opsForHash().put(key, item, value);
  219.             return true;
  220.         } catch (Exception e) {
  221.             e.printStackTrace();
  222.             return false;
  223.         }
  224.     }
  225.     /**
  226.      * 向一张hash表中放入数据,如果不存在将创建
  227.      * @param key 键
  228.      * @param item 项
  229.      * @param value 值
  230.      * @param time 时间(秒)  注意:如果已存在的hash表有时间,这里将会替换原有的时间
  231.      * @return true 成功 false失败
  232.      */
  233.     public boolean hset(String key, String item, Object value, long time) {
  234.         try {
  235.             redisTemplate.opsForHash().put(key, item, value);
  236.             if (time > 0) {
  237.                 expire(key, time);
  238.             }
  239.             return true;
  240.         } catch (Exception e) {
  241.             e.printStackTrace();
  242.             return false;
  243.         }
  244.     }
  245.     /**
  246.      * 删除hash表中的值
  247.      * @param key 键 不能为null
  248.      * @param item 项 可以使多个 不能为null
  249.      */
  250.     public void hdel(String key, Object... item) {
  251.         redisTemplate.opsForHash().delete(key, item);
  252.     }
  253.     /**
  254.      * 判断hash表中是否有该项的值
  255.      * @param key 键 不能为null
  256.      * @param item 项 不能为null
  257.      * @return true 存在 false不存在
  258.      */
  259.     public boolean hHasKey(String key, String item) {
  260.         return redisTemplate.opsForHash().hasKey(key, item);
  261.     }
  262.     /**
  263.      * hash递增 如果不存在,就会创建一个 并把新增后的值返回
  264.      * @param key 键
  265.      * @param item 项
  266.      * @param by 要增加几(大于0)
  267.      * @return
  268.      */
  269.     public double hincr(String key, String item, double by) {
  270.         return redisTemplate.opsForHash().increment(key, item, by);
  271.     }
  272.     /**
  273.      * hash递减
  274.      * @param key 键
  275.      * @param item 项
  276.      * @param by 要减少记(小于0)
  277.      * @return
  278.      */
  279.     public double hdecr(String key, String item, double by) {
  280.         return redisTemplate.opsForHash().increment(key, item, -by);
  281.     }
  282.     //============================set=============================
  283.     /**
  284.      * 根据key获取Set中的所有值
  285.      * @param key 键
  286.      * @return
  287.      */
  288.     public Set<Object> sGet(String key) {
  289.         try {
  290.             return redisTemplate.opsForSet().members(key);
  291.         } catch (Exception e) {
  292.             e.printStackTrace();
  293.             return null;
  294.         }
  295.     }
  296.     /**
  297.      * 根据value从一个set中查询,是否存在
  298.      * @param key 键
  299.      * @param value 值
  300.      * @return true 存在 false不存在
  301.      */
  302.     public boolean sHasKey(String key, Object value) {
  303.         try {
  304.             return redisTemplate.opsForSet().isMember(key, value);
  305.         } catch (Exception e) {
  306.             e.printStackTrace();
  307.             return false;
  308.         }
  309.     }
  310.     /**
  311.      * 将数据放入set缓存
  312.      * @param key 键
  313.      * @param values 值 可以是多个
  314.      * @return 成功个数
  315.      */
  316.     public long sSet(String key, Object... values) {
  317.         try {
  318.             return redisTemplate.opsForSet().add(key, values);
  319.         } catch (Exception e) {
  320.             e.printStackTrace();
  321.             return 0;
  322.         }
  323.     }
  324.     /**
  325.      * 将set数据放入缓存
  326.      * @param key 键
  327.      * @param time 时间(秒)
  328.      * @param values 值 可以是多个
  329.      * @return 成功个数
  330.      */
  331.     public long sSetAndTime(String key, long time, Object... values) {
  332.         try {
  333.             Long count = redisTemplate.opsForSet().add(key, values);
  334.             if (time > 0) expire(key, time);
  335.             return count;
  336.         } catch (Exception e) {
  337.             e.printStackTrace();
  338.             return 0;
  339.         }
  340.     }
  341.     /**
  342.      * 获取set缓存的长度
  343.      * @param key 键
  344.      * @return
  345.      */
  346.     public long sGetSetSize(String key) {
  347.         try {
  348.             return redisTemplate.opsForSet().size(key);
  349.         } catch (Exception e) {
  350.             e.printStackTrace();
  351.             return 0;
  352.         }
  353.     }
  354.     /**
  355.      * 移除值为value的
  356.      * @param key 键
  357.      * @param values 值 可以是多个
  358.      * @return 移除的个数
  359.      */
  360.     public long setRemove(String key, Object... values) {
  361.         try {
  362.             Long count = redisTemplate.opsForSet().remove(key, values);
  363.             return count;
  364.         } catch (Exception e) {
  365.             e.printStackTrace();
  366.             return 0;
  367.         }
  368.     }
  369.     //===============================list=================================
  370.     /**
  371.      * 获取list缓存的内容
  372.      * @param key 键
  373.      * @param start 开始
  374.      * @param end 结束  0 到 -1代表所有值
  375.      * @return
  376.      */
  377.     public List<Object> lGet(String key, long start, long end) {
  378.         try {
  379.             return redisTemplate.opsForList().range(key, start, end);
  380.         } catch (Exception e) {
  381.             e.printStackTrace();
  382.             return null;
  383.         }
  384.     }
  385.     /**
  386.      * 获取list缓存的长度
  387.      * @param key 键
  388.      * @return
  389.      */
  390.     public long lGetListSize(String key) {
  391.         try {
  392.             return redisTemplate.opsForList().size(key);
  393.         } catch (Exception e) {
  394.             e.printStackTrace();
  395.             return 0;
  396.         }
  397.     }
  398.     /**
  399.      * 通过索引 获取list中的值
  400.      * @param key 键
  401.      * @param index 索引  index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
  402.      * @return
  403.      */
  404.     public Object lGetIndex(String key, long index) {
  405.         try {
  406.             return redisTemplate.opsForList().index(key, index);
  407.         } catch (Exception e) {
  408.             e.printStackTrace();
  409.             return null;
  410.         }
  411.     }
  412.     /**
  413.      * 将list放入缓存
  414.      * @param key 键
  415.      * @param value 值
  416.      * @return
  417.      */
  418.     public boolean lSet(String key, Object value) {
  419.         try {
  420.             redisTemplate.opsForList().rightPush(key, value);
  421.             return true;
  422.         } catch (Exception e) {
  423.             e.printStackTrace();
  424.             return false;
  425.         }
  426.     }
  427.     /**
  428.      * 将list放入缓存
  429.      * @param key 键
  430.      * @param value 值
  431.      * @param time 时间(秒)
  432.      * @return
  433.      */
  434.     public boolean lSet(String key, Object value, long time) {
  435.         try {
  436.             redisTemplate.opsForList().rightPush(key, value);
  437.             if (time > 0) expire(key, time);
  438.             return true;
  439.         } catch (Exception e) {
  440.             e.printStackTrace();
  441.             return false;
  442.         }
  443.     }
  444.     /**
  445.      * 将list放入缓存
  446.      * @param key 键
  447.      * @param value 值
  448.      * @return
  449.      */
  450.     public boolean lSet(String key, List<Object> value) {
  451.         try {
  452.             redisTemplate.opsForList().rightPushAll(key, value);
  453.             return true;
  454.         } catch (Exception e) {
  455.             e.printStackTrace();
  456.             return false;
  457.         }
  458.     }
  459.     /**
  460.      * 将list放入缓存
  461.      * @param key 键
  462.      * @param value 值
  463.      * @param time 时间(秒)
  464.      * @return
  465.      */
  466.     public boolean lSet(String key, List<Object> value, long time) {
  467.         try {
  468.             redisTemplate.opsForList().rightPushAll(key, value);
  469.             if (time > 0) expire(key, time);
  470.             return true;
  471.         } catch (Exception e) {
  472.             e.printStackTrace();
  473.             return false;
  474.         }
  475.     }
  476.     /**
  477.      * 根据索引修改list中的某条数据
  478.      * @param key 键
  479.      * @param index 索引
  480.      * @param value 值
  481.      * @return
  482.      */
  483.     public boolean lUpdateIndex(String key, long index, Object value) {
  484.         try {
  485.             redisTemplate.opsForList().set(key, index, value);
  486.             return true;
  487.         } catch (Exception e) {
  488.             e.printStackTrace();
  489.             return false;
  490.         }
  491.     }
  492.     /**
  493.      * 移除N个值为value
  494.      * @param key 键
  495.      * @param count 移除多少个
  496.      * @param value 值
  497.      * @return 移除的个数
  498.      */
  499.     public long lRemove(String key, long count, Object value) {
  500.         try {
  501.             Long remove = redisTemplate.opsForList().remove(key, count, value);
  502.             return remove;
  503.         } catch (Exception e) {
  504.             e.printStackTrace();
  505.             return 0;
  506.         }
  507.     }
  508.     //================有序集合 sort set===================
  509.     /**
  510.      * 有序set添加元素
  511.      * @param key
  512.      * @param value
  513.      * @param score
  514.      * @return
  515.      */
  516.     public boolean zSet(String key, Object value, double score) {
  517.         return redisTemplate.opsForZSet().add(key, value, score);
  518.     }
  519.     public long batchZSet(String key, Set<ZSetOperations.TypedTuple> typles) {
  520.         return redisTemplate.opsForZSet().add(key, typles);
  521.     }
  522.     public void zIncrementScore(String key, Object value, long delta) {
  523.         redisTemplate.opsForZSet().incrementScore(key, value, delta);
  524.     }
  525.     public void zUnionAndStore(String key, Collection otherKeys, String destKey) {
  526.         redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey);
  527.     }
  528.     /**
  529.      * 获取zset数量
  530.      * @param key
  531.      * @param value
  532.      * @return
  533.      */
  534.     public long getZsetScore(String key, Object value) {
  535.         Double score = redisTemplate.opsForZSet().score(key, value);
  536.         if (score == null) {
  537.             return 0;
  538.         } else {
  539.             return score.longValue();
  540.         }
  541.     }
  542.     /**
  543.      * 获取有序集 key 中成员 member 的排名 。
  544.      * 其中有序集成员按 score 值递减 (从大到小) 排序。
  545.      * @param key
  546.      * @param start
  547.      * @param end
  548.      * @return
  549.      */
  550.     public Set<ZSetOperations.TypedTuple> getZSetRank(String key, long start, long end) {
  551.         return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
  552.     }
  553. }
复制代码
  1. package net.junnan.religious.base.api.entity.common;
  2. import lombok.Data;
  3. import java.io.Serializable;
  4. /**
  5. * @title: ShardFilesUpload
  6. * @Author CaoJun
  7. * @Date: 2025/5/6 上午11:14
  8. * @Version 1.0
  9. */
  10. @Data
  11. public class ShardFilesUpload implements Serializable {
  12.     private static final long serialVersionUID = 1L;
  13.     private String id ;
  14.     /** 文件上传id */
  15.     private String uploadId ;
  16.     /** 文件计算md5 */
  17.     private String md5 ;
  18.     /** 文件访问地址 */
  19.     private String url ;
  20.     /** 存储桶 */
  21.     private String bucket ;
  22.     /** minio中文件名 */
  23.     private String object ;
  24.     /** 原始文件名 */
  25.     private String originFileName ;
  26.     /** 文件大小 */
  27.     private Long size ;
  28.     /** 文件类型 */
  29.     private String type ;
  30.     /** 分片大小 */
  31.     private Long chunkSize ;
  32.     /** 分片数量 */
  33.     private Integer chunkCount ;
  34.     /** 是否删除 */
  35.     private Integer isDelete ;
  36.     /** 创建时间 */
  37.     private Long createTime ;
  38. }
复制代码
   
  1. package net.junnan.religious.base.api.mapper.common;
  2. import net.junnan.religious.base.api.entity.common.ShardFilesUpload;
  3. import org.apache.ibatis.annotations.Mapper;
  4. /**
  5. * @title: ShardFilesUploadMapper
  6. * @Author CaoJun
  7. * @Date: 2025/5/6 上午11:13
  8. * @Version 1.0
  9. */
  10. @Mapper
  11. public interface ShardFilesUploadMapper{
  12.     /**
  13.      * 新增数据
  14.      *
  15.      * @param shardFilesUpload 实例对象
  16.      * @return 影响行数
  17.      */
  18.     int insert(ShardFilesUpload shardFilesUpload);
  19.     ShardFilesUpload selectShardFilesUploadByMd5(String md5,String bucket);
  20. }
复制代码
   
  1. @SneakyThrows
  2. @Override
  3. public Result checkFileByMd5(FileCheckAndMergeForm fileCheckAndMergeForm)  {
  4.     String selector = myProperties.getStorage().getSelector();
  5.     switch (selector) {
  6.         case "minio":
  7.             return minioStorage.checkFileByMd5(fileCheckAndMergeForm);
  8.         case "aliyun":
  9.             throw new Exception("aliyunStorage的方法缺失");
  10.         default:
  11.             throw new Exception("不支持的 my.storage.selector");
  12.     }
  13. }
  14. @SneakyThrows
  15. @Override
  16. public Result initMultipartUpload(FileUploadInfo fileUploadInfo)  {
  17.     String selector = myProperties.getStorage().getSelector();
  18.     switch (selector) {
  19.         case "minio":
  20.             return minioStorage.initMultipartUpload(fileUploadInfo);
  21.         case "aliyun":
  22.             throw new Exception("aliyunStorage的方法缺失");
  23.         default:
  24.             throw new Exception("不支持的 my.storage.selector");
  25.     }
  26. }
  27. @SneakyThrows
  28. @Override
  29. public Result mergeMultipartUpload(FileCheckAndMergeForm fileCheckAndMergeForm) {
  30.     String selector = myProperties.getStorage().getSelector();
  31.     switch (selector) {
  32.         case "minio":
  33.             return minioStorage.mergeMultipartUpload(fileCheckAndMergeForm);
  34.         case "aliyun":
  35.             throw new Exception("aliyunStorage的方法缺失");
  36.         default:
  37.             throw new Exception("不支持的 my.storage.selector");
  38.     }
  39. }
复制代码
   
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  3. <mapper namespace="net.junnan.religious.base.api.mapper.common.ShardFilesUploadMapper">
  4.     <resultMap type="net.junnan.religious.base.api.entity.common.ShardFilesUpload" id="BaseResultMap">
  5.         <result property="id" column="id" jdbcType="VARCHAR"/>
  6.         <result property="uploadId" column="upload_id" jdbcType="VARCHAR"/>
  7.         <result property="md5" column="md5" jdbcType="VARCHAR"/>
  8.         <result property="url" column="url" jdbcType="VARCHAR"/>
  9.         <result property="bucket" column="bucket" jdbcType="VARCHAR"/>
  10.         <result property="object" column="object" jdbcType="VARCHAR"/>
  11.         <result property="originFileName" column="origin_file_name" jdbcType="VARCHAR"/>
  12.         <result property="size" column="size" jdbcType="BIGINT"/>
  13.         <result property="type" column="type" jdbcType="VARCHAR"/>
  14.         <result property="chunkSize" column="chunk_size" jdbcType="BIGINT"/>
  15.         <result property="chunkCount" column="chunk_count" jdbcType="INTEGER"/>
  16.         <result property="isDelete" column="is_delete" jdbcType="INTEGER"/>
  17.         <result property="createTime" column="create_time" jdbcType="BIGINT"/>
  18.     </resultMap>
  19.     <select id="selectShardFilesUploadByMd5" parameterType="String" resultMap="BaseResultMap">
  20.         select id,
  21.                upload_id,
  22.                md5,
  23.                url,
  24.                bucket,
  25.                object,
  26.                origin_file_name, size, type, chunk_size, chunk_count, is_delete, create_time
  27.         from RELIGIOUS.SHARD_FILES_UPLOAD
  28.         WHERE md5 = #{md5}
  29.           and bucket = #{bucket}
  30.           and is_delete =0
  31.     </select>
  32.     <!--新增数据-->
  33.     <insert id="insert" keyProperty="id" useGeneratedKeys="true">
  34.         insert into RELIGIOUS.SHARD_FILES_UPLOAD(id, upload_id, md5, url, bucket, object, origin_file_name, size, type,
  35.                                                  chunk_size, chunk_count, is_delete, create_time)
  36.         values (#{id}, #{uploadId}, #{md5}, #{url}, #{bucket}, #{object}, #{originFileName}, #{size}, #{type},
  37.                 #{chunkSize}, #{chunkCount}, #{isDelete}, #{createTime})
  38.     </insert>
  39. </mapper>
复制代码

  1. package net.junnan.religious.base.api.form.religious.ShardFilesUpload;
  2. import lombok.Data;
  3. import lombok.experimental.Accessors;
  4. import java.util.List;
  5. /**
  6. * 返回文件生成的分片上传地址
  7. */
  8. @Data
  9. @Accessors(chain = true)
  10. public class UploadUrlsVO {
  11.     private String uploadId;
  12.     private List<String> urls;
  13. }
复制代码
  1. package net.junnan.religious.base.api.util;
  2. import com.alibaba.fastjson.JSON;
  3. import java.lang.reflect.InvocationTargetException;
  4. import java.lang.reflect.Type;
  5. public class BeanUtil {
  6.   
  7.     public static <T> T copyFrom(Object obj, Class<T> clazz) {
  8.         try {
  9.             if (obj == null) {
  10.                 return null;
  11.             }
  12.             T      bean = clazz.getDeclaredConstructor().newInstance();
  13.             String json = JSON.toJSONString(obj);
  14.             return JSON.parseObject(json, (Type) bean.getClass());
  15.         } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
  16.             e.printStackTrace();
  17.             return null;
  18.         }
  19.     }
  20. }
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

一给

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表