liu
13 小时以前 5d34bdd3c426bb2ca5f6627424ae67984f745603
yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/util/storage/StorageFileUtil.java
@@ -23,6 +23,7 @@
import javax.crypto.SecretKey;
import java.io.File;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@@ -41,7 +42,7 @@
 * - token使用次数控制(Redis)
 * - 图片压缩
 *
 * @author 芋道源码
 * @author 超级管理员
 */
@Component
@RequiredArgsConstructor
@@ -104,21 +105,20 @@
            throw new IllegalArgumentException("关联记录id不能为空");
        }
        // 删除旧附件信息
        // 只删除旧的附件关联记录,保留 blob 记录(文件本身不删除)
        if (application == null || application.trim().isEmpty()) {
            for (SystemStorageAttachmentSaveReqVO.BlobItem item : blobItems) {
                String itemApp = item.getApplication();
                if (itemApp == null || itemApp.trim().isEmpty()) {
                    throw new IllegalArgumentException("文件用途不能为空");
                }
                deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordId(itemApp, recordType.getType(), recordId);
                storageAttachmentMapper.deleteByApplicationAndRecordTypeAndRecordId(itemApp, recordType.getType(), recordId);
            }
        } else {
            deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType.getType(), recordId);
            storageAttachmentMapper.deleteByApplicationAndRecordTypeAndRecordId(application, recordType.getType(), recordId);
        }
        if (CollUtil.isEmpty(blobItems)) {
            deleteStorageAttachmentsByRecordTypeAndRecordId(recordType.getType(), recordId);
            return;
        }
@@ -279,7 +279,8 @@
        List<SystemStorageAttachmentDO> attachments = getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(
                application, recordType, recordId);
        if (CollUtil.isEmpty(attachments)) {
            return null;
            // 返回空集合而非 null:调用方常把它直接塞进 Collectors.toMap 做分组(value 为 null 会抛 NPE)
            return new ArrayList<>();
        }
        Map<Long, Long> blobIdToAttachmentIdMap = attachments.stream()
                .collect(Collectors.toMap(SystemStorageAttachmentDO::getStorageBlobId, SystemStorageAttachmentDO::getId));
@@ -303,7 +304,8 @@
    public List<SystemStorageBlobRespVO> getStorageBlobVOsByRecordTypeAndRecordId(String recordType, Long recordId) {
        List<SystemStorageAttachmentDO> attachments = getStorageAttachmentsByRecordTypeAndRecordId(recordType, recordId);
        if (CollUtil.isEmpty(attachments)) {
            return null;
            // 返回空集合而非 null,避免调用方直接使用返回值时抛 NPE
            return new ArrayList<>();
        }
        List<Long> storageBlobIds = attachments.stream()
                .map(SystemStorageAttachmentDO::getStorageBlobId)
@@ -460,7 +462,10 @@
        }
        String domain = StringUtils.trimTrailingCharacter(properties.getDomain(), '/');
        String prefix = properties.getUrlPrefix().startsWith("/") ? properties.getUrlPrefix() : "/" + properties.getUrlPrefix();
        String baseUrl = domain + prefix + actionPath + uidFilename;
        // 文件名可能包含中文、空格等字符,必须编码后再拼接到 URL,否则部分客户端/容器会直接返回 400
        String encodedUidFilename = URLEncoder.encode(uidFilename, StandardCharsets.UTF_8)
                .replace("+", "%20");
        String baseUrl = domain + prefix + actionPath + encodedUidFilename;
        // -1 表示永久有效,不生成 token,改为 publicKey 组合校验
        if (expired != null && BigDecimal.valueOf(-1L).compareTo(expired) == 0) {