From 395c5e91b5693039b3877bbfd398f5fb8cd8d434 Mon Sep 17 00:00:00 2001 From: ChiveHao Date: Sun, 10 Nov 2024 14:52:03 +0800 Subject: [PATCH] =?UTF-8?q?optimize:=20=E5=89=A7=E9=9B=86=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E6=9F=A5=E8=AF=A2=E6=96=B9=E6=B3=95=20(#726)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * optimize: 移除缓存配置 * optimize: 剧集资源查询方法 --- CHANGELOG.MD | 7 ++ .../ikaros/api/infra/utils/ReflectUtils.java | 69 +++++++++++++++++++ gradle.properties | 2 +- .../server/cache/CacheConfiguration.java | 20 ------ .../core/episode/DefaultEpisodeService.java | 53 ++++---------- 5 files changed, 91 insertions(+), 60 deletions(-) create mode 100644 api/src/main/java/run/ikaros/api/infra/utils/ReflectUtils.java delete mode 100644 server/src/main/java/run/ikaros/server/cache/CacheConfiguration.java diff --git a/CHANGELOG.MD b/CHANGELOG.MD index cecb3952..1b42dad7 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -2,6 +2,13 @@ 更新日志文档,版本顺序从新到旧,最新版本在最前(上)面。 +# 0.19.4 + +## 优化 + +- 移除缓存配置 +- 优化查询剧集附件接口 + # 0.19.3 ## 优化 diff --git a/api/src/main/java/run/ikaros/api/infra/utils/ReflectUtils.java b/api/src/main/java/run/ikaros/api/infra/utils/ReflectUtils.java new file mode 100644 index 00000000..e5ac6fb1 --- /dev/null +++ b/api/src/main/java/run/ikaros/api/infra/utils/ReflectUtils.java @@ -0,0 +1,69 @@ +package run.ikaros.api.infra.utils; + +import java.lang.reflect.Field; +import java.util.Map; + +public class ReflectUtils { + + /** + * 将数据库字段名转换为驼峰命名法的 Java 字段名. + * + * @param dbFieldName 数据库字段名(如 ATTACHMENT_ID) + * @return 转换后的 Java 字段名(如 attachmentId) + */ + public static String convertToCamelCase(String dbFieldName) { + if (dbFieldName == null || dbFieldName.isEmpty()) { + return dbFieldName; + } + + StringBuilder result = new StringBuilder(); + boolean toUpperCase = false; + + for (int i = 0; i < dbFieldName.length(); i++) { + char ch = dbFieldName.charAt(i); + if (ch == '_') { + toUpperCase = true; + } else { + if (toUpperCase) { + result.append(Character.toUpperCase(ch)); + toUpperCase = false; + } else { + result.append(Character.toLowerCase(ch)); + } + } + } + + return result.toString(); + } + + /** + * Map to Object instance. + */ + public static T mapToClass(Map map, Class clazz, + boolean ignoreMissingField) { + T instance; + try { + instance = clazz.getDeclaredConstructor().newInstance(); + for (Map.Entry entry : map.entrySet()) { + String fieldName = convertToCamelCase(entry.getKey()); + Object fieldValue = entry.getValue(); + + Field field; + try { + field = clazz.getDeclaredField(fieldName); + } catch (NoSuchFieldException noSuchFieldException) { + if (ignoreMissingField) { + continue; + } else { + throw noSuchFieldException; + } + } + field.setAccessible(true); // 允许访问私有字段 + field.set(instance, fieldValue); + } + } catch (Exception e) { + throw new RuntimeException("Mapping failed", e); + } + return instance; + } +} diff --git a/gradle.properties b/gradle.properties index 64f0c8c7..b4a939ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1 +1 @@ -version=0.19.3 +version=0.19.4 diff --git a/server/src/main/java/run/ikaros/server/cache/CacheConfiguration.java b/server/src/main/java/run/ikaros/server/cache/CacheConfiguration.java deleted file mode 100644 index 68a82689..00000000 --- a/server/src/main/java/run/ikaros/server/cache/CacheConfiguration.java +++ /dev/null @@ -1,20 +0,0 @@ -package run.ikaros.server.cache; - -import org.springframework.cache.CacheManager; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.cache.concurrent.ConcurrentMapCacheManager; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableCaching -public class CacheConfiguration { - /** - * 内存缓存配置. - */ - @Bean - public CacheManager simpleCacheManager() { - return new ConcurrentMapCacheManager(); - } - -} diff --git a/server/src/main/java/run/ikaros/server/core/episode/DefaultEpisodeService.java b/server/src/main/java/run/ikaros/server/core/episode/DefaultEpisodeService.java index 03420d7d..4aa53513 100644 --- a/server/src/main/java/run/ikaros/server/core/episode/DefaultEpisodeService.java +++ b/server/src/main/java/run/ikaros/server/core/episode/DefaultEpisodeService.java @@ -4,8 +4,6 @@ import java.util.List; import lombok.extern.slf4j.Slf4j; -import org.springframework.cache.annotation.CacheEvict; -import org.springframework.cache.annotation.Cacheable; import org.springframework.context.ApplicationEventPublisher; import org.springframework.r2dbc.core.DatabaseClient; import org.springframework.stereotype.Service; @@ -14,7 +12,7 @@ import reactor.core.publisher.Mono; import run.ikaros.api.core.subject.Episode; import run.ikaros.api.core.subject.EpisodeResource; -import run.ikaros.api.store.enums.AttachmentReferenceType; +import run.ikaros.api.infra.utils.ReflectUtils; import run.ikaros.api.store.enums.EpisodeGroup; import run.ikaros.server.store.entity.EpisodeEntity; import run.ikaros.server.store.repository.AttachmentReferenceRepository; @@ -47,12 +45,6 @@ public DefaultEpisodeService(EpisodeRepository episodeRepository, @Override - @CacheEvict(value = {"episodeWithId", "episodesWithSubjectId", - "episodeWithSubjectIdAndGroupAndSeqAndName", - "episodesWithSubjectIdAndGroupAndSeq", - "episodeCountWithSubjectId", "episodeMatchingCountWithSubjectId", - "episodesWithId", "episodeWithName" - }, allEntries = true) public Mono save(Episode episode) { Assert.notNull(episode, "episode must not be null"); Long episodeId = episode.getId(); @@ -69,7 +61,6 @@ public Mono save(Episode episode) { } @Override - @Cacheable(value = "episodeWithId", key = "#episodeId") public Mono findById(Long episodeId) { Assert.isTrue(episodeId != null && episodeId > 0, "episode id must >= 0."); return episodeRepository.findById(episodeId) @@ -77,7 +68,6 @@ public Mono findById(Long episodeId) { } @Override - @Cacheable(value = "episodesWithSubjectId", key = "#subjectId") public Flux findAllBySubjectId(Long subjectId) { Assert.isTrue(subjectId >= 0, "'subjectId' must >= 0."); return episodeRepository.findAllBySubjectId(subjectId) @@ -85,8 +75,6 @@ public Flux findAllBySubjectId(Long subjectId) { } @Override - @Cacheable(value = "episodeWithSubjectIdAndGroupAndSeqAndName", - key = "#subjectId + '-' + #group + '-' + #name") public Mono findBySubjectIdAndGroupAndSequenceAndName( Long subjectId, EpisodeGroup group, Float sequence, String name) { Assert.isTrue(subjectId >= 0, "'subjectId' must >= 0."); @@ -99,8 +87,6 @@ public Mono findBySubjectIdAndGroupAndSequenceAndName( } @Override - @Cacheable(value = "episodesWithSubjectIdAndGroupAndSeq", - key = "#subjectId + '-' + #group + '-' + #sequence") public Flux findBySubjectIdAndGroupAndSequence(Long subjectId, EpisodeGroup group, Float sequence) { Assert.isTrue(subjectId >= 0, "'subjectId' must >= 0."); @@ -112,7 +98,6 @@ public Flux findBySubjectIdAndGroupAndSequence(Long subjectId, EpisodeG } @Override - @CacheEvict(value = "episodeWithId", key = "#episodeId") public Mono deleteById(Long episodeId) { Assert.isTrue(episodeId >= 0, "'episodeId' must >= 0."); return episodeRepository.findById(episodeId) @@ -125,14 +110,12 @@ public Mono deleteById(Long episodeId) { } @Override - @Cacheable(value = "episodeCountWithSubjectId", key = "#subjectId") public Mono countBySubjectId(Long subjectId) { Assert.isTrue(subjectId >= 0, "'subjectId' must >= 0."); return episodeRepository.countBySubjectId(subjectId); } @Override - @Cacheable(value = "episodeMatchingCountWithSubjectId", key = "#subjectId") public Mono countMatchingBySubjectId(Long subjectId) { Assert.isTrue(subjectId >= 0, "'subjectId' must >= 0."); return databaseClient.sql("select count(e.ID) from EPISODE e, ATTACHMENT_REFERENCE ar " @@ -145,32 +128,24 @@ public Mono countMatchingBySubjectId(Long subjectId) { @Override - @Cacheable(value = "episodesWithId", key = "#episodeId") public Flux findResourcesById(Long episodeId) { Assert.isTrue(episodeId >= 0, "'episodeId' must >= 0."); - return attachmentReferenceRepository - .findAllByTypeAndReferenceIdOrderByTypeAscAttachmentIdAsc( - AttachmentReferenceType.EPISODE, episodeId) - .flatMap(attachmentReferenceEntity -> - attachmentRepository.findById(attachmentReferenceEntity.getAttachmentId()) - .map(attachmentEntity -> EpisodeResource.builder() - .episodeId(episodeId) - .attachmentId(attachmentEntity.getId()) - .parentAttachmentId(attachmentEntity.getParentId()) - .name(attachmentEntity.getName()) - .url(attachmentEntity.getUrl()) - .canRead(true) - .build()) - ); + return databaseClient.sql("select att_ref.ATTACHMENT_ID as attachment_id, " + + "att.PARENT_ID as parent_attachment_id, " + + "att_ref.REFERENCE_ID as episode_id, " + + "att.URL as url, " + + "att.NAME as name " + + "from ATTACHMENT_REFERENCE att_ref, ATTACHMENT att " + + "where att_ref.TYPE = 'EPISODE' and att_ref.REFERENCE_ID = :episodeId " + + "and att_ref.ATTACHMENT_ID = att.ID " + + "order by att_ref.TYPE, att_ref.ATTACHMENT_ID") + .bind("episodeId", episodeId) + .fetch() + .all() + .map(row -> ReflectUtils.mapToClass(row, EpisodeResource.class, true)); } @Override - @CacheEvict(value = {"episodeWithId", "episodesWithSubjectId", - "episodeWithSubjectIdAndGroupAndSeqAndName", - "episodesWithSubjectIdAndGroupAndSeq", - "episodeCountWithSubjectId", "episodeMatchingCountWithSubjectId", - "episodesWithId", "episodeWithName" - }, allEntries = true) public Flux updateEpisodesWithSubjectId(Long subjectId, List episodes) { Assert.isTrue(subjectId >= 0, "'subjectId' must >= 0."); Assert.notNull(episodes, "'episodes' must not be null.");