diff --git a/src/main/java/com/ycwl/basic/image/pipeline/stages/UploadStage.java b/src/main/java/com/ycwl/basic/image/pipeline/stages/UploadStage.java index 9e573687..ffc5d5f5 100644 --- a/src/main/java/com/ycwl/basic/image/pipeline/stages/UploadStage.java +++ b/src/main/java/com/ycwl/basic/image/pipeline/stages/UploadStage.java @@ -25,6 +25,8 @@ import java.io.File; ) public class UploadStage extends AbstractPipelineStage { + private static final String DEFAULT_STORAGE = "assets-ext"; + @Override public String getName() { return "UploadStage"; @@ -37,11 +39,17 @@ public class UploadStage extends AbstractPipelineStage { return StageResult.failed("没有可上传的文件"); } - IStorageAdapter adapter; - try { - adapter = StorageFactory.use(); - } catch (Exception e) { - return StageResult.failed("无法获取存储: " + e.getMessage(), e); + IStorageAdapter adapter = context.getStorageAdapter(); + boolean usingDefaultStorage = false; + + if (adapter == null) { + log.debug("未配置存储适配器,使用默认存储: {}", DEFAULT_STORAGE); + try { + adapter = StorageFactory.use(DEFAULT_STORAGE); + usingDefaultStorage = true; + } catch (Exception e) { + return StageResult.failed("无法获取默认存储: " + e.getMessage(), e); + } } try { @@ -49,10 +57,32 @@ public class UploadStage extends AbstractPipelineStage { context.setResultUrl(uploadedUrl); log.info("文件上传成功: {}", uploadedUrl); + + if (usingDefaultStorage) { + return StageResult.degraded("降级: 使用默认存储 " + DEFAULT_STORAGE); + } + return StageResult.success("已上传"); } catch (Exception e) { log.error("文件上传失败", e); + + if (!usingDefaultStorage) { + log.warn("尝试降级到默认存储"); + try { + IStorageAdapter defaultAdapter = StorageFactory.use(DEFAULT_STORAGE); + String uploadedUrl = uploadFile(defaultAdapter, fileToUpload); + context.setResultUrl(uploadedUrl); + + log.info("降级上传成功: {}", uploadedUrl); + return StageResult.degraded("降级: 使用默认存储 " + DEFAULT_STORAGE); + + } catch (Exception fallbackEx) { + log.error("降级上传也失败", fallbackEx); + return StageResult.failed("上传失败(包括降级): " + fallbackEx.getMessage(), fallbackEx); + } + } + return StageResult.failed("上传失败: " + e.getMessage(), e); } } diff --git a/src/main/java/com/ycwl/basic/puzzle/service/impl/PuzzleGenerateServiceImpl.java b/src/main/java/com/ycwl/basic/puzzle/service/impl/PuzzleGenerateServiceImpl.java index 2aaeb56b..c7e7fd85 100644 --- a/src/main/java/com/ycwl/basic/puzzle/service/impl/PuzzleGenerateServiceImpl.java +++ b/src/main/java/com/ycwl/basic/puzzle/service/impl/PuzzleGenerateServiceImpl.java @@ -468,14 +468,12 @@ public class PuzzleGenerateServiceImpl implements IPuzzleGenerateService { // 上传到OSS try (FileInputStream fis = new FileInputStream(qrcode)) { String fileName = String.format("qrcode_%d.jpg", faceId); - var storageAdapter = StorageFactory.use(); - boolean exists = storageAdapter.isExists("puzzle", "wechat_qrcode", fileName); + boolean exists = StorageFactory.use().isExists("puzzle", "wechat_qrcode", fileName); if (exists) { - String url = storageAdapter.getUrl("puzzle", "wechat_qrcode", fileName); - log.debug("微信小程序二维码已存在, 不重复上传: faceId={}, url={}", faceId, url); - return url; + log.debug("微信小程序二维码已存在, 不重复上传: faceId={}, url={}", faceId, StorageFactory.use().getUrl("puzzle", "wechat_qrcode", fileName)); + return StorageFactory.use().getUrl("puzzle", "wechat_qrcode", fileName); } - return storageAdapter.uploadFile( + return StorageFactory.use().uploadFile( "image/jpeg", fis, "puzzle", diff --git a/src/main/java/com/ycwl/basic/repository/SourceRepository.java b/src/main/java/com/ycwl/basic/repository/SourceRepository.java index 7d45d213..8a0d0698 100644 --- a/src/main/java/com/ycwl/basic/repository/SourceRepository.java +++ b/src/main/java/com/ycwl/basic/repository/SourceRepository.java @@ -19,6 +19,7 @@ import com.ycwl.basic.pricing.enums.VoucherDiscountType; import com.ycwl.basic.pricing.service.IVoucherService; import com.ycwl.basic.storage.StorageFactory; import com.ycwl.basic.storage.adapters.IStorageAdapter; +import com.ycwl.basic.storage.exceptions.StorageUnsupportedException; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; @@ -153,7 +154,14 @@ public class SourceRepository { .build(); context.enableStage("image_sr"); context.enableStage("image_enhance"); - IStorageAdapter adapter = StorageFactory.use(); + ScenicConfigManager configManager = scenicRepository.getScenicConfigManager(source.getScenicId()); + IStorageAdapter adapter; + try { + adapter = StorageFactory.get(configManager.getString("store_type")); + adapter.loadConfig(configManager.getObject("store_config_json", Map.class)); + } catch (StorageUnsupportedException ignored) { + adapter = StorageFactory.use("assets-ext"); + } context.setStorageAdapter(adapter); // 2. 设置结果URL回调 - 更新source记录 diff --git a/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java b/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java index 9a314f8f..32a12539 100644 --- a/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/mobile/impl/GoodsServiceImpl.java @@ -51,6 +51,7 @@ import com.ycwl.basic.model.repository.TaskUpdateResult; import com.ycwl.basic.storage.StorageFactory; import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.storage.enums.StorageAcl; +import com.ycwl.basic.storage.enums.StorageType; import com.ycwl.basic.utils.ApiResponse; import com.ycwl.basic.utils.WxMpUtil; import lombok.extern.slf4j.Slf4j; @@ -572,7 +573,13 @@ public class GoodsServiceImpl implements GoodsService { if (configManager != null && configManager.getString("watermark_type") != null && !isBuy.isBuy()) { ImageWatermarkOperatorEnum type = ImageWatermarkOperatorEnum.getByCode(configManager.getString("watermark_type")); if (type != null) { - IStorageAdapter adapter = StorageFactory.use(); + IStorageAdapter adapter; + if (configManager.getEnum("store_type", StorageType.class) != null) { + adapter = StorageFactory.get(configManager.getEnum("store_type", StorageType.class)); + adapter.loadConfig(JacksonUtil.parseObject(configManager.getString("store_config_json"), Map.class)); + } else { + adapter = StorageFactory.use("assets-ext"); + } List watermarkEntityList = sourceMapper.listSourceWatermark(list.stream().map(SourceRespVO::getId).collect(Collectors.toList()), face.getId(), type.getType()); // 边缘端处理:需要二维码和头像 URL diff --git a/src/main/java/com/ycwl/basic/service/pc/impl/SourceServiceImpl.java b/src/main/java/com/ycwl/basic/service/pc/impl/SourceServiceImpl.java index 68c0480c..dc6aa81f 100644 --- a/src/main/java/com/ycwl/basic/service/pc/impl/SourceServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/pc/impl/SourceServiceImpl.java @@ -13,6 +13,7 @@ import com.ycwl.basic.model.pc.source.resp.SourceRespVO; import com.ycwl.basic.repository.DeviceRepository; import com.ycwl.basic.repository.ScenicRepository; import com.ycwl.basic.repository.SourceRepository; +import com.ycwl.basic.service.pc.ScenicService; import com.ycwl.basic.service.pc.SourceService; import com.ycwl.basic.storage.adapters.IStorageAdapter; import com.ycwl.basic.task.VideoPieceGetter; @@ -46,6 +47,8 @@ public class SourceServiceImpl implements SourceService { @Autowired private SourceRepository sourceRepository; @Autowired + private ScenicService scenicService; + @Autowired private ScenicRepository scenicRepository; @Autowired private DeviceRepository deviceRepository; @@ -181,7 +184,7 @@ public class SourceServiceImpl implements SourceService { throw new BaseException("该素材不存在"); } try { - IStorageAdapter adapter = StorageFactory.use(); + IStorageAdapter adapter = scenicService.getScenicStorageAdapter(source.getScenicId()); String uploadedUrl = adapter.uploadFile("image/jpeg", file, PHOTO_PATH, id + "_q_.jpg"); SourceEntity sourceUpd = new SourceEntity(); diff --git a/src/main/java/com/ycwl/basic/service/printer/impl/PrinterServiceImpl.java b/src/main/java/com/ycwl/basic/service/printer/impl/PrinterServiceImpl.java index 375ea463..5ff4f70a 100644 --- a/src/main/java/com/ycwl/basic/service/printer/impl/PrinterServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/printer/impl/PrinterServiceImpl.java @@ -1103,7 +1103,25 @@ public class PrinterServiceImpl implements PrinterService { * 从context中的scenicConfigManager获取配置 */ private void prepareStorageAdapter(PhotoProcessContext context) { - context.setStorageAdapter(StorageFactory.use()); + ScenicConfigManager scenicConfig = context.getScenicConfigManager(); + if (scenicConfig == null) { + log.warn("scenicConfigManager未设置,将使用默认存储"); + return; + } + + try { + String storeType = scenicConfig.getString("store_type"); + if (storeType != null) { + IStorageAdapter adapter = StorageFactory.get(storeType); + String storeConfigJson = scenicConfig.getString("store_config_json"); + if (StringUtils.isNotBlank(storeConfigJson)) { + adapter.loadConfig(JacksonUtil.parseObject(storeConfigJson, Map.class)); + } + context.setStorageAdapter(adapter); + } + } catch (Exception e) { + log.warn("准备存储适配器失败,将使用默认存储: {}", e.getMessage()); + } } @Override diff --git a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java index 4a3fb66d..76298775 100644 --- a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java +++ b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java @@ -601,7 +601,14 @@ public class TaskTaskServiceImpl implements TaskService { if (worker == null) { return null; } - IStorageAdapter adapter = scenicService.getScenicStorageAdapter(task.getScenicId()); + RenderWorkerConfigManager config = repository.getWorkerConfigManager(worker.getId()); + IStorageAdapter adapter; + try { + adapter = StorageFactory.get(config.getString("store_type")); + adapter.loadConfig(config.getObject("store_config_json", Map.class)); + } catch (Exception e) { + adapter = scenicService.getScenicStorageAdapter(task.getScenicId()); + } String hash = MD5.create().digestHex(task.getTaskParams() + task.getFaceId().toString()); String filename = StorageUtil.joinPath(StorageConstant.VLOG_PATH, task.getTemplateId().toString() + "_" + hash + "_" + task.getScenicId() + ".mp4"); // 生成 diff --git a/src/main/java/com/ycwl/basic/task/FaceCleaner.java b/src/main/java/com/ycwl/basic/task/FaceCleaner.java index 6290cb5f..8c0f204e 100644 --- a/src/main/java/com/ycwl/basic/task/FaceCleaner.java +++ b/src/main/java/com/ycwl/basic/task/FaceCleaner.java @@ -34,9 +34,7 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import static com.ycwl.basic.constant.FaceConstant.USER_FACE_DB_NAME; @@ -228,16 +226,6 @@ public class FaceCleaner { public void cleanSourceOss() { log.info("开始清理源视频素材文件"); List list = sourceMapper.list(new SourceReqQuery()); - Map sourceImageUrlMap = new HashMap<>(); - Map sourceScenicIdMap = new HashMap<>(); - list.forEach(item -> { - if (item.getId() != null && item.getScenicId() != null) { - sourceScenicIdMap.put(item.getId(), item.getScenicId()); - } - if (item.getId() != null) { - sourceImageUrlMap.put(item.getId(), item.getUrl()); - } - }); ArrayList adapterIdentity = new ArrayList<>(); ScenicReqQuery query = new ScenicReqQuery(); query.setPageSize(1000); @@ -272,45 +260,22 @@ public class FaceCleaner { log.info("文件存在关系:{},未删除", fileObject); } }); - }); - - log.info("开始清理图片文件"); - IStorageAdapter imageAdapter = StorageFactory.use(); - List fileObjectList = imageAdapter.listDir(StorageConstant.PHOTO_PATH); - fileObjectList.parallelStream().forEach(fileObject -> { - if (fileObject.getModifyTime() != null) { - // 如果是一天以内修改的,则跳过 - if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) <= 1) { - return; + log.info("开始清理图片文件"); + fileObjectList = adapter.listDir(StorageConstant.PHOTO_PATH); + fileObjectList.parallelStream().forEach(fileObject -> { + if (fileObject.getModifyTime() != null) { + // 如果是一天以内修改的,则跳过 + if (DateUtil.between(fileObject.getModifyTime(), new Date(), DateUnit.DAY) <= 1) { + return; + } } - } - - String name = fileObject.getName(); - if (name == null) { - return; - } - int underscoreIndex = name.indexOf('_'); - if (underscoreIndex <= 0) { - return; - } - Long sourceId; - try { - sourceId = Long.parseLong(name.substring(0, underscoreIndex)); - } catch (NumberFormatException e) { - return; - } - Long scenicId = sourceScenicIdMap.get(sourceId); - if (scenicId == null || disableDeleteScenicIds.contains(scenicId.toString())) { - return; - } - - String imageUrl = sourceImageUrlMap.get(sourceId); - if (imageUrl != null && imageUrl.contains(name)) { - log.info("文件存在关系:{},未删除", fileObject); - return; - } - log.info("删除文件:{}", fileObject); - imageAdapter.deleteFile(fileObject.getFullPath()); + if (list.parallelStream().filter(videoRespVO -> Objects.nonNull(videoRespVO.getUrl())).noneMatch(videoRespVO -> videoRespVO.getUrl().contains(fileObject.getName()))){ + log.info("删除文件:{}", fileObject); + adapter.deleteFile(fileObject.getFullPath()); + } else { + log.info("文件存在关系:{},未删除", fileObject); + } + }); }); } public void cleanVideoOss() {