Browse Source

更新对 media 文件的处理

reghao 2 years ago
parent
commit
d5951a1751
21 changed files with 239 additions and 189 deletions
  1. 0 11
      dfs-store/pom.xml
  2. 15 9
      dfs-store/src/main/java/cn/reghao/dfs/store/controller/ObjectUploadController.java
  3. 3 1
      dfs-store/src/main/java/cn/reghao/dfs/store/db/mapper/AudioFileMapper.java
  4. 2 1
      dfs-store/src/main/java/cn/reghao/dfs/store/db/mapper/ImageFileMapper.java
  5. 8 2
      dfs-store/src/main/java/cn/reghao/dfs/store/db/repository/AudioRepository.java
  6. 4 4
      dfs-store/src/main/java/cn/reghao/dfs/store/db/repository/ImageRepository.java
  7. 0 1
      dfs-store/src/main/java/cn/reghao/dfs/store/db/repository/VideoRepository.java
  8. 5 7
      dfs-store/src/main/java/cn/reghao/dfs/store/rpc/PermissionServiceImpl.java
  9. 2 1
      dfs-store/src/main/java/cn/reghao/dfs/store/rpc/media/ImageFileServiceImpl.java
  10. 1 10
      dfs-store/src/main/java/cn/reghao/dfs/store/rpc/media/VideoFileServiceImpl.java
  11. 37 23
      dfs-store/src/main/java/cn/reghao/dfs/store/service/ChannelValidateService.java
  12. 6 3
      dfs-store/src/main/java/cn/reghao/dfs/store/service/PutObjectService.java
  13. 3 5
      dfs-store/src/main/java/cn/reghao/dfs/store/task/FileProcessor.java
  14. 32 16
      dfs-store/src/main/java/cn/reghao/dfs/store/task/processor/AudioFileProcessor.java
  15. 99 85
      dfs-store/src/main/java/cn/reghao/dfs/store/task/processor/ImageFileProcessor.java
  16. 2 5
      dfs-store/src/main/java/cn/reghao/dfs/store/task/processor/VideoFileProcessor.java
  17. 1 1
      dfs-store/src/main/resources/mapper/ImageFileMapper.xml
  18. 15 0
      oss-api/src/main/java/cn/reghao/oss/api/constant/SupportedMedia.java
  19. 2 2
      oss-api/src/main/java/cn/reghao/oss/api/iface/PermissionService.java
  20. 2 1
      oss-api/src/main/java/cn/reghao/oss/api/iface/media/ImageFileService.java
  21. 0 1
      oss-api/src/main/java/cn/reghao/oss/api/iface/media/VideoFileService.java

+ 0 - 11
dfs-store/pom.xml

@@ -48,13 +48,6 @@
             <artifactId>media</artifactId>
             <version>1.0.0-SNAPSHOT</version>
         </dependency>
-
-        <dependency>
-            <groupId>net.coobird</groupId>
-            <artifactId>thumbnailator</artifactId>
-            <version>0.4.20</version>
-        </dependency>
-
         <dependency>
             <groupId>cn.reghao.oss</groupId>
             <artifactId>oss-api</artifactId>
@@ -100,10 +93,6 @@
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-cache</artifactId>
         </dependency>
-        <!--<dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-data-redis</artifactId>
-        </dependency>-->
         <dependency>
             <groupId>com.github.ben-manes.caffeine</groupId>
             <artifactId>caffeine</artifactId>

+ 15 - 9
dfs-store/src/main/java/cn/reghao/dfs/store/controller/ObjectUploadController.java

@@ -8,12 +8,15 @@ import cn.reghao.dfs.store.service.ObjectNameService;
 import cn.reghao.dfs.store.service.PutObjectService;
 import cn.reghao.dfs.store.task.FileProcessor;
 import cn.reghao.dfs.store.util.JwtUtil;
+import cn.reghao.jutil.jdk.result.Result;
 import cn.reghao.jutil.jdk.result.WebResult;
 import cn.reghao.jutil.jdk.security.DigestUtil;
 import cn.reghao.jutil.web.ServletUtil;
 import cn.reghao.oss.api.dto.OssPayload;
 import cn.reghao.oss.api.rest.UploadFileRet;
 import org.apache.commons.io.FileUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -48,23 +51,26 @@ public class ObjectUploadController {
     }
 
     @PostMapping(value = "/")
-    public String postObject(MultipartFile file, Integer channelId, String client) throws Exception {
+    public ResponseEntity<String> postObject(MultipartFile file, Integer channelId, String client) throws Exception {
         /* permission check */
         if (client == null) {
             String token = ServletUtil.getBearerToken();
             if (token == null) {
-                return WebResult.failWithMsg("no token in request");
+                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                        .body(WebResult.failWithMsg("no token in request"));
             }
 
             OssPayload ossPayload = JwtUtil.getOssPayload(token);
             String action = ossPayload.getAction();
             if (!"upload".equals(action)) {
-                return WebResult.failWithMsg("it's not upload token");
+                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                        .body(WebResult.failWithMsg("it's not upload token"));
             }
 
             int channelId1 = ossPayload.getChannelId();
             if (channelId != channelId1) {
-                return WebResult.failWithMsg("channel not match in token");
+                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
+                        .body(WebResult.failWithMsg("channel not match in token"));
             }
             /*long userId1 = ossPayload.getUserId();
             UserContext context = new UserContext(userId1);*/
@@ -74,10 +80,10 @@ public class ObjectUploadController {
         String contentId = UUID.randomUUID().toString().replace("-", "");
         long size = file.getSize();
         File savedFile = fileStoreService.saveFile(file.getInputStream(), contentId, size);
-        boolean ret = channelValidateService.validate(savedFile, channelId);
-        if (!ret) {
+        Result result = channelValidateService.validate(savedFile, channelId);
+        if (result.getCode() != 0) {
             FileUtils.deleteQuietly(savedFile);
-            return WebResult.failWithMsg("the format or size of upload file error");
+            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(WebResult.result(result));
         }
 
         /* store file */
@@ -93,14 +99,14 @@ public class ObjectUploadController {
         try {
             uploadFileRet = fileProcessor.process(objectResult, channelId);
             if (uploadFileRet != null) {
-                return WebResult.success(uploadFileRet);
+                return ResponseEntity.status(HttpStatus.OK).body(WebResult.success(uploadFileRet));
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
 
         putObjectService.deleteObject(objectResult.getObjectId());
-        return WebResult.fail();
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(WebResult.fail());
     }
 
     @DeleteMapping(value = "/")

+ 3 - 1
dfs-store/src/main/java/cn/reghao/dfs/store/db/mapper/AudioFileMapper.java

@@ -5,12 +5,14 @@ import cn.reghao.jutil.jdk.db.BaseMapper;
 import cn.reghao.oss.api.dto.media.AudioInfo;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * @author reghao
  * @date 2023-07-05 16:47:46
  */
 @Mapper
 public interface AudioFileMapper extends BaseMapper<AudioFile> {
-    AudioFile findByAudioFileId(String audioFileId);
+    List<AudioFile> findByAudioFileId(String audioFileId);
     AudioInfo findAudioInfo(String audioFileId);
 }

+ 2 - 1
dfs-store/src/main/java/cn/reghao/dfs/store/db/mapper/ImageFileMapper.java

@@ -6,6 +6,7 @@ import cn.reghao.jutil.jdk.db.BaseMapper;
 import org.apache.ibatis.annotations.Mapper;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * @author reghao
@@ -17,6 +18,6 @@ public interface ImageFileMapper extends BaseMapper<ImageFile> {
     void deleteByImageFileIds(List<String> list);
 
     List<ImageFile> findByImageFileId(String imageFileId);
-    List<ImageFile> findByImageFileIds(List<String> list);
+    List<ImageFile> findByImageFileIds(Set<String> list);
     List<ImageObject> findAll1();
 }

+ 8 - 2
dfs-store/src/main/java/cn/reghao/dfs/store/db/repository/AudioRepository.java

@@ -5,6 +5,8 @@ import cn.reghao.dfs.store.model.po.*;
 import cn.reghao.oss.api.dto.media.AudioInfo;
 import org.springframework.stereotype.Repository;
 
+import java.util.List;
+
 /**
  * @author reghao
  * @date 2023-08-28 15:00:43
@@ -17,11 +19,15 @@ public class AudioRepository {
         this.audioFileMapper = audioFileMapper;
     }
 
-    public void saveAudioFile(AudioFile audioFile) {
-        audioFileMapper.save(audioFile);
+    public void saveAudioFiles(List<AudioFile> audioFiles) {
+        audioFileMapper.saveAll(audioFiles);
     }
 
     public AudioFile findAudioFile(String audioFileId) {
+        return null;
+    }
+
+    public List<AudioFile> findAudioFiles(String audioFileId) {
         return audioFileMapper.findByAudioFileId(audioFileId);
     }
 

+ 4 - 4
dfs-store/src/main/java/cn/reghao/dfs/store/db/repository/ImageRepository.java

@@ -8,6 +8,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -40,12 +41,11 @@ public class ImageRepository {
         imageFileMapper.deleteByImageFileId(imageFileId);
     }
 
-    public ImageFile getImageFile(String imageFileId) {
-        List<ImageFile> list = imageFileMapper.findByImageFileId(imageFileId);
-        return list.isEmpty() ? null : list.get(0);
+    public List<ImageFile> findImageFiles(String imageFileId) {
+        return imageFileMapper.findByImageFileId(imageFileId);
     }
 
-    public List<ImageUrlDto> getImageUrls(List<String> imageFileIds) {
+    public List<ImageUrlDto> getImageUrls(Set<String> imageFileIds) {
         List<ImageUrlDto> list = new ArrayList<>();
         for (String imageFileId : imageFileIds) {
             ImageUrlDto imageUrlDto = getImageUrl(imageFileId);

+ 0 - 1
dfs-store/src/main/java/cn/reghao/dfs/store/db/repository/VideoRepository.java

@@ -8,7 +8,6 @@ import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Repository;
 import org.springframework.transaction.annotation.Transactional;
 
-import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.Collectors;
 

+ 5 - 7
dfs-store/src/main/java/cn/reghao/dfs/store/rpc/PermissionServiceImpl.java

@@ -10,6 +10,7 @@ import org.apache.dubbo.config.annotation.DubboService;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 /**
@@ -54,19 +55,16 @@ public class PermissionServiceImpl implements PermissionService {
 
     @Override
     public void setAudioPermission(String audioFileId, int scope) {
-        AudioFile audioFile = audioFileMapper.findByAudioFileId(audioFileId);
-        if (audioFile == null) {
-            return;
-        }
-
-        List<String> objectIds = List.of(audioFile.getObjectId());
+        List<String> objectIds = audioFileMapper.findByAudioFileId(audioFileId).stream()
+                .map(AudioFile::getObjectId)
+                .collect(Collectors.toList());
         if (!objectIds.isEmpty()) {
             fileMetaMapper.updateScopeByObjectIds(scope, objectIds);
         }
     }
 
     @Override
-    public void setImagesPermission(List<String> imageFileIds, int scope) {
+    public void setImagesPermission(Set<String> imageFileIds, int scope) {
         List<String> objectIds = imageFileMapper.findByImageFileIds(imageFileIds).stream()
                 .map(ImageFile::getObjectId)
                 .collect(Collectors.toList());

+ 2 - 1
dfs-store/src/main/java/cn/reghao/dfs/store/rpc/media/ImageFileServiceImpl.java

@@ -9,6 +9,7 @@ import org.apache.dubbo.config.annotation.DubboService;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * @author reghao
@@ -46,7 +47,7 @@ public class ImageFileServiceImpl implements ImageFileService {
     }
 
     @Override
-    public List<ImageUrlDto> getImageUrls(List<String> imageFileIds) {
+    public List<ImageUrlDto> getImageUrls(Set<String> imageFileIds) {
         return imageRepository.getImageUrls(imageFileIds);
     }
 }

+ 1 - 10
dfs-store/src/main/java/cn/reghao/dfs/store/rpc/media/VideoFileServiceImpl.java

@@ -2,7 +2,6 @@ package cn.reghao.dfs.store.rpc.media;
 
 import cn.reghao.dfs.store.db.repository.ObjectRepository;
 import cn.reghao.dfs.store.db.repository.VideoRepository;
-import cn.reghao.dfs.store.task.MediaConverter;
 import cn.reghao.oss.api.dto.media.VideoInfo;
 import cn.reghao.oss.api.dto.media.VideoUrlDto;
 import cn.reghao.oss.api.iface.media.VideoFileService;
@@ -20,13 +19,10 @@ import java.util.List;
 public class VideoFileServiceImpl implements VideoFileService {
     private final VideoRepository videoRepository;
     private final ObjectRepository objectRepository;
-    private final MediaConverter mediaConverter;
 
-    public VideoFileServiceImpl(VideoRepository videoRepository, ObjectRepository objectRepository,
-                                MediaConverter mediaConverter) {
+    public VideoFileServiceImpl(VideoRepository videoRepository, ObjectRepository objectRepository) {
         this.videoRepository = videoRepository;
         this.objectRepository = objectRepository;
-        this.mediaConverter = mediaConverter;
     }
 
     @Override
@@ -45,9 +41,4 @@ public class VideoFileServiceImpl implements VideoFileService {
         List<VideoUrlDto> list = videoRepository.findVideoUrls(videoFileId);
         return list;
     }
-
-    @Override
-    public void convert(String videoFileId) {
-        mediaConverter.convertVideo(videoFileId);
-    }
 }

+ 37 - 23
dfs-store/src/main/java/cn/reghao/dfs/store/service/ChannelValidateService.java

@@ -1,6 +1,8 @@
 package cn.reghao.dfs.store.service;
 
 import cn.reghao.dfs.store.util.FileType;
+import cn.reghao.jutil.jdk.result.Result;
+import cn.reghao.oss.api.constant.SupportedMedia;
 import cn.reghao.oss.api.constant.UploadChannel;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -14,55 +16,67 @@ import java.io.File;
 @Slf4j
 @Service
 public class ChannelValidateService {
-    public boolean validate(File file, int channelId) {
+    public Result validate(File file, int channelId) {
         UploadChannel channel = UploadChannel.getUploadChannel(channelId);
         switch (channel) {
             case disk:
-                return true;
+                return Result.success();
             case video:
                 return validateVideo(file);
             case audio:
                 return validateAudio(file);
             case avatar:
-                return validateAvatar(file);
+                return validateImage(file, UploadChannel.avatar.getMaxSize());
             case image:
             case img:
-                return validateImage(file);
+                return validateImage(file, UploadChannel.image.getMaxSize());
             case photo:
-                return validatePhoto(file);
+                return validateImage(file, UploadChannel.photo.getMaxSize());
             default:
-                log.info("{} 的文件暂时无法处理", channel.getPrefix());
-                return false;
+                String errMsg = String.format("%s 的文件暂时无法处理", channel.getPrefix());
+                return Result.fail(errMsg);
         }
     }
 
-    private boolean validateVideo(File file) {
+    private Result validateVideo(File file) {
         String mediaType = FileType.getMediaType(file.getAbsolutePath());
+        long maxSize = UploadChannel.video.getMaxSize();
         long len = file.length();
-        return len < UploadChannel.video.getMaxSize() && mediaType.startsWith("video");
-    }
+        if (len > maxSize) {
+            String errMsg = String.format("视频文件大小不能超过 %s bytes", maxSize);
+            return Result.fail(errMsg);
+        } else if (!mediaType.startsWith("video")) {
+            return Result.fail("非视频文件格式");
+        }
 
-    private boolean validateAudio(File file) {
-        String mediaType = FileType.getMediaType(file.getAbsolutePath());
-        long len = file.length();
-        return len < UploadChannel.audio.getMaxSize() && mediaType.startsWith("audio");
+        return Result.success();
     }
 
-    private boolean validateAvatar(File file) {
+    private Result validateAudio(File file) {
         String mediaType = FileType.getMediaType(file.getAbsolutePath());
+        long maxSize = UploadChannel.audio.getMaxSize();
         long len = file.length();
-        return len < UploadChannel.avatar.getMaxSize() && mediaType.startsWith("image");
-    }
+        if (len > maxSize) {
+            String errMsg = String.format("音频文件大小不能超过 %s bytes", maxSize);
+            return Result.fail(errMsg);
+        } else if (!mediaType.startsWith("audio")) {
+            return Result.fail("非音频文件格式");
+        }
 
-    private boolean validateImage(File file) {
-        String mediaType = FileType.getMediaType(file.getAbsolutePath());
-        long len = file.length();
-        return len < UploadChannel.image.getMaxSize() && mediaType.startsWith("image");
+        return Result.success();
     }
 
-    private boolean validatePhoto(File file) {
+    private Result validateImage(File file, long maxSize) {
         String mediaType = FileType.getMediaType(file.getAbsolutePath());
         long len = file.length();
-        return len < UploadChannel.photo.getMaxSize() && mediaType.startsWith("image");
+        if (len > maxSize) {
+            String errMsg = String.format("图片文件大小不能超过 %s bytes", maxSize);
+            return Result.fail(errMsg);
+        } else if (!SupportedMedia.imageFormats.contains(mediaType.replace("image/", ""))) {
+            String errMsg = String.format("系统仅支持 %s 等图片格式", SupportedMedia.imageFormats);
+            return Result.fail(errMsg);
+        }
+
+        return Result.success();
     }
 }

+ 6 - 3
dfs-store/src/main/java/cn/reghao/dfs/store/service/PutObjectService.java

@@ -7,6 +7,7 @@ import cn.reghao.dfs.store.model.vo.ObjectProp;
 import cn.reghao.dfs.store.model.vo.ObjectResult;
 import cn.reghao.dfs.store.util.FileType;
 import cn.reghao.dfs.store.util.StringUtil;
+import cn.reghao.oss.api.dto.ObjectMeta;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.FileUtils;
 import org.springframework.stereotype.Service;
@@ -60,8 +61,10 @@ public class PutObjectService {
 
     public ObjectResult copyObject(ObjectProp objectProp, String filename, FileMeta fileMeta) {
         String dupObjectId = fileMeta.getObjectId();
+        ObjectMeta objectMeta = objectRepository.getObjectMeta(fileMeta.getObjectName());
+
         int fileType = fileMeta.getFileType();
-        String savedPath = "";
+        String savedPath = objectMeta.getAbsolutePath();
         String objectName = objectProp.getObjectName();
         String objectId = UUID.randomUUID().toString().replace("-", "");
         boolean diskFile = objectProp.isDiskFile();
@@ -71,7 +74,7 @@ public class PutObjectService {
         return new ObjectResult(objectName, objectId, fileType, savedPath, dupObjectId);
     }
 
-    public ObjectResult copyObject(String fromObjectName) {
+    public ObjectResult copyFromObjectName(String fromObjectName) {
         FileMeta fileMeta = objectRepository.getByObjectName(fromObjectName);
         int fileType = fileMeta.getFileType();
 
@@ -87,7 +90,7 @@ public class PutObjectService {
         return new ObjectResult(toObjectName, toObjectId, fileType, savedPath);
     }
 
-    public ObjectResult copyObject1(String fromObjectId) {
+    public ObjectResult copyFromObjectId(String fromObjectId) {
         FileMeta fileMeta = objectRepository.getByObjectId(fromObjectId);
         int fileType = fileMeta.getFileType();
 

+ 3 - 5
dfs-store/src/main/java/cn/reghao/dfs/store/task/FileProcessor.java

@@ -58,17 +58,15 @@ public class FileProcessor {
                 break;
             case avatar:
             case image:
-                uploadFileRet = imageFileProcessor.processImage(objectResult);
+            case photo:
+                uploadFileRet = imageFileProcessor.processImage(objectResult, channelId);
                 break;
             case img:
-                uploadFileRet = imageFileProcessor.processImage(objectResult);
+                uploadFileRet = imageFileProcessor.processImage(objectResult, channelId);
                 String uploadId = uploadFileRet.getUploadId();
                 String url = imageRepository.getImageUrl(uploadId).getOriginalUrl();
                 uploadFileRet.setUrl(url);
                 break;
-            case photo:
-                uploadFileRet = imageFileProcessor.processPhoto(objectResult);
-                break;
             default:
                 log.info("{} 类型的 {} 文件暂时无法处理", objectType.name(), objectName);
         }

+ 32 - 16
dfs-store/src/main/java/cn/reghao/dfs/store/task/processor/AudioFileProcessor.java

@@ -8,19 +8,19 @@ import cn.reghao.dfs.store.service.FileStoreService;
 import cn.reghao.dfs.store.service.ObjectNameService;
 import cn.reghao.dfs.store.service.PutObjectService;
 import cn.reghao.jutil.jdk.security.DigestUtil;
-import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
 import cn.reghao.jutil.media.FFmpegWrapper;
 import cn.reghao.jutil.media.model.AudioProps;
 import cn.reghao.jutil.media.model.MediaProps;
+import cn.reghao.oss.api.constant.SupportedMedia;
 import cn.reghao.oss.api.rest.UploadFileRet;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.UUID;
-import java.util.concurrent.ExecutorService;
 
 /**
  * @author reghao
@@ -33,8 +33,6 @@ public class AudioFileProcessor {
     private final PutObjectService putObjectService;
     private final ObjectNameService objectNameService;
     private final FileStoreService fileStoreService;
-    private final ExecutorService threadPool = ThreadPoolWrapper.threadPool("converter-pool", 10);
-    private final Set<String> audioCodecs = Set.of("aac", "mp3");
 
     public AudioFileProcessor(AudioRepository audioRepository, PutObjectService putObjectService,
                               ObjectNameService objectNameService, FileStoreService fileStoreService) {
@@ -52,9 +50,23 @@ public class AudioFileProcessor {
         boolean duplicate = objectResult.isDuplicate();
         if (duplicate) {
             String dupObjectId = objectResult.getDupObjectId();
-            AudioFile audioFile = audioRepository.findAudioFile(dupObjectId);
+            List<AudioFile> audioFiles = audioRepository.findAudioFiles(dupObjectId);
+            AudioFile audioFile = audioFiles.get(0);
             AudioFile audioFile1 = new AudioFile(audioFileId, objectId, objectUrl, audioFile);
-            audioRepository.saveAudioFile(audioFile1);
+            List<AudioFile> list = new ArrayList<>();
+            list.add(audioFile1);
+
+            if (audioFiles.size() > 1) {
+                for (int i = 1; i < audioFiles.size(); i++) {
+                    AudioFile audioFile2 = audioFiles.get(i);
+                    ObjectResult objectResult1 = putObjectService.copyFromObjectId(audioFile2.getObjectId());
+                    String objectId1 = objectResult1.getObjectId();
+                    String objectUrl1 = objectNameService.getObjectUrl(objectResult1.getObjectName());
+                    list.add(new AudioFile(audioFileId, objectId1, objectUrl1, audioFile2));
+                }
+            }
+
+            audioRepository.saveAudioFiles(list);
             return new UploadFileRet(objectId, null);
         }
 
@@ -69,18 +81,24 @@ public class AudioFileProcessor {
         String audioCodec = audioProps.getCodecName();
         int duration = audioProps.getDuration().intValue();
         long bitRate = audioProps.getBitRate();
-        if (!audioCodecs.contains(audioCodec)) {
+        AudioFile audioFile;
+        if (!SupportedMedia.audioCodecs.contains(audioCodec)) {
             log.info("将 {} 对象的音频转换为 aac 编码", objectName);
             File file = new File(objectResult.getAbsolutePath());
-            return getConvertedAudioFile(audioFileId, file, objectName, ".m4a");
+            audioFile = getConvertedAudioFile(audioFileId, file, objectName, ".m4a");
+        } else {
+            audioFile = new AudioFile(audioFileId, objectId, duration, audioCodec, bitRate, objectUrl);
         }
 
-        AudioFile audioFile = new AudioFile(audioFileId, objectId, duration, audioCodec, bitRate, objectUrl);
-        audioRepository.saveAudioFile(audioFile);
-        return new UploadFileRet(audioFileId, null);
+        if (audioFile != null) {
+            audioRepository.saveAudioFiles(List.of(audioFile));
+            return new UploadFileRet(audioFileId, null);
+        }
+
+        return null;
     }
 
-    private UploadFileRet getConvertedAudioFile(String audioFileId, File file, String originalObjectName, String suffix) {
+    private AudioFile getConvertedAudioFile(String audioFileId, File file, String originalObjectName, String suffix) {
         String contentId = UUID.randomUUID().toString().replace("-", "");
         String destPath = fileStoreService.genFilePath(contentId, file.length(), suffix);
         try {
@@ -103,9 +121,7 @@ public class AudioFileProcessor {
             int duration = 0;
             String codec = "aac";
             long bitRate = 0;
-            AudioFile audioFile = new AudioFile(audioFileId, objectId, duration, codec, bitRate, url);
-            audioRepository.saveAudioFile(audioFile);
-            return new UploadFileRet(objectId, null);
+            return new AudioFile(audioFileId, objectId, duration, codec, bitRate, url);
         } catch (Exception e) {
             e.printStackTrace();
         }

+ 99 - 85
dfs-store/src/main/java/cn/reghao/dfs/store/task/processor/ImageFileProcessor.java

@@ -9,17 +9,15 @@ import cn.reghao.dfs.store.service.PutObjectService;
 import cn.reghao.jutil.jdk.security.DigestUtil;
 import cn.reghao.dfs.store.model.po.ImageFile;
 import cn.reghao.jutil.media.ImageOps;
+import cn.reghao.oss.api.constant.SupportedMedia;
+import cn.reghao.oss.api.constant.UploadChannel;
 import cn.reghao.oss.api.rest.UploadFileRet;
 import lombok.extern.slf4j.Slf4j;
-import net.coobird.thumbnailator.Thumbnails;
 import org.springframework.stereotype.Service;
 
-import javax.imageio.ImageIO;
-import java.awt.image.BufferedImage;
 import java.io.*;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 import java.util.UUID;
 
 /**
@@ -33,7 +31,6 @@ public class ImageFileProcessor {
     private final FileStoreService fileStoreService;
     private final ObjectNameService objectNameService;
     private final PutObjectService putObjectService;
-    private final Set<String> imageFormats = Set.of("jpg", "jpeg", "webp", "gif", "png");
 
     public ImageFileProcessor(ImageRepository imageRepository, FileStoreService fileStoreService,
                               ObjectNameService objectNameService, PutObjectService putObjectService) {
@@ -43,125 +40,142 @@ public class ImageFileProcessor {
         this.putObjectService = putObjectService;
     }
 
-    public UploadFileRet processImage(ObjectResult objectResult) {
+    public UploadFileRet processImage(ObjectResult objectResult, int channelId) {
         String objectName = objectResult.getObjectName();
         String objectId = objectResult.getObjectId();
         String imageFileId = objectId;
         String objectUrl = objectNameService.getObjectUrl(objectName);
         boolean duplicate = objectResult.isDuplicate();
         if (duplicate) {
-            String dupObjectId = objectResult.getDupObjectId();
-            ImageFile imageFile = imageRepository.getImageFile(dupObjectId);
-            ImageFile imageFile1 = new ImageFile(imageFileId, objectId, objectUrl, imageFile);
-            imageRepository.saveImageFiles(List.of(imageFile1));
-            return new UploadFileRet(objectId, null);
+            return processDuplicate(objectResult,channelId);
         }
 
         String absolutePath = objectResult.getAbsolutePath();
-        String format = ImageOps.getFormat(new File(absolutePath));
+        File file = new File(absolutePath);
+        String format = ImageOps.getFormat(file);
+        if (!SupportedMedia.imageFormats.contains(format)) {
+            // 在 ChannelValidateService#validateImage 中已做过判断, 理论上不会执行这行代码
+            log.error("不支持 {} 图片格式", format);
+            return null;
+        }
+
         try {
-            if (imageFormats.contains(format)) {
-                ImageOps.Size size = ImageOps.info(new File(absolutePath));
-                int width = size.getWidth();
-                int height = size.getHeight();
-
-                ImageFile imageFile = new ImageFile(imageFileId, objectId, format, objectUrl, width, height);
-                imageRepository.saveImageFiles(List.of(imageFile));
-                return new UploadFileRet(objectId, null);
-            } else {
-                log.info("不支持 {} 格式的文件", format);
+            ImageOps.Size size = ImageOps.info(new File(absolutePath));
+            int width = size.getWidth();
+            int height = size.getHeight();
+            List<ImageFile> list = new ArrayList<>();
+            list.add(new ImageFile(imageFileId, objectId, format, objectUrl, width, height));
+            if (channelId == UploadChannel.photo.getCode()) {
+                ImageFile imageFile = getConvertedImageFile(objectResult, "webp", width, height);
+                if (imageFile != null) {
+                    list.add(imageFile);
+                }
             }
+
+            imageRepository.saveImageFiles(list);
+            return new UploadFileRet(objectId, null);
         } catch (Exception e) {
             e.printStackTrace();
         }
         return null;
     }
 
-    public UploadFileRet processPhoto(ObjectResult objectResult) {
+    private UploadFileRet processDuplicate(ObjectResult objectResult, int channelId) {
         String objectName = objectResult.getObjectName();
         String objectId = objectResult.getObjectId();
         String imageFileId = objectId;
         String objectUrl = objectNameService.getObjectUrl(objectName);
-        boolean duplicate = objectResult.isDuplicate();
-        if (duplicate) {
-            String dupObjectId = objectResult.getDupObjectId();
-            ImageFile imageFile = imageRepository.getImageFile(dupObjectId);
-            ImageFile imageFile1 = new ImageFile(imageFileId, objectId, objectUrl, imageFile);
-            imageRepository.saveImageFiles(List.of(imageFile1));
-            return new UploadFileRet(objectId, null);
+        String dupObjectId = objectResult.getDupObjectId();
+        List<ImageFile> imageFiles = imageRepository.findImageFiles(dupObjectId);
+        ImageFile imageFile = imageFiles.get(0);
+        ImageFile imageFile1 = new ImageFile(imageFileId, objectId, objectUrl, imageFile);
+        List<ImageFile> list = new ArrayList<>();
+        list.add(imageFile1);
+
+        if (imageFiles.size() > 1) {
+            for (int i = 1; i < imageFiles.size(); i++) {
+                ImageFile imageFile2 = imageFiles.get(i);
+                ObjectResult objectResult1 = putObjectService.copyFromObjectId(imageFile2.getObjectId());
+                String objectId1 = objectResult1.getObjectId();
+                String objectUrl1 = objectNameService.getObjectUrl(objectResult1.getObjectName());
+                list.add(new ImageFile(imageFileId, objectId1, objectUrl1, imageFile2));
+            }
+        } else if (imageFiles.size() == 1 && channelId == UploadChannel.photo.getCode()) {
+            int width = imageFile.getWidth();
+            int height = imageFile.getHeight();
+            ImageFile imageFile2 = getConvertedImageFile(objectResult, "webp", width, height);
+            if (imageFile2 != null) {
+                list.add(imageFile2);
+            }
         }
 
+        imageRepository.saveImageFiles(list);
+        return new UploadFileRet(objectId, null);
+    }
+
+    private ImageFile getConvertedImageFile(ObjectResult objectResult, String format, int width, int height) {
+        String imageFileId = objectResult.getObjectId();
+        String originalObjectName = objectResult.getObjectName();
         String absolutePath = objectResult.getAbsolutePath();
-        String format = ImageOps.getFormat(new File(absolutePath));
-        try {
-            if (imageFormats.contains(format)) {
-                ImageOps.Size size = ImageOps.info(new File(absolutePath));
-                int width = size.getWidth();
-                int height = size.getHeight();
-
-                List<ImageFile> imageFiles = new ArrayList<>();
-                imageFiles.add(new ImageFile(imageFileId, objectId, format, objectUrl, width, height));
-                if (!"webp".equals(format)) {
-                    ObjectResult webpResult = getWebpObject(objectResult);
-                    String webpObjectName = webpResult.getObjectName();
-                    String webpObjectId = webpResult.getObjectId();
-                    String webpUrl = objectNameService.getObjectUrl(webpObjectName);
-                    imageFiles.add(new ImageFile(imageFileId, webpObjectId, "webp", webpUrl, width, height));
-                }
+        File srcFile = new File(absolutePath);
 
-                imageRepository.saveImageFiles(imageFiles);
-                return new UploadFileRet(objectId, null);
+        String contentId = UUID.randomUUID().toString().replace("-", "");
+        String destPath = fileStoreService.genFilePath(contentId, srcFile.length(), "."+format);
+        File destFile = new File(destPath);
+        try {
+            if ("jpeg".equals(format)) {
+                ImageOps.convert2jpeg(srcFile, destFile);
+            } else if ("webp".equals(format)) {
+                ImageOps.convert2webp(srcFile, destFile);
             } else {
-                log.info("不支持 {} 格式的文件", format);
+                ImageOps.convert2thumbnail(srcFile, destFile, width, height);
+            }
+
+            if (destFile.exists()) {
+                ObjectResult objectResult1 = saveImage(originalObjectName, contentId, "."+format, destFile);
+                String objectName1 = objectResult1.getObjectName();
+                String objectId1 = objectResult1.getObjectId();
+                String objectUrl1 = objectNameService.getObjectUrl(objectName1);
+                return new ImageFile(imageFileId, objectId1, format, objectUrl1, width, height);
             }
         } catch (Exception e) {
             e.printStackTrace();
         }
+
         return null;
     }
 
-    private ObjectResult getJpegObject(ObjectResult objectResult, String format) throws Exception {
+    private ImageFile getThumbnailFile(ObjectResult objectResult, int width, int height) {
+        String imageFileId = objectResult.getObjectId();
         String originalObjectName = objectResult.getObjectName();
         String absolutePath = objectResult.getAbsolutePath();
-        ObjectResult objectResult1;
-        if (imageFormats.contains(format)) {
-            String jpegObjectName = objectResult.getObjectName();
-            objectResult1 = putObjectService.copyObject(jpegObjectName);
-        } else {
-            byte[] bytes = ImageOps.convert2jpg(new File(absolutePath));
-            objectResult1 = saveImage(originalObjectName, bytes, ".jpeg");
-        }
-
-        return objectResult1;
-    }
-
-    private ObjectResult getWebpObject(ObjectResult objectResult) throws Exception {
-        String objectName = objectResult.getObjectName();
-        String absolutePath = objectResult.getAbsolutePath();
-        BufferedImage bi = ImageIO.read(new File(absolutePath));
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        ImageIO.write(bi, "webp", baos);
-        return saveImage(objectName, baos.toByteArray(), ".webp");
-    }
+        File srcFile = new File(absolutePath);
 
-    private ObjectResult getThumbnailObject(ObjectResult objectResult) throws Exception {
-        String originalObjectName = objectResult.getObjectName();
-        String absolutePath = objectResult.getAbsolutePath();
+        //int width = 480;
+        //int height = 360;
+        String format = "jpeg";
+        String contentId = UUID.randomUUID().toString().replace("-", "");
+        String destPath = fileStoreService.genFilePath(contentId, srcFile.length(), "."+format);
+        File destFile = new File(destPath);
+        try {
+            ImageOps.convert2thumbnail(srcFile, destFile, width, height);
+            if (destFile.exists()) {
+                ObjectResult objectResult1 = saveImage(originalObjectName, contentId, "."+format, destFile);
+                String objectName1 = objectResult1.getObjectName();
+                String objectId1 = objectResult1.getObjectId();
+                String objectUrl1 = objectNameService.getObjectUrl(objectName1);
+                return new ImageFile(imageFileId, objectId1, format, objectUrl1, width, height);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
 
-        int width = 480;
-        int height = 360;
-        BufferedImage bi = Thumbnails.of(absolutePath)
-                .size(width, height)
-                .asBufferedImage();
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        ImageIO.write(bi, "jpeg", baos);
-        return saveImage(originalObjectName, baos.toByteArray(), ".jpeg");
+        return null;
     }
 
-    private ObjectResult saveImage(String objectName, byte[] bytes, String suffix) throws Exception {
-        ObjectProp objectProp = objectNameService.getObjectProp(objectName, suffix);
-        String contentId = UUID.randomUUID().toString().replace("-", "");
-        File savedFile = fileStoreService.saveFile(bytes, contentId);
+    private ObjectResult saveImage(String originalObjectName, String contentId, String suffix, File savedFile)
+            throws Exception {
+        ObjectProp objectProp = objectNameService.getObjectProp(originalObjectName, suffix);
         String sha256sum = DigestUtil.sha256sum(savedFile.getAbsolutePath());
         return putObjectService.putObject(objectProp, contentId, savedFile, "", sha256sum);
     }

+ 2 - 5
dfs-store/src/main/java/cn/reghao/dfs/store/task/processor/VideoFileProcessor.java

@@ -18,7 +18,6 @@ import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 /**
  * @author reghao
@@ -29,9 +28,7 @@ import java.util.Set;
 public class VideoFileProcessor {
     private final VideoRepository videoRepository;
     private final ObjectNameService objectNameService;
-    private PutObjectService putObjectService;
-    private final Set<String> audioCodecs = Set.of("aac", "mp3");
-    private final Set<String> videoCodecs = Set.of("h264");
+    private final PutObjectService putObjectService;
 
     public VideoFileProcessor(VideoRepository videoRepository, ObjectNameService objectNameService,
                               PutObjectService putObjectService) {
@@ -57,7 +54,7 @@ public class VideoFileProcessor {
             if (videoFiles.size() > 1) {
                 for (int i = 1; i < videoFiles.size(); i++) {
                     VideoFile videoFile2 = videoFiles.get(i);
-                    ObjectResult objectResult1 = putObjectService.copyObject1(videoFile2.getObjectId());
+                    ObjectResult objectResult1 = putObjectService.copyFromObjectId(videoFile2.getObjectId());
                     String objectId1 = objectResult1.getObjectId();
                     String objectUrl1 = objectNameService.getObjectUrl(objectResult1.getObjectName());
                     list.add(new VideoFile(videoFileId, objectId1, objectUrl1, videoFile2));

+ 1 - 1
dfs-store/src/main/resources/mapper/ImageFileMapper.xml

@@ -41,7 +41,7 @@
         select *
         from image_file
         where image_file_id in
-        <foreach collection="list" item="item" separator="," open="(" close=")">
+        <foreach collection="collection" item="item" separator="," open="(" close=")">
             #{item}
         </foreach>
     </select>

+ 15 - 0
oss-api/src/main/java/cn/reghao/oss/api/constant/SupportedMedia.java

@@ -0,0 +1,15 @@
+package cn.reghao.oss.api.constant;
+
+import java.util.Set;
+
+/**
+ * 系统支持的媒体文件格式
+ *
+ * @author reghao
+ * @date 2023-10-09 10:34:42
+ */
+public class SupportedMedia {
+    public static final Set<String> videoCodecs = Set.of("h264");
+    public static final Set<String> audioCodecs = Set.of("aac", "mp3");
+    public static final Set<String> imageFormats = Set.of("jpeg", "webp", "gif", "png");
+}

+ 2 - 2
oss-api/src/main/java/cn/reghao/oss/api/iface/PermissionService.java

@@ -1,6 +1,6 @@
 package cn.reghao.oss.api.iface;
 
-import java.util.List;
+import java.util.Set;
 
 /**
  * @author reghao
@@ -11,5 +11,5 @@ public interface PermissionService {
     void getDirPermission(String prefix);
     void setVideoPermission(String videoFileId, int scope);
     void setAudioPermission(String audioFileId, int scope);
-    void setImagesPermission(List<String> imageFileIds, int scope);
+    void setImagesPermission(Set<String> imageFileIds, int scope);
 }

+ 2 - 1
oss-api/src/main/java/cn/reghao/oss/api/iface/media/ImageFileService.java

@@ -3,6 +3,7 @@ package cn.reghao.oss.api.iface.media;
 import cn.reghao.oss.api.dto.media.ImageUrlDto;
 
 import java.util.List;
+import java.util.Set;
 
 /**
  * @author reghao
@@ -12,5 +13,5 @@ public interface ImageFileService {
     void deleteImageFile(String objectId);
     void deleteByObjectName(String objectName);
     ImageUrlDto getImageUrl(String imageFileId);
-    List<ImageUrlDto> getImageUrls(List<String> imageFileIds);
+    List<ImageUrlDto> getImageUrls(Set<String> imageFileIds);
 }

+ 0 - 1
oss-api/src/main/java/cn/reghao/oss/api/iface/media/VideoFileService.java

@@ -13,5 +13,4 @@ public interface VideoFileService {
     void deleteVideoFile(String videoFileId);
     VideoInfo getVideoInfo(String videoFileId);
     List<VideoUrlDto> getVideoUrls(String videoFileId);
-    void convert(String videoFileId);
 }