huminmin
2026-04-25 a85ac2fba03244c3e93a74e498681483e466dc08
src/main/java/com/ruoyi/basic/utils/FileUtil.java
@@ -1,7 +1,10 @@
package com.ruoyi.basic.utils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.dto.StorageAttachmentDTO;
import com.ruoyi.basic.dto.StorageAttachmentVO;
import com.ruoyi.basic.dto.StorageBlobDTO;
import com.ruoyi.basic.dto.StorageBlobVO;
@@ -52,9 +55,6 @@
     * @param storageBlobDTOS 文件信息
     */
    public void saveStorageAttachment(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, List<StorageBlobDTO> storageBlobDTOS) {
        if (CollectionUtils.isEmpty(storageBlobDTOS)) {
            throw new RuntimeException("文件信息不能为空");
        }
        if (application == null) {
            throw new RuntimeException("文件用途不能为空");
        }
@@ -66,6 +66,9 @@
        }
        // 删除旧附件信息
        deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId);
        if (CollectionUtils.isEmpty(storageBlobDTOS)) {
            return;
        }
        List<StorageAttachment> storageAttachments = new ArrayList<>();
        for (StorageBlobDTO storageBlobDTO : storageBlobDTOS) {
            StorageAttachment storageAttachment = new StorageAttachment();
@@ -74,6 +77,7 @@
            storageAttachment.setRecordId(recordId);
            storageAttachment.setStorageBlobId(storageBlobDTO.getId());
            storageAttachment.setDeleted(0L);
            storageAttachments.add(storageAttachment);
        }
        storageAttachmentMapper.insert(storageAttachments);
    }
@@ -103,10 +107,10 @@
     *
     * @param application 文件用途
     * @param recordType  关联记录类型
     * @param recordId    关联记录id
     * @param recordIds    关联记录id
     */
    public void deleteStorageBlobsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId) {
        if (recordId == null || recordId <= 0) {
    public void deleteStorageBlobsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum application, RecordTypeEnum recordType, List<Long> recordIds) {
        if (recordIds == null || recordIds.isEmpty()) {
            throw new RuntimeException("关联记录id不能为空");
        }
        if (application == null) {
@@ -117,7 +121,7 @@
        }
        List<StorageAttachment> storageAttachments = storageAttachmentMapper.selectList(new LambdaQueryWrapper<StorageAttachment>()
                .eq(StorageAttachment::getRecordType, recordType.getType())
                .eq(StorageAttachment::getRecordId, recordId)
                .in(StorageAttachment::getRecordId, recordIds)
                .eq(StorageAttachment::getApplication, application.getType()));
        if (CollectionUtils.isNotEmpty(storageAttachments)) {
            List<Long> storageAttachmentIds = storageAttachments.stream().map(StorageAttachment::getStorageBlobId)
@@ -136,6 +140,13 @@
        storageAttachmentMapper.deleteByIds(storageAttachmentIds);
    }
    /**
     * 删除文件关联信息
     *
     * @param application 文件用途
     * @param recordType  关联记录类型
     * @param recordId    关联记录id
     */
    public void deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId) {
        if (recordId == null || recordId <= 0) {
            throw new RuntimeException("关联记录id不能为空");
@@ -146,10 +157,34 @@
        if (recordType == null) {
            throw new RuntimeException("关联记录类型不能为空");
        }
        deleteStorageBlobsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId);
        deleteStorageBlobsByApplicationAndRecordTypeAndRecordIds(application, recordType, Arrays.asList(recordId));
        storageAttachmentMapper.delete(new LambdaQueryWrapper<StorageAttachment>()
                .eq(StorageAttachment::getRecordType, recordType.getType())
                .eq(StorageAttachment::getRecordId, recordId)
                .eq(StorageAttachment::getApplication, application.getType()));
    }
    /**
     * 批量删除文件关联信息 attachment
     *
     * @param application 文件用途
     * @param recordType  关联记录类型
     * @param recordIds   关联记录id
     */
    public void deleteStorageAttachmentsByApplicationAndRecordTypeAndRecordIds(ApplicationTypeEnum application, RecordTypeEnum recordType, List<Long> recordIds) {
        if (recordIds == null || recordIds.isEmpty()) {
            throw new RuntimeException("关联记录id不能为空");
        }
        if (application == null) {
            throw new RuntimeException("文件用途不能为空");
        }
        if (recordType == null) {
            throw new RuntimeException("关联记录类型不能为空");
        }
        deleteStorageBlobsByApplicationAndRecordTypeAndRecordIds(application, recordType, recordIds);
        storageAttachmentMapper.delete(new LambdaQueryWrapper<StorageAttachment>()
                .eq(StorageAttachment::getRecordType, recordType.getType())
                .in(StorageAttachment::getRecordId, recordIds)
                .eq(StorageAttachment::getApplication, application.getType()));
    }
@@ -163,6 +198,46 @@
            throw new RuntimeException("文件id不能为空");
        }
        return storageAttachmentMapper.selectByIds(storageAttachmentIds);
    }
    /**
     * 通过记录类型获取文件信息 attachment(分页)
     *
     * @param page       分页参数
     * @param storageAttachmentDTO 关联记录信息
     */
    public IPage<StorageAttachmentVO> getStorageAttachmentVosPageListByApplicationAndRecordTypeAndRecordId(Page page, StorageAttachmentDTO storageAttachmentDTO) {
        // 分页查询符合条件的 StorageAttachment 记录
        LambdaQueryWrapper<StorageAttachment> queryWrapper = new LambdaQueryWrapper<StorageAttachment>()
                .eq(StorageAttachment::getRecordType, storageAttachmentDTO.getRecordType())
                .eq(StorageAttachment::getRecordId, storageAttachmentDTO.getRecordId());
        if (storageAttachmentDTO.getApplication() != null) {
            queryWrapper.eq(StorageAttachment::getApplication, storageAttachmentDTO.getApplication());
        }
        IPage<StorageAttachmentVO> storageAttachmentIPage = storageAttachmentMapper.selectPage(page, queryWrapper);
        // 转换为 StorageAttachmentVO 并获取对应的 StorageBlobVO
        List<StorageAttachmentVO> storageAttachmentVOS = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(storageAttachmentIPage.getRecords())) {
            for (StorageAttachment storageAttachment : storageAttachmentIPage.getRecords()) {
                StorageAttachmentVO storageAttachmentVO = new StorageAttachmentVO();
                BeanUtils.copyProperties(storageAttachment, storageAttachmentVO);
                List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()));
                if (CollectionUtils.isEmpty(storageBlobVOS)) {
                    storageAttachmentVO.setStorageBlobVOS(new ArrayList<>());
                } else {
                    storageAttachmentVO.setStorageBlobVOS(storageBlobVOS);
                }
                storageAttachmentVOS.add(storageAttachmentVO);
            }
        }
        // 构建分页结果
        IPage<StorageAttachmentVO> resultPage = new Page<>();
        BeanUtils.copyProperties(storageAttachmentIPage, resultPage);
        resultPage.setRecords(storageAttachmentVOS);
        return resultPage;
    }
    /**
@@ -192,7 +267,7 @@
     *
     * @param storageAttachmentIds 文件id
     */
    public List<StorageBlobVO> getStorageBlobDTOsByStorageAttachmentIds(List<Long> storageAttachmentIds) {
    public List<StorageBlobVO> getStorageBlobVOsByStorageAttachmentIds(List<Long> storageAttachmentIds) {
        List<StorageAttachment> storageAttachments = getStorageAttachmentsByStorageAttachmentIds(storageAttachmentIds);
        if (CollectionUtils.isEmpty(storageAttachments)) {
            return null;
@@ -217,7 +292,7 @@
     * @param recordType  关联记录类型
     * @param recordId    关联记录id
     */
    public List<StorageBlobVO> getStorageBlobDTOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId) {
    public List<StorageBlobVO> getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId) {
        List<StorageAttachment> storageAttachments = getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId);
        if (CollectionUtils.isEmpty(storageAttachments)) {
            return null;
@@ -243,7 +318,7 @@
     * @param recordId    关联记录id
     * @param expired     过期时间
     */
    public List<StorageBlobVO> getStorageBlobDTOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, BigDecimal expired) {
    public List<StorageBlobVO> getStorageBlobVOsByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, BigDecimal expired) {
        List<StorageAttachment> storageAttachments = getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId);
        if (CollectionUtils.isEmpty(storageAttachments)) {
            return null;
@@ -267,7 +342,7 @@
     * @param storageAttachmentIds 文件id
     * @param expired              过期时间
     */
    public List<StorageBlobVO> getStorageBlobDTOsByStorageAttachmentIds(List<Long> storageAttachmentIds, BigDecimal expired) {
    public List<StorageBlobVO> getStorageBlobVOsByStorageAttachmentIds(List<Long> storageAttachmentIds, BigDecimal expired) {
        List<StorageAttachment> storageAttachments = getStorageAttachmentsByStorageAttachmentIds(storageAttachmentIds);
        if (CollectionUtils.isEmpty(storageAttachments)) {
            return null;
@@ -299,7 +374,7 @@
        for (StorageAttachment storageAttachment : storageAttachments) {
            StorageAttachmentVO storageAttachmentVO = new StorageAttachmentVO();
            BeanUtils.copyProperties(storageAttachment, storageAttachmentVO);
            List<StorageBlobVO> storageBlobVOS = getStorageBlobDTOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()));
            List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()));
            if (CollectionUtils.isEmpty(storageBlobVOS)) {
                storageAttachmentVO.setStorageBlobVOS(new ArrayList<>());
            } else {
@@ -325,7 +400,7 @@
        for (StorageAttachment storageAttachment : storageAttachments) {
            StorageAttachmentVO storageAttachmentVO = new StorageAttachmentVO();
            BeanUtils.copyProperties(storageAttachment, storageAttachmentVO);
            List<StorageBlobVO> storageBlobVOS = getStorageBlobDTOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()), expired);
            List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()), expired);
            if (CollectionUtils.isEmpty(storageBlobVOS)) {
                storageAttachmentVO.setStorageBlobVOS(new ArrayList<>());
            } else {
@@ -352,7 +427,7 @@
        for (StorageAttachment storageAttachment : storageAttachments) {
            StorageAttachmentVO storageAttachmentVO = new StorageAttachmentVO();
            BeanUtils.copyProperties(storageAttachment, storageAttachmentVO);
            List<StorageBlobVO> storageBlobVOS = getStorageBlobDTOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()));
            List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()));
            if (CollectionUtils.isEmpty(storageBlobVOS)) {
                storageAttachmentVO.setStorageBlobVOS(new ArrayList<>());
            } else {
@@ -380,7 +455,7 @@
        for (StorageAttachment storageAttachment : storageAttachments) {
            StorageAttachmentVO storageAttachmentVO = new StorageAttachmentVO();
            BeanUtils.copyProperties(storageAttachment, storageAttachmentVO);
            List<StorageBlobVO> storageBlobVOS = getStorageBlobDTOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()), expired);
            List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(Collections.singletonList(storageAttachment.getId()), expired);
            if (CollectionUtils.isEmpty(storageBlobVOS)) {
                storageAttachmentVO.setStorageBlobVOS(new ArrayList<>());
            } else {
@@ -398,7 +473,7 @@
     */
    public List<String> getFilePreviewURLByStorageAttachmentIds(List<Long> storageAttachmentIds) {
        List<String> res = new ArrayList<>();
        List<StorageBlobVO> storageBlobVOS = getStorageBlobDTOsByStorageAttachmentIds(storageAttachmentIds);
        List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(storageAttachmentIds);
        for (StorageBlobVO storageBlobVO : storageBlobVOS) {
            res.add(buildSignedPreviewUrl(storageBlobVO));
        }
@@ -413,7 +488,7 @@
     */
    public List<String> getFilePreviewURLByStorageAttachmentIds(List<Long> storageAttachmentIds, BigDecimal expired) {
        List<String> res = new ArrayList<>();
        List<StorageBlobVO> storageBlobVOS = getStorageBlobDTOsByStorageAttachmentIds(storageAttachmentIds);
        List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(storageAttachmentIds);
        for (StorageBlobVO storageBlobVO : storageBlobVOS) {
            res.add(buildSignedUrl(storageBlobVO, "/preview/", expired));
        }
@@ -427,7 +502,7 @@
     */
    public List<String> getFileDownloadURLByStorageAttachmentIds(List<Long> storageAttachmentIds) {
        List<String> res = new ArrayList<>();
        List<StorageBlobVO> storageBlobVOS = getStorageBlobDTOsByStorageAttachmentIds(storageAttachmentIds);
        List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(storageAttachmentIds);
        for (StorageBlobVO storageBlobVO : storageBlobVOS) {
            res.add(buildSignedDownloadUrl(storageBlobVO));
        }
@@ -442,13 +517,75 @@
     */
    public List<String> getFileDownloadURLByStorageAttachmentIds(List<Long> storageAttachmentIds, BigDecimal expired) {
        List<String> res = new ArrayList<>();
        List<StorageBlobVO> storageBlobVOS = getStorageBlobDTOsByStorageAttachmentIds(storageAttachmentIds);
        List<StorageBlobVO> storageBlobVOS = getStorageBlobVOsByStorageAttachmentIds(storageAttachmentIds);
        for (StorageBlobVO storageBlobVO : storageBlobVOS) {
            res.add(buildSignedUrl(storageBlobVO, "/download/", expired));
        }
        return res;
    }
    /**
     * 通过文件关联id获取文件预览地址
     *
     * @param application 应用
     * @param recordType  记录类型
     * @param recordId    记录id
     */
    public List<String> getFilePreviewURLByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId) {
        List<StorageAttachment> storageAttachments = getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId);
        if (CollectionUtils.isEmpty(storageAttachments)) {
            return new ArrayList<>();
        }
        return getFilePreviewURLByStorageAttachmentIds(storageAttachments.stream().map(StorageAttachment::getId).collect(Collectors.toList()));
    }
    /**
     * 通过文件关联id获取文件预览地址存在过期时间
     *
     * @param application 应用
     * @param recordType  记录类型
     * @param recordId    记录id
     * @param expired     过期时间(分钟)
     */
    public List<String> getFilePreviewURLByApplicationAndRecordTypeAndRecordIdAndExpired(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, BigDecimal expired) {
        List<StorageAttachment> storageAttachments = getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId);
        if (CollectionUtils.isEmpty(storageAttachments)) {
            return new ArrayList<>();
        }
        return getFilePreviewURLByStorageAttachmentIds(storageAttachments.stream().map(StorageAttachment::getId).collect(Collectors.toList()), expired);
    }
    /**
     * 通过文件关联id获取文件下载地址
     *
     * @param application 应用
     * @param recordType  记录类型
     * @param recordId    记录id
     */
    public List<String> getFileDownloadURLByApplicationAndRecordTypeAndRecordId(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId) {
        List<StorageAttachment> storageAttachments = getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId);
        if (CollectionUtils.isEmpty(storageAttachments)) {
            return new ArrayList<>();
        }
        return getFileDownloadURLByStorageAttachmentIds(storageAttachments.stream().map(StorageAttachment::getId).collect(Collectors.toList()));
    }
    /**
     * 通过文件关联id获取文件下载地址存在过期时间
     *
     * @param application 应用
     * @param recordType  记录类型
     * @param recordId    记录id
     * @param expired     过期时间(分钟)
     */
    public List<String> getFileDownloadURLByApplicationAndRecordTypeAndRecordIdAndExpired(ApplicationTypeEnum application, RecordTypeEnum recordType, Long recordId, BigDecimal expired) {
        List<StorageAttachment> storageAttachments = getStorageAttachmentsByApplicationAndRecordTypeAndRecordId(application, recordType, recordId);
        if (CollectionUtils.isEmpty(storageAttachments)) {
            return new ArrayList<>();
        }
        return getFileDownloadURLByStorageAttachmentIds(storageAttachments.stream().map(StorageAttachment::getId).collect(Collectors.toList()), expired);
    }
    public String buildSignedPreviewUrl(StorageBlobVO storageBlob) {
        return buildSignedUrl(storageBlob, "/preview/", properties.getExpired());
    }