package com.ruoyi.basic.service.impl; 
 | 
  
 | 
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; 
 | 
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; 
 | 
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; 
 | 
import com.ruoyi.basic.dto.StorageBlobDTO; 
 | 
import com.ruoyi.basic.mapper.StorageAttachmentMapper; 
 | 
import com.ruoyi.basic.mapper.StorageBlobMapper; 
 | 
import com.ruoyi.basic.pojo.StorageAttachment; 
 | 
import com.ruoyi.basic.pojo.StorageBlob; 
 | 
import com.ruoyi.basic.service.StorageBlobService; 
 | 
import com.ruoyi.common.exception.base.BaseException; 
 | 
import com.ruoyi.common.exception.file.InvalidExtensionException; 
 | 
import com.ruoyi.common.utils.DateUtils; 
 | 
import com.ruoyi.common.utils.MinioUtils; 
 | 
import com.ruoyi.common.utils.StringUtils; 
 | 
import com.ruoyi.common.utils.uuid.IdUtils; 
 | 
import com.ruoyi.framework.web.domain.MinioResult; 
 | 
import lombok.RequiredArgsConstructor; 
 | 
import org.apache.commons.io.FilenameUtils; 
 | 
import org.springframework.beans.factory.annotation.Autowired; 
 | 
import org.springframework.stereotype.Service; 
 | 
import org.springframework.util.CollectionUtils; 
 | 
import org.springframework.web.multipart.MultipartFile; 
 | 
  
 | 
import java.time.LocalDateTime; 
 | 
import java.util.ArrayList; 
 | 
import java.util.Arrays; 
 | 
import java.util.List; 
 | 
import java.util.stream.Collectors; 
 | 
  
 | 
/** 
 | 
 * <p> 
 | 
 * 通用文件上传的附件信息 服务实现类 
 | 
 * </p> 
 | 
 * 
 | 
 * @author ruoyi 
 | 
 * @since 2025-05-29 
 | 
 */ 
 | 
@Service 
 | 
@RequiredArgsConstructor 
 | 
public class StorageBlobServiceImpl extends ServiceImpl<StorageBlobMapper, StorageBlob> implements StorageBlobService { 
 | 
    @Autowired 
 | 
    private StorageAttachmentMapper storageAttachmentMapper; 
 | 
  
 | 
    @Autowired 
 | 
    private StorageBlobMapper storageBlobMapper; 
 | 
  
 | 
    @Autowired 
 | 
    private MinioUtils minioUtils; 
 | 
  
 | 
    @Override 
 | 
    public List<StorageBlobDTO> updateStorageBlobs(List<MultipartFile> files, String bucketName) { 
 | 
  
 | 
        // 若没传入bucketName,则使用默认bucketName 
 | 
        if (StringUtils.isEmpty(bucketName)) { 
 | 
            bucketName  = minioUtils.getDefaultBucket(); 
 | 
        } 
 | 
  
 | 
        List<StorageBlobDTO> storageBlobDTOs = new ArrayList<>(); 
 | 
        for (MultipartFile file : files) { 
 | 
            try { 
 | 
                MinioResult res = minioUtils.upload(bucketName, file, false); 
 | 
                StorageBlobDTO dto = new StorageBlobDTO(); 
 | 
                dto.setContentType(file.getContentType()); 
 | 
                dto.setBucketFilename(res.getBucketFileName()); 
 | 
                dto.setOriginalFilename(res.getOriginalName()); 
 | 
                dto.setByteSize(file.getSize()); 
 | 
                dto.setResourceKey(IdUtils.simpleUUID()); 
 | 
                dto.setBucketName(bucketName); 
 | 
                dto.setUrl(minioUtils.getPreviewUrl(res.getBucketFileName(), bucketName, false)); 
 | 
                // 插入数据库 
 | 
                storageBlobMapper.insert(dto); 
 | 
  
 | 
                storageBlobDTOs.add(dto); 
 | 
            } catch (InvalidExtensionException e) { 
 | 
                throw new RuntimeException("minio文件上传异常:" +  e); 
 | 
            } 
 | 
        } 
 | 
  
 | 
  
 | 
        return storageBlobDTOs; 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public List<StorageBlobDTO> updateStorageBlobs(List<MultipartFile> files, String bucketName, Long type) { 
 | 
  
 | 
        // 若没传入bucketName,则使用默认bucketName 
 | 
        if (StringUtils.isEmpty(bucketName)) { 
 | 
            bucketName = minioUtils.getDefaultBucket(); 
 | 
        } 
 | 
        List<StorageBlobDTO> storageBlobDTOs = new ArrayList<>(); 
 | 
        for (MultipartFile file : files) { 
 | 
            try { 
 | 
                validateFileExtension(file); 
 | 
  
 | 
                MinioResult res = minioUtils.upload(bucketName, file, false); 
 | 
  
 | 
                StorageBlobDTO dto = buildStorageBlobDTO(file, res, bucketName, type); 
 | 
  
 | 
                storageBlobMapper.insert(dto); 
 | 
                storageBlobDTOs.add(dto); 
 | 
  
 | 
            } catch (InvalidExtensionException e) { 
 | 
                throw new RuntimeException("不支持的文件类型:" + file.getOriginalFilename(), e); 
 | 
            } catch (Exception e) { 
 | 
                throw new RuntimeException("上传文件失败:" + file.getOriginalFilename(), e); 
 | 
            } 
 | 
        } 
 | 
        return storageBlobDTOs; 
 | 
    } 
 | 
  
 | 
    private StorageBlobDTO buildStorageBlobDTO(MultipartFile file, MinioResult res, String bucketName, Long type) { 
 | 
        StorageBlobDTO dto = new StorageBlobDTO(); 
 | 
        dto.setContentType(file.getContentType()); 
 | 
        dto.setBucketFilename(res.getBucketFileName()); 
 | 
        dto.setOriginalFilename(res.getOriginalName()); 
 | 
        dto.setByteSize(file.getSize()); 
 | 
        dto.setResourceKey(IdUtils.simpleUUID()); 
 | 
        dto.setBucketName(bucketName); 
 | 
        dto.setUrl(minioUtils.getPreviewUrl(res.getBucketFileName(), bucketName, false)); 
 | 
        dto.setDownloadUrl(minioUtils.getDownloadUrl(res.getBucketFileName(), bucketName)); 
 | 
  
 | 
        if (type != null) { 
 | 
            dto.setType(type); 
 | 
        } 
 | 
  
 | 
        return dto; 
 | 
    } 
 | 
  
 | 
    private void validateFileExtension(MultipartFile file) throws InvalidExtensionException { 
 | 
        String filename = file.getOriginalFilename(); 
 | 
        String extension = FilenameUtils.getExtension(filename).toLowerCase(); 
 | 
        List<String> allowedExtensions = Arrays.asList( 
 | 
                // 图片 
 | 
                "jpg", "jpeg", "png", "gif", "bmp", "webp", "tiff", "ico", "svg", 
 | 
  
 | 
                // 文档 
 | 
                "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt", "rtf", "md", "csv", "odt", 
 | 
  
 | 
                // 视频 
 | 
                "mp4", "mov", "avi", "wmv", "flv", "mkv", "webm", "mpeg", "3gp", "MOV", 
 | 
  
 | 
                // 音频 
 | 
                "mp3", "wav", "ogg", "aac", "flac", "m4a", "wma", "amr", 
 | 
  
 | 
                // 压缩包 
 | 
                "zip", "rar", "7z", "tar", "gz", "bz2", "xz", 
 | 
  
 | 
                // 编程代码文件 
 | 
                "java", "py", "js", "ts", "html", "css", "cpp", "c", "cs", "json", "xml", "sql", "yaml", "yml", "sh", "bat", 
 | 
  
 | 
                // 安装程序 & 二进制 
 | 
                "exe", "apk", "dmg", "msi", "bin", "iso", 
 | 
  
 | 
                // 设计类 
 | 
                "psd", "ai", "xd", "sketch", "fig" 
 | 
        ); 
 | 
  
 | 
        if (!allowedExtensions.contains(extension)) { 
 | 
            throw new BaseException("文件类型不被允许:" + extension); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public int deleteStorageBlobs(StorageAttachment attachment) { 
 | 
        List<StorageAttachment> attachments = storageAttachmentMapper.selectList(new LambdaQueryWrapper<StorageAttachment>() 
 | 
                .eq(StorageAttachment::getRecordId, attachment.getRecordId()) 
 | 
                .eq(StorageAttachment::getRecordType, attachment.getRecordType()) 
 | 
                .eq(StorageAttachment::getName, attachment.getName())); 
 | 
        List<Long> ids = attachments.stream().map(StorageAttachment::getStorageBlobId).collect(Collectors.toList()); 
 | 
        if(CollectionUtils.isEmpty(ids)){ 
 | 
            return 0; 
 | 
        } 
 | 
        List<StorageBlob> storageBlobs = storageBlobMapper.selectList(new LambdaQueryWrapper<StorageBlob>() 
 | 
                .in(StorageBlob::getId, ids)); 
 | 
        if (!storageBlobs.isEmpty()) { 
 | 
            for (StorageBlob storageBlob : storageBlobs) { 
 | 
                // 移除桶内文件 
 | 
                minioUtils.removeObjectsResult(storageBlob.getBucketName(), storageBlob.getBucketName()); 
 | 
            } 
 | 
        } 
 | 
  
 | 
        if (!ids.isEmpty()) { 
 | 
            return storageBlobMapper.delete(new QueryWrapper<StorageBlob>().lambda().in(StorageBlob::getId, ids)); 
 | 
        } 
 | 
  
 | 
        return 0; 
 | 
    } 
 | 
} 
 |