package cn.iocoder.yudao.module.system.service.storage;
|
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.system.controller.admin.storage.vo.SystemStorageBlobRespVO;
|
import cn.iocoder.yudao.module.system.dal.dataobject.storage.SystemStorageBlobDO;
|
import cn.iocoder.yudao.module.system.dal.mysql.storage.SystemStorageBlobMapper;
|
import cn.iocoder.yudao.module.system.framework.storage.config.StorageProperties;
|
import cn.iocoder.yudao.module.system.util.storage.StorageFileUtil;
|
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Jwts;
|
import io.jsonwebtoken.security.Keys;
|
import jakarta.annotation.Resource;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
import org.springframework.util.StringUtils;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import javax.crypto.SecretKey;
|
import java.io.File;
|
import java.io.IOException;
|
import java.math.BigDecimal;
|
import java.nio.charset.StandardCharsets;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.UUID;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
|
|
/**
|
* 文件主表 Service 实现类
|
*
|
* @author 芋道源码
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class SystemStorageBlobServiceImpl implements SystemStorageBlobService {
|
|
private final StorageProperties properties;
|
@Resource
|
private SystemStorageBlobMapper storageBlobMapper;
|
private final StorageFileUtil fileUtil;
|
|
@Override
|
public List<SystemStorageBlobRespVO> upload(List<MultipartFile> files, Boolean isPublic) {
|
if (files == null || files.isEmpty()) {
|
throw exception(STORAGE_FILE_EMPTY);
|
}
|
|
List<SystemStorageBlobRespVO> result = new ArrayList<>();
|
|
for (MultipartFile file : files) {
|
if (file == null || file.isEmpty()) {
|
throw exception(STORAGE_FILE_EMPTY);
|
}
|
|
String originalFileName = StringUtils.hasText(file.getOriginalFilename())
|
? StringUtils.cleanPath(file.getOriginalFilename())
|
: UUID.randomUUID().toString();
|
String fileName = UUID.randomUUID() + "_" + originalFileName;
|
String relativePath = fileUtil.buildRelativePath();
|
File targetDirectory = new File(properties.getPath(), relativePath);
|
if (!targetDirectory.exists() && !targetDirectory.mkdirs()) {
|
throw exception(STORAGE_BLOB_UPLOAD_FAILED);
|
}
|
File dest = new File(targetDirectory, fileName);
|
|
SystemStorageBlobRespVO blobRespVO;
|
try {
|
file.transferTo(dest);
|
blobRespVO = createStorageBlob(file, originalFileName, fileName, relativePath, isPublic);
|
if (blobRespVO == null || blobRespVO.getId() == null) {
|
throw exception(STORAGE_BLOB_UPLOAD_FAILED);
|
}
|
} catch (RuntimeException e) {
|
if (dest.exists()) {
|
dest.delete();
|
}
|
throw e;
|
} catch (IOException e) {
|
throw exception(STORAGE_BLOB_UPLOAD_FAILED);
|
}
|
|
result.add(blobRespVO);
|
}
|
return result;
|
}
|
|
@Override
|
public File getFileByToken(String fileName, String token) {
|
if (!StringUtils.hasText(token)) {
|
throw exception(STORAGE_BLOB_TOKEN_INVALID);
|
}
|
|
String secretStr = properties.getJwtSecret();
|
SecretKey key = Keys.hmacShaKeyFor(secretStr.getBytes(StandardCharsets.UTF_8));
|
Claims claims;
|
try {
|
claims = Jwts.parser()
|
.verifyWith(key)
|
.build()
|
.parseSignedClaims(token)
|
.getPayload();
|
} catch (Exception e) {
|
throw exception(STORAGE_BLOB_TOKEN_INVALID);
|
}
|
if (!fileName.equals(claims.getSubject())) {
|
throw exception(STORAGE_BLOB_TOKEN_MISMATCH);
|
}
|
fileUtil.validateTokenUsage(token);
|
|
SystemStorageBlobDO blob = storageBlobMapper.selectByUidFilename(fileName);
|
String path = blob == null ? claims.get("path", String.class) : blob.getPath();
|
if (!StringUtils.hasText(path)) {
|
return new File(properties.getPath(), fileName);
|
}
|
return new File(new File(properties.getPath(), path), fileName);
|
}
|
|
@Override
|
public File getPublicFile(String fileName, String publicKey) {
|
if (!StringUtils.hasText(fileName)) {
|
throw exception(STORAGE_BLOB_NOT_EXISTS);
|
}
|
if (!StringUtils.hasText(publicKey)) {
|
throw exception(STORAGE_BLOB_PUBLIC_KEY_INVALID);
|
}
|
SystemStorageBlobDO blob = storageBlobMapper.selectByUidFilenameAndResourceKey(fileName, publicKey);
|
if (blob == null) {
|
throw exception(STORAGE_BLOB_PUBLIC_KEY_INVALID);
|
}
|
String path = blob.getPath();
|
if (!StringUtils.hasText(path)) {
|
return new File(properties.getPath(), fileName);
|
}
|
return new File(new File(properties.getPath(), path), fileName);
|
}
|
|
@Override
|
public String getDownloadFileName(String fileName) {
|
SystemStorageBlobDO blob = storageBlobMapper.selectByUidFilename(fileName);
|
if (blob == null || !StringUtils.hasText(blob.getOriginalFilename())) {
|
return fileName;
|
}
|
return blob.getOriginalFilename();
|
}
|
|
@Override
|
public SystemStorageBlobDO getStorageBlob(Long id) {
|
return storageBlobMapper.selectById(id);
|
}
|
|
@Override
|
public void deleteStorageBlobs(List<Long> ids) {
|
fileUtil.deleteStorageBlobs(ids);
|
}
|
|
private SystemStorageBlobRespVO createStorageBlob(MultipartFile file, String originalFileName,
|
String fileName, String relativePath, Boolean isPublic) {
|
SystemStorageBlobDO blob = new SystemStorageBlobDO();
|
blob.setResourceKey(UUID.randomUUID().toString().replace("-", ""));
|
blob.setContentType(file.getContentType());
|
blob.setOriginalFilename(originalFileName);
|
blob.setUidFilename(fileName);
|
blob.setByteSize(file.getSize());
|
blob.setPath(relativePath);
|
storageBlobMapper.insert(blob);
|
|
// 构建返回 VO
|
SystemStorageBlobRespVO respVO = BeanUtils.toBean(blob, SystemStorageBlobRespVO.class);
|
if (Boolean.TRUE.equals(isPublic)) {
|
respVO.setPreviewURL(fileUtil.buildSignedUrl(blob, "/preview/", BigDecimal.valueOf(-1)));
|
respVO.setDownloadURL(fileUtil.buildSignedUrl(blob, "/download/", BigDecimal.valueOf(-1)));
|
} else {
|
respVO.setPreviewURL(fileUtil.buildSignedPreviewUrl(blob));
|
respVO.setUrl(fileUtil.buildSignedPreviewUrl(blob));
|
respVO.setName(blob.getOriginalFilename());
|
respVO.setDownloadURL(fileUtil.buildSignedDownloadUrl(blob));
|
}
|
return respVO;
|
}
|
|
}
|