package com.ruoyi.basic.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.basic.dto.StorageBlobVO; import com.ruoyi.basic.mapper.StorageBlobMapper; import com.ruoyi.basic.pojo.StorageBlob; import com.ruoyi.basic.service.StorageBlobService; import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.common.config.FileProperties; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.security.Keys; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; 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.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.UUID; /** *

* 通用文件上传的附件信息 服务实现类 *

* */ @Service @RequiredArgsConstructor public class StorageBlobServiceImpl extends ServiceImpl implements StorageBlobService { private final FileProperties properties; private final StorageBlobMapper storageBlobMapper; private final FileUtil fileUtil; @Override public List upload(List files) { if (CollectionUtils.isEmpty(files)) { throw new IllegalArgumentException("文件不能为空"); } List storageBlobVOS = new ArrayList<>(); for (MultipartFile file : files) { if (file == null || file.isEmpty()) { throw new IllegalArgumentException("文件不能为空"); } 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 new RuntimeException("创建上传目录失败"); } File dest = new File(targetDirectory, fileName); StorageBlobVO storageBlob; try { file.transferTo(dest); storageBlob = getStorageBlob(file, originalFileName, fileName, relativePath); if (storageBlob == null || storageBlob.getId() == null) { throw new RuntimeException("文件元数据保存失败"); } } catch (RuntimeException e) { if (dest.exists()) { dest.delete(); } throw e; } catch (IOException e) { throw new RuntimeException("文件保存失败", e); } storageBlobVOS.add(storageBlob); } return storageBlobVOS; } @Override public File getFileByToken(String fileName, String token) { if (!StringUtils.hasText(token)) { throw new IllegalArgumentException("token不能为空"); } String secretStr = StringUtils.hasText(properties.getJwtSecret()) ? properties.getJwtSecret() : "local-file-jwt-secret"; SecretKey key = Keys.hmacShaKeyFor(secretStr.getBytes(StandardCharsets.UTF_8)); Claims claims = Jwts.parser() .verifyWith(key) // 代替旧版的 setSigningKey .build() // 必须先构建解析器 .parseSignedClaims(token) // 代替旧版的 parseClaimsJws .getPayload(); // 代替旧版的 getBody() if (!fileName.equals(claims.getSubject())) { throw new IllegalArgumentException("token与文件不匹配"); } fileUtil.validateTokenUsage(token); StorageBlob storageBlob = findStorageBlob(fileName); String path = storageBlob == null ? claims.get("path", String.class) : storageBlob.getPath(); if (!StringUtils.hasText(path)) { return new File(properties.getPath(), fileName); } return new File(new File(properties.getPath(), path), fileName); } private StorageBlob findStorageBlob(String fileName) { return storageBlobMapper.selectOne(new LambdaQueryWrapper() .eq(StorageBlob::getUidFilename, fileName) .last("limit 1")); } private StorageBlobVO getStorageBlob(MultipartFile file, String originalFileName, String fileName, String relativePath) { StorageBlobVO storageBlob = new StorageBlobVO(); storageBlob.setResourceKey(UUID.randomUUID().toString().replace("-", "")); storageBlob.setContentType(file.getContentType()); storageBlob.setOriginalFilename(originalFileName); storageBlob.setUidFilename(fileName); storageBlob.setByteSize(file.getSize()); storageBlob.setPath(relativePath); storageBlob.setPreviewURL(fileUtil.buildSignedPreviewUrl(storageBlob)); storageBlob.setDownloadURL(fileUtil.buildSignedDownloadUrl(storageBlob)); int affectedRows = storageBlobMapper.insert(storageBlob); if (affectedRows <= 0) { throw new RuntimeException("文件元数据保存失败"); } return storageBlob; } @Override public String getDownloadFileName(String fileName) { StorageBlob storageBlob = findStorageBlob(fileName); if (storageBlob == null || !StringUtils.hasText(storageBlob.getOriginalFilename())) { return fileName; } return storageBlob.getOriginalFilename(); } }