Ver código fonte

完成素材(CRUD)接口

tsurumure 1 mês atrás
pai
commit
0ea6c8d9b5

+ 19 - 19
db/ai_media_ttv_timbre.sql

@@ -19,23 +19,23 @@ CREATE TABLE `ai_media_ttv_timbre` (
 
 
 INSERT INTO ai_media_ttv_timbre(timbre_key, category_id, name, tag, description, avatar, audio_url) VALUES
-    ('0', '2', '小美-女', '成熟女声', '可使用于金融、零售、广告场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/0:小美-女.mp3'),
-    ('1', '1', '小宇-男', '温润男声', '可使用于小说、故事场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/1:小宇-男.mp3'),
-    ('3', '1', '小云-男', '磁性男声', '可使用于通用场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/3:小云-男.mp3'),
-    ('4', '4', '小丫-女童', '乖巧童声', '可使用于小说、故事场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-child-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4:小丫-女童.mp3'),
-    ('5', '2', '小娇-女', '情感女声', '可使用于小说、故事场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/5:小娇-女.mp3'),
-    ('103', '4', '小朵-女童', '可爱童声', '可使用于通用场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-child-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/103:小朵-女童.mp3'),
-    ('106', '1', '小博-男', '成熟男声', '可使用于新闻、金融、零售场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/106:小博-男.mp3'),
-    ('110', '3', '小童-男童', '活泼童声', '可使用于通用场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-child-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/110:小童-男童.mp3'),
-    ('111', '2', '小萌-女', '萝莉女声', '可使用于社交、游戏场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-child-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/111:小萌-女.mp3'),
-    ('4003', '1', '小耀-男', '磁性男声', '可使用于金融、零售、广告场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4003:小耀-男.mp3'),
-    ('4100', '2', '小雯-女', '成熟女声', '可使用于新闻、金融、零售场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4100:小雯-女.mp3'),
-    ('4103', '3', '小米-男童', '可爱童声', '可使用于通用场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-child-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4103:小米-男童.mp3'),
-    ('4105', '2', '小灵-女', '清澈女声', '可使用于通用场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4105:小灵-女.mp3'),
-    ('4106', '1', '小文-男', '情感男声', '可使用于社交、游戏场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4106:小文-男.mp3'),
-    ('4115', '1', '小贤-男', '情感男声', '可使用于社交、故事场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4115:小贤-男.mp3'),
-    ('4117', '2', '小乔-女', '情感女声', '可使用于社交、故事场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4117:小乔-女.mp3'),
-    ('4119', '2', '小鹿-女', '甜美女声', '可使用于社交、游戏场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4119:小鹿-女.mp3'),
-    ('5003', '1', '小遥-男', '甜美男声', '可使用于社交、故事场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/5003:小遥-男.mp3'),
-    ('5118', '2', '小婷-女', '甜美女声', '可使用于社交、游戏场景', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'http://cos.daogu.ai/materials/baidu/ai-generate-video/audio/5118:小婷-女.mp3')
+    ('0', '2', '小美-女', '成熟女声', '可使用于金融、零售、广告场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/0:小美-女.mp3'),
+    ('1', '1', '小宇-男', '温润男声', '可使用于小说、故事场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/1:小宇-男.mp3'),
+    ('3', '1', '小云-男', '磁性男声', '可使用于通用场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/3:小云-男.mp3'),
+    ('4', '4', '小丫-女童', '乖巧童声', '可使用于小说、故事场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-child-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4:小丫-女童.mp3'),
+    ('5', '2', '小娇-女', '情感女声', '可使用于小说、故事场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/5:小娇-女.mp3'),
+    ('103', '4', '小朵-女童', '可爱童声', '可使用于通用场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-child-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/103:小朵-女童.mp3'),
+    ('106', '1', '小博-男', '成熟男声', '可使用于新闻、金融、零售场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/106:小博-男.mp3'),
+    ('110', '3', '小童-男童', '活泼童声', '可使用于通用场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-child-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/110:小童-男童.mp3'),
+    ('111', '2', '小萌-女', '萝莉女声', '可使用于社交、游戏场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-child-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/111:小萌-女.mp3'),
+    ('4003', '1', '小耀-男', '磁性男声', '可使用于金融、零售、广告场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4003:小耀-男.mp3'),
+    ('4100', '2', '小雯-女', '成熟女声', '可使用于新闻、金融、零售场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4100:小雯-女.mp3'),
+    ('4103', '3', '小米-男童', '可爱童声', '可使用于通用场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-child-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4103:小米-男童.mp3'),
+    ('4105', '2', '小灵-女', '清澈女声', '可使用于通用场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4105:小灵-女.mp3'),
+    ('4106', '1', '小文-男', '情感男声', '可使用于社交、游戏场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4106:小文-男.mp3'),
+    ('4115', '1', '小贤-男', '情感男声', '可使用于社交、故事场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4115:小贤-男.mp3'),
+    ('4117', '2', '小乔-女', '情感女声', '可使用于社交、故事场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4117:小乔-女.mp3'),
+    ('4119', '2', '小鹿-女', '甜美女声', '可使用于社交、游戏场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/4119:小鹿-女.mp3'),
+    ('5003', '1', '小遥-男', '甜美男声', '可使用于社交、故事场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/male-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/5003:小遥-男.mp3'),
+    ('5118', '2', '小婷-女', '甜美女声', '可使用于社交、游戏场景', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/avatar/female-1.png', 'https://cos.daogu.ai/materials/baidu/ai-generate-video/audio/5118:小婷-女.mp3')
 ;

+ 28 - 2
src/main/java/com/backendsys/modules/ai/material/controller/MaterialController.java

@@ -3,13 +3,14 @@ package com.backendsys.modules.ai.material.controller;
 import com.backendsys.modules.ai.material.entity.Material;
 import com.backendsys.modules.ai.material.entity.MaterialTag;
 import com.backendsys.modules.ai.material.service.MaterialService;
+import com.backendsys.modules.common.aspect.SysLog;
+import com.backendsys.modules.common.config.security.utils.SecurityUtil;
 import com.backendsys.modules.common.utils.Result;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 
 @Validated
 @RestController
@@ -26,4 +27,29 @@ public class MaterialController {
         return Result.success().put("data", materialService.selectMaterialList(material));
     }
 
+    @Operation(summary = "创建素材")
+//    @PreAuthorize("@sr.hasPermission('31')")
+    @PostMapping("/api/ai/material/createMaterial")
+    public Result createMaterial(@Validated(Material.Create.class) @RequestBody Material material) {
+        material.setUser_id(SecurityUtil.getUserId());
+        return Result.success().put("data", materialService.insertMaterial(material));
+    }
+
+    @SysLog("编辑素材")
+    @Operation(summary = "编辑素材")
+//    @PreAuthorize("@sr.hasPermission('31')")
+    @PutMapping("/api/ai/material/updateMaterial")
+    public Result updateMaterial(@Validated(Material.Update.class) @RequestBody Material material) {
+        material.setUser_id(SecurityUtil.getUserId());
+        return Result.success().put("data", materialService.updateMaterial(material));
+    }
+
+    @SysLog("删除素材")
+    @Operation(summary = "删除素材")
+//    @PreAuthorize("@sr.hasPermission('31')")
+    @DeleteMapping("/api/ai/material/deleteMaterial")
+    public Result deleteMaterial(@Validated(Material.Delete.class) @RequestBody Material material) {
+        return Result.success().put("data", materialService.deleteMaterial(material));
+    }
+
 }

+ 7 - 1
src/main/java/com/backendsys/modules/ai/material/dao/MaterialDao.java

@@ -10,7 +10,13 @@ import java.util.Map;
 @Mapper
 public interface MaterialDao extends BaseMapper<Material> {
 
-    // 获取素材分类列表
+    // 获取素材列表
     List<Material> selectMaterialList(Material material);
+    // 创建素材
+    int insertMaterial(Material material);
+    // 编辑素材
+    int updateMaterial(Material material);
+    // 删除素材
+    int deleteMaterial(Material material);
 
 }

+ 2 - 0
src/main/java/com/backendsys/modules/ai/material/dao/MaterialTagDao.java

@@ -11,4 +11,6 @@ public interface MaterialTagDao extends BaseMapper<MaterialTag> {
 
     List<MaterialTag> selectMaterialTagList(MaterialTag materialTag);
 
+
+
 }

+ 1 - 1
src/main/java/com/backendsys/modules/ai/material/entity/Material.java

@@ -59,7 +59,7 @@ public class Material {
     @Size(max = 1000, message = "PSD路径长度不超过 {max} 个字符", groups = { Create.class, Update.class })
     private String psd_url;
 
-    @RangeArray(message="是否有版权,范围应是(-1否, 1是)", value = {"-1", "1"})
+    @RangeArray(message="是否有版权,范围应是(-1否, 1是)", value = {"-1", "1"}, groups = { Create.class, Update.class })
     private Integer is_copyright;
 
     @JsonAdapter(LocalDateTimeAdapter.class)

+ 11 - 0
src/main/java/com/backendsys/modules/ai/material/service/MaterialService.java

@@ -3,9 +3,20 @@ package com.backendsys.modules.ai.material.service;
 import com.backendsys.modules.ai.material.entity.Material;
 import com.backendsys.utils.response.PageEntity;
 
+import java.util.Map;
+
 public interface MaterialService {
 
     // 获取素材列表
     PageEntity selectMaterialList(Material material);
 
+    // 创建素材
+    Map<String, Object> insertMaterial(Material material);
+
+    // 编辑素材
+    Map<String, Object> updateMaterial(Material material);
+
+    // 删除素材
+    Map<String, Object> deleteMaterial(Material material);
+
 }

+ 73 - 3
src/main/java/com/backendsys/modules/ai/material/service/impl/MaterialServiceImpl.java

@@ -1,22 +1,28 @@
 package com.backendsys.modules.ai.material.service.impl;
 
 import cn.hutool.core.util.StrUtil;
+import com.backendsys.exception.CustException;
+import com.backendsys.modules.ai.material.dao.MaterialCategoryDao;
 import com.backendsys.modules.ai.material.dao.MaterialDao;
 import com.backendsys.modules.ai.material.dao.MaterialTagDao;
 import com.backendsys.modules.ai.material.entity.Material;
+import com.backendsys.modules.ai.material.entity.MaterialCategory;
 import com.backendsys.modules.ai.material.entity.MaterialTag;
 import com.backendsys.modules.ai.material.service.MaterialService;
-import com.backendsys.modules.upload.enums.StyleEnums;
-import com.backendsys.modules.upload.utils.UploadUtil;
+import com.backendsys.modules.upload.service.SysFileService;
+import com.backendsys.modules.upload.utils.ObjectKey.ObjectKeyEntity;
+import com.backendsys.modules.upload.utils.ObjectKey.ObjectKeyUtil;
 import com.backendsys.utils.response.PageEntity;
 import com.backendsys.utils.response.PageInfoResult;
 import com.backendsys.utils.v2.PageUtils;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.CompletableFuture;
 import java.util.stream.Collectors;
 
 @Service
@@ -26,6 +32,13 @@ public class MaterialServiceImpl implements MaterialService {
     private MaterialDao materialDao;
     @Autowired
     private MaterialTagDao materialTagDao;
+    @Autowired
+    private MaterialCategoryDao materialCategoryDao;
+    @Autowired
+    private SysFileService sysFileService;
+
+    @Autowired
+    private ObjectKeyUtil objectKeyUtil;
 
     /**
      * 获取素材列表
@@ -59,9 +72,66 @@ public class MaterialServiceImpl implements MaterialService {
         }
 
         return pageEntity;
+    }
+
+    /**
+     * 创建素材
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> insertMaterial(Material material) {
+
+        MaterialCategory materialCategory = materialCategoryDao.selectById(material.getCategory_id());
+        if (materialCategory == null) throw new CustException("素材分类不存在");
+
+        materialDao.insertMaterial(material);
+
+        return Map.of("material_id", material.getMaterial_id());
+    }
+
+    /**
+     * 编辑素材
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> updateMaterial(Material material) {
+
+        Material detail = materialDao.selectById(material.getMaterial_id());
+        if (detail == null) throw new CustException("素材不存在");
+
+        if (material.getCategory_id() != null) {
+            MaterialCategory materialCategory = materialCategoryDao.selectById(material.getCategory_id());
+            if (materialCategory == null) throw new CustException("素材分类不存在");
+        }
+
+        // 编辑的时候,如果素材图片有修改,需要删除之前的图片
+
+        materialDao.updateMaterial(material);
+        return Map.of("material_id", material.getMaterial_id());
+    };
+
+    /**
+     * 删除素材
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public Map<String, Object> deleteMaterial(Material material) {
+
+        Material detail = materialDao.selectById(material.getMaterial_id());
+        if (detail == null) throw new CustException("素材不存在");
 
+        // 删除的时候,同时删除对象存储中的素材图片 (异步)
+        ObjectKeyEntity image_url_object = objectKeyUtil.urlToObjectKey(detail.getImage_url());
+        ObjectKeyEntity fla_url_object = objectKeyUtil.urlToObjectKey(detail.getFla_url());
+        ObjectKeyEntity psd_url_object = objectKeyUtil.urlToObjectKey(detail.getPsd_url());
+        CompletableFuture.runAsync(() -> {
+            sysFileService.deleteObject(image_url_object.getObject_key(), image_url_object.getTarget());
+            sysFileService.deleteObject(fla_url_object.getObject_key(), fla_url_object.getTarget());
+            sysFileService.deleteObject(psd_url_object.getObject_key(), psd_url_object.getTarget());
+        });
 
-//        return new PageInfoResult(list).toEntity();
+        materialDao.deleteMaterial(material);
+        return Map.of("material_id", material.getMaterial_id());
     }
 
 }

+ 1 - 2
src/main/java/com/backendsys/modules/crt/service/impl/CrtDramaProjectStoryboardServiceImpl.java

@@ -1,6 +1,5 @@
 package com.backendsys.modules.crt.service.impl;
 
-import cn.hutool.core.convert.Convert;
 import com.backendsys.exception.CustException;
 import com.backendsys.modules.common.config.security.enums.SecurityEnum;
 import com.backendsys.modules.common.config.security.utils.SecurityUtil;
@@ -13,7 +12,7 @@ import com.backendsys.modules.crt.entity.*;
 import com.backendsys.modules.crt.service.CrtDramaProjectStoryboardService;
 import com.backendsys.modules.upload.entity.ObjectKey;
 import com.backendsys.modules.upload.enums.StyleEnums;
-import com.backendsys.modules.upload.utils.ObjectKeyUtil;
+import com.backendsys.modules.upload.utils.ObjectKey.ObjectKeyUtil;
 import com.backendsys.modules.upload.utils.UploadUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.springframework.beans.factory.annotation.Autowired;

+ 4 - 0
src/main/java/com/backendsys/modules/upload/service/SysFileService.java

@@ -3,6 +3,7 @@ package com.backendsys.modules.upload.service;
 import com.backendsys.modules.upload.entity.SysFile;
 import com.backendsys.modules.upload.entity.SysFileMergeByMd5;
 import com.backendsys.modules.upload.entity.SysFileResult;
+import com.backendsys.modules.upload.utils.ObjectKey.ObjectKeyEntity;
 import com.backendsys.utils.response.PageEntity;
 import com.baomidou.mybatisplus.extension.service.IService;
 import org.springframework.web.multipart.MultipartFile;
@@ -39,5 +40,8 @@ public interface SysFileService extends IService<SysFile> {
     // 合并重复 MD5 文件
     Map<String, Object> mergeFileByMd5(SysFileMergeByMd5 sysFileMergeByMd5);
 
+    // 删除存储桶对象 (单个)
+    void deleteObject(String object_key, Integer target);
+    void deleteObjects(List<ObjectKeyEntity> list);
 
 }

+ 27 - 2
src/main/java/com/backendsys/modules/upload/service/impl/SysFileServiceImpl.java

@@ -25,6 +25,7 @@ import com.backendsys.modules.upload.entity.SysFileResult;
 import com.backendsys.modules.upload.enums.StyleEnums;
 import com.backendsys.modules.upload.enums.TargetEnums;
 import com.backendsys.modules.upload.service.SysFileService;
+import com.backendsys.modules.upload.utils.ObjectKey.ObjectKeyEntity;
 import com.backendsys.modules.upload.utils.UploadUtil;
 import com.backendsys.utils.response.PageEntity;
 import com.backendsys.utils.response.PageInfoResult;
@@ -324,8 +325,12 @@ public class SysFileServiceImpl extends ServiceImpl<SysFileDao, SysFile> impleme
     }
 
 
-    // target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
-    private void deleteObject(String object_key, Integer target) {
+    /**
+     * 删除存储桶对象 (单个)
+     * target: 上传目标 (-1:本地, 1:腾讯云, 2:阿里云, 3.抖音云)
+     */
+    @Override
+    public void deleteObject(String object_key, Integer target) {
         if (target == -1) {
             // [本地] 删除文件
             uploadUtil.delete(object_key);
@@ -341,6 +346,26 @@ public class SysFileServiceImpl extends ServiceImpl<SysFileDao, SysFile> impleme
             System.out.println("Delete douyin tos object: " + object_key);
         }
     }
+    /**
+     * 删除存储桶对象 (批量)
+     */
+    @Override
+    public void deleteObjects(List<ObjectKeyEntity> list) {
+        list.stream().forEach(item -> {
+            if (item.getTarget() == 1) {
+                // [腾讯云] 删除对象
+                List<String> object_keys = list.stream().map(it -> it.getObject_key()).collect(Collectors.toList());
+                tencentCosService.deleteObjects(object_keys);
+                System.out.println("Delete tencent cos object (batch): " + object_keys);
+            }
+            if (item.getTarget() == 3) {
+                // [抖音云] 删除对象
+                List<String> object_keys = list.stream().map(it -> it.getObject_key()).collect(Collectors.toList());
+                douyinTosService.deleteObjects(object_keys);
+                System.out.println("Delete douyin tos object (batch): " + object_keys);
+            }
+        });
+    }
 
     /**
      * 删除文件 (包括缩略图,如果有的话)

+ 11 - 0
src/main/java/com/backendsys/modules/upload/utils/ObjectKey/ObjectKeyEntity.java

@@ -0,0 +1,11 @@
+package com.backendsys.modules.upload.utils.ObjectKey;
+
+import lombok.Data;
+
+@Data
+public class ObjectKeyEntity {
+
+    private String object_key;
+    private Integer target;
+
+}

+ 38 - 1
src/main/java/com/backendsys/modules/upload/utils/ObjectKeyUtil.java → src/main/java/com/backendsys/modules/upload/utils/ObjectKey/ObjectKeyUtil.java

@@ -1,11 +1,13 @@
-package com.backendsys.modules.upload.utils;
+package com.backendsys.modules.upload.utils.ObjectKey;
 
 import com.backendsys.modules.sdk.douyincloud.tos.service.DouyinTosService;
 import com.backendsys.modules.sdk.tencentcloud.cos.service.TencentCosService;
 import com.backendsys.modules.upload.entity.ObjectKey;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
@@ -13,8 +15,13 @@ import java.util.stream.Collectors;
 @Component
 public class ObjectKeyUtil {
 
+    @Value("${tencent.cos.accessible-domain}")
+    private String TENCENT_DOMAIN;
     @Autowired
     private TencentCosService tencentCosService;
+
+    @Value("${douyin.tos.domain}")
+    private String DOUYIN_DOMAIN;
     @Autowired
     private DouyinTosService douyinTosService;
 
@@ -25,6 +32,36 @@ public class ObjectKeyUtil {
         return objectKeys.stream().collect(Collectors.groupingBy(ObjectKey::getTarget));
     }
 
+    /**
+     * 根据 url 获取 object_key
+     */
+    public ObjectKeyEntity urlToObjectKey(String url) {
+        String prefix = null;
+        Integer target = -1;
+        if (url.startsWith(TENCENT_DOMAIN)) {
+            prefix = TENCENT_DOMAIN;
+            target = 1;
+        } else if (url.startsWith(DOUYIN_DOMAIN)) {
+            prefix = DOUYIN_DOMAIN;
+            target = 3;
+        }
+        // 去掉协议头(http://、https://)后,再取前缀
+        int domainStart = url.indexOf(prefix);
+        if (domainStart == -1) {
+            return null;
+        }
+        // 去掉域名前缀,取后面的路径
+        String object_key = url.substring(domainStart + prefix.length());
+        // 去掉可能的前导斜杠
+        if (object_key.startsWith("/")) {
+            object_key = object_key.substring(1);
+        }
+        ObjectKeyEntity result = new ObjectKeyEntity();
+        result.setObject_key(object_key);
+        result.setTarget(target);
+        return result;
+    }
+
     /**
      * 批量删除 ObjectKeys (By target)
      */

+ 1 - 1
src/main/resources/application-dev.yml

@@ -149,7 +149,7 @@ tencent:
     region: ap-hongkong
     bucket-name: storage-1320301544
     # accessible-domain: https://storage-1320301544.cos.ap-hongkong.myqcloud.com
-    accessible-domain: http://cos.daogu.ai
+    accessible-domain: https://cos.daogu.ai
   ivh:
     empty-app-key: 283ca6dc9d4147debc60bf9fc3fbbe03         # 空数据账号 (我自己的子账号)
     empty-access-token: eea44503a2f64c119fb0acd2006dacb0

+ 1 - 1
src/main/resources/application-local.yml

@@ -153,7 +153,7 @@ tencent:
     # 香港
     region: ap-hongkong
     bucket-name: storage-1320301544
-    accessible-domain: http://cos.daogu.ai
+    accessible-domain: https://cos.daogu.ai
 #    # 广州
 #    region: ap-guangzhou
 #    bucket-name: duanju3-1320301544

+ 1 - 1
src/main/resources/application-prod.yml

@@ -150,7 +150,7 @@ tencent:
     region: ap-hongkong
     bucket-name: storage-1320301544
     # accessible-domain: https://storage-1320301544.cos.ap-hongkong.myqcloud.com
-    accessible-domain: http://cos.daogu.ai
+    accessible-domain: https://cos.daogu.ai
   ivh:
     empty-app-key: 283ca6dc9d4147debc60bf9fc3fbbe03         # 空数据账号 (我自己的子账号)
     empty-access-token: eea44503a2f64c119fb0acd2006dacb0

+ 43 - 1
src/main/resources/mapper/ai/material/MaterialDao.xml

@@ -18,7 +18,7 @@
         m.create_time,
         m.update_time
     </sql>
-    <!-- java.util.LinkedHashMap -->
+
     <resultMap id="resultMapMaterial" type="com.backendsys.modules.ai.material.entity.Material">
         <id property="id" column="id" jdbcType="BIGINT" />
         <result property="material_id" column="id" javaType="java.lang.Long" />
@@ -60,5 +60,47 @@
         ORDER BY m.create_time DESC
     </select>
 
+    <!-- 增 -->
+    <insert id="insertMaterial" parameterType="com.backendsys.modules.ai.material.entity.Material"
+        useGeneratedKeys="true" keyProperty="material_id">
+        INSERT INTO ai_material (
+            user_id, category_id, material_name
+            <if test="tag_ids != null and tag_ids != ''">, tag_ids</if>
+            <if test="image_thumb_url != null and image_thumb_url != ''">, image_thumb_url</if>
+            <if test="image_url != null and image_url != ''">, image_url</if>
+            <if test="fla_url != null and fla_url != ''">, fla_url</if>
+            <if test="psd_url != null and psd_url != ''">, psd_url</if>
+            <if test="is_copyright != null and is_copyright != ''">, is_copyright</if>
+        )
+        VALUES (
+           #{user_id}, #{category_id}, #{material_name}
+            <if test="tag_ids != null and tag_ids != ''">, #{tag_ids}</if>
+            <if test="image_thumb_url != null and image_thumb_url != ''">, #{image_thumb_url}</if>
+            <if test="image_url != null and image_url != ''">, #{image_url}</if>
+            <if test="fla_url != null and fla_url != ''">, #{fla_url}</if>
+            <if test="psd_url != null and psd_url != ''">, #{psd_url}</if>
+            <if test="is_copyright != null and is_copyright != ''">, #{is_copyright}</if>
+       )
+    </insert>
+
+    <!-- 改 -->
+    <update id="updateMaterial" parameterType="com.backendsys.modules.ai.material.entity.Material"
+        useGeneratedKeys="true" keyProperty="material_id">
+        UPDATE ai_material SET
+        user_id = #{user_id}
+        <if test="category_id != null and category_id != ''">, category_id = #{category_id}</if>
+        <if test="material_name != null and material_name != ''">, material_name = #{material_name}</if>
+        <if test="tag_ids != null and tag_ids != ''">, tag_ids = #{tag_ids}</if>
+        <if test="image_thumb_url != null and image_thumb_url != ''">, image_thumb_url = #{image_thumb_url}</if>
+        <if test="image_url != null and image_url != ''">, image_url = #{image_url}</if>
+        <if test="fla_url != null and fla_url != ''">, fla_url = #{fla_url}</if>
+        <if test="psd_url != null and psd_url != ''">, psd_url = #{psd_url}</if>
+        <if test="is_copyright != null and is_copyright != ''">, is_copyright = #{is_copyright}</if>
+        WHERE id = #{material_id}
+    </update>
+
+    <delete id="deleteMaterial">
+        DELETE FROM ai_material WHERE id = #{material_id}
+    </delete>
 
 </mapper>