数据库效果图:
代码部门:本身搭建minio测试 Result和配置文件可以本身编写 不必要和我一样
- my.storage.minio.protocol = http
- my.storage.minio.endPoint = 192.168.3.115:9000
- my.storage.minio.stsEndPoint = 192.168.3.115:9000
- my.storage.minio.accessKey = ZCEqAP5ECpdyt4pg9VIx
- my.storage.minio.secretKey = dAlXmXdHWjYOZb8IWBowJGnGZzeKL9OC3TmYR8uO
- my.storage.minio.internetProtocol = http
- my.storage.minio.internetEndPoint = 192.168.3.115:9000
- my.storage.minio.intranetProtocol = http
- my.storage.minio.intranetEndPoint = 192.168.3.115:9000
复制代码
- public Result checkFileByMd5(FileCheckAndMergeForm fileCheckAndMergeForm) {
- String md5 = fileCheckAndMergeForm.getMd5();
- String bucket = fileCheckAndMergeForm.getBucket();
- FileUploadInfo fileUploadInfo = (FileUploadInfo)redisUtil.get(md5);
- if (fileUploadInfo != null) {
- List<Integer> listParts = minioUtil.getListParts(fileUploadInfo.getObject(), fileUploadInfo.getUploadId(),bucket);
- fileUploadInfo.setListParts(listParts);
- return Result.ok("上传中")
- .build("fileUploadInfo", fileUploadInfo);
- }
- ShardFilesUpload shardFilesUpload = shardFilesUploadMapper.selectShardFilesUploadByMd5(md5,bucket);
- if (shardFilesUpload != null) {
- FileUploadInfo dbFileInfo = BeanUtil.copyFrom(shardFilesUpload, FileUploadInfo.class);
- return Result.ok("上传成功")
- .build("fileUploadInfo", dbFileInfo);
- }
- return Result.ok("未上传");
- }
- @SneakyThrows
- public Result initMultipartUpload(FileUploadInfo fileUploadInfo) {
- FileUploadInfo redisFileUploadInfo = (FileUploadInfo)redisUtil.get(fileUploadInfo.getMd5());
- String bucket = fileUploadInfo.getBucket();
- // 若 redis 中有该 md5 的记录,以 redis 中为主
- String object;
- if (redisFileUploadInfo != null) {
- fileUploadInfo = redisFileUploadInfo;
- object = redisFileUploadInfo.getObject();
- } else {
- String originFileName = fileUploadInfo.getOriginFileName();
- String suffix = FileUtil.extName(originFileName);
- String fileName = FileUtil.mainName(originFileName);
- // 对文件重命名,并以年月日文件夹格式存储
- String nestFile = DateUtil.format(LocalDateTime.now(), "yyyy/MM/dd");
- object = nestFile + "/" + fileName + "_" + fileUploadInfo.getMd5() + "." + suffix;
- fileUploadInfo.setObject(object).setType(suffix);
- }
- UploadUrlsVO urlsVO;
- // 单文件上传
- if (fileUploadInfo.getChunkCount() == 1) {
- urlsVO = minioUtil.getUploadObjectUrl(fileUploadInfo.getContentType(), object,bucket);
- } else {
- // 分片上传
- urlsVO = minioUtil.initMultiPartUpload(fileUploadInfo, object,bucket);
- }
- fileUploadInfo.setUploadId(urlsVO.getUploadId());
- // 存入 redis
- redisUtil.set(fileUploadInfo.getMd5(), fileUploadInfo, 1, TimeUnit.DAYS);
- return Result.ok()
- .build("urlsVO", urlsVO);
- }
- public Result mergeMultipartUpload(FileCheckAndMergeForm fileCheckAndMergeForm){
- String md5 = fileCheckAndMergeForm.getMd5();
- String bucket = fileCheckAndMergeForm.getBucket();
- FileUploadInfo redisFileUploadInfo = (FileUploadInfo)redisUtil.get(md5);
- if (redisFileUploadInfo==null){
- return Result.error("文件处理失败");
- }
- MyProperties.Minio minio = myProperties.getStorage().getMinio();
- String url = String.format("%s://%s/%s/%s", minio.getProtocol(), minio.getEndPoint(), bucket, redisFileUploadInfo.getObject());
- //获取真实的请求IP 如果是互联网地址,则将minio 地址替换
- if (getRequest() != null) {
- String ipAddr = IpUtil.getIpAddr(getRequest());
- if (IpUtil.isExternalIP(ipAddr)) {
- url = url.replaceFirst(minio.getProtocol(), minio.getInternetProtocol());
- url = url.replaceFirst(minio.getEndPoint(), minio.getInternetEndPoint());
- } else {
- url = url.replaceFirst(minio.getProtocol(), minio.getIntranetProtocol());
- url = url.replaceFirst(minio.getEndPoint(), minio.getIntranetEndPoint());
- }
- }
- // 更新数据库
- ShardFilesUpload shardFilesUpload = BeanUtil.copyFrom(redisFileUploadInfo, ShardFilesUpload.class);
- shardFilesUpload.setId(UUID.randomUUID().toString());
- shardFilesUpload.setUrl(url);
- shardFilesUpload.setIsDelete(0);
- shardFilesUpload.setBucket(bucket);
- shardFilesUpload.setCreateTime(System.currentTimeMillis());
- Integer chunkCount = redisFileUploadInfo.getChunkCount();
- // 分片为 1 ,不需要合并,否则合并后看返回的是 true 还是 false
- boolean isSuccess = chunkCount == 1 || minioUtil.mergeMultipartUpload(redisFileUploadInfo.getObject(), redisFileUploadInfo.getUploadId(),bucket);
- if (isSuccess) {
- shardFilesUploadMapper.insert(shardFilesUpload);
- redisUtil.del(md5);
- return Result.ok()
- .build("storage", "minio")
- .build("url", url);
- }
- return Result.error("文件处理失败");
- }
复制代码- /**
- * 检查文件是否存在
- */
- @RequestMapping (value = "/multipart/check", method = RequestMethod.POST)
- public Result checkFileByMd5(@RequestBody @Valid FileCheckAndMergeForm fileCheckAndMergeForm) {
- return sdkService.checkFileByMd5(fileCheckAndMergeForm);
- }
- /**
- * 初始化文件分片地址及相关数据
- */
- @RequestMapping (value = "/multipart/init", method = RequestMethod.POST)
- public Result initMultiPartUpload(@RequestBody @Valid FileUploadInfo fileUploadInfo) {
- return sdkService.initMultipartUpload(fileUploadInfo);
- }
- /**
- * 文件合并(单文件不会合并,仅信息入库)
- */
- @RequestMapping (value = "/multipart/merge", method = RequestMethod.POST)
- public Result mergeMultipartUpload(@RequestBody @Valid FileCheckAndMergeForm fileCheckAndMergeForm) {
- return sdkService.mergeMultipartUpload(fileCheckAndMergeForm);
- }
复制代码- Result checkFileByMd5(FileCheckAndMergeForm fileCheckAndMergeForm) ;
- Result initMultipartUpload(FileUploadInfo fileUploadInfo) ;
- Result mergeMultipartUpload(FileCheckAndMergeForm fileCheckAndMergeForm);
复制代码 数据库是postgresSQL
- DROP TABLE IF EXISTS religious.shard_files_upload;
- CREATE TABLE religious.shard_files_upload
- (
- id VARCHAR(255) NOT NULL,
- upload_id VARCHAR(255),
- md5 VARCHAR(255),
- url VARCHAR(255),
- bucket VARCHAR(64),
- object VARCHAR(255),
- origin_file_name VARCHAR(255),
- size BIGINT,
- type VARCHAR(64),
- chunk_size BIGINT,
- chunk_count INTEGER,
- is_delete INTEGER,
- create_time BIGINT,
- PRIMARY KEY (id)
- );
- COMMENT ON TABLE religious.shard_files_upload IS '分片上传记录明细表';
- COMMENT ON COLUMN religious.shard_files_upload.upload_id IS '文件上传id';
- COMMENT ON COLUMN religious.shard_files_upload.md5 IS '文件计算md5';
- COMMENT ON COLUMN religious.shard_files_upload.url IS '文件访问地址';
- COMMENT ON COLUMN religious.shard_files_upload.bucket IS '存储桶';
- COMMENT ON COLUMN religious.shard_files_upload.object IS 'minio中文件名';
- COMMENT ON COLUMN religious.shard_files_upload.origin_file_name IS '原始文件名';
- COMMENT ON COLUMN religious.shard_files_upload.size IS '文件大小';
- COMMENT ON COLUMN religious.shard_files_upload.type IS '文件类型';
- COMMENT ON COLUMN religious.shard_files_upload.chunk_size IS '分片大小';
- COMMENT ON COLUMN religious.shard_files_upload.chunk_count IS '分片数量';
- COMMENT ON COLUMN religious.shard_files_upload.is_delete IS '是否删除';
- COMMENT ON COLUMN religious.shard_files_upload.create_time IS '创建时间';
复制代码- package net.junnan.religious.base.api.config;
- import com.google.common.collect.Multimap;
- import io.minio.CreateMultipartUploadResponse;
- import io.minio.ListPartsResponse;
- import io.minio.MinioAsyncClient;
- import io.minio.ObjectWriteResponse;
- import io.minio.messages.Part;
- public class CustomMinioClient extends MinioAsyncClient {
- /**
- * 继承父类
- * @param client
- */
- public CustomMinioClient(MinioAsyncClient client) {
- super(client);
- }
- /**
- * 初始化分片上传、获取 uploadId
- * @param bucket String 存储桶名称
- * @param region String
- * @param object String 文件名称
- * @param headers Multimap<String, String> 请求头
- * @param extraQueryParams Multimap<String, String>
- * @return String
- */
- public String initMultiPartUpload(String bucket, String region, String object, Multimap<String, String> headers, Multimap<String, String> extraQueryParams) throws Exception {
- CreateMultipartUploadResponse response = super.createMultipartUploadAsync(bucket, region, object, headers, extraQueryParams).get();
- return response.result().uploadId();
- }
- /**
- * 合并分片
- * @param bucketName String 桶名称
- * @param region String
- * @param objectName String 文件名称
- * @param uploadId String 上传的 uploadId
- * @param parts Part[] 分片集合
- * @param extraHeaders Multimap<String, String>
- * @param extraQueryParams Multimap<String, String>
- * @return ObjectWriteResponse
- */
- public ObjectWriteResponse mergeMultipartUpload(String bucketName, String region, String objectName, String uploadId, Part[] parts, Multimap<String, String> extraHeaders, Multimap<String, String> extraQueryParams) throws Exception {
- return super.completeMultipartUploadAsync(bucketName, region, objectName, uploadId, parts, extraHeaders, extraQueryParams).get();
- }
- /**
- * 查询当前上传后的分片信息
- * @param bucketName String 桶名称
- * @param region String
- * @param objectName String 文件名称
- * @param maxParts Integer 分片数量
- * @param partNumberMarker Integer 分片起始值
- * @param uploadId String 上传的 uploadId
- * @param extraHeaders Multimap<String, String>
- * @param extraQueryParams Multimap<String, String>
- * @return ListPartsResponse
- */
- 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 {
- return super.listPartsAsync(bucketName, region, objectName, maxParts, partNumberMarker, uploadId, extraHeaders, extraQueryParams).get();
- }
- }
复制代码- package net.junnan.religious.base.api.form.common.Sdk;
- import lombok.Data;
- import javax.validation.constraints.NotBlank;
- /**
- * @title: FileCheckAndMergeForm
- * @Author CaoJun
- * @Date: 2025/5/7 上午11:27
- * @Version 1.0
- */
- @Data
- public class FileCheckAndMergeForm {
- @NotBlank(message = "bucket 不可为空")
- private String bucket;
- @NotBlank(message = "文件的MD5值不可为空")
- private String md5;
- }
复制代码- package net.junnan.religious.base.api.form.religious.ShardFilesUpload;
- import lombok.Data;
- import lombok.experimental.Accessors;
- import javax.validation.constraints.NotBlank;
- import javax.validation.constraints.NotNull;
- import java.util.List;
- /**
- * 文件上传信息,查询 redis 后的返回信息
- */
- @Data
- @Accessors(chain = true)
- public class FileUploadInfo {
- @NotBlank(message = "md5 不能为空")
- private String md5;
- private String uploadId;
- @NotBlank(message = "文件名不能为空")
- private String originFileName;
- // 仅秒传会有值
- private String url;
- // 后端使用
- private String object;
- private String type;
- @NotNull(message = "文件大小不能为空")
- private Long size;
- @NotNull(message = "分片数量不能为空")
- private Integer chunkCount;
- @NotNull(message = "分片大小不能为空")
- private Long chunkSize;
- private String contentType;
- // listParts 从 1 开始,前端需要上传的分片索引+1
- private List<Integer> listParts;
- @NotBlank(message = "bucket 不可为空")
- private String bucket;
- }
复制代码- package net.junnan.religious.base.api.util;
- import cn.hutool.core.util.IdUtil;
- import com.google.common.collect.HashMultimap;
- import io.minio.*;
- import io.minio.http.Method;
- import io.minio.messages.Part;
- import lombok.SneakyThrows;
- import lombok.extern.slf4j.Slf4j;
- import net.junnan.religious.base.api.config.CustomMinioClient;
- import net.junnan.religious.base.api.form.religious.ShardFilesUpload.FileUploadInfo;
- import net.junnan.religious.base.api.form.religious.ShardFilesUpload.UploadUrlsVO;
- import net.junnan.religious.base.api.properties.MyProperties;
- import org.springframework.stereotype.Component;
- import javax.annotation.PostConstruct;
- import javax.annotation.Resource;
- import javax.validation.constraints.NotNull;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.concurrent.TimeUnit;
- import java.util.stream.Collectors;
- @Slf4j
- @Component
- public class MinioUtil {
- private CustomMinioClient customMinioClient;
- @Resource
- MyProperties myProperties;
- // spring自动注入会失败
- @PostConstruct
- public void init() {
- MyProperties.Minio minio = myProperties.getStorage().getMinio();
- MinioAsyncClient minioClient = MinioAsyncClient.builder()
- .endpoint(String.format("%s://%s", minio.getProtocol(), minio.getEndPoint()))
- .credentials(minio.getAccessKey(), minio.getSecretKey())
- .build();
- customMinioClient = new CustomMinioClient(minioClient);
- }
- /**
- * 获取 Minio 中已经上传的分片文件
- * @param object 文件名称
- * @param uploadId 上传的文件id(由 minio 生成)
- * @return List<Integer>
- */
- @SneakyThrows
- public List<Integer> getListParts(String object, String uploadId,String bucketName) {
- List<Part> parts = getParts(object, uploadId,bucketName);
- return parts.stream()
- .map(Part::partNumber)
- .collect(Collectors.toList());
- }
- /**
- * 单文件签名上传
- * @param object 文件名称(uuid 格式)
- * @return UploadUrlsVO
- */
- public UploadUrlsVO getUploadObjectUrl(String contentType, String object,String bucketName) throws Exception {
- try {
- UploadUrlsVO urlsVO = new UploadUrlsVO();
- List<String> urlList = new ArrayList<>();
- // 主要是针对图片,若需要通过浏览器直接查看,而不是下载,需要指定对应的 content-type
- HashMultimap<String, String> headers = HashMultimap.create();
- if (contentType == null || contentType.equals("")) {
- contentType = "application/octet-stream";
- }
- headers.put("Content-Type", contentType);
- String uploadId = IdUtil.simpleUUID();
- Map<String, String> reqParams = new HashMap<>();
- reqParams.put("uploadId", uploadId);
- String url = customMinioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
- .method(Method.PUT)
- .bucket(bucketName)
- .object(object)
- .extraHeaders(headers)
- .extraQueryParams(reqParams)
- .expiry(1, TimeUnit.DAYS)
- .build());
- urlList.add(url);
- urlsVO.setUploadId(uploadId).setUrls(urlList);
- return urlsVO;
- } catch (Exception e) {
- throw new Exception(e);
- }
- }
- /**
- * 初始化分片上传
- * @param fileUploadInfo 前端传入的文件信息
- * @param object object
- * @return UploadUrlsVO
- */
- public UploadUrlsVO initMultiPartUpload(FileUploadInfo fileUploadInfo, String object,String bucketName) throws Exception {
- Integer chunkCount = fileUploadInfo.getChunkCount();
- String contentType = fileUploadInfo.getContentType();
- String uploadId = fileUploadInfo.getUploadId();
- UploadUrlsVO urlsVO = new UploadUrlsVO();
- try {
- HashMultimap<String, String> headers = HashMultimap.create();
- if (contentType == null || contentType.equals("")) {
- contentType = "application/octet-stream";
- }
- headers.put("Content-Type", contentType);
- // 如果初始化时有 uploadId,说明是断点续传,不能重新生成 uploadId
- if (fileUploadInfo.getUploadId() == null || fileUploadInfo.getUploadId().equals("")) {
- uploadId = customMinioClient.initMultiPartUpload(bucketName, null, object, headers, null);
- }
- urlsVO.setUploadId(uploadId);
- List<String> partList = new ArrayList<>();
- Map<String, String> reqParams = new HashMap<>();
- reqParams.put("uploadId", uploadId);
- for (int i = 1; i <= chunkCount; i++) {
- reqParams.put("partNumber", String.valueOf(i));
- String uploadUrl = customMinioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
- .method(Method.PUT)
- .bucket(bucketName)
- .object(object)
- .expiry(1, TimeUnit.DAYS)
- .extraQueryParams(reqParams)
- .build());
- partList.add(uploadUrl);
- }
- urlsVO.setUrls(partList);
- return urlsVO;
- } catch (Exception e) {
- throw new Exception(e);
- }
- }
- /**
- * 合并文件
- * @param object object
- * @param uploadId uploadUd
- */
- @SneakyThrows
- public boolean mergeMultipartUpload(String object, String uploadId,String bucketName) {
- // 获取所有分片
- List<Part> partsList = getParts(object, uploadId,bucketName);
- Part[] parts = new Part[partsList.size()];
- int partNumber = 1;
- for (Part part : partsList) {
- parts[partNumber - 1] = new Part(partNumber, part.etag());
- partNumber++;
- }
- // 合并分片
- customMinioClient.mergeMultipartUpload(bucketName, null, object, uploadId, parts, null, null);
- return true;
- }
- @NotNull
- private List<Part> getParts(String object, String uploadId,String bucketName) throws Exception {
- int partNumberMarker = 0;
- boolean isTruncated = true;
- List<Part> parts = new ArrayList<>();
- while(isTruncated){
- ListPartsResponse partResult = customMinioClient.listMultipart(bucketName, null, object, 1000, partNumberMarker, uploadId, null, null);
- parts.addAll(partResult.result().partList());
- // 检查是否还有更多分片
- isTruncated = partResult.result().isTruncated();
- if (isTruncated) {
- // 更新partNumberMarker以获取下一页的分片数据
- partNumberMarker = partResult.result().nextPartNumberMarker();
- }
- }
- return parts;
- }
- }
复制代码- package net.junnan.religious.base.api.util;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.data.redis.core.ZSetOperations;
- import org.springframework.stereotype.Component;
- import org.springframework.util.CollectionUtils;
- import javax.annotation.Resource;
- import java.util.Collection;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.concurrent.TimeUnit;
- @Component
- public class RedisUtil {
- @Resource
- private RedisTemplate redisTemplate;
- /**
- * 指定缓存失效时间
- * @param key 键
- * @param time 时间(秒)
- * @return
- */
- public boolean expire(String key, long time) {
- try {
- if (time > 0) {
- redisTemplate.expire(key, time, TimeUnit.SECONDS);
- }
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 根据key 获取过期时间
- * @param key 键 不能为null
- * @return 时间(秒) 返回0代表为永久有效
- */
- public long getExpire(String key) {
- return redisTemplate.getExpire(key, TimeUnit.SECONDS);
- }
- /**
- * 判断key是否存在
- * @param key 键
- * @return true 存在 false不存在
- */
- public boolean hasKey(String key) {
- try {
- return redisTemplate.hasKey(key);
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 删除缓存
- * @param key 可以传一个值 或多个
- */
- @SuppressWarnings("unchecked")
- public void del(String... key) {
- if (key != null && key.length > 0) {
- if (key.length == 1) {
- redisTemplate.delete(key[0]);
- } else {
- redisTemplate.delete(CollectionUtils.arrayToList(key));
- }
- }
- }
- //============================String=============================
- /**
- * 普通缓存获取
- * @param key 键
- * @return 值
- */
- public Object get(String key) {
- return key == null ? null : redisTemplate.opsForValue().get(key);
- }
- /**
- * 普通缓存放入
- * @param key 键
- * @param value 值
- * @return true成功 false失败
- */
- public boolean set(String key, Object value) {
- try {
- redisTemplate.opsForValue().set(key, value);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 普通缓存放入并设置时间
- * @param key 键
- * @param value 值
- * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
- * @return true成功 false 失败
- */
- public boolean set(String key, Object value, long time) {
- try {
- if (time > 0) {
- redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
- } else {
- set(key, value);
- }
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 普通缓存放入并设置时间和单位
- * @param key 键
- * @param value 值
- * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
- * @param unit 单位
- * @return true成功 false 失败
- */
- public boolean set(String key, Object value, long time, TimeUnit unit) {
- try {
- if (time > 0) {
- redisTemplate.opsForValue().set(key, value, time, unit);
- } else {
- set(key, value);
- }
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 递增
- * @param key 键
- * @param delta 要增加几(大于0)
- * @return
- */
- public long incr(String key, long delta) {
- if (delta < 0) {
- throw new RuntimeException("递增因子必须大于0");
- }
- return redisTemplate.opsForValue().increment(key, delta);
- }
- /**
- * 递减
- * @param key 键
- * @param delta 要减少几(小于0)
- * @return
- */
- public long decr(String key, long delta) {
- if (delta < 0) {
- throw new RuntimeException("递减因子必须大于0");
- }
- return redisTemplate.opsForValue().increment(key, -delta);
- }
- //================================Map=================================
- /**
- * HashGet
- * @param key 键 不能为null
- * @param item 项 不能为null
- * @return 值
- */
- public Object hget(String key, String item) {
- return redisTemplate.opsForHash().get(key, item);
- }
- /**
- * 获取hashKey对应的所有键值
- * @param key 键
- * @return 对应的多个键值
- */
- public Map<Object, Object> hmget(String key) {
- return redisTemplate.opsForHash().entries(key);
- }
- /**
- * HashSet
- * @param key 键
- * @param map 对应多个键值
- * @return true 成功 false 失败
- */
- public boolean hmset(String key, Map<String, Object> map) {
- try {
- redisTemplate.opsForHash().putAll(key, map);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * HashSet 并设置时间
- * @param key 键
- * @param map 对应多个键值
- * @param time 时间(秒)
- * @return true成功 false失败
- */
- public boolean hmset(String key, Map<String, Object> map, long time) {
- try {
- redisTemplate.opsForHash().putAll(key, map);
- if (time > 0) {
- expire(key, time);
- }
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 向一张hash表中放入数据,如果不存在将创建
- * @param key 键
- * @param item 项
- * @param value 值
- * @return true 成功 false失败
- */
- public boolean hset(String key, String item, Object value) {
- try {
- redisTemplate.opsForHash().put(key, item, value);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 向一张hash表中放入数据,如果不存在将创建
- * @param key 键
- * @param item 项
- * @param value 值
- * @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
- * @return true 成功 false失败
- */
- public boolean hset(String key, String item, Object value, long time) {
- try {
- redisTemplate.opsForHash().put(key, item, value);
- if (time > 0) {
- expire(key, time);
- }
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 删除hash表中的值
- * @param key 键 不能为null
- * @param item 项 可以使多个 不能为null
- */
- public void hdel(String key, Object... item) {
- redisTemplate.opsForHash().delete(key, item);
- }
- /**
- * 判断hash表中是否有该项的值
- * @param key 键 不能为null
- * @param item 项 不能为null
- * @return true 存在 false不存在
- */
- public boolean hHasKey(String key, String item) {
- return redisTemplate.opsForHash().hasKey(key, item);
- }
- /**
- * hash递增 如果不存在,就会创建一个 并把新增后的值返回
- * @param key 键
- * @param item 项
- * @param by 要增加几(大于0)
- * @return
- */
- public double hincr(String key, String item, double by) {
- return redisTemplate.opsForHash().increment(key, item, by);
- }
- /**
- * hash递减
- * @param key 键
- * @param item 项
- * @param by 要减少记(小于0)
- * @return
- */
- public double hdecr(String key, String item, double by) {
- return redisTemplate.opsForHash().increment(key, item, -by);
- }
- //============================set=============================
- /**
- * 根据key获取Set中的所有值
- * @param key 键
- * @return
- */
- public Set<Object> sGet(String key) {
- try {
- return redisTemplate.opsForSet().members(key);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 根据value从一个set中查询,是否存在
- * @param key 键
- * @param value 值
- * @return true 存在 false不存在
- */
- public boolean sHasKey(String key, Object value) {
- try {
- return redisTemplate.opsForSet().isMember(key, value);
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 将数据放入set缓存
- * @param key 键
- * @param values 值 可以是多个
- * @return 成功个数
- */
- public long sSet(String key, Object... values) {
- try {
- return redisTemplate.opsForSet().add(key, values);
- } catch (Exception e) {
- e.printStackTrace();
- return 0;
- }
- }
- /**
- * 将set数据放入缓存
- * @param key 键
- * @param time 时间(秒)
- * @param values 值 可以是多个
- * @return 成功个数
- */
- public long sSetAndTime(String key, long time, Object... values) {
- try {
- Long count = redisTemplate.opsForSet().add(key, values);
- if (time > 0) expire(key, time);
- return count;
- } catch (Exception e) {
- e.printStackTrace();
- return 0;
- }
- }
- /**
- * 获取set缓存的长度
- * @param key 键
- * @return
- */
- public long sGetSetSize(String key) {
- try {
- return redisTemplate.opsForSet().size(key);
- } catch (Exception e) {
- e.printStackTrace();
- return 0;
- }
- }
- /**
- * 移除值为value的
- * @param key 键
- * @param values 值 可以是多个
- * @return 移除的个数
- */
- public long setRemove(String key, Object... values) {
- try {
- Long count = redisTemplate.opsForSet().remove(key, values);
- return count;
- } catch (Exception e) {
- e.printStackTrace();
- return 0;
- }
- }
- //===============================list=================================
- /**
- * 获取list缓存的内容
- * @param key 键
- * @param start 开始
- * @param end 结束 0 到 -1代表所有值
- * @return
- */
- public List<Object> lGet(String key, long start, long end) {
- try {
- return redisTemplate.opsForList().range(key, start, end);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 获取list缓存的长度
- * @param key 键
- * @return
- */
- public long lGetListSize(String key) {
- try {
- return redisTemplate.opsForList().size(key);
- } catch (Exception e) {
- e.printStackTrace();
- return 0;
- }
- }
- /**
- * 通过索引 获取list中的值
- * @param key 键
- * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
- * @return
- */
- public Object lGetIndex(String key, long index) {
- try {
- return redisTemplate.opsForList().index(key, index);
- } catch (Exception e) {
- e.printStackTrace();
- return null;
- }
- }
- /**
- * 将list放入缓存
- * @param key 键
- * @param value 值
- * @return
- */
- public boolean lSet(String key, Object value) {
- try {
- redisTemplate.opsForList().rightPush(key, value);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 将list放入缓存
- * @param key 键
- * @param value 值
- * @param time 时间(秒)
- * @return
- */
- public boolean lSet(String key, Object value, long time) {
- try {
- redisTemplate.opsForList().rightPush(key, value);
- if (time > 0) expire(key, time);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 将list放入缓存
- * @param key 键
- * @param value 值
- * @return
- */
- public boolean lSet(String key, List<Object> value) {
- try {
- redisTemplate.opsForList().rightPushAll(key, value);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 将list放入缓存
- * @param key 键
- * @param value 值
- * @param time 时间(秒)
- * @return
- */
- public boolean lSet(String key, List<Object> value, long time) {
- try {
- redisTemplate.opsForList().rightPushAll(key, value);
- if (time > 0) expire(key, time);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 根据索引修改list中的某条数据
- * @param key 键
- * @param index 索引
- * @param value 值
- * @return
- */
- public boolean lUpdateIndex(String key, long index, Object value) {
- try {
- redisTemplate.opsForList().set(key, index, value);
- return true;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * 移除N个值为value
- * @param key 键
- * @param count 移除多少个
- * @param value 值
- * @return 移除的个数
- */
- public long lRemove(String key, long count, Object value) {
- try {
- Long remove = redisTemplate.opsForList().remove(key, count, value);
- return remove;
- } catch (Exception e) {
- e.printStackTrace();
- return 0;
- }
- }
- //================有序集合 sort set===================
- /**
- * 有序set添加元素
- * @param key
- * @param value
- * @param score
- * @return
- */
- public boolean zSet(String key, Object value, double score) {
- return redisTemplate.opsForZSet().add(key, value, score);
- }
- public long batchZSet(String key, Set<ZSetOperations.TypedTuple> typles) {
- return redisTemplate.opsForZSet().add(key, typles);
- }
- public void zIncrementScore(String key, Object value, long delta) {
- redisTemplate.opsForZSet().incrementScore(key, value, delta);
- }
- public void zUnionAndStore(String key, Collection otherKeys, String destKey) {
- redisTemplate.opsForZSet().unionAndStore(key, otherKeys, destKey);
- }
- /**
- * 获取zset数量
- * @param key
- * @param value
- * @return
- */
- public long getZsetScore(String key, Object value) {
- Double score = redisTemplate.opsForZSet().score(key, value);
- if (score == null) {
- return 0;
- } else {
- return score.longValue();
- }
- }
- /**
- * 获取有序集 key 中成员 member 的排名 。
- * 其中有序集成员按 score 值递减 (从大到小) 排序。
- * @param key
- * @param start
- * @param end
- * @return
- */
- public Set<ZSetOperations.TypedTuple> getZSetRank(String key, long start, long end) {
- return redisTemplate.opsForZSet().reverseRangeWithScores(key, start, end);
- }
- }
复制代码 - package net.junnan.religious.base.api.entity.common;
- import lombok.Data;
- import java.io.Serializable;
- /**
- * @title: ShardFilesUpload
- * @Author CaoJun
- * @Date: 2025/5/6 上午11:14
- * @Version 1.0
- */
- @Data
- public class ShardFilesUpload implements Serializable {
- private static final long serialVersionUID = 1L;
- private String id ;
- /** 文件上传id */
- private String uploadId ;
- /** 文件计算md5 */
- private String md5 ;
- /** 文件访问地址 */
- private String url ;
- /** 存储桶 */
- private String bucket ;
- /** minio中文件名 */
- private String object ;
- /** 原始文件名 */
- private String originFileName ;
- /** 文件大小 */
- private Long size ;
- /** 文件类型 */
- private String type ;
- /** 分片大小 */
- private Long chunkSize ;
- /** 分片数量 */
- private Integer chunkCount ;
- /** 是否删除 */
- private Integer isDelete ;
- /** 创建时间 */
- private Long createTime ;
- }
复制代码
- package net.junnan.religious.base.api.mapper.common;
- import net.junnan.religious.base.api.entity.common.ShardFilesUpload;
- import org.apache.ibatis.annotations.Mapper;
- /**
- * @title: ShardFilesUploadMapper
- * @Author CaoJun
- * @Date: 2025/5/6 上午11:13
- * @Version 1.0
- */
- @Mapper
- public interface ShardFilesUploadMapper{
- /**
- * 新增数据
- *
- * @param shardFilesUpload 实例对象
- * @return 影响行数
- */
- int insert(ShardFilesUpload shardFilesUpload);
- ShardFilesUpload selectShardFilesUploadByMd5(String md5,String bucket);
- }
复制代码
- @SneakyThrows
- @Override
- public Result checkFileByMd5(FileCheckAndMergeForm fileCheckAndMergeForm) {
- String selector = myProperties.getStorage().getSelector();
- switch (selector) {
- case "minio":
- return minioStorage.checkFileByMd5(fileCheckAndMergeForm);
- case "aliyun":
- throw new Exception("aliyunStorage的方法缺失");
- default:
- throw new Exception("不支持的 my.storage.selector");
- }
- }
- @SneakyThrows
- @Override
- public Result initMultipartUpload(FileUploadInfo fileUploadInfo) {
- String selector = myProperties.getStorage().getSelector();
- switch (selector) {
- case "minio":
- return minioStorage.initMultipartUpload(fileUploadInfo);
- case "aliyun":
- throw new Exception("aliyunStorage的方法缺失");
- default:
- throw new Exception("不支持的 my.storage.selector");
- }
- }
- @SneakyThrows
- @Override
- public Result mergeMultipartUpload(FileCheckAndMergeForm fileCheckAndMergeForm) {
- String selector = myProperties.getStorage().getSelector();
- switch (selector) {
- case "minio":
- return minioStorage.mergeMultipartUpload(fileCheckAndMergeForm);
- case "aliyun":
- throw new Exception("aliyunStorage的方法缺失");
- default:
- throw new Exception("不支持的 my.storage.selector");
- }
- }
复制代码
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="net.junnan.religious.base.api.mapper.common.ShardFilesUploadMapper">
- <resultMap type="net.junnan.religious.base.api.entity.common.ShardFilesUpload" id="BaseResultMap">
- <result property="id" column="id" jdbcType="VARCHAR"/>
- <result property="uploadId" column="upload_id" jdbcType="VARCHAR"/>
- <result property="md5" column="md5" jdbcType="VARCHAR"/>
- <result property="url" column="url" jdbcType="VARCHAR"/>
- <result property="bucket" column="bucket" jdbcType="VARCHAR"/>
- <result property="object" column="object" jdbcType="VARCHAR"/>
- <result property="originFileName" column="origin_file_name" jdbcType="VARCHAR"/>
- <result property="size" column="size" jdbcType="BIGINT"/>
- <result property="type" column="type" jdbcType="VARCHAR"/>
- <result property="chunkSize" column="chunk_size" jdbcType="BIGINT"/>
- <result property="chunkCount" column="chunk_count" jdbcType="INTEGER"/>
- <result property="isDelete" column="is_delete" jdbcType="INTEGER"/>
- <result property="createTime" column="create_time" jdbcType="BIGINT"/>
- </resultMap>
- <select id="selectShardFilesUploadByMd5" parameterType="String" resultMap="BaseResultMap">
- select id,
- upload_id,
- md5,
- url,
- bucket,
- object,
- origin_file_name, size, type, chunk_size, chunk_count, is_delete, create_time
- from RELIGIOUS.SHARD_FILES_UPLOAD
- WHERE md5 = #{md5}
- and bucket = #{bucket}
- and is_delete =0
- </select>
- <!--新增数据-->
- <insert id="insert" keyProperty="id" useGeneratedKeys="true">
- insert into RELIGIOUS.SHARD_FILES_UPLOAD(id, upload_id, md5, url, bucket, object, origin_file_name, size, type,
- chunk_size, chunk_count, is_delete, create_time)
- values (#{id}, #{uploadId}, #{md5}, #{url}, #{bucket}, #{object}, #{originFileName}, #{size}, #{type},
- #{chunkSize}, #{chunkCount}, #{isDelete}, #{createTime})
- </insert>
- </mapper>
复制代码
- package net.junnan.religious.base.api.form.religious.ShardFilesUpload;
- import lombok.Data;
- import lombok.experimental.Accessors;
- import java.util.List;
- /**
- * 返回文件生成的分片上传地址
- */
- @Data
- @Accessors(chain = true)
- public class UploadUrlsVO {
- private String uploadId;
- private List<String> urls;
- }
复制代码- package net.junnan.religious.base.api.util;
- import com.alibaba.fastjson.JSON;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Type;
- public class BeanUtil {
-
- public static <T> T copyFrom(Object obj, Class<T> clazz) {
- try {
- if (obj == null) {
- return null;
- }
- T bean = clazz.getDeclaredConstructor().newInstance();
- String json = JSON.toJSONString(obj);
- return JSON.parseObject(json, (Type) bean.getClass());
- } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
- e.printStackTrace();
- return null;
- }
- }
- }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |