From b28446c4b62fa4e14f1f7ba2a08485ff10ce1dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=84=E5=AD=9F?= <3111696955@qq.com> Date: Wed, 6 Aug 2025 17:29:11 +0800 Subject: [PATCH] =?UTF-8?q?feat(image):=20=E6=B7=BB=E5=8A=A0=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E6=B8=85=E7=90=86=E5=8A=9F=E8=83=BD-=20=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=20FileStorageService=20=E7=94=A8=E4=BA=8E=E6=96=87?= =?UTF-8?q?=E4=BB=B6=E4=B8=8A=E4=BC=A0=E3=80=81=E4=B8=8B=E8=BD=BD=E5=92=8C?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=93=8D=E4=BD=9C-=20=E5=AE=9E=E7=8E=B0=20Im?= =?UTF-8?q?ageCleanupService=20=E6=B8=85=E7=90=86=E5=86=97=E4=BD=99?= =?UTF-8?q?=E5=9B=BE=E7=89=87=20-=20=E6=B7=BB=E5=8A=A0=20ImageCleanupContr?= =?UTF-8?q?oller=20=E6=8F=90=E4=BE=9B=E6=89=8B=E5=8A=A8=E6=B8=85=E7=90=86?= =?UTF-8?q?=E5=9B=BE=E7=89=87=E7=9A=84=20API=20-=20=E5=88=9B=E5=BB=BA=20Im?= =?UTF-8?q?ageCleanupScheduler=E5=AE=9A=E6=97=B6=E6=B8=85=E7=90=86?= =?UTF-8?q?=E5=86=97=E4=BD=99=E5=9B=BE=E7=89=87=20-=20=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=20Mapper=20=E6=8E=A5=E5=8F=A3=EF=BC=8C?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BF=85=E8=A6=81=E7=9A=84=E6=9F=A5=E8=AF=A2?= =?UTF-8?q?=E5=92=8C=E5=88=A0=E9=99=A4=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ImageCleanupController.java | 32 ++++++++ .../test/bijihoudaun/mapper/ImageMapper.java | 9 +++ .../bijihoudaun/mapper/ImageNameMapper.java | 9 +++ .../mapper/MarkdownFileMapper.java | 7 ++ .../scheduler/ImageCleanupScheduler.java | 27 +++++++ .../service/FileStorageService.java | 44 ++++++++++ .../service/ImageCleanupService.java | 81 +++++++++++++++++++ .../src/main/resources/application-dev.yml | 4 +- 8 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 biji-houdaun/src/main/java/com/test/bijihoudaun/controller/ImageCleanupController.java create mode 100644 biji-houdaun/src/main/java/com/test/bijihoudaun/scheduler/ImageCleanupScheduler.java create mode 100644 biji-houdaun/src/main/java/com/test/bijihoudaun/service/FileStorageService.java create mode 100644 biji-houdaun/src/main/java/com/test/bijihoudaun/service/ImageCleanupService.java diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/ImageCleanupController.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/ImageCleanupController.java new file mode 100644 index 0000000..e9e7af4 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/controller/ImageCleanupController.java @@ -0,0 +1,32 @@ +package com.test.bijihoudaun.controller; + +import com.test.bijihoudaun.service.ImageCleanupService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * 图片清理控制器 + * 提供手动触发清理冗余图片的API端点 + */ +@RestController +@RequestMapping("/api/admin") +public class ImageCleanupController { + + @Autowired + private ImageCleanupService imageCleanupService; + + /** + * 手动触发清理冗余图片 + * @return 清理结果 + */ + @PostMapping("/cleanup-images") + @PreAuthorize("hasRole('ADMIN')") + public ResponseEntity cleanupImages() { + int deletedCount = imageCleanupService.cleanupRedundantImages(); + return ResponseEntity.ok().body("成功清理 " + deletedCount + " 个冗余图片"); + } +} diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/ImageMapper.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/ImageMapper.java index 6a91a43..11d57fe 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/ImageMapper.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/ImageMapper.java @@ -3,6 +3,8 @@ package com.test.bijihoudaun.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.test.bijihoudaun.entity.Image; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Select; +import java.util.List; @Mapper public interface ImageMapper extends BaseMapper { @@ -11,4 +13,11 @@ public interface ImageMapper extends BaseMapper { // 自定义方法:根据Markdown文件ID获取关联图片 // List findByMarkdownId(Integer markdownId); + + /** + * 获取所有图片记录 + * @return 所有图片列表 + */ + @Select("SELECT * FROM image") + List findAll(); } \ No newline at end of file diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/ImageNameMapper.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/ImageNameMapper.java index 1bf88f4..5cb7db1 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/ImageNameMapper.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/ImageNameMapper.java @@ -3,8 +3,17 @@ package com.test.bijihoudaun.mapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.test.bijihoudaun.entity.ImageName; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Delete; @Mapper public interface ImageNameMapper extends BaseMapper { // 可以在这里添加自定义方法 + + /** + * 根据文件名删除记录 + * @param fileName 文件名 + * @return 删除的记录数 + */ + @Delete("DELETE FROM image_name WHERE file_name = #{fileName}") + int deleteByFileName(String fileName); } diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/MarkdownFileMapper.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/MarkdownFileMapper.java index 5a9872d..c85d32b 100644 --- a/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/MarkdownFileMapper.java +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/mapper/MarkdownFileMapper.java @@ -43,4 +43,11 @@ public interface MarkdownFileMapper extends BaseMapper { void restoreById(@Param("id") Long id); @Delete("DELETE FROM markdown_file WHERE is_deleted = 1") void physicalDeleteByIsDeleted(); + + /** + * 获取所有笔记ID + * @return 所有笔记ID列表 + */ + @Select("SELECT id FROM markdown_file WHERE is_deleted = 0") + List findAllIds(); } diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/scheduler/ImageCleanupScheduler.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/scheduler/ImageCleanupScheduler.java new file mode 100644 index 0000000..c7574b9 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/scheduler/ImageCleanupScheduler.java @@ -0,0 +1,27 @@ +package com.test.bijihoudaun.scheduler; + +import com.test.bijihoudaun.service.ImageCleanupService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * 图片清理定时任务 + * 定期自动清理冗余图片 + */ +@Component +public class ImageCleanupScheduler { + + @Autowired + private ImageCleanupService imageCleanupService; + + /** + * 定时清理任务 + * 每天凌晨3点执行一次清理任务 + */ + @Scheduled(cron = "0 0 3 * * ?") + public void scheduledCleanup() { + int deletedCount = imageCleanupService.cleanupRedundantImages(); + System.out.println("定时清理任务完成,清理了 " + deletedCount + " 个冗余图片"); + } +} diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/FileStorageService.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/FileStorageService.java new file mode 100644 index 0000000..bf1297d --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/FileStorageService.java @@ -0,0 +1,44 @@ +package com.test.bijihoudaun.service; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/** + * 文件存储服务 + * 用于处理文件上传、下载和删除等操作 + */ +@Service +public class FileStorageService { + + @Value("${file.upload-dir}") + private String uploadDir; + + /** + * 加载文件作为File对象 + * @param filename 文件名 + * @return 文件对象 + */ + public java.io.File loadAsFile(String filename) { + return new java.io.File(uploadDir + java.io.File.separator + filename); + } + + /** + * 删除文件 + * @param filename 文件名 + * @return 是否删除成功 + */ + public boolean deleteFile(String filename) { + try { + Path filePath = Paths.get(uploadDir, filename); + return Files.deleteIfExists(filePath); + } catch (IOException e) { + System.err.println("Failed to delete file: " + filename); + return false; + } + } +} diff --git a/biji-houdaun/src/main/java/com/test/bijihoudaun/service/ImageCleanupService.java b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/ImageCleanupService.java new file mode 100644 index 0000000..427d7e8 --- /dev/null +++ b/biji-houdaun/src/main/java/com/test/bijihoudaun/service/ImageCleanupService.java @@ -0,0 +1,81 @@ +package com.test.bijihoudaun.service; + +import com.test.bijihoudaun.util.MarkdownImageExtractor; +import com.test.bijihoudaun.mapper.ImageMapper; +import com.test.bijihoudaun.mapper.MarkdownFileMapper; +import com.test.bijihoudaun.mapper.ImageNameMapper; +import com.test.bijihoudaun.entity.Image; +import com.test.bijihoudaun.entity.MarkdownFile; +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.Set; +import java.util.HashSet; + +/** + * 图片清理服务类 + * 用于清理不再被笔记引用的冗余图片 + */ +@Service +public class ImageCleanupService { + + @Autowired + private ImageMapper imageMapper; + + @Autowired + private MarkdownFileMapper markdownFileMapper; + + @Autowired + private ImageNameMapper imageNameMapper; + + @Autowired + private FileStorageService fileStorageService; + + /** + * 清理冗余图片 + * @return 清理的图片数量 + */ + @Transactional + public int cleanupRedundantImages() { + // 获取所有笔记ID + List allMarkdownIds = markdownFileMapper.findAllIds(); + + // 用于存储所有被引用的图片文件名 + Set referencedImageNames = new HashSet<>(); + + // 遍历所有笔记,收集被引用的图片 + for (Integer markdownId : allMarkdownIds) { + MarkdownFile markdownFile = markdownFileMapper.selectById(markdownId); + String content = (markdownFile != null) ? markdownFile.getContent() : ""; + + List imageNames = MarkdownImageExtractor.extractImageFilenames(content); + referencedImageNames.addAll(imageNames); + } + + // 获取所有图片记录 + List allImages = imageMapper.findAll(); + + // 记录被删除的图片数量 + int deletedCount = 0; + + // 遍历所有图片,删除未被引用的 + for (Image image : allImages) { + if (!referencedImageNames.contains(image.getStoredName())) { + // 删除物理文件 + fileStorageService.deleteFile(image.getStoredName()); + + // 删除数据库记录 + imageMapper.deleteById(image.getId()); + + // 如果存在image_name表中的记录,也一并删除 + imageNameMapper.deleteByFileName(image.getStoredName()); + + deletedCount++; + } + } + + return deletedCount; + } +} diff --git a/biji-houdaun/src/main/resources/application-dev.yml b/biji-houdaun/src/main/resources/application-dev.yml index 023ec84..ec5da6e 100644 --- a/biji-houdaun/src/main/resources/application-dev.yml +++ b/biji-houdaun/src/main/resources/application-dev.yml @@ -1,8 +1,8 @@ spring: datasource: driver-class-name: org.sqlite.JDBC - url: jdbc:sqlite:C:\it\houtaigunli\biji\mydatabase.db -# url: jdbc:sqlite:C:\KAIFA\2\mydatabase.db +# url: jdbc:sqlite:C:\it\houtaigunli\biji\mydatabase.db + url: jdbc:sqlite:C:\KAIFA\2\mydatabase.db jpa: hibernate: ddl-auto: none