feat(image): 添加图片清理功能- 新增 FileStorageService 用于文件上传、下载和删除操作- 实现 ImageCleanupService 清理冗余图片
- 添加 ImageCleanupController 提供手动清理图片的 API - 创建 ImageCleanupScheduler定时清理冗余图片 - 更新相关 Mapper 接口,增加必要的查询和删除方法
This commit is contained in:
@@ -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 + " 个冗余图片");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,8 @@ package com.test.bijihoudaun.mapper;
|
|||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.test.bijihoudaun.entity.Image;
|
import com.test.bijihoudaun.entity.Image;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ImageMapper extends BaseMapper<Image> {
|
public interface ImageMapper extends BaseMapper<Image> {
|
||||||
@@ -11,4 +13,11 @@ public interface ImageMapper extends BaseMapper<Image> {
|
|||||||
|
|
||||||
// 自定义方法:根据Markdown文件ID获取关联图片
|
// 自定义方法:根据Markdown文件ID获取关联图片
|
||||||
// List<Image> findByMarkdownId(Integer markdownId);
|
// List<Image> findByMarkdownId(Integer markdownId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有图片记录
|
||||||
|
* @return 所有图片列表
|
||||||
|
*/
|
||||||
|
@Select("SELECT * FROM image")
|
||||||
|
List<Image> findAll();
|
||||||
}
|
}
|
||||||
@@ -3,8 +3,17 @@ package com.test.bijihoudaun.mapper;
|
|||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.test.bijihoudaun.entity.ImageName;
|
import com.test.bijihoudaun.entity.ImageName;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.apache.ibatis.annotations.Delete;
|
||||||
|
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface ImageNameMapper extends BaseMapper<ImageName> {
|
public interface ImageNameMapper extends BaseMapper<ImageName> {
|
||||||
// 可以在这里添加自定义方法
|
// 可以在这里添加自定义方法
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据文件名删除记录
|
||||||
|
* @param fileName 文件名
|
||||||
|
* @return 删除的记录数
|
||||||
|
*/
|
||||||
|
@Delete("DELETE FROM image_name WHERE file_name = #{fileName}")
|
||||||
|
int deleteByFileName(String fileName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,4 +43,11 @@ public interface MarkdownFileMapper extends BaseMapper<MarkdownFile> {
|
|||||||
void restoreById(@Param("id") Long id);
|
void restoreById(@Param("id") Long id);
|
||||||
@Delete("DELETE FROM markdown_file WHERE is_deleted = 1")
|
@Delete("DELETE FROM markdown_file WHERE is_deleted = 1")
|
||||||
void physicalDeleteByIsDeleted();
|
void physicalDeleteByIsDeleted();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有笔记ID
|
||||||
|
* @return 所有笔记ID列表
|
||||||
|
*/
|
||||||
|
@Select("SELECT id FROM markdown_file WHERE is_deleted = 0")
|
||||||
|
List<Integer> findAllIds();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 + " 个冗余图片");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<Integer> allMarkdownIds = markdownFileMapper.findAllIds();
|
||||||
|
|
||||||
|
// 用于存储所有被引用的图片文件名
|
||||||
|
Set<String> referencedImageNames = new HashSet<>();
|
||||||
|
|
||||||
|
// 遍历所有笔记,收集被引用的图片
|
||||||
|
for (Integer markdownId : allMarkdownIds) {
|
||||||
|
MarkdownFile markdownFile = markdownFileMapper.selectById(markdownId);
|
||||||
|
String content = (markdownFile != null) ? markdownFile.getContent() : "";
|
||||||
|
|
||||||
|
List<String> imageNames = MarkdownImageExtractor.extractImageFilenames(content);
|
||||||
|
referencedImageNames.addAll(imageNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有图片记录
|
||||||
|
List<Image> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
spring:
|
spring:
|
||||||
datasource:
|
datasource:
|
||||||
driver-class-name: org.sqlite.JDBC
|
driver-class-name: org.sqlite.JDBC
|
||||||
url: jdbc:sqlite:C:\it\houtaigunli\biji\mydatabase.db
|
# url: jdbc:sqlite:C:\it\houtaigunli\biji\mydatabase.db
|
||||||
# url: jdbc:sqlite:C:\KAIFA\2\mydatabase.db
|
url: jdbc:sqlite:C:\KAIFA\2\mydatabase.db
|
||||||
jpa:
|
jpa:
|
||||||
hibernate:
|
hibernate:
|
||||||
ddl-auto: none
|
ddl-auto: none
|
||||||
|
|||||||
Reference in New Issue
Block a user