|
|
@@ -1,12 +1,15 @@
|
|
|
package cn.reghao.tnb.file.app.service;
|
|
|
|
|
|
import cn.reghao.jutil.jdk.security.DigestUtil;
|
|
|
-import cn.reghao.tnb.file.app.util.redis.RedisKey;
|
|
|
-import cn.reghao.tnb.file.app.util.redis.ds.RedisSet;
|
|
|
-import cn.reghao.tnb.file.app.config.PathUrl;
|
|
|
+import cn.reghao.tnb.file.app.model.vo.FileMap;
|
|
|
+import cn.reghao.tnb.file.app.model.vo.UploadFilePartRet;
|
|
|
+import cn.reghao.tnb.file.app.model.vo.UploadFileRet;
|
|
|
+import cn.reghao.tnb.file.app.model.vo.UploadPrepareRet;
|
|
|
+import cn.reghao.tnb.file.app.model.dto.PathUrl;
|
|
|
import cn.reghao.tnb.file.app.db.repository.FileRepository;
|
|
|
import cn.reghao.tnb.file.app.model.dto.*;
|
|
|
import cn.reghao.tnb.file.app.model.po.FileInfo;
|
|
|
+import cn.reghao.tnb.file.app.util.StringUtil;
|
|
|
import cn.reghao.tnb.file.app.util.media.ImageOps;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
@@ -14,6 +17,10 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
import org.springframework.web.multipart.MultipartFile;
|
|
|
|
|
|
import java.io.*;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.HashSet;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Set;
|
|
|
|
|
|
/**
|
|
|
* @author reghao
|
|
|
@@ -29,22 +36,20 @@ public class FileUploadService {
|
|
|
private final FileStoreService fileStoreService;
|
|
|
private final FileTypeService fileTypeService;
|
|
|
private final FileRepository fileRepository;
|
|
|
- private final RedisSet redisSet;
|
|
|
+ private Map<String, Set<Integer>> map = new HashMap<>();
|
|
|
|
|
|
public FileUploadService(FileUrlService fileUrlService, FileStoreService fileStoreService,
|
|
|
- FileTypeService fileTypeService, FileRepository fileRepository,
|
|
|
- RedisSet redisSet) {
|
|
|
+ FileTypeService fileTypeService, FileRepository fileRepository) {
|
|
|
this.fileUrlService = fileUrlService;
|
|
|
this.fileStoreService = fileStoreService;
|
|
|
this.fileTypeService = fileTypeService;
|
|
|
this.fileRepository = fileRepository;
|
|
|
- this.redisSet = redisSet;
|
|
|
}
|
|
|
|
|
|
public synchronized UploadPrepareRet prepareUpload(UploadPrepare uploadPrepare) {
|
|
|
// TODO 避免用户通过 sha256sum 查询文件是否存在, 这是一个不安全的行为, 用户可能会伪造 sha256sum 来获取不属于他权限的文件
|
|
|
// TODO 解决办法是检查用户已上传文件的 sha256sum, 这样可确保他拥有 sha256sum 所属文件的权限, 但这会带来服务器带宽和磁盘 IO 的性能开销
|
|
|
- String sha256sum = uploadPrepare.getFileSha256sum();
|
|
|
+ String sha256sum = uploadPrepare.getSha256sum();
|
|
|
FileInfo fileInfo = fileRepository.getFileInfo(sha256sum);
|
|
|
if (fileInfo == null) {
|
|
|
String uploadId = fileRepository.createFileUploadId(uploadPrepare);
|
|
|
@@ -64,16 +69,18 @@ public class FileUploadService {
|
|
|
* @return
|
|
|
* @date 2021-12-08 下午3:30
|
|
|
*/
|
|
|
- public void putFile(UploadFile uploadFile) throws Exception {
|
|
|
+ public PathUrl putFile(UploadFile uploadFile) throws Exception {
|
|
|
String uploadId = uploadFile.getUploadId();
|
|
|
FileInfo fileInfo = fileRepository.getFileInfoByUploadId(uploadId);
|
|
|
if (!fileInfo.getUploaded()) {
|
|
|
- put(uploadFile.getFile(), fileInfo, uploadId);
|
|
|
+ return put(uploadFile.getFile(), fileInfo, uploadId);
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
- public synchronized String put(MultipartFile multipartFile, FileInfo fileInfo, String uploadId) throws Exception {
|
|
|
+ public synchronized PathUrl put(MultipartFile multipartFile, FileInfo fileInfo, String uploadId) throws Exception {
|
|
|
byte[] bytes = multipartFile.getBytes();
|
|
|
long size = multipartFile.getSize();
|
|
|
String sha256sum = DigestUtil.sha256sum(bytes);
|
|
|
@@ -84,19 +91,47 @@ public class FileUploadService {
|
|
|
String contentType = multipartFile.getContentType();
|
|
|
String fileId = fileInfo.getFileId();
|
|
|
String suffix = fileInfo.getSuffix();
|
|
|
- PathUrl pathUrl;
|
|
|
- if (contentType != null && contentType.startsWith("image")) {
|
|
|
+ PathUrl pathUrl = fileUrlService.genPathUrl(contentType, sha256sum, size, fileId, suffix, uploadId);
|
|
|
+
|
|
|
+ /*if (contentType != null && contentType.startsWith("image")) {
|
|
|
ImageOps.Size size1 = ImageOps.info(new ByteArrayInputStream(bytes));
|
|
|
- pathUrl = fileUrlService.getImagePathAndUrl(sha256sum, uploadId, size, fileId, suffix,
|
|
|
+ fileUrlService.getImagePathAndUrl(sha256sum, uploadId, size, fileId, suffix,
|
|
|
size1.getWidth(), size1.getHeight());
|
|
|
- } else {
|
|
|
- pathUrl = fileUrlService.genVideoPathAndUrl(sha256sum, uploadId, size, fileId, suffix);
|
|
|
- }
|
|
|
+ }*/
|
|
|
|
|
|
FileContentType fileType = fileTypeService.getFileType(contentType, pathUrl.getFilePath());
|
|
|
fileStoreService.saveFile(pathUrl.getFilePath(), bytes);
|
|
|
fileRepository.saveFile(fileId, fileType, pathUrl);
|
|
|
- return pathUrl.getUrl();
|
|
|
+ return pathUrl;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ public synchronized UploadFileRet put(UploadedFile uploadedFile) throws Exception {
|
|
|
+ byte[] bytes = uploadedFile.getInputStream().readAllBytes();
|
|
|
+ String sha256sum = DigestUtil.sha256sum(bytes);
|
|
|
+ FileInfo fileInfo = fileRepository.getFileInfo(sha256sum);
|
|
|
+ if (fileInfo != null) {
|
|
|
+ String fileId = fileInfo.getFileId();
|
|
|
+ String uploadId = fileRepository.getOrCreateUploadId(fileInfo.getFileId());
|
|
|
+ String url = fileRepository.getPathUrlByFileId(fileId);
|
|
|
+ return new UploadFileRet(uploadId, url);
|
|
|
+ } else {
|
|
|
+ int size = bytes.length;
|
|
|
+ String filename = uploadedFile.getFilename();
|
|
|
+ String suffix = StringUtil.getSuffix(filename);
|
|
|
+ String contentType = uploadedFile.getContentType();
|
|
|
+ FileMap fileMap = fileRepository.createUploadId(uploadedFile, sha256sum, size);
|
|
|
+
|
|
|
+ String fileId = fileMap.getFileId();
|
|
|
+ String uploadId = fileMap.getUploadId();
|
|
|
+ PathUrl pathUrl = fileUrlService.genPathUrl(contentType, sha256sum, size, fileId, suffix, uploadId);
|
|
|
+ FileContentType fileType = fileTypeService.getFileType(contentType, pathUrl.getFilePath());
|
|
|
+ fileStoreService.saveFile(pathUrl.getFilePath(), bytes);
|
|
|
+ fileRepository.saveFile(fileId, fileType, pathUrl);
|
|
|
+
|
|
|
+ String url = pathUrl.getUrl();
|
|
|
+ return new UploadFileRet(uploadId, url);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -121,18 +156,18 @@ public class FileUploadService {
|
|
|
String fileId = fileInfo.getFileId();
|
|
|
String sha256sum = fileInfo.getSha256sum();
|
|
|
String suffix = fileInfo.getSuffix();
|
|
|
- PathUrl pathUrl = fileUrlService.genPathAndUrl(sha256sum, fileId, suffix);
|
|
|
- String key = RedisKey.filePartKey(fileId);
|
|
|
- if (!redisSet.sismember(key, partIndex)) {
|
|
|
- redisSet.sadd(key, partIndex);
|
|
|
-
|
|
|
+ @Deprecated
|
|
|
+ PathUrl pathUrl = fileUrlService.genPathAndUrl(sha256sum, 0, fileId, suffix, null);
|
|
|
+ Set<Integer> set = map.computeIfAbsent(fileId, k -> new HashSet<>());
|
|
|
+ if (!set.contains(partIndex)) {
|
|
|
+ set.add(partIndex);
|
|
|
long size = fileInfo.getSize();
|
|
|
File file = fileStoreService.createFile(pathUrl.getFilePath(), size);
|
|
|
long pos = partIndex * PART_SIZE;
|
|
|
fileStoreService.writeToFile(multipartFile.getInputStream(), file, pos);
|
|
|
}
|
|
|
|
|
|
- long len = redisSet.scard(key);
|
|
|
+ long len = set.size();
|
|
|
if (len != partNum) {
|
|
|
return new UploadFilePartRet(fileId, false);
|
|
|
} else {
|
|
|
@@ -145,7 +180,7 @@ public class FileUploadService {
|
|
|
|
|
|
FileContentType fileType = fileTypeService.getFileType(fileInfo.getContentType(), pathUrl.getFilePath());
|
|
|
fileRepository.saveFile(fileId, fileType, pathUrl);
|
|
|
- redisSet.spop(key, len);
|
|
|
+ map.remove(fileId);
|
|
|
return new UploadFilePartRet(uploadId, true);
|
|
|
}
|
|
|
}
|