From fa11b388db0b2ffecc1d8b613ce8a19ba7e183ea Mon Sep 17 00:00:00 2001 From: Timi Date: Mon, 5 Jan 2026 14:35:38 +0800 Subject: [PATCH] refactor TempFileService, use Attachment and mongodb --- .../api/modules/common/bean/SettingKey.java | 19 ++- .../modules/common/bean/TempFileMetaData.java | 26 ---- .../common/controller/CommonController.java | 67 ++++---- .../api/modules/common/entity/Attachment.java | 21 ++- .../common/mapper/AttachmentMapper.java | 10 +- .../common/service/AttachmentService.java | 4 +- .../common/service/TempFileService.java | 12 +- .../implement/AttachmentServiceImplement.java | 43 +++--- .../implement/TempFileServiceImplement.java | 144 +++++++----------- .../common/task/AttachmentClearTask.java | 49 ++++++ .../implement/JournalServiceImplement.java | 25 ++- .../TravelLocationServiceImplement.java | 15 +- .../resources/mapper/git/ReleaseMapper.xml | 2 +- 13 files changed, 222 insertions(+), 215 deletions(-) delete mode 100644 src/main/java/com/imyeyu/api/modules/common/bean/TempFileMetaData.java create mode 100644 src/main/java/com/imyeyu/api/modules/common/task/AttachmentClearTask.java diff --git a/src/main/java/com/imyeyu/api/modules/common/bean/SettingKey.java b/src/main/java/com/imyeyu/api/modules/common/bean/SettingKey.java index 69f5480..e63121a 100644 --- a/src/main/java/com/imyeyu/api/modules/common/bean/SettingKey.java +++ b/src/main/java/com/imyeyu/api/modules/common/bean/SettingKey.java @@ -131,7 +131,7 @@ public enum SettingKey { MUSIC_CONTROLLER_URI, - // ---------- ---------- + // ---------- 日记 ---------- JOURNAL_KEY, @@ -139,7 +139,22 @@ public enum SettingKey { JOURNAL_APP_SECRET, - JOURNAL_TRAVEL, + // ---------- 临时文件 ---------- + + /** 临时文件最小缓存时间 */ + TEMP_FILE_TTL_MIN, + + /** 临时文件最长缓存时间 */ + TEMP_FILE_TTL_MAX, + + /** 临时文件默认缓存时间 */ + TEMP_FILE_TTL_DEFAULT, + + /** 已过期的临时文件保留时间 */ + TEMP_FILE_RESIDUE_TIME, + + /** 每个 IP 限制有效临时文件容量 */ + TEMP_FILE_LIMIT, // ---------- 系统 ---------- diff --git a/src/main/java/com/imyeyu/api/modules/common/bean/TempFileMetaData.java b/src/main/java/com/imyeyu/api/modules/common/bean/TempFileMetaData.java deleted file mode 100644 index 4f44ef0..0000000 --- a/src/main/java/com/imyeyu/api/modules/common/bean/TempFileMetaData.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.imyeyu.api.modules.common.bean; - -import lombok.Data; - -import java.nio.file.Path; - -/** - * @author 夜雨 - * @since 2025-09-27 01:47 - */ -@Data -public class TempFileMetaData { - - private String id; - - private String name; - - private String originalName; - - private Path path; - - private Long lastAccessAt; - - /** 缓存时长(毫秒) */ - private Long ttl; -} diff --git a/src/main/java/com/imyeyu/api/modules/common/controller/CommonController.java b/src/main/java/com/imyeyu/api/modules/common/controller/CommonController.java index f00e144..aa50490 100644 --- a/src/main/java/com/imyeyu/api/modules/common/controller/CommonController.java +++ b/src/main/java/com/imyeyu/api/modules/common/controller/CommonController.java @@ -5,7 +5,6 @@ import com.google.gson.reflect.TypeToken; import com.imyeyu.api.bean.CaptchaFrom; import com.imyeyu.api.modules.common.bean.ImageType; import com.imyeyu.api.modules.common.bean.SettingKey; -import com.imyeyu.api.modules.common.bean.TempFileMetaData; import com.imyeyu.api.modules.common.entity.Attachment; import com.imyeyu.api.modules.common.entity.Setting; import com.imyeyu.api.modules.common.entity.Task; @@ -63,12 +62,8 @@ import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; -import java.io.File; import java.io.IOException; -import java.io.RandomAccessFile; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -392,29 +387,28 @@ public class CommonController { /** * 读取临时文件 * - * @param fileId - * @param req - * @param resp + * @param mongoId mongoId + * @param req 请求 + * @param resp 返回 */ @AOPLog @RequestRateLimit @IgnoreGlobalReturn - @GetMapping("/temp/file/read/{fileId}") - public void tempFileRead(@PathVariable String fileId, HttpServletRequest req, HttpServletResponse resp) { + @GetMapping("/temp/file/read/{mongoId}") + public void tempFileRead(@PathVariable String mongoId, HttpServletRequest req, HttpServletResponse resp) { try { - File file = tempFileService.get(fileId); - if (TimiJava.isEmpty(file) && file.exists()) { + Attachment attach = attachmentService.getByMongoId(mongoId); + if (TimiJava.isEmpty(attach)) { resp.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } - Path filePath = file.toPath(); - resp.setContentLengthLong(Files.size(filePath)); - String mimeType = new Tika().detect(filePath); - if (TimiJava.isNotEmpty(mimeType)) { - resp.setContentType(mimeType); - } - req.setAttribute(ResourceHandler.ATTR_TYPE, ResourceHandler.Type.FILE); - req.setAttribute(ResourceHandler.ATTR_VALUE, filePath); + GridFSFile file = attachmentService.readByMongoId(attach.getMongoId()); + GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(file.getObjectId()); + GridFsResource gridFsResource = new GridFsResource(file, downloadStream); + req.setAttribute(ResourceHandler.ATTR_TYPE, ResourceHandler.Type.MONGO); + req.setAttribute(ResourceHandler.ATTR_VALUE, gridFsResource); + + resp.setContentType(attach.getMimeType()); resourceHandler.handleRequest(req, resp); } catch (Exception e) { resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); @@ -424,41 +418,40 @@ public class CommonController { /** * 下载临时文件 * - * @param fileId + * @param mongoId * @param resp */ @AOPLog @RequestRateLimit @IgnoreGlobalReturn - @RequestMapping("/temp/file/download/{fileId}") - public void tempFileDownload(@PathVariable String fileId, HttpServletResponse resp) { + @RequestMapping("/temp/file/download/{mongoId}") + public void tempFileDownload(@PathVariable String mongoId, HttpServletResponse resp) { try { - TempFileMetaData metadata = tempFileService.metadata(fileId); - File file = tempFileService.get(fileId); - if (TimiJava.isEmpty(file) && file.exists()) { + Attachment attach = attachmentService.getByMongoId(mongoId); + if (TimiJava.isEmpty(attach)) { resp.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } - String mimeType = new Tika().detect(file); - resp.setContentType(mimeType); - resp.setHeader("Content-Disposition", Network.getFileDownloadHeader(metadata.getOriginalName())); + resp.setContentType(attach.getMimeType()); + resp.setHeader("Content-Disposition", Network.getFileDownloadHeader(attach.getName())); resp.setHeader("Accept-Ranges", "bytes"); - RequestRange range = TimiSpring.requestRange(file.length()); + GridFSFile file = attachmentService.readByMongoId(mongoId); + @Cleanup + GridFSDownloadStream downloadStream = gridFSBucket.openDownloadStream(file.getObjectId()); + RequestRange range = TimiSpring.requestRange(attach.getSize()); if (range == null) { // 完整文件 - resp.setContentLengthLong(file.length()); + resp.setContentLengthLong(attach.getSize()); resp.setStatus(HttpServletResponse.SC_OK); - IO.toOutputStream(resp.getOutputStream(), file); + IO.toOutputStream(downloadStream, resp.getOutputStream()); } else { // 分片文件 resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); - resp.setHeader("Content-Range", "bytes %s-%s/%s".formatted(range.getStart(), range.getEnd(), file.length())); + resp.setHeader("Content-Range", "bytes %s-%s/%s".formatted(range.getStart(), range.getEnd(), attach.getSize())); resp.setContentLengthLong(range.getLength()); - - @Cleanup RandomAccessFile raf = new RandomAccessFile(file, "r"); - raf.seek(range.getStart()); - IO.toOutputStream(resp.getOutputStream(), raf, range.getStart(), range.getLength()); + IO.toOutputStream(downloadStream, resp.getOutputStream(), range.getStart(), range.getEnd()); + resp.flushBuffer(); } } catch (Exception e) { log.error("download error", e); diff --git a/src/main/java/com/imyeyu/api/modules/common/entity/Attachment.java b/src/main/java/com/imyeyu/api/modules/common/entity/Attachment.java index 01aada5..cfe8c0e 100644 --- a/src/main/java/com/imyeyu/api/modules/common/entity/Attachment.java +++ b/src/main/java/com/imyeyu/api/modules/common/entity/Attachment.java @@ -1,7 +1,9 @@ package com.imyeyu.api.modules.common.entity; import com.google.gson.JsonObject; +import com.imyeyu.api.TimiServerAPI; import com.imyeyu.api.bean.MultilingualHandler; +import com.imyeyu.api.modules.common.service.AttachmentService; import com.imyeyu.java.ref.Ref; import com.imyeyu.spring.annotation.table.Transient; import com.imyeyu.spring.entity.Entity; @@ -48,14 +50,20 @@ public class Attachment extends Entity implements MultilingualHandler { /** 镜像 */ MIRROR, + /** 日记 */ JOURNAL, + /** 日记出行 */ JOURNAL_TRAVEL, + /** 日记瞬间 */ JOURNAL_MOMENT, /** 系统 */ - SYSTEM + SYSTEM, + + /** 临时文件 */ + TEMP_FILE } protected BizType bizType; @@ -79,11 +87,20 @@ public class Attachment extends Entity implements MultilingualHandler { protected String md5; + protected String uploaderIp; + + protected Boolean isDestroyed; + protected Long destroyAt; @Transient protected InputStream inputStream; - + + public InputStream openInputStream() { + AttachmentService service = TimiServerAPI.applicationContext.getBean(AttachmentService.class); + return service.getInputStreamByMongoId(mongoId); + } + public void setAttachTypeValue(Enum attachType) { this.attachType = attachType.toString(); } diff --git a/src/main/java/com/imyeyu/api/modules/common/mapper/AttachmentMapper.java b/src/main/java/com/imyeyu/api/modules/common/mapper/AttachmentMapper.java index acba67c..6ffce84 100644 --- a/src/main/java/com/imyeyu/api/modules/common/mapper/AttachmentMapper.java +++ b/src/main/java/com/imyeyu/api/modules/common/mapper/AttachmentMapper.java @@ -3,6 +3,7 @@ package com.imyeyu.api.modules.common.mapper; import com.imyeyu.api.modules.common.entity.Attachment; import com.imyeyu.spring.bean.Page; import com.imyeyu.spring.mapper.BaseMapper; +import com.imyeyu.spring.mapper.RawMapper; import org.apache.ibatis.annotations.Select; import java.util.List; @@ -11,10 +12,10 @@ import java.util.List; * @author 夜雨 * @since 2023-08-15 10:22 */ -public interface AttachmentMapper extends BaseMapper { +public interface AttachmentMapper extends BaseMapper, RawMapper { /** 有效条件,非删除和销毁 */ - String VALID = NOT_DELETE + " AND destroy_at IS NULL"; + String VALID = NOT_DELETE + " AND (`destroy_at` IS NULL OR " + UNIX_TIME + " < `destroy_at`)"; @Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} " + VALID + LIMIT_1) Attachment selectByBizId(Attachment.BizType bizType, long bizId); @@ -25,9 +26,12 @@ public interface AttachmentMapper extends BaseMapper { @Select("SELECT * FROM attachment WHERE biz_type = #{bizType} AND biz_id = #{bizId} AND attach_type = #{attachType} " + VALID + LIMIT_1) Attachment selectByAttachType(Attachment.BizType bizType, long bizId, Enum attachType); - List listByBizId(Attachment.BizType bizType, Long bizId, List> attachTypes, Page page); + List listByBizId(Attachment.BizType bizType, Long bizId, List> attachTypes, Page page); long countByBizId(Attachment.BizType bizType, Long bizId, List> attachTypes); List listByMd5s(Attachment.BizType bizType, Long bizId, List> attachTypes, List md5s); + + @Select("SELECT * FROM attachment WHERE `is_destroyed` = FALSE AND `destroy_at` < " + UNIX_TIME) + List selectNeedDestroy(); } diff --git a/src/main/java/com/imyeyu/api/modules/common/service/AttachmentService.java b/src/main/java/com/imyeyu/api/modules/common/service/AttachmentService.java index f56114c..0d72edc 100644 --- a/src/main/java/com/imyeyu/api/modules/common/service/AttachmentService.java +++ b/src/main/java/com/imyeyu/api/modules/common/service/AttachmentService.java @@ -56,7 +56,9 @@ public interface AttachmentService extends BaseService { */ long countByBizId(Attachment.BizType bizType, Long bizId, Enum ...attachTypes); - List listByMd5s(Attachment.BizType bizType, Long bizId, List> attachTypeList, List md5s) throws TimiException; + List listByMd5s(Attachment.BizType bizType, Long bizId, List> attachTypeList, List md5s); void deleteByBizId(Attachment.BizType bizType, long bizId, Enum ...attachTypes); + + List listNeedDestroy(); } diff --git a/src/main/java/com/imyeyu/api/modules/common/service/TempFileService.java b/src/main/java/com/imyeyu/api/modules/common/service/TempFileService.java index 22c3590..80d911c 100644 --- a/src/main/java/com/imyeyu/api/modules/common/service/TempFileService.java +++ b/src/main/java/com/imyeyu/api/modules/common/service/TempFileService.java @@ -1,12 +1,8 @@ package com.imyeyu.api.modules.common.service; -import com.imyeyu.api.modules.common.bean.TempFileMetaData; import com.imyeyu.api.modules.common.vo.TempFileResponse; -import com.imyeyu.java.bean.timi.TimiException; import org.springframework.web.multipart.MultipartFile; -import java.io.File; -import java.io.InputStream; import java.util.List; /** @@ -15,11 +11,5 @@ import java.util.List; */ public interface TempFileService { - List store(List files, Long ttl) throws TimiException; - - File get(String id) throws TimiException; - - InputStream getInputStream(String id) throws TimiException; - - TempFileMetaData metadata(String id) throws TimiException; + List store(List files, Long ttl); } diff --git a/src/main/java/com/imyeyu/api/modules/common/service/implement/AttachmentServiceImplement.java b/src/main/java/com/imyeyu/api/modules/common/service/implement/AttachmentServiceImplement.java index f6e02c0..701efa0 100644 --- a/src/main/java/com/imyeyu/api/modules/common/service/implement/AttachmentServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/common/service/implement/AttachmentServiceImplement.java @@ -15,6 +15,7 @@ import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiCode; import com.imyeyu.java.bean.timi.TimiException; import com.imyeyu.network.Network; +import com.imyeyu.spring.TimiSpring; import com.imyeyu.spring.mapper.BaseMapper; import com.imyeyu.spring.service.AbstractEntityService; import com.imyeyu.utils.Time; @@ -67,13 +68,11 @@ public class AttachmentServiceImplement extends AbstractEntityService { - Thumbnails.of(sourceStream).width(256).keepAspectRatio(true).toOutputStream(thumbStream); - } + case "image/png", "image/bmp", "image/jpeg" -> Thumbnails.of(sourceStream).width(256).keepAspectRatio(true).toOutputStream(thumbStream); case "video/mp4", "video/quicktime" -> { log.info("capturing thumbnail: {}", attachment.getName()); long start = Time.now(); @@ -201,9 +203,9 @@ public class AttachmentServiceImplement extends AbstractEntityService listNeedDestroy() { + return mapper.selectNeedDestroy(); + } } diff --git a/src/main/java/com/imyeyu/api/modules/common/service/implement/TempFileServiceImplement.java b/src/main/java/com/imyeyu/api/modules/common/service/implement/TempFileServiceImplement.java index 9c0373c..8f74d1a 100644 --- a/src/main/java/com/imyeyu/api/modules/common/service/implement/TempFileServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/common/service/implement/TempFileServiceImplement.java @@ -1,38 +1,27 @@ package com.imyeyu.api.modules.common.service.implement; +import com.google.gson.Gson; import com.imyeyu.api.modules.common.bean.SettingKey; -import com.imyeyu.api.modules.common.bean.TempFileMetaData; +import com.imyeyu.api.modules.common.entity.Attachment; import com.imyeyu.api.modules.common.service.AttachmentService; import com.imyeyu.api.modules.common.service.SettingService; import com.imyeyu.api.modules.common.service.TempFileService; import com.imyeyu.api.modules.common.vo.TempFileResponse; -import com.imyeyu.io.IO; import com.imyeyu.io.IOSize; import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiCode; import com.imyeyu.java.bean.timi.TimiException; -import com.imyeyu.network.Network; import com.imyeyu.spring.TimiSpring; +import com.imyeyu.spring.bean.Page; import com.imyeyu.utils.Time; -import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; /** * @author 夜雨 @@ -43,61 +32,58 @@ import java.util.concurrent.ConcurrentHashMap; @RequiredArgsConstructor public class TempFileServiceImplement implements TempFileService { - private static final Long DEFAULT_TTL = Time.H * 6; - private static final Long MAX_TTL = Time.D * 3; - private static final Long LIMIT = IOSize.GB * 10; + private final Gson gson; private final SettingService settingService; private final AttachmentService attachmentService; - private Path storagePath; - - private final Map metadataMap = new ConcurrentHashMap<>(); - private final Map usageMap = new ConcurrentHashMap<>(); - - @PostConstruct - public void init() throws IOException { - storagePath = Paths.get(settingService.getAsString(SettingKey.TEMP_FILE_PATH)); - IO.destroy(storagePath.toFile()); - Files.createDirectories(storagePath); - } - public List store(List files, Long ttl) throws TimiException { - ttl = TimiJava.defaultIfNull(ttl, DEFAULT_TTL); - TimiException.requiredTrue(0 < ttl && ttl <= MAX_TTL, "ttl must be between 1ms and 3 days(259200000ms)"); + String ttlMinStr = settingService.getAsString(SettingKey.TEMP_FILE_TTL_MIN); + String ttlMaxStr = settingService.getAsString(SettingKey.TEMP_FILE_TTL_MAX); + String limitStr = settingService.getAsString(SettingKey.TEMP_FILE_LIMIT); + + long minTTL = Time.parseToMS(ttlMinStr); + long maxTTL = Time.parseToMS(ttlMaxStr); + long defaultTTL = Time.parseToMS(settingService.getAsString(SettingKey.TEMP_FILE_TTL_DEFAULT)); + long limit = IOSize.parse(limitStr); + long residueTime = Time.parseToMS(settingService.getAsString(SettingKey.TEMP_FILE_RESIDUE_TIME)); + + ttl = TimiJava.defaultIfNull(ttl, defaultTTL); + TimiException.requiredTrue(minTTL < ttl && ttl <= maxTTL, String.format("ttl must be between %s and %s", ttlMinStr, ttlMaxStr)); long newFileSize = files.stream().mapToLong(MultipartFile::getSize).sum(); - long currentUsage = usageMap.getOrDefault(TimiSpring.getRequestIP(), 0L); - TimiException.requiredTrue(currentUsage + newFileSize < LIMIT, "out of storage limit(10 GB)"); - + { + // 缓存池大小限制 + Page page = new Page<>(); + page.setIndex(0); + page.setSize(Long.MAX_VALUE); + { + Attachment example = new Attachment(); + example.setUploaderIp(TimiSpring.getRequestIP()); + page.setEqualsExample(example); + } + long currentUsage = attachmentService.page(page).getList().stream().mapToLong(Attachment::getSize).sum(); + TimiException.requiredTrue(currentUsage + newFileSize < limit, "out of storage limit(%s)".formatted(limitStr)); + } try { List result = new ArrayList<>(); + + long deletedAt = Time.now() + ttl; + long destroyAt = deletedAt + residueTime; for (int i = 0; i < files.size(); i++) { MultipartFile file = files.get(i); - String fileId = UUID.randomUUID().toString(); - String fileName = fileId; - if (TimiJava.isNotEmpty(file.getOriginalFilename())) { - fileName = fileId + "." + Network.uriFileExtension(file.getOriginalFilename()); - } - Path filePath = storagePath.resolve(fileName); - Files.copy(file.getInputStream(), filePath); - - // 创建元数据 - TempFileMetaData metadata = new TempFileMetaData(); - metadata.setId(fileId); - metadata.setPath(filePath); - metadata.setName(fileName); - metadata.setOriginalName(file.getOriginalFilename()); - metadata.setLastAccessAt(Time.now()); - metadata.setTtl(ttl); - metadataMap.put(metadata.getId(), metadata); + Attachment attach = new Attachment(); + attach.setBizType(Attachment.BizType.TEMP_FILE); + attach.setName(file.getOriginalFilename()); + attach.setDeletedAt(deletedAt); + attach.setDestroyAt(destroyAt); + attach.setInputStream(file.getInputStream()); + attachmentService.create(attach); TempFileResponse resp = new TempFileResponse(); - resp.setId(metadata.getId()); - resp.setExpireAt(metadata.getLastAccessAt() + ttl); - - usageMap.put(TimiSpring.getRequestIP(), currentUsage + newFileSize); + resp.setId(attach.getMongoId()); + resp.setExpireAt(deletedAt); result.add(resp); } return result; @@ -107,42 +93,20 @@ public class TempFileServiceImplement implements TempFileService { } } - @Override - public File get(String id) throws TimiException { - TempFileMetaData metaData = metadataMap.get(id); - TimiException.required(metaData, "not found temp file"); - metaData.setLastAccessAt(Time.now()); - return metaData.getPath().toFile(); - } - - @Override - public InputStream getInputStream(String id) throws TimiException { - try { - return IO.getInputStream(get(id)); - } catch (FileNotFoundException e) { - throw new TimiException(TimiCode.RESULT_NULL, "not found temp file"); - } - } - - @Override - public TempFileMetaData metadata(String id) throws TimiException { - return metadataMap.get(id); - } - @Scheduled(fixedRate = 3600000) public void cleanup() { - List expiredIds = metadataMap.values() - .stream() - .filter(metadata -> metadata.getLastAccessAt() + metadata.getTtl() < Time.now()) - .map(TempFileMetaData::getId) - .toList(); - for (int i = 0; i < expiredIds.size(); i++) { - TempFileMetaData removed = metadataMap.remove(expiredIds.get(i)); - if (TimiJava.isNotEmpty(removed)) { - File file = removed.getPath().toFile(); - IO.destroy(file); - usageMap.computeIfPresent(TimiSpring.getRequestIP(), (ip, usage) -> usage - file.length()); - } - } +// List expiredIds = metadataMap.values() +// .stream() +// .filter(metadata -> metadata.getLastAccessAt() + metadata.getTtl() < Time.now()) +// .map(TempFileMetaData::getId) +// .toList(); +// for (int i = 0; i < expiredIds.size(); i++) { +// TempFileMetaData removed = metadataMap.remove(expiredIds.get(i)); +// if (TimiJava.isNotEmpty(removed)) { +// File file = removed.getPath().toFile(); +// IO.destroy(file); +// usageMap.computeIfPresent(TimiSpring.getRequestIP(), (ip, usage) -> usage - file.length()); +// } +// } } } diff --git a/src/main/java/com/imyeyu/api/modules/common/task/AttachmentClearTask.java b/src/main/java/com/imyeyu/api/modules/common/task/AttachmentClearTask.java new file mode 100644 index 0000000..5befa55 --- /dev/null +++ b/src/main/java/com/imyeyu/api/modules/common/task/AttachmentClearTask.java @@ -0,0 +1,49 @@ +package com.imyeyu.api.modules.common.task; + +import com.imyeyu.api.modules.common.entity.Attachment; +import com.imyeyu.api.modules.common.service.AttachmentService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.List; + +/** + * 附件清除定时任务。每天凌晨 1 点执行,清除已过期但未销毁的附件 + * + * @author 夜雨 + * @since 2026-01-05 12:37 + */ +@Slf4j +@Configuration +@EnableScheduling +@RequiredArgsConstructor +public class AttachmentClearTask { + + private final AttachmentService attachmentService; + + @Scheduled(cron = "0 0 1 * * ?") + public void run() { + log.info("start clear expired attachments"); + try { + List needDestroyList = attachmentService.listNeedDestroy(); + if (needDestroyList.isEmpty()) { + log.info("nothing attachment need clear"); + return; + } + for (Attachment attach : needDestroyList) { + try { + attachmentService.destroy(attach.getId()); + log.info("clear attachment success: id[{}]", attach.getId()); + } catch (Exception e) { + log.error("clear attachment error: id[{}]", attach.getId(), e); + } + } + log.info("end clear expired attachments"); + } catch (Exception e) { + log.error("attachment clear task error", e); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/imyeyu/api/modules/journal/service/implement/JournalServiceImplement.java b/src/main/java/com/imyeyu/api/modules/journal/service/implement/JournalServiceImplement.java index 01b2a4d..874e2cb 100644 --- a/src/main/java/com/imyeyu/api/modules/journal/service/implement/JournalServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/journal/service/implement/JournalServiceImplement.java @@ -4,7 +4,6 @@ import com.google.gson.Gson; import com.imyeyu.api.config.dbsource.TimiServerDBConfig; import com.imyeyu.api.modules.common.bean.MediaAttach; import com.imyeyu.api.modules.common.bean.Metadata; -import com.imyeyu.api.modules.common.bean.TempFileMetaData; import com.imyeyu.api.modules.common.entity.Attachment; import com.imyeyu.api.modules.common.service.AttachmentService; import com.imyeyu.api.modules.common.service.SettingService; @@ -15,7 +14,6 @@ import com.imyeyu.api.modules.journal.service.JournalService; import com.imyeyu.api.modules.journal.vo.journal.ArchiveRequest; import com.imyeyu.api.modules.journal.vo.journal.JournalRequest; import com.imyeyu.api.modules.journal.vo.journal.UpdateRequest; -import com.imyeyu.io.IO; import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiCode; import com.imyeyu.java.bean.timi.TimiException; @@ -27,7 +25,6 @@ import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -69,14 +66,13 @@ public class JournalServiceImplement extends AbstractEntityService thumbResult = new ArrayList<>(); for (int i = 0; i < tempFileIds.length; i++) { - TempFileMetaData metadata = tempFileService.metadata(tempFileIds[i]); - File file = tempFileService.get(tempFileIds[i]); + Attachment tempFileAttach = attachmentService.getByMongoId(tempFileIds[i]); Attachment sourceAttach = new Attachment(); - sourceAttach.setName(metadata.getOriginalName()); + sourceAttach.setName(tempFileAttach.getName()); sourceAttach.setBizType(Attachment.BizType.JOURNAL_MOMENT); sourceAttach.setBizId(0L); sourceAttach.setAttachTypeValue(MediaAttach.Type.SOURCE); - sourceAttach.setSize(file.length()); - sourceAttach.setInputStream(IO.getInputStream(file)); + sourceAttach.setSize(tempFileAttach.getSize()); + sourceAttach.setInputStream(tempFileAttach.openInputStream()); thumbResult.add(attachmentService.createMedia(sourceAttach)); } return thumbResult; diff --git a/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelLocationServiceImplement.java b/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelLocationServiceImplement.java index f574490..5c79d09 100644 --- a/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelLocationServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/journal/service/implement/TravelLocationServiceImplement.java @@ -2,10 +2,8 @@ package com.imyeyu.api.modules.journal.service.implement; import com.imyeyu.api.config.dbsource.TimiServerDBConfig; import com.imyeyu.api.modules.common.bean.MediaAttach; -import com.imyeyu.api.modules.common.bean.TempFileMetaData; import com.imyeyu.api.modules.common.entity.Attachment; import com.imyeyu.api.modules.common.service.AttachmentService; -import com.imyeyu.api.modules.common.service.TempFileService; import com.imyeyu.api.modules.journal.entity.TravelLocation; import com.imyeyu.api.modules.journal.mapper.TravelLocationMapper; import com.imyeyu.api.modules.journal.service.TravelLocationService; @@ -36,7 +34,6 @@ import java.util.stream.Collectors; public class TravelLocationServiceImplement extends AbstractEntityService implements TravelLocationService { private final TravelService travelService; - private final TempFileService tempFileService; private final AttachmentService attachmentService; private final TravelLocationMapper mapper; @@ -51,13 +48,13 @@ public class TravelLocationServiceImplement extends AbstractEntityService - +