1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
|
@Service @Slf4j public class ChunkUploadService { @Autowired private MinioClient minioClient; @Autowired private RedisTemplate<String, Object> redisTemplate; @Autowired private FileUploadRepository fileUploadRepository; @Autowired private ChunkInfoRepository chunkInfoRepository; private static final long CHUNK_SIZE = 5 * 1024 * 1024;
@Transactional public void uploadChunk(ChunkUploadRequest request) { String fileMd5 = request.getFileMd5(); int chunkIndex = request.getChunkIndex(); String userId = request.getUserId(); if (isChunkUploaded(fileMd5, chunkIndex, userId)) { log.info("分片已上传,跳过处理: fileMd5={}, chunkIndex={}", fileMd5, chunkIndex); return; } String chunkMd5 = calculateChunkMd5(request.getFile().getBytes()); String storagePath = String.format("chunks/%s/%s/%d", userId, fileMd5, chunkIndex); try { minioClient.putObject( PutObjectArgs.builder() .bucket("uploads") .object(storagePath) .stream(request.getFile().getInputStream(), request.getFile().getSize(), -1) .contentType(request.getFile().getContentType()) .build() ); markChunkUploaded(fileMd5, chunkIndex, userId); saveChunkInfo(fileMd5, chunkIndex, chunkMd5, storagePath); log.info("分片上传成功: fileMd5={}, chunkIndex={}", fileMd5, chunkIndex); } catch (Exception e) { log.error("分片上传失败: fileMd5={}, chunkIndex={}", fileMd5, chunkIndex, e); throw new ChunkUploadException("分片上传失败", e); } }
public boolean isChunkUploaded(String fileMd5, int chunkIndex, String userId) { String redisKey = String.format("upload:%s:%s", userId, fileMd5); return Boolean.TRUE.equals( redisTemplate.opsForValue().getBit(redisKey, chunkIndex) ); }
public void markChunkUploaded(String fileMd5, int chunkIndex, String userId) { String redisKey = String.format("upload:%s:%s", userId, fileMd5); redisTemplate.opsForValue().setBit(redisKey, chunkIndex, true); redisTemplate.expire(redisKey, 7, TimeUnit.DAYS); }
public List<Integer> getUploadedChunks(String fileMd5, String userId) { String redisKey = String.format("upload:%s:%s", userId, fileMd5); int totalChunks = getTotalChunks(fileMd5, userId); List<Boolean> statusList = redisTemplate.executePipelined( (RedisCallback<Object>) connection -> { for (int i = 0; i < totalChunks; i++) { connection.getBit(redisKey.getBytes(), i); } return null; } ).stream() .map(obj -> (Boolean) obj) .collect(Collectors.toList()); List<Integer> uploadedChunks = new ArrayList<>(); for (int i = 0; i < statusList.size(); i++) { if (Boolean.TRUE.equals(statusList.get(i))) { uploadedChunks.add(i); } } return uploadedChunks; } }
|