From 3eaf133718a99b56cf74bfc692b56bf87c09de26 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Fri, 17 Nov 2023 21:16:51 +0800 Subject: [PATCH 001/168] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=BB=98=E8=AE=A4?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E6=98=BE=E7=A4=BA=E8=AF=84=E5=88=86?= =?UTF-8?q?=E4=B8=8D=E8=B6=B3=E6=97=B6=E6=89=80=E9=9C=80=E7=9A=84=E8=AF=84?= =?UTF-8?q?=E5=88=86=E9=87=8F=EF=BC=8C=E5=B9=B6=E5=85=81=E8=AE=B8=E8=AF=A5?= =?UTF-8?q?=E9=A1=B9=E9=85=8D=E7=BD=AE=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/config/external/Copilot.java | 12 ++++++++++++ .../config/external/MaaCopilotProperties.java | 2 ++ .../plus/maa/backend/service/CopilotService.java | 7 ++++++- 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 src/main/java/plus/maa/backend/config/external/Copilot.java diff --git a/src/main/java/plus/maa/backend/config/external/Copilot.java b/src/main/java/plus/maa/backend/config/external/Copilot.java new file mode 100644 index 00000000..0d674ad0 --- /dev/null +++ b/src/main/java/plus/maa/backend/config/external/Copilot.java @@ -0,0 +1,12 @@ +package plus.maa.backend.config.external; + +import lombok.Data; + +@Data +public class Copilot { + + /** + * 作业评分总数少于指定值时显示评分不足 + */ + private int minValueShowNotEnoughRating = 100; +} diff --git a/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java b/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java index c7975d63..c7cc9615 100644 --- a/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java +++ b/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java @@ -26,4 +26,6 @@ public class MaaCopilotProperties { private Mail mail; @NestedConfigurationProperty private SensitiveWord sensitiveWord; + @NestedConfigurationProperty + private Copilot copilot; } diff --git a/src/main/java/plus/maa/backend/service/CopilotService.java b/src/main/java/plus/maa/backend/service/CopilotService.java index 12b7f2e0..ee33d8f9 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.java +++ b/src/main/java/plus/maa/backend/service/CopilotService.java @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -66,6 +67,10 @@ public class CopilotService { private final CopilotConverter copilotConverter; private final AtomicLong copilotIncrementId = new AtomicLong(20000); + // 评分总数少于指定值时显示评分不足 + @Value("${maa-copilot.copilot.min-value-show-not-enough-rating:100}") + private int minValueShowNotEnoughRating; + /* 首页分页查询缓存配置 格式为:需要缓存的 orderBy 类型(也就是榜单类型) -> 缓存时间 @@ -525,7 +530,7 @@ private CopilotInfo formatCopilot(Copilot copilot, @Nullable RatingType ratingTy info.setRatingType(ratingType.getDisplay()); } // 评分数少于一定数量 - info.setNotEnoughRating(copilot.getLikeCount() + copilot.getDislikeCount() <= 5); + info.setNotEnoughRating(copilot.getLikeCount() + copilot.getDislikeCount() <= minValueShowNotEnoughRating); info.setAvailable(true); From f075b8e85f3db516776eb1eb03ed6dbc50dcce21 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Fri, 17 Nov 2023 21:25:31 +0800 Subject: [PATCH 002/168] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E9=98=88=E5=80=BC=E4=B8=BA50?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application-template.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/resources/application-template.yml b/src/main/resources/application-template.yml index f04a8ee3..bea8501b 100644 --- a/src/main/resources/application-template.yml +++ b/src/main/resources/application-template.yml @@ -60,6 +60,8 @@ maa-copilot: ssl: false #邮件通知 notification: true + copilot: + min-value-show-not-enough-rating: 50 From 47481a97150dab4654384160039a96e466493c4f Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Fri, 17 Nov 2023 22:33:45 +0800 Subject: [PATCH 003/168] =?UTF-8?q?=E4=BF=AE=E6=94=B9@Value=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E7=9A=84=E6=96=B9=E5=BC=8F=E4=BB=A5=E5=8F=8AmaaCopilo?= =?UTF-8?q?tProperties.copilot=E7=9A=84=E9=BB=98=E8=AE=A4=E5=80=BC?= =?UTF-8?q?=EF=BC=8C=E5=94=AF=E4=B8=80=E7=9A=84=E5=A5=BD=E5=A4=84=E6=98=AF?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=BB=98=E8=AE=A4=E5=80=BC=E5=8F=AA=E9=9C=80?= =?UTF-8?q?=E8=A6=81=E6=94=B9=E4=B8=80=E4=B8=AA=E5=9C=B0=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/plus/maa/backend/config/external/Copilot.java | 4 +++- .../maa/backend/config/external/MaaCopilotProperties.java | 7 +++++-- src/main/java/plus/maa/backend/service/CopilotService.java | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main/java/plus/maa/backend/config/external/Copilot.java b/src/main/java/plus/maa/backend/config/external/Copilot.java index 0d674ad0..9d06b5dd 100644 --- a/src/main/java/plus/maa/backend/config/external/Copilot.java +++ b/src/main/java/plus/maa/backend/config/external/Copilot.java @@ -7,6 +7,8 @@ public class Copilot { /** * 作业评分总数少于指定值时显示评分不足 + *

+ * 默认值:50 */ - private int minValueShowNotEnoughRating = 100; + private int minValueShowNotEnoughRating = 50; } diff --git a/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java b/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java index c7cc9615..7ecc8141 100644 --- a/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java +++ b/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java @@ -1,10 +1,13 @@ package plus.maa.backend.config.external; +import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.stereotype.Component; +@Data +@Component @ConfigurationProperties("maa-copilot") -@lombok.Data public class MaaCopilotProperties { @NestedConfigurationProperty private Jwt jwt; @@ -27,5 +30,5 @@ public class MaaCopilotProperties { @NestedConfigurationProperty private SensitiveWord sensitiveWord; @NestedConfigurationProperty - private Copilot copilot; + private Copilot copilot = new Copilot(); } diff --git a/src/main/java/plus/maa/backend/service/CopilotService.java b/src/main/java/plus/maa/backend/service/CopilotService.java index ee33d8f9..04b8bc95 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.java +++ b/src/main/java/plus/maa/backend/service/CopilotService.java @@ -68,7 +68,7 @@ public class CopilotService { private final AtomicLong copilotIncrementId = new AtomicLong(20000); // 评分总数少于指定值时显示评分不足 - @Value("${maa-copilot.copilot.min-value-show-not-enough-rating:100}") + @Value("#{maaCopilotProperties.copilot.minValueShowNotEnoughRating}") private int minValueShowNotEnoughRating; /* From 625e2ba45c72709530516be9ef54f0cad5348bca Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Fri, 17 Nov 2023 23:36:55 +0800 Subject: [PATCH 004/168] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=98=88=E5=80=BC?= =?UTF-8?q?=E7=9A=84=E6=B3=A8=E5=85=A5=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/plus/maa/backend/service/CopilotService.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/CopilotService.java b/src/main/java/plus/maa/backend/service/CopilotService.java index 04b8bc95..ee088492 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.java +++ b/src/main/java/plus/maa/backend/service/CopilotService.java @@ -8,7 +8,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.Nullable; -import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; @@ -20,6 +19,7 @@ import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import plus.maa.backend.common.utils.converter.CopilotConverter; +import plus.maa.backend.config.external.MaaCopilotProperties; import plus.maa.backend.controller.request.copilot.CopilotCUDRequest; import plus.maa.backend.controller.request.copilot.CopilotDTO; import plus.maa.backend.controller.request.copilot.CopilotQueriesRequest; @@ -63,14 +63,11 @@ public class CopilotService { private final RedisCache redisCache; private final UserRepository userRepository; private final CommentsAreaRepository commentsAreaRepository; + private final MaaCopilotProperties properties; private final CopilotConverter copilotConverter; private final AtomicLong copilotIncrementId = new AtomicLong(20000); - // 评分总数少于指定值时显示评分不足 - @Value("#{maaCopilotProperties.copilot.minValueShowNotEnoughRating}") - private int minValueShowNotEnoughRating; - /* 首页分页查询缓存配置 格式为:需要缓存的 orderBy 类型(也就是榜单类型) -> 缓存时间 @@ -530,7 +527,7 @@ private CopilotInfo formatCopilot(Copilot copilot, @Nullable RatingType ratingTy info.setRatingType(ratingType.getDisplay()); } // 评分数少于一定数量 - info.setNotEnoughRating(copilot.getLikeCount() + copilot.getDislikeCount() <= minValueShowNotEnoughRating); + info.setNotEnoughRating(copilot.getLikeCount() + copilot.getDislikeCount() <= properties.getCopilot().getMinValueShowNotEnoughRating()); info.setAvailable(true); From 238f6a9595504cf80d49c151f539545cdd8c1b81 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 18 Nov 2023 00:35:58 +0800 Subject: [PATCH 005/168] =?UTF-8?q?=E5=90=AF=E7=94=A8=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E4=BD=93=E8=87=AA=E5=8A=A8=E5=8E=8B=E7=BC=A9=EF=BC=8C=E8=BF=9B?= =?UTF-8?q?=E4=B8=80=E6=AD=A5=E8=8A=82=E7=BA=A6=E6=9C=8D=E5=8A=A1=E5=99=A8?= =?UTF-8?q?=E5=B8=A6=E5=AE=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/plus/maa/backend/filter/MaaEtagHeaderFilter.java | 7 +++++++ src/main/resources/application.yml | 2 ++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java index 731b1173..4676a189 100644 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java @@ -28,6 +28,13 @@ @RequiredArgsConstructor public class MaaEtagHeaderFilter extends ShallowEtagHeaderFilter { + @Override + protected void initFilterBean() throws ServletException { + super.initFilterBean(); + // Etag 必须使用弱校验才能与自动压缩兼容 + setWriteWeakETag(true); + } + @Override protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { if (!HttpMethod.GET.matches(request.getMethod())) { diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fd86378f..4ced4110 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -31,6 +31,8 @@ server: tomcat: #限制post表单最大为30KB max-http-form-post-size: 30KB + compression: + enabled: true logging: file: From 9091b2870ffc0ec0d0bb220128d61c12dbc54a60 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 18 Nov 2023 13:15:20 +0800 Subject: [PATCH 006/168] =?UTF-8?q?=E8=B0=83=E6=95=B4=20Etag=20=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E5=99=A8=E7=9A=84=E5=B7=A5=E4=BD=9C=E9=80=BB=E8=BE=91?= =?UTF-8?q?=EF=BC=8C=E4=BD=BF=E5=BE=97=E8=87=AA=E5=8A=A8=E5=8E=8B=E7=BC=A9?= =?UTF-8?q?=E8=83=BD=E6=AD=A3=E7=A1=AE=E5=A4=84=E7=90=86=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E7=9A=84=20min-response-size?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/MainApplication.java | 2 -- .../backend/controller/CopilotController.java | 4 +-- .../backend/filter/MaaEtagHeaderFilter.java | 31 ++++++++++--------- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/main/java/plus/maa/backend/MainApplication.java b/src/main/java/plus/maa/backend/MainApplication.java index 20683a8d..91038693 100644 --- a/src/main/java/plus/maa/backend/MainApplication.java +++ b/src/main/java/plus/maa/backend/MainApplication.java @@ -3,7 +3,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.ConfigurationPropertiesScan; -import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.cache.annotation.EnableCaching; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @@ -18,7 +17,6 @@ @SpringBootApplication @ConfigurationPropertiesScan @EnableMethodSecurity -@ServletComponentScan public class MainApplication { public static void main(String[] args) { SpringApplication.run(MainApplication.class, args); diff --git a/src/main/java/plus/maa/backend/controller/CopilotController.java b/src/main/java/plus/maa/backend/controller/CopilotController.java index 04da198e..9f1c1dba 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotController.java @@ -78,8 +78,8 @@ public MaaResult getCopilotById( public MaaResult queriesCopilot( @Parameter(description = "作业查询请求") @Valid CopilotQueriesRequest parsed ) { - // 两秒防抖,缓解前端重复请求问题 - response.setHeader(HttpHeaders.CACHE_CONTROL, "private, max-age=2, must-revalidate"); + // 三秒防抖,缓解前端重复请求问题 + response.setHeader(HttpHeaders.CACHE_CONTROL, "private, max-age=3, must-revalidate"); return MaaResult.success(copilotService.queriesCopilot(helper.getUserId(), parsed)); } diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java index 4676a189..15207adf 100644 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java @@ -2,16 +2,15 @@ import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; -import jakarta.servlet.annotation.WebFilter; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; import org.jetbrains.annotations.NotNull; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; import org.springframework.web.filter.ShallowEtagHeaderFilter; import java.io.IOException; +import java.util.Set; /** @@ -20,14 +19,18 @@ * @author lixuhuilll */ -// 配置需要使用 Etag 机制的 URL,注意和 Spring 的 UrlPattern 语法不太一样 -@WebFilter(urlPatterns = { - "/arknights/level", - "/copilot/query" -}) -@RequiredArgsConstructor +@Component public class MaaEtagHeaderFilter extends ShallowEtagHeaderFilter { + private static final String CACHE_HEAD = "private, no-cache, max-age=0, must-revalidate"; + private static final String NO_STORE_HEAD = "no-store, " + CACHE_HEAD; + + // 配置需要使用 Etag 机制的 URI,注意和 Spring 的 UrlPattern 语法不太一样 + private static final Set CACHE_URI = Set.of( + "/arknights/level", + "/copilot/query" + ); + @Override protected void initFilterBean() throws ServletException { super.initFilterBean(); @@ -37,13 +40,11 @@ protected void initFilterBean() throws ServletException { @Override protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { - if (!HttpMethod.GET.matches(request.getMethod())) { - // ETag 只处理安全的请求 - filterChain.doFilter(request, response); - return; + if (CACHE_URI.contains(request.getRequestURI())) { + response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); + } else { + response.setHeader(HttpHeaders.CACHE_CONTROL, NO_STORE_HEAD); } - // 允许使用 Etag (实际是避免默认添加的 no-store) - response.setHeader(HttpHeaders.CACHE_CONTROL, "no-cache, max-age=0, must-revalidate"); // 其他接口默认处理即可,注意默认操作相当于牺牲 CPU 来节约网络带宽,不适用于结果变更过快的接口 super.doFilterInternal(request, response, filterChain); } From 095cdff49e5b1383d831b1e199698f3b6c9a47d9 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 18 Nov 2023 14:17:50 +0800 Subject: [PATCH 007/168] =?UTF-8?q?=E4=BC=98=E5=8C=96=20ETag=20=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E5=99=A8=E7=9A=84=E5=B7=A5=E4=BD=9C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/filter/MaaEtagHeaderFilter.java | 14 +++++++++----- .../java/plus/maa/backend/filter/package-info.java | 4 ++++ 2 files changed, 13 insertions(+), 5 deletions(-) create mode 100644 src/main/java/plus/maa/backend/filter/package-info.java diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java index 15207adf..9af71e0d 100644 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java @@ -4,12 +4,12 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import org.jetbrains.annotations.NotNull; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import org.springframework.web.filter.ShallowEtagHeaderFilter; import java.io.IOException; +import java.io.InputStream; import java.util.Set; @@ -23,7 +23,6 @@ public class MaaEtagHeaderFilter extends ShallowEtagHeaderFilter { private static final String CACHE_HEAD = "private, no-cache, max-age=0, must-revalidate"; - private static final String NO_STORE_HEAD = "no-store, " + CACHE_HEAD; // 配置需要使用 Etag 机制的 URI,注意和 Spring 的 UrlPattern 语法不太一样 private static final Set CACHE_URI = Set.of( @@ -39,13 +38,18 @@ protected void initFilterBean() throws ServletException { } @Override - protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException { + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (CACHE_URI.contains(request.getRequestURI())) { response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); - } else { - response.setHeader(HttpHeaders.CACHE_CONTROL, NO_STORE_HEAD); } // 其他接口默认处理即可,注意默认操作相当于牺牲 CPU 来节约网络带宽,不适用于结果变更过快的接口 super.doFilterInternal(request, response, filterChain); } + + @Override + protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, + int responseStatusCode, InputStream inputStream) { + return CACHE_URI.contains(request.getRequestURI()) && + super.isEligibleForEtag(request, response, responseStatusCode, inputStream); + } } diff --git a/src/main/java/plus/maa/backend/filter/package-info.java b/src/main/java/plus/maa/backend/filter/package-info.java new file mode 100644 index 00000000..19141fe0 --- /dev/null +++ b/src/main/java/plus/maa/backend/filter/package-info.java @@ -0,0 +1,4 @@ +@NonNullApi +package plus.maa.backend.filter; + +import org.springframework.lang.NonNullApi; \ No newline at end of file From c2e2f1f0d7b99476fe318a69c66e7b519ada73d2 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 18 Nov 2023 15:00:06 +0800 Subject: [PATCH 008/168] =?UTF-8?q?=E8=BF=9B=E4=B8=80=E6=AD=A5=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20ETag=20=E8=BF=87=E6=BB=A4=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/filter/MaaEtagHeaderFilter.java | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java index 9af71e0d..1e9fb9f4 100644 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java @@ -1,14 +1,13 @@ package plus.maa.backend.filter; -import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; import org.springframework.stereotype.Component; import org.springframework.web.filter.ShallowEtagHeaderFilter; -import java.io.IOException; import java.io.InputStream; import java.util.Set; @@ -37,19 +36,24 @@ protected void initFilterBean() throws ServletException { setWriteWeakETag(true); } - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - if (CACHE_URI.contains(request.getRequestURI())) { - response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); - } - // 其他接口默认处理即可,注意默认操作相当于牺牲 CPU 来节约网络带宽,不适用于结果变更过快的接口 - super.doFilterInternal(request, response, filterChain); - } - @Override protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, int responseStatusCode, InputStream inputStream) { - return CACHE_URI.contains(request.getRequestURI()) && - super.isEligibleForEtag(request, response, responseStatusCode, inputStream); + + if (CACHE_URI.contains(request.getRequestURI()) && + !response.isCommitted() && + responseStatusCode >= 200 && responseStatusCode < 300 && + HttpMethod.GET.matches(request.getMethod())) { + + String cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL); + if (cacheControl == null) { + response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); + return true; + } + + return !cacheControl.contains("no-store"); + } + + return false; } } From 26d5924b544a77136cc7ca69b860198f69c5a438 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 18 Nov 2023 17:01:01 +0800 Subject: [PATCH 009/168] =?UTF-8?q?=E8=BF=9B=E4=B8=80=E6=AD=A5=E4=BC=98?= =?UTF-8?q?=E5=8C=96=20ETag=20=E8=BF=87=E6=BB=A4=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E5=B7=A5=E4=BD=9C=E9=80=BB=E8=BE=91=EF=BC=8C=E4=BD=BF=E5=85=B6?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20URI=20Pattern=20=E8=AF=AD=E6=B3=95?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/filter/MaaEtagHeaderFilter.java | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java index 1e9fb9f4..e79b27b4 100644 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java @@ -5,10 +5,14 @@ import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; +import org.springframework.http.server.PathContainer; import org.springframework.stereotype.Component; import org.springframework.web.filter.ShallowEtagHeaderFilter; +import org.springframework.web.util.pattern.PathPattern; +import org.springframework.web.util.pattern.PathPatternParser; import java.io.InputStream; +import java.util.List; import java.util.Set; @@ -21,14 +25,22 @@ @Component public class MaaEtagHeaderFilter extends ShallowEtagHeaderFilter { - private static final String CACHE_HEAD = "private, no-cache, max-age=0, must-revalidate"; - - // 配置需要使用 Etag 机制的 URI,注意和 Spring 的 UrlPattern 语法不太一样 + /** + * 配置需要使用 Etag 机制的 URI,采用 PathPatter 语法 + * + * @see PathPattern + */ private static final Set CACHE_URI = Set.of( "/arknights/level", "/copilot/query" ); + private static final String CACHE_HEAD = "private, no-cache, max-age=0, must-revalidate"; + + private static final List CACHE_URI_PATTERNS = CACHE_URI.stream() + .map(PathPatternParser.defaultInstance::parse) + .toList(); + @Override protected void initFilterBean() throws ServletException { super.initFilterBean(); @@ -40,8 +52,16 @@ protected void initFilterBean() throws ServletException { protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, int responseStatusCode, InputStream inputStream) { - if (CACHE_URI.contains(request.getRequestURI()) && - !response.isCommitted() && + boolean isMatch = false; + + for (PathPattern pattern : CACHE_URI_PATTERNS) { + if (pattern.matches(PathContainer.parsePath(request.getRequestURI()))) { + isMatch = true; + break; + } + } + + if (isMatch && !response.isCommitted() && responseStatusCode >= 200 && responseStatusCode < 300 && HttpMethod.GET.matches(request.getMethod())) { From 24c34c3ed3fc6dbefd7bda2aa296a52a1e639720 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 18 Nov 2023 17:50:35 +0800 Subject: [PATCH 010/168] =?UTF-8?q?=E4=BC=98=E5=8C=96=20URI=20Pattern=20?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E7=9A=84=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/filter/MaaEtagHeaderFilter.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java index e79b27b4..78e11367 100644 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java @@ -54,16 +54,21 @@ protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletRespo boolean isMatch = false; - for (PathPattern pattern : CACHE_URI_PATTERNS) { - if (pattern.matches(PathContainer.parsePath(request.getRequestURI()))) { - isMatch = true; - break; + if (HttpMethod.GET.matches(request.getMethod())) { + + PathContainer pathContainer = PathContainer.parsePath(request.getRequestURI()); + + for (PathPattern pattern : CACHE_URI_PATTERNS) { + + if (pattern.matches(pathContainer)) { + isMatch = true; + break; + } } } if (isMatch && !response.isCommitted() && - responseStatusCode >= 200 && responseStatusCode < 300 && - HttpMethod.GET.matches(request.getMethod())) { + responseStatusCode >= 200 && responseStatusCode < 300) { String cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL); if (cacheControl == null) { From c3bccdd81bd6c13be6587851624fecb386bbedb1 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sun, 19 Nov 2023 11:07:45 +0800 Subject: [PATCH 011/168] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=8F=AF=E8=AF=BB=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/filter/MaaEtagHeaderFilter.java | 36 ++++++++----------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java index 78e11367..585c4253 100644 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java @@ -1,10 +1,8 @@ package plus.maa.backend.filter; -import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.springframework.http.HttpHeaders; -import org.springframework.http.HttpMethod; import org.springframework.http.server.PathContainer; import org.springframework.stereotype.Component; import org.springframework.web.filter.ShallowEtagHeaderFilter; @@ -18,6 +16,10 @@ /** * 提供基于 Etag 机制的 HTTP 缓存,有助于降低网络传输的压力 + *

+ * 同时还解决了 GZIP 无法对 JSON 响应正常处理 min-response-size 的问题, + * 借助了 ETag 处理流程中的 Response 包装类包装所有响应, + * 从而正常获取 Content-Length * * @author lixuhuilll */ @@ -42,8 +44,7 @@ public class MaaEtagHeaderFilter extends ShallowEtagHeaderFilter { .toList(); @Override - protected void initFilterBean() throws ServletException { - super.initFilterBean(); + protected void initFilterBean() { // Etag 必须使用弱校验才能与自动压缩兼容 setWriteWeakETag(true); } @@ -52,33 +53,24 @@ protected void initFilterBean() throws ServletException { protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, int responseStatusCode, InputStream inputStream) { - boolean isMatch = false; - - if (HttpMethod.GET.matches(request.getMethod())) { + if (super.isEligibleForEtag(request, response, responseStatusCode, inputStream)) { + // 如果该请求符合产生 ETag 的条件,判断是否为需要使用 ETag 机制的 URI PathContainer pathContainer = PathContainer.parsePath(request.getRequestURI()); - for (PathPattern pattern : CACHE_URI_PATTERNS) { if (pattern.matches(pathContainer)) { - isMatch = true; - break; + // 如果是需要使用 ETag 机制的 URI,若其响应中不存在缓存控制头,则配置默认值 + String cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL); + if (cacheControl == null) { + response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); + } + // 不论是否进行默认值处理,均返回 true + return true; } } } - if (isMatch && !response.isCommitted() && - responseStatusCode >= 200 && responseStatusCode < 300) { - - String cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL); - if (cacheControl == null) { - response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); - return true; - } - - return !cacheControl.contains("no-store"); - } - return false; } } From 041fd20fd6bce7df6690fa8a6b84cfa04d5b1087 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sun, 19 Nov 2023 18:35:44 +0800 Subject: [PATCH 012/168] =?UTF-8?q?=E5=8A=9F=E8=83=BD=E6=8B=86=E5=88=86?= =?UTF-8?q?=EF=BC=8C=E5=B0=86=20ETag=20=E5=92=8C=E8=8E=B7=E5=8F=96=20Conte?= =?UTF-8?q?nt-Length=20=E5=88=86=E4=B8=BA=E4=B8=A4=E4=B8=AA=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filter/ContentLengthRepairFilter.java | 39 ++++++++++ .../backend/filter/MaaEtagHeaderFilter.java | 76 ------------------- .../MaaEtagHeaderFilterRegistrationBean.java | 65 ++++++++++++++++ 3 files changed, 104 insertions(+), 76 deletions(-) create mode 100644 src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java delete mode 100644 src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java create mode 100644 src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.java diff --git a/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java b/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java new file mode 100644 index 00000000..71953ddd --- /dev/null +++ b/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java @@ -0,0 +1,39 @@ +package plus.maa.backend.filter; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.ShallowEtagHeaderFilter; +import org.springframework.web.util.ContentCachingResponseWrapper; + +import java.io.IOException; +import java.io.InputStream; + +/** + * 解决了 GZIP 无法对 JSON 响应正常处理 min-response-size 的问题, + * 借助了 ETag 处理流程中的 Response 包装类包装所有响应, + * 从而正常获取 Content-Length + * + * @author lixuhuilll + */ + +@Component +public class ContentLengthRepairFilter extends ShallowEtagHeaderFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + if (response instanceof ContentCachingResponseWrapper) { + // 不对已包装过的响应体做处理 + filterChain.doFilter(request, response); + } else { + super.doFilterInternal(request, response, filterChain); + } + } + + @Override + protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, int responseStatusCode, InputStream inputStream) { + return false; + } +} diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java deleted file mode 100644 index 585c4253..00000000 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilter.java +++ /dev/null @@ -1,76 +0,0 @@ -package plus.maa.backend.filter; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.http.HttpHeaders; -import org.springframework.http.server.PathContainer; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.ShallowEtagHeaderFilter; -import org.springframework.web.util.pattern.PathPattern; -import org.springframework.web.util.pattern.PathPatternParser; - -import java.io.InputStream; -import java.util.List; -import java.util.Set; - - -/** - * 提供基于 Etag 机制的 HTTP 缓存,有助于降低网络传输的压力 - *

- * 同时还解决了 GZIP 无法对 JSON 响应正常处理 min-response-size 的问题, - * 借助了 ETag 处理流程中的 Response 包装类包装所有响应, - * 从而正常获取 Content-Length - * - * @author lixuhuilll - */ - -@Component -public class MaaEtagHeaderFilter extends ShallowEtagHeaderFilter { - - /** - * 配置需要使用 Etag 机制的 URI,采用 PathPatter 语法 - * - * @see PathPattern - */ - private static final Set CACHE_URI = Set.of( - "/arknights/level", - "/copilot/query" - ); - - private static final String CACHE_HEAD = "private, no-cache, max-age=0, must-revalidate"; - - private static final List CACHE_URI_PATTERNS = CACHE_URI.stream() - .map(PathPatternParser.defaultInstance::parse) - .toList(); - - @Override - protected void initFilterBean() { - // Etag 必须使用弱校验才能与自动压缩兼容 - setWriteWeakETag(true); - } - - @Override - protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, - int responseStatusCode, InputStream inputStream) { - - if (super.isEligibleForEtag(request, response, responseStatusCode, inputStream)) { - - // 如果该请求符合产生 ETag 的条件,判断是否为需要使用 ETag 机制的 URI - PathContainer pathContainer = PathContainer.parsePath(request.getRequestURI()); - for (PathPattern pattern : CACHE_URI_PATTERNS) { - - if (pattern.matches(pathContainer)) { - // 如果是需要使用 ETag 机制的 URI,若其响应中不存在缓存控制头,则配置默认值 - String cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL); - if (cacheControl == null) { - response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); - } - // 不论是否进行默认值处理,均返回 true - return true; - } - } - } - - return false; - } -} diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.java new file mode 100644 index 00000000..239bebfc --- /dev/null +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.java @@ -0,0 +1,65 @@ +package plus.maa.backend.filter; + +import jakarta.annotation.PostConstruct; +import jakarta.servlet.Filter; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.ShallowEtagHeaderFilter; + +import java.io.InputStream; +import java.util.Set; + + +/** + * 提供基于 Etag 机制的 HTTP 缓存,有助于降低网络传输的压力 + * + * @author lixuhuilll + */ + +@Component +public class MaaEtagHeaderFilterRegistrationBean extends FilterRegistrationBean { + + /** + * 配置需要使用 Etag 机制的 URI,采用 Servlet 的 URI 匹配语法 + */ + private final Set ETAG_URI = Set.of( + "/arknights/level", + "/copilot/query" + ); + + @PostConstruct + public void init() { + setFilter(new MaaEtagHeaderFilter()); + setUrlPatterns(ETAG_URI); + } + + private static class MaaEtagHeaderFilter extends ShallowEtagHeaderFilter { + + private static final String CACHE_HEAD = "private, no-cache, max-age=0, must-revalidate"; + + @Override + protected void initFilterBean() { + // Etag 必须使用弱校验才能与自动压缩兼容 + setWriteWeakETag(true); + } + + @Override + protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, + int responseStatusCode, InputStream inputStream) { + + if (super.isEligibleForEtag(request, response, responseStatusCode, inputStream)) { + // 使用 ETag 机制的 URI,若其响应中不存在缓存控制头,则配置默认值 + final String cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL); + if (cacheControl == null) { + response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); + } + return true; + } + + return false; + } + } +} From 65b895c60cb50bf30ef1d03a9abf84a4db80bca7 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sun, 19 Nov 2023 23:57:40 +0800 Subject: [PATCH 013/168] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=20ContentLengthRepai?= =?UTF-8?q?rFilter=20=E7=9A=84=E6=9D=A1=E4=BB=B6=E8=A3=85=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/plus/maa/backend/filter/ContentLengthRepairFilter.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java b/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java index 71953ddd..fc2d1fc5 100644 --- a/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java +++ b/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java @@ -4,6 +4,7 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Component; import org.springframework.web.filter.ShallowEtagHeaderFilter; import org.springframework.web.util.ContentCachingResponseWrapper; @@ -20,6 +21,7 @@ */ @Component +@ConditionalOnProperty(name = "server.compression.enabled", havingValue = "true") public class ContentLengthRepairFilter extends ShallowEtagHeaderFilter { @Override From 80e47319d6c5efaf367bf49d09b42ae0491347a0 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Thu, 23 Nov 2023 21:22:22 +0800 Subject: [PATCH 014/168] =?UTF-8?q?=E7=83=AD=E5=BA=A6=E6=8E=92=E8=A1=8C?= =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E9=99=8D=E4=BD=8E=E6=9C=AA=E5=BC=80=E6=94=BE?= =?UTF-8?q?=E5=85=B3=E5=8D=A1=E6=9D=83=E9=87=8D=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/copilot/ArkLevelInfo.java | 4 + .../backend/repository/GithubRepository.java | 4 + .../backend/repository/entity/ArkLevel.java | 4 + .../entity/github/GithubContent.java | 7 ++ .../maa/backend/service/ArkLevelService.java | 83 +++++++++++++++++++ .../maa/backend/task/ArkLevelSyncTask.java | 12 ++- .../backend/task/CopilotScoreRefreshTask.java | 13 ++- 7 files changed, 123 insertions(+), 4 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java index 7df5976d..27e19731 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java +++ b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java @@ -5,6 +5,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; +import org.jetbrains.annotations.Nullable; import java.io.Serializable; @@ -25,4 +26,7 @@ public class ArkLevelInfo implements Serializable { private String name; private int width; private int height; + // 当前版本地图是否开放 + @Nullable + private Boolean isOpen; } diff --git a/src/main/java/plus/maa/backend/repository/GithubRepository.java b/src/main/java/plus/maa/backend/repository/GithubRepository.java index 69872aa4..7d495c20 100644 --- a/src/main/java/plus/maa/backend/repository/GithubRepository.java +++ b/src/main/java/plus/maa/backend/repository/GithubRepository.java @@ -4,6 +4,7 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.service.annotation.GetExchange; import plus.maa.backend.repository.entity.github.GithubCommit; +import plus.maa.backend.repository.entity.github.GithubContent; import plus.maa.backend.repository.entity.github.GithubTrees; import java.util.List; @@ -23,4 +24,7 @@ public interface GithubRepository { @GetExchange(value = "/repos/MaaAssistantArknights/MaaAssistantArknights/commits") List getCommits(@RequestHeader("Authorization") String token); + @GetExchange(value = "/repos/MaaAssistantArknights/MaaAssistantArknights/contents/{path}") + List getContents(@RequestHeader("Authorization") String token, @PathVariable("path") String path); + } diff --git a/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java b/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java index da54514c..fd5d9238 100644 --- a/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java +++ b/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java @@ -4,6 +4,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.jetbrains.annotations.Nullable; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; @@ -38,4 +39,7 @@ public class ArkLevel { private String name; private int width; private int height; + // 当前版本地图是否开放 + @Nullable + private Boolean isOpen; } diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java b/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java index eb69dda6..5cd6d80f 100644 --- a/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java +++ b/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java @@ -1,5 +1,7 @@ package plus.maa.backend.repository.entity.github; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; import lombok.Data; import org.apache.commons.lang3.StringUtils; @@ -10,6 +12,7 @@ * created on 2022/12/23 */ @Data +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class GithubContent { // 文件名 @@ -37,6 +40,10 @@ public boolean isDir() { return Objects.equals(type, "dir"); } + public boolean isFile() { + return Objects.equals(type, "file"); + } + public String getFileExtension() { return name == null ? StringUtils.EMPTY : diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index d7ad06de..26a48455 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -1,5 +1,6 @@ package plus.maa.backend.service; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Data; import lombok.RequiredArgsConstructor; @@ -8,6 +9,8 @@ import org.jetbrains.annotations.NotNull; import org.springframework.beans.factory.annotation.Value; import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -20,6 +23,7 @@ import plus.maa.backend.repository.entity.ArkLevelSha; import plus.maa.backend.repository.entity.gamedata.ArkTilePos; import plus.maa.backend.repository.entity.github.GithubCommit; +import plus.maa.backend.repository.entity.github.GithubContent; import plus.maa.backend.repository.entity.github.GithubTree; import plus.maa.backend.repository.entity.github.GithubTrees; @@ -28,6 +32,8 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.List; +import java.util.Map; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -161,6 +167,83 @@ public void runSyncLevelDataTask() { levelTrees.forEach(tree -> download(task, tree)); } + /** + * 更新地图开放状态 + */ + public void updateLevelOpenStatus() { + log.info("[LEVEL-OPEN-STATUS]准备更新地图开放状态"); + GithubContent stages = githubRepo.getContents(githubToken, "resource").stream() + .filter(content -> content.isFile() && "stages.json".equals(content.getName())) + .findFirst() + .orElse(null); + if (stages == null) { + log.info("[LEVEL-OPEN-STATUS]地图开放状态数据不存在"); + return; + } + + String lastStagesSha = redisCache.getCache("level:stages:sha", String.class); + if (lastStagesSha != null && lastStagesSha.equals(stages.getSha())) { + log.info("[LEVEL-OPEN-STATUS]地图开放状态已是最新"); + return; + } + + log.info("[LEVEL-OPEN-STATUS]开始更新地图开放状态"); + // 就一个文件,直接在当前线程下载数据 + try (Response response = okHttpClient + .newCall(new Request.Builder().url(stages.getDownloadUrl()).build()) + .execute()) { + + if (!response.isSuccessful() || response.body() == null) { + log.error("[LEVEL-OPEN-STATUS]地图开放状态下载失败"); + return; + } + + String body = response.body().string(); + List> stagesList = mapper.readValue(body, new TypeReference<>() { + }); + + Set stageIds = stagesList.stream() + .map(stage -> (String) stage.get("stageId")) + // 去除复刻后缀 + .map(stageId -> stageId.replace("_perm", "")) + .collect(Collectors.toUnmodifiableSet()); + + Set codes = stagesList.stream() + .map(stage -> (String) stage.get("code")) + // 提取地图的系列名,例如 GT、OF + .map(code -> code.split("-")[0]) + .collect(Collectors.toUnmodifiableSet()); + + // 分页修改 + Pageable pageable = Pageable.ofSize(1000); + Page arkLevelPage = arkLevelRepo.findAll(pageable); + while (arkLevelPage.hasContent()) { + for (ArkLevel arkLevel : arkLevelPage) { + if (stageIds.contains(arkLevel.getStageId()) || + codes.contains(arkLevel.getCatThree().split("-")[0])) { + arkLevel.setIsOpen(true); + } else if (arkLevel.getIsOpen() != null) { + // Maa 仓库的数据存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 + arkLevel.setIsOpen(false); + } + } + arkLevelRepo.saveAll(arkLevelPage); + + if (!arkLevelPage.hasNext()) { + // 没有下一页了,跳出循环 + break; + } + pageable = arkLevelPage.nextPageable(); + arkLevelPage = arkLevelRepo.findAll(pageable); + } + + redisCache.setData("level:stages:sha", stages.getSha()); + log.info("[LEVEL-OPEN-STATUS]地图开放状态更新完成"); + } catch (Exception e) { + log.error("[LEVEL-OPEN-STATUS]地图开放状态更新失败", e); + } + } + /** * 下载地图数据 */ diff --git a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java index a8c460b8..f0b2bf94 100644 --- a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java +++ b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java @@ -1,9 +1,8 @@ package plus.maa.backend.task; +import lombok.RequiredArgsConstructor; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; - -import lombok.RequiredArgsConstructor; import plus.maa.backend.service.ArkLevelService; @Component @@ -21,4 +20,13 @@ public void syncArkLevels() { arkLevelService.runSyncLevelDataTask(); } + /** + * 更新地图开放状态,每天凌晨执行,最好和热度值刷入任务保持相对顺序 + * 4:00、4:15 各执行一次,避免网络波动导致更新失败 + */ + @Scheduled(cron = "0 0-15/15 4 * * ?") + public void updateArkLevelsOpenStatus() { + arkLevelService.updateLevelOpenStatus(); + } + } diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java index 56d46fff..16cdf9ce 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java @@ -10,10 +10,12 @@ import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; +import plus.maa.backend.controller.response.copilot.ArkLevelInfo; import plus.maa.backend.repository.CopilotRepository; import plus.maa.backend.repository.RedisCache; import plus.maa.backend.repository.entity.Copilot; import plus.maa.backend.repository.entity.Rating; +import plus.maa.backend.service.ArkLevelService; import plus.maa.backend.service.CopilotService; import plus.maa.backend.service.model.RatingCount; import plus.maa.backend.service.model.RatingType; @@ -36,14 +38,15 @@ @FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) public class CopilotScoreRefreshTask { + ArkLevelService arkLevelService; RedisCache redisCache; CopilotRepository copilotRepository; MongoTemplate mongoTemplate; /** - * 热度值刷入任务,每日三点执行 + * 热度值刷入任务,每日四点三十执行(实际可能会更晚,因为需要等待之前启动的定时任务完成) */ - @Scheduled(cron = "0 0 3 * * ?") + @Scheduled(cron = "0 30 4 * * ?") public void refreshHotScores() { // 分页获取所有未删除的作业 Pageable pageable = Pageable.ofSize(1000); @@ -105,6 +108,12 @@ private void refresh(Collection copilotIdSTRs, Iterable copilot long likeCount = likeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 1L); long dislikeCount = dislikeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 0L); double hotScore = CopilotService.getHotScore(copilot, likeCount, dislikeCount); + // 判断关卡是否开放 + ArkLevelInfo arkLevelInfo = arkLevelService.findByLevelIdFuzzy(copilot.getStageName()); + if (arkLevelInfo != null && Boolean.FALSE.equals(arkLevelInfo.getIsOpen())) { + // 非开放关卡打入冷宫 + hotScore += Integer.MIN_VALUE; + } copilot.setHotScore(hotScore); } // 批量更新热度值 From e515a48ffc9cecbc6dac8f47561000a56b13c7d7 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Fri, 24 Nov 2023 07:53:55 +0800 Subject: [PATCH 015/168] =?UTF-8?q?=E8=BF=87=E6=BB=A4=20null=20=E5=80=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/plus/maa/backend/service/ArkLevelService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index 26a48455..c557399a 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -30,10 +30,7 @@ import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -204,12 +201,14 @@ public void updateLevelOpenStatus() { Set stageIds = stagesList.stream() .map(stage -> (String) stage.get("stageId")) + .filter(Objects::nonNull) // 去除复刻后缀 .map(stageId -> stageId.replace("_perm", "")) .collect(Collectors.toUnmodifiableSet()); Set codes = stagesList.stream() .map(stage -> (String) stage.get("code")) + .filter(Objects::nonNull) // 提取地图的系列名,例如 GT、OF .map(code -> code.split("-")[0]) .collect(Collectors.toUnmodifiableSet()); @@ -221,6 +220,7 @@ public void updateLevelOpenStatus() { for (ArkLevel arkLevel : arkLevelPage) { if (stageIds.contains(arkLevel.getStageId()) || codes.contains(arkLevel.getCatThree().split("-")[0])) { + arkLevel.setIsOpen(true); } else if (arkLevel.getIsOpen() != null) { // Maa 仓库的数据存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 From 516fc43841d71bb56a393e14546a75f23ec82f34 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Fri, 24 Nov 2023 17:04:22 +0800 Subject: [PATCH 016/168] =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=8F=AA=E9=80=9A?= =?UTF-8?q?=E8=BF=87=E5=9C=B0=E5=9B=BE=E5=89=8D=E7=BC=80=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=BC=80=E6=94=BE=E3=80=82=E4=BC=98=E5=8C=96?= =?UTF-8?q?=20Json=20=E8=A7=A3=E6=9E=90=E8=BF=87=E7=A8=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entity/gamedata/MaaArkStage.java | 20 +++++++++++++++ .../maa/backend/service/ArkLevelService.java | 25 ++++++++----------- 2 files changed, 31 insertions(+), 14 deletions(-) create mode 100644 src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.java diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.java new file mode 100644 index 00000000..1c16ceed --- /dev/null +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.java @@ -0,0 +1,20 @@ +package plus.maa.backend.repository.entity.gamedata; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; + +@Data +// 忽略对服务器无用的数据 +@JsonIgnoreProperties(ignoreUnknown = true) +public class MaaArkStage { + + /** + * 例: CB-EX8 + */ + private String code; + + /** + * 例: act5d0_ex08 + */ + private String stageId; +} diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index c557399a..7de8fbc0 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -22,6 +22,7 @@ import plus.maa.backend.repository.entity.ArkLevel; import plus.maa.backend.repository.entity.ArkLevelSha; import plus.maa.backend.repository.entity.gamedata.ArkTilePos; +import plus.maa.backend.repository.entity.gamedata.MaaArkStage; import plus.maa.backend.repository.entity.github.GithubCommit; import plus.maa.backend.repository.entity.github.GithubContent; import plus.maa.backend.repository.entity.github.GithubTree; @@ -30,7 +31,10 @@ import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.stream.Collectors; @@ -195,19 +199,12 @@ public void updateLevelOpenStatus() { return; } - String body = response.body().string(); - List> stagesList = mapper.readValue(body, new TypeReference<>() { + var body = response.body().charStream(); + List stagesList = mapper.readValue(body, new TypeReference<>() { }); - Set stageIds = stagesList.stream() - .map(stage -> (String) stage.get("stageId")) - .filter(Objects::nonNull) - // 去除复刻后缀 - .map(stageId -> stageId.replace("_perm", "")) - .collect(Collectors.toUnmodifiableSet()); - Set codes = stagesList.stream() - .map(stage -> (String) stage.get("code")) + .map(MaaArkStage::getCode) .filter(Objects::nonNull) // 提取地图的系列名,例如 GT、OF .map(code -> code.split("-")[0]) @@ -218,12 +215,12 @@ public void updateLevelOpenStatus() { Page arkLevelPage = arkLevelRepo.findAll(pageable); while (arkLevelPage.hasContent()) { for (ArkLevel arkLevel : arkLevelPage) { - if (stageIds.contains(arkLevel.getStageId()) || - codes.contains(arkLevel.getCatThree().split("-")[0])) { + // 只考虑地图系列名,例如 GT、OF + if (codes.contains(arkLevel.getCatThree().split("-")[0])) { arkLevel.setIsOpen(true); } else if (arkLevel.getIsOpen() != null) { - // Maa 仓库的数据存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 + // 数据可能存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 arkLevel.setIsOpen(false); } } From a6584fe381b949be7387c39adcf398b931ce0e3f Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 25 Nov 2023 02:06:55 +0800 Subject: [PATCH 017/168] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20arkLevel=20?= =?UTF-8?q?=E7=9A=84=E8=BF=AD=E4=BB=A3=E6=96=B9=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/service/ArkLevelService.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index 7de8fbc0..e5a50ae8 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -214,16 +214,20 @@ public void updateLevelOpenStatus() { Pageable pageable = Pageable.ofSize(1000); Page arkLevelPage = arkLevelRepo.findAll(pageable); while (arkLevelPage.hasContent()) { - for (ArkLevel arkLevel : arkLevelPage) { - // 只考虑地图系列名,例如 GT、OF - if (codes.contains(arkLevel.getCatThree().split("-")[0])) { - - arkLevel.setIsOpen(true); - } else if (arkLevel.getIsOpen() != null) { - // 数据可能存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 - arkLevel.setIsOpen(false); - } - } + + arkLevelPage.stream() + .filter(arkLevel -> Objects.nonNull(arkLevel.getCatThree())) + .forEach(arkLevel -> { + // 只考虑地图系列名,例如 GT、OF + if (codes.contains(arkLevel.getCatThree().split("-")[0])) { + + arkLevel.setIsOpen(true); + } else if (arkLevel.getIsOpen() != null) { + // 数据可能存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 + arkLevel.setIsOpen(false); + } + }); + arkLevelRepo.saveAll(arkLevelPage); if (!arkLevelPage.hasNext()) { From 87b4f140865c61929de02b156e43bd9edb29cc19 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Sat, 25 Nov 2023 10:29:11 +0800 Subject: [PATCH 018/168] refactor: enable profile to specify max quantity of jwt login devices --- src/main/java/plus/maa/backend/config/external/Jwt.java | 4 ++++ src/main/java/plus/maa/backend/service/UserService.java | 9 +++------ src/main/resources/application-template.yml | 1 + 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/plus/maa/backend/config/external/Jwt.java b/src/main/java/plus/maa/backend/config/external/Jwt.java index f3718e39..94f6f578 100644 --- a/src/main/java/plus/maa/backend/config/external/Jwt.java +++ b/src/main/java/plus/maa/backend/config/external/Jwt.java @@ -19,4 +19,8 @@ public class Jwt { * JwtToken的加密密钥 */ private String secret; + /** + * Jwt 最大同时登录设备数 + */ + private int maxLogin = 1; } \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/service/UserService.java b/src/main/java/plus/maa/backend/service/UserService.java index 764c55e4..9c80e178 100644 --- a/src/main/java/plus/maa/backend/service/UserService.java +++ b/src/main/java/plus/maa/backend/service/UserService.java @@ -10,11 +10,11 @@ import org.springframework.stereotype.Service; import plus.maa.backend.common.MaaStatusCode; import plus.maa.backend.common.utils.converter.MaaUserConverter; +import plus.maa.backend.config.external.MaaCopilotProperties; import plus.maa.backend.controller.request.user.*; import plus.maa.backend.controller.response.MaaResultException; import plus.maa.backend.controller.response.user.MaaLoginRsp; import plus.maa.backend.controller.response.user.MaaUserInfo; -import plus.maa.backend.repository.RedisCache; import plus.maa.backend.repository.UserRepository; import plus.maa.backend.repository.entity.MaaUser; import plus.maa.backend.service.jwt.JwtExpiredException; @@ -34,16 +34,13 @@ @Service @RequiredArgsConstructor public class UserService { - - // 未来转为配置项 - private static final int LOGIN_LIMIT = 1; - private final UserRepository userRepository; private final EmailService emailService; private final PasswordEncoder passwordEncoder; private final UserDetailServiceImpl userDetailService; private final JwtService jwtService; private final MaaUserConverter maaUserConverter; + private final MaaCopilotProperties properties; /** * 登录方法 @@ -64,7 +61,7 @@ public MaaLoginRsp login(LoginDTO loginDTO) { var jwtId = UUID.randomUUID().toString(); var jwtIds = user.getRefreshJwtIds(); jwtIds.add(jwtId); - while (jwtIds.size() > LOGIN_LIMIT) jwtIds.remove(0); + while (jwtIds.size() > properties.getJwt().getMaxLogin()) jwtIds.remove(0); userRepository.save(user); var authorities = userDetailService.collectAuthoritiesFor(user); diff --git a/src/main/resources/application-template.yml b/src/main/resources/application-template.yml index bea8501b..6d8ae4f3 100644 --- a/src/main/resources/application-template.yml +++ b/src/main/resources/application-template.yml @@ -30,6 +30,7 @@ maa-copilot: expire: 21600 # JwtToken的加密密钥 secret: $I_Am_The_Bone_Of_My_Sword!Steel_Is_My_Body_And_Fire_Is_My_Blood!$ + max-login: 1 github: # GitHub api token token: github_pat_xxx From 4a307d885c8a7d7164c2b0c4ca5a808654b5efd1 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Mon, 27 Nov 2023 19:10:41 +0800 Subject: [PATCH 019/168] =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E9=80=82=E9=85=8D=E6=96=B0=E5=8D=B1=E6=9C=BA=E5=90=88=E7=BA=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/plus/maa/backend/service/model/ArkLevelType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/plus/maa/backend/service/model/ArkLevelType.java b/src/main/java/plus/maa/backend/service/model/ArkLevelType.java index 2db6d5e8..b5ea677b 100644 --- a/src/main/java/plus/maa/backend/service/model/ArkLevelType.java +++ b/src/main/java/plus/maa/backend/service/model/ArkLevelType.java @@ -33,7 +33,7 @@ public static ArkLevelType fromLevelId(String levelId) { case "activities" -> ACTIVITIES; case "campaign" -> CAMPAIGN; case "memory" -> MEMORY; - case "rune" -> RUNE; + case "rune", "crisis" -> RUNE; case "legion" -> LEGION; case "roguelike" -> ROGUELIKE; case "training" -> TRAINING; From e6f498ab9fbe091f897d4ccee45af502db4ee701 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Tue, 28 Nov 2023 19:26:56 +0800 Subject: [PATCH 020/168] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20EmailService=20?= =?UTF-8?q?=E6=B3=A8=E5=85=A5=E8=87=AA=E8=BA=AB=E4=BB=A3=E7=90=86=E7=B1=BB?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E5=BC=8F=EF=BC=8C=E5=9B=A0=E4=B8=BA=20JUnit?= =?UTF-8?q?=20=E4=B8=8D=E5=85=BC=E5=AE=B9=20@Lazy=EF=BC=8C=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=97=B6=E4=BC=9A=E6=8A=A5=E9=94=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/service/EmailService.java | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/EmailService.java b/src/main/java/plus/maa/backend/service/EmailService.java index b1a6ba5d..96799fc3 100644 --- a/src/main/java/plus/maa/backend/service/EmailService.java +++ b/src/main/java/plus/maa/backend/service/EmailService.java @@ -2,14 +2,13 @@ import cn.hutool.extra.mail.MailAccount; import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import plus.maa.backend.common.bo.EmailBusinessObject; import plus.maa.backend.config.external.MaaCopilotProperties; @@ -44,9 +43,7 @@ public class EmailService { private final MailAccount MAIL_ACCOUNT = new MailAccount(); - // 注入自身代理类的延迟加载代理类 - @Lazy - @Resource + // 注入自身代理类 private EmailService emailService; /** @@ -140,4 +137,32 @@ public void sendCommentNotification(String email, CommentNotification commentNot .sendCommentNotification(map); } + + /** + * 注入 EmailService 的代理类 + *

+ * 不得为 private,否则静态内部类只会修改内部类作用域内的副本而不是本类 + * + * @param emailService 被注入的 EmailService + */ + void setEmailService(EmailService emailService) { + synchronized (this) { + if (this.emailService == null) { + this.emailService = emailService; + } + } + } + + @Component + @RequiredArgsConstructor + public static class EmailServiceInject { + + private final EmailService emailService; + + @PostConstruct + private void init() { + emailService.setEmailService(emailService); + } + + } } From e565dabf425fe952d656f2302870c4303885db17 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Tue, 28 Nov 2023 20:39:15 +0800 Subject: [PATCH 021/168] =?UTF-8?q?=E8=A1=A5=E5=85=85=E5=8D=95=E5=85=83?= =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/repository/GithubRepositoryTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java b/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java index cc4a3989..e1dbdd1a 100644 --- a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java +++ b/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java @@ -5,7 +5,8 @@ import org.springframework.boot.test.context.SpringBootTest; import plus.maa.backend.config.external.MaaCopilotProperties; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; @SpringBootTest class GithubRepositoryTest { @@ -28,4 +29,10 @@ public void testGetCommits() { assertFalse(commits.isEmpty()); } + @Test + void getContents() { + var contents = repository.getContents(properties.getGithub().getToken(),""); + assertNotNull(contents); + assertFalse(contents.isEmpty()); + } } \ No newline at end of file From 863d843a178e670264664873cbc176081a4f88a0 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Tue, 28 Nov 2023 20:52:06 +0800 Subject: [PATCH 022/168] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=96=B0=E7=9A=84?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB=E3=80=82=E8=A1=A5=E5=85=85=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/common/utils/ArkLevelUtil.java | 31 +++++++++++++++++++ .../common/utils/ArkLevelUtilTest.java | 26 ++++++++++++++++ .../repository/GithubRepositoryTest.java | 2 +- 3 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java create mode 100644 src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java diff --git a/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java b/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java new file mode 100644 index 00000000..9ce93680 --- /dev/null +++ b/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java @@ -0,0 +1,31 @@ +package plus.maa.backend.common.utils; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.regex.Pattern; + +public class ArkLevelUtil { + + private static final Pattern NOT_KEY_INFO = Pattern.compile( + // level_、season_、前导零、以-或者_划分的后缀 + "level_|season_|(? + * 例如:a1(骑兵与猎人)、act11d0(沃伦姆德的薄暮)、act11mini(未尽篇章)、crisis_v2_1(浊燃作战) + */ + @NotNull + public static String getKeyInfoById(@Nullable String id) { + if (id == null) { + return ""; + } + // 去除所有非关键信息 + return NOT_KEY_INFO.matcher(id).replaceAll(""); + } + +} diff --git a/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java b/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java new file mode 100644 index 00000000..2c18ab51 --- /dev/null +++ b/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java @@ -0,0 +1,26 @@ +package plus.maa.backend.common.utils; + +import org.junit.jupiter.api.Test; + +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static plus.maa.backend.common.utils.ArkLevelUtil.getKeyInfoById; + +class ArkLevelUtilTest { + + @Test + void testGetKeyInfoById() { + Map ids = Map.of( + "level_rune_09-01", "level_rune_09-02", + "level_crisis_v2_01-07", "crisis_v2_season_1_1", + "a001_01_perm", "a001_ex05", + "act11d0_ex08#f#", "act11d0_s02", + "act11mini_03#f#", "act11mini_04" + ); + + for (var entity : ids.entrySet()) { + assertEquals(getKeyInfoById(entity.getKey()), getKeyInfoById(entity.getValue())); + } + } +} \ No newline at end of file diff --git a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java b/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java index e1dbdd1a..30f8012e 100644 --- a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java +++ b/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java @@ -30,7 +30,7 @@ public void testGetCommits() { } @Test - void getContents() { + void testGetContents() { var contents = repository.getContents(properties.getGithub().getToken(),""); assertNotNull(contents); assertFalse(contents.isEmpty()); From 6307307bd00ea47aaace317f6177a47a14c307ba Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Tue, 28 Nov 2023 22:04:14 +0800 Subject: [PATCH 023/168] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=85=B3=E5=8D=A1?= =?UTF-8?q?=E5=BC=80=E6=94=BE=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=EF=BC=8C=E6=94=AF=E6=8C=81=E5=8D=B1=E6=9C=BA=E5=90=88?= =?UTF-8?q?=E7=BA=A6=E7=9A=84=E5=85=B3=E5=8D=A1=E5=BC=80=E6=94=BE=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/common/utils/ArkLevelUtil.java | 4 +- .../repository/ArkLevelRepository.java | 13 +++-- .../entity/gamedata/ArkCrisisV2Info.java | 16 ++++++ .../backend/service/ArkGameDataService.java | 55 +++++++++++++++++++ .../maa/backend/service/ArkLevelService.java | 53 +++++++++++++++--- .../maa/backend/task/ArkLevelSyncTask.java | 5 +- 6 files changed, 128 insertions(+), 18 deletions(-) create mode 100644 src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.java diff --git a/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java b/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java index 9ce93680..6b171d9b 100644 --- a/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java +++ b/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java @@ -8,8 +8,8 @@ public class ArkLevelUtil { private static final Pattern NOT_KEY_INFO = Pattern.compile( - // level_、season_、前导零、以-或者_划分的后缀 - "level_|season_|(? { List findAllShaBy(); + Page findAllByCatOne(String catOne, Pageable pageable); + @Query(""" { "$or": [ diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.java new file mode 100644 index 00000000..373a0ef0 --- /dev/null +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.java @@ -0,0 +1,16 @@ +package plus.maa.backend.repository.entity.gamedata; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class ArkCrisisV2Info { + private String seasonId; + private String name; + // 时间戳,单位:秒 + private long startTs; + private long endTs; +} diff --git a/src/main/java/plus/maa/backend/service/ArkGameDataService.java b/src/main/java/plus/maa/backend/service/ArkGameDataService.java index 5edd5f99..5ddd79b9 100644 --- a/src/main/java/plus/maa/backend/service/ArkGameDataService.java +++ b/src/main/java/plus/maa/backend/service/ArkGameDataService.java @@ -11,8 +11,10 @@ import okhttp3.Request; import okhttp3.Response; import okhttp3.ResponseBody; +import org.jetbrains.annotations.Nullable; import org.springframework.stereotype.Service; import org.springframework.util.ObjectUtils; +import plus.maa.backend.common.utils.ArkLevelUtil; import plus.maa.backend.repository.entity.gamedata.*; import java.util.Map; @@ -30,6 +32,7 @@ public class ArkGameDataService { private static final String ARK_ACTIVITY = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/activity_table.json"; private static final String ARK_CHARACTER = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/character_table.json"; private static final String ARK_TOWER = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/climb_tower_table.json"; + private static final String ARK_CRISIS_V2 = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/crisis_v2_table.json"; private final OkHttpClient okHttpClient; private final ObjectMapper mapper = JsonMapper.builder() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) @@ -40,6 +43,7 @@ public class ArkGameDataService { private Map zoneActivityMap = new ConcurrentHashMap<>(); private Map arkCharacterMap = new ConcurrentHashMap<>(); private Map arkTowerMap = new ConcurrentHashMap<>(); + private Map arkCrisisV2InfoMap = new ConcurrentHashMap<>(); public void syncGameData() { syncStage(); @@ -47,8 +51,10 @@ public void syncGameData() { syncActivity(); syncCharacter(); syncTower(); + syncCrisisV2Info(); } + @Nullable public ArkStage findStage(String levelId, String code, String stageId) { ArkStage stage = levelStageMap.get(levelId.toLowerCase()); if (stage != null && stage.getCode().equalsIgnoreCase(code)) { @@ -57,6 +63,7 @@ public ArkStage findStage(String levelId, String code, String stageId) { return stageMap.get(stageId); } + @Nullable public ArkZone findZone(String levelId, String code, String stageId) { ArkStage stage = findStage(levelId, code, stageId); if (stage == null) { @@ -70,19 +77,44 @@ public ArkZone findZone(String levelId, String code, String stageId) { return zone; } + @Nullable public ArkTower findTower(String zoneId) { return arkTowerMap.get(zoneId); } + @Nullable public ArkCharacter findCharacter(String characterId) { String[] ids = characterId.split("_"); return arkCharacterMap.get(ids[ids.length - 1]); } + @Nullable public ArkActivity findActivityByZoneId(String zoneId) { return zoneActivityMap.get(zoneId); } + /** + * 通过 stageId 或者 seasonId 提取危机合约信息 + * + * @param id stageId 或者 seasonId + * @return 危机合约信息,包含合约名、开始时间、结束时间等 + */ + @Nullable + public ArkCrisisV2Info findCrisisV2InfoById(String id) { + return findCrisisV2InfoByKeyInfo(ArkLevelUtil.getKeyInfoById(id)); + } + + /** + * 通过地图系列的唯一标识提取危机合约信息 + * + * @param keyInfo 地图系列的唯一标识 + * @return 危机合约信息,包含合约名、开始时间、结束时间等 + */ + @Nullable + public ArkCrisisV2Info findCrisisV2InfoByKeyInfo(String keyInfo) { + return arkCrisisV2InfoMap.get(keyInfo); + } + private void syncStage() { Request req = new Request.Builder().url(ARK_STAGE).get().build(); try (Response rsp = okHttpClient.newCall(req).execute()) { @@ -211,4 +243,27 @@ private void syncTower() { log.error("[DATA]同步tower数据异常", e); } } + + public void syncCrisisV2Info() { + Request req = new Request.Builder().url(ARK_CRISIS_V2).get().build(); + try (Response rsp = okHttpClient.newCall(req).execute()) { + ResponseBody body = rsp.body(); + if (!rsp.isSuccessful() || body == null) { + log.error("[DATA]获取crisisV2Info数据失败"); + return; + } + JsonNode node = mapper.reader().readTree(body.charStream()); + JsonNode crisisV2InfoNode = node.get("seasonInfoDataMap"); + Map crisisV2InfoMap = mapper.convertValue(crisisV2InfoNode, new TypeReference<>() { + }); + Map temp = new ConcurrentHashMap<>(); + + crisisV2InfoMap.forEach((k, v) -> temp.put(ArkLevelUtil.getKeyInfoById(k), v)); + arkCrisisV2InfoMap = temp; + + log.info("[DATA]获取crisisV2Info数据成功, 共{}条", arkCrisisV2InfoMap.size()); + } catch (Exception e) { + log.error("[DATA]同步crisisV2Info数据异常", e); + } + } } diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index e5a50ae8..e071a0c9 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -14,6 +14,7 @@ import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; +import plus.maa.backend.common.utils.ArkLevelUtil; import plus.maa.backend.common.utils.converter.ArkLevelConverter; import plus.maa.backend.controller.response.copilot.ArkLevelInfo; import plus.maa.backend.repository.ArkLevelRepository; @@ -27,13 +28,15 @@ import plus.maa.backend.repository.entity.github.GithubContent; import plus.maa.backend.repository.entity.github.GithubTree; import plus.maa.backend.repository.entity.github.GithubTrees; +import plus.maa.backend.service.model.ArkLevelType; import java.io.IOException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.time.Instant; import java.util.Arrays; import java.util.List; -import java.util.Objects; +import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; @@ -203,11 +206,10 @@ public void updateLevelOpenStatus() { List stagesList = mapper.readValue(body, new TypeReference<>() { }); - Set codes = stagesList.stream() - .map(MaaArkStage::getCode) - .filter(Objects::nonNull) - // 提取地图的系列名,例如 GT、OF - .map(code -> code.split("-")[0]) + Set keyInfos = stagesList.stream() + .map(MaaArkStage::getStageId) + // 提取地图系列的唯一标识 + .map(ArkLevelUtil::getKeyInfoById) .collect(Collectors.toUnmodifiableSet()); // 分页修改 @@ -216,10 +218,11 @@ public void updateLevelOpenStatus() { while (arkLevelPage.hasContent()) { arkLevelPage.stream() - .filter(arkLevel -> Objects.nonNull(arkLevel.getCatThree())) + // 不处理危机合约 + .filter(arkLevel -> !ArkLevelType.RUNE.getDisplay().equals(arkLevel.getCatOne())) .forEach(arkLevel -> { - // 只考虑地图系列名,例如 GT、OF - if (codes.contains(arkLevel.getCatThree().split("-")[0])) { + // 只考虑地图系列的唯一标识 + if (keyInfos.contains(ArkLevelUtil.getKeyInfoById(arkLevel.getStageId()))) { arkLevel.setIsOpen(true); } else if (arkLevel.getIsOpen() != null) { @@ -245,6 +248,38 @@ public void updateLevelOpenStatus() { } } + public void updateCrisisV2OpenStatus() { + log.info("[CRISIS-V2-OPEN-STATUS]准备更新危机合约开放状态"); + // 同步危机合约信息 + gameDataService.syncCrisisV2Info(); + + // 分页修改 + Pageable pageable = Pageable.ofSize(1000); + Page arkCrisisV2Page = arkLevelRepo.findAllByCatOne(ArkLevelType.RUNE.getDisplay(), pageable); + + // 获取当前时间 + Instant nowInstant = Instant.now(); + + while (arkCrisisV2Page.hasContent()) { + + arkCrisisV2Page.forEach(arkCrisisV2 -> Optional + .ofNullable(gameDataService.findCrisisV2InfoById(arkCrisisV2.getStageId())) + .map(crisisV2Info -> Instant.ofEpochSecond(crisisV2Info.getEndTs())) + .ifPresent(endInstant -> arkCrisisV2.setIsOpen(endInstant.isAfter(nowInstant))) + ); + + arkLevelRepo.saveAll(arkCrisisV2Page); + + if (!arkCrisisV2Page.hasNext()) { + // 没有下一页了,跳出循环 + break; + } + pageable = arkCrisisV2Page.nextPageable(); + arkCrisisV2Page = arkLevelRepo.findAllByCatOne(ArkLevelType.RUNE.getDisplay(), pageable); + } + log.info("[CRISIS-V2-OPEN-STATUS]危机合约开放状态更新完毕"); + } + /** * 下载地图数据 */ diff --git a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java index f0b2bf94..1c86ed1a 100644 --- a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java +++ b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java @@ -21,12 +21,13 @@ public void syncArkLevels() { } /** - * 更新地图开放状态,每天凌晨执行,最好和热度值刷入任务保持相对顺序 + * 更新开放状态,每天凌晨执行,最好和热度值刷入任务保持相对顺序 * 4:00、4:15 各执行一次,避免网络波动导致更新失败 */ @Scheduled(cron = "0 0-15/15 4 * * ?") - public void updateArkLevelsOpenStatus() { + public void updateOpenStatus() { arkLevelService.updateLevelOpenStatus(); + arkLevelService.updateCrisisV2OpenStatus(); } } From 7831fe5c4639a4ba1e6a789a4769be27146670f3 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Wed, 29 Nov 2023 14:14:37 +0800 Subject: [PATCH 024/168] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=BC=80=E6=94=BE?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E6=9B=B4=E6=96=B0=E4=BB=BB=E5=8A=A1,?= =?UTF-8?q?=E5=87=8F=E5=B0=91=E5=B7=B2=E5=85=B3=E9=97=AD=E5=9C=B0=E5=9B=BE?= =?UTF-8?q?=E7=9A=84=E7=83=AD=E5=BA=A6=E6=83=A9=E7=BD=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/common/utils/ArkLevelUtil.java | 2 +- .../maa/backend/service/ArkLevelService.java | 61 +++++++++---------- .../maa/backend/task/ArkLevelSyncTask.java | 2 +- .../backend/task/CopilotScoreRefreshTask.java | 2 +- .../common/utils/ArkLevelUtilTest.java | 3 +- 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java b/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java index 6b171d9b..e422adc7 100644 --- a/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java +++ b/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java @@ -9,7 +9,7 @@ public class ArkLevelUtil { private static final Pattern NOT_KEY_INFO = Pattern.compile( // level_、各种难度前缀、season_、前导零、以-或者_划分的后缀 - "^level_|^easy_|^hard_|^tough_|^main_|season_|(? content.isFile() && "stages.json".equals(content.getName())) .findFirst() .orElse(null); if (stages == null) { - log.info("[LEVEL-OPEN-STATUS]地图开放状态数据不存在"); + log.info("[ACTIVITIES-OPEN-STATUS]活动地图开放状态数据不存在"); return; } String lastStagesSha = redisCache.getCache("level:stages:sha", String.class); if (lastStagesSha != null && lastStagesSha.equals(stages.getSha())) { - log.info("[LEVEL-OPEN-STATUS]地图开放状态已是最新"); + log.info("[ACTIVITIES-OPEN-STATUS]活动地图开放状态已是最新"); return; } - log.info("[LEVEL-OPEN-STATUS]开始更新地图开放状态"); + log.info("[ACTIVITIES-OPEN-STATUS]开始更新活动地图开放状态"); // 就一个文件,直接在当前线程下载数据 try (Response response = okHttpClient .newCall(new Request.Builder().url(stages.getDownloadUrl()).build()) .execute()) { if (!response.isSuccessful() || response.body() == null) { - log.error("[LEVEL-OPEN-STATUS]地图开放状态下载失败"); + log.error("[ACTIVITIES-OPEN-STATUS]活动地图开放状态下载失败"); return; } @@ -212,24 +212,19 @@ public void updateLevelOpenStatus() { .map(ArkLevelUtil::getKeyInfoById) .collect(Collectors.toUnmodifiableSet()); + // 修改活动地图 + final String catOne = ArkLevelType.ACTIVITIES.getDisplay(); // 分页修改 Pageable pageable = Pageable.ofSize(1000); - Page arkLevelPage = arkLevelRepo.findAll(pageable); + Page arkLevelPage = arkLevelRepo.findAllByCatOne(catOne, pageable); while (arkLevelPage.hasContent()) { - arkLevelPage.stream() - // 不处理危机合约 - .filter(arkLevel -> !ArkLevelType.RUNE.getDisplay().equals(arkLevel.getCatOne())) - .forEach(arkLevel -> { - // 只考虑地图系列的唯一标识 - if (keyInfos.contains(ArkLevelUtil.getKeyInfoById(arkLevel.getStageId()))) { - - arkLevel.setIsOpen(true); - } else if (arkLevel.getIsOpen() != null) { - // 数据可能存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 - arkLevel.setIsOpen(false); - } - }); + // 未匹配一律视为已关闭 + arkLevelPage.forEach(arkLevel -> arkLevel.setIsOpen( + keyInfos.contains( + ArkLevelUtil.getKeyInfoById(arkLevel.getStageId())) + ) + ); arkLevelRepo.saveAll(arkLevelPage); @@ -238,13 +233,13 @@ public void updateLevelOpenStatus() { break; } pageable = arkLevelPage.nextPageable(); - arkLevelPage = arkLevelRepo.findAll(pageable); + arkLevelPage = arkLevelRepo.findAllByCatOne(catOne, pageable); } redisCache.setData("level:stages:sha", stages.getSha()); - log.info("[LEVEL-OPEN-STATUS]地图开放状态更新完成"); + log.info("[ACTIVITIES-OPEN-STATUS]活动地图开放状态更新完成"); } catch (Exception e) { - log.error("[LEVEL-OPEN-STATUS]地图开放状态更新失败", e); + log.error("[ACTIVITIES-OPEN-STATUS]活动地图开放状态更新失败", e); } } @@ -253,20 +248,24 @@ public void updateCrisisV2OpenStatus() { // 同步危机合约信息 gameDataService.syncCrisisV2Info(); + final String catOne = ArkLevelType.RUNE.getDisplay(); // 分页修改 Pageable pageable = Pageable.ofSize(1000); - Page arkCrisisV2Page = arkLevelRepo.findAllByCatOne(ArkLevelType.RUNE.getDisplay(), pageable); + Page arkCrisisV2Page = arkLevelRepo.findAllByCatOne(catOne, pageable); // 获取当前时间 Instant nowInstant = Instant.now(); while (arkCrisisV2Page.hasContent()) { - arkCrisisV2Page.forEach(arkCrisisV2 -> Optional - .ofNullable(gameDataService.findCrisisV2InfoById(arkCrisisV2.getStageId())) - .map(crisisV2Info -> Instant.ofEpochSecond(crisisV2Info.getEndTs())) - .ifPresent(endInstant -> arkCrisisV2.setIsOpen(endInstant.isAfter(nowInstant))) - ); + arkCrisisV2Page.forEach(arkCrisisV2 -> { + // 未匹配一律视为已关闭 + arkCrisisV2.setIsOpen(false); + Optional.ofNullable(gameDataService.findCrisisV2InfoById(arkCrisisV2.getStageId())) + .map(crisisV2Info -> Instant.ofEpochSecond(crisisV2Info.getEndTs())) + .ifPresent(endInstant -> arkCrisisV2.setIsOpen(endInstant.isAfter(nowInstant))); + + }); arkLevelRepo.saveAll(arkCrisisV2Page); @@ -275,7 +274,7 @@ public void updateCrisisV2OpenStatus() { break; } pageable = arkCrisisV2Page.nextPageable(); - arkCrisisV2Page = arkLevelRepo.findAllByCatOne(ArkLevelType.RUNE.getDisplay(), pageable); + arkCrisisV2Page = arkLevelRepo.findAllByCatOne(catOne, pageable); } log.info("[CRISIS-V2-OPEN-STATUS]危机合约开放状态更新完毕"); } diff --git a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java index 1c86ed1a..3921d258 100644 --- a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java +++ b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java @@ -26,7 +26,7 @@ public void syncArkLevels() { */ @Scheduled(cron = "0 0-15/15 4 * * ?") public void updateOpenStatus() { - arkLevelService.updateLevelOpenStatus(); + arkLevelService.updateActivitiesOpenStatus(); arkLevelService.updateCrisisV2OpenStatus(); } diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java index 16cdf9ce..08f115cd 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java @@ -112,7 +112,7 @@ private void refresh(Collection copilotIdSTRs, Iterable copilot ArkLevelInfo arkLevelInfo = arkLevelService.findByLevelIdFuzzy(copilot.getStageName()); if (arkLevelInfo != null && Boolean.FALSE.equals(arkLevelInfo.getIsOpen())) { // 非开放关卡打入冷宫 - hotScore += Integer.MIN_VALUE; + hotScore /= 3; } copilot.setHotScore(hotScore); } diff --git a/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java b/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java index 2c18ab51..6ec5c0e6 100644 --- a/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java +++ b/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java @@ -16,7 +16,8 @@ void testGetKeyInfoById() { "level_crisis_v2_01-07", "crisis_v2_season_1_1", "a001_01_perm", "a001_ex05", "act11d0_ex08#f#", "act11d0_s02", - "act11mini_03#f#", "act11mini_04" + "act11mini_03#f#", "act11mini_04", + "act17side_01", "act17side_s01_a" ); for (var entity : ids.entrySet()) { From 52ecb46eda08532f9ae727525c249fa7801c1c04 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Wed, 29 Nov 2023 18:36:02 +0800 Subject: [PATCH 025/168] =?UTF-8?q?=E6=B4=BB=E5=8A=A8=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E4=B8=8D=E5=A4=AA=E5=87=86=E7=A1=AE=EF=BC=8C=E5=87=8F=E5=B0=91?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E4=B8=BA=E5=85=B3=E9=97=AD=E7=9A=84=E6=95=B0?= =?UTF-8?q?=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/service/ArkLevelService.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index d32468c8..c1bf0cd9 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -219,12 +219,16 @@ public void updateActivitiesOpenStatus() { Page arkLevelPage = arkLevelRepo.findAllByCatOne(catOne, pageable); while (arkLevelPage.hasContent()) { - // 未匹配一律视为已关闭 - arkLevelPage.forEach(arkLevel -> arkLevel.setIsOpen( - keyInfos.contains( - ArkLevelUtil.getKeyInfoById(arkLevel.getStageId())) - ) - ); + arkLevelPage.forEach(arkLevel -> { + // 只考虑地图系列的唯一标识 + if (keyInfos.contains(ArkLevelUtil.getKeyInfoById(arkLevel.getStageId()))) { + + arkLevel.setIsOpen(true); + } else if (arkLevel.getIsOpen() != null) { + // 数据可能存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 + arkLevel.setIsOpen(false); + } + }); arkLevelRepo.saveAll(arkLevelPage); @@ -259,7 +263,7 @@ public void updateCrisisV2OpenStatus() { while (arkCrisisV2Page.hasContent()) { arkCrisisV2Page.forEach(arkCrisisV2 -> { - // 未匹配一律视为已关闭 + // 危机合约信息比较准,因此未匹配一律视为已关闭 arkCrisisV2.setIsOpen(false); Optional.ofNullable(gameDataService.findCrisisV2InfoById(arkCrisisV2.getStageId())) .map(crisisV2Info -> Instant.ofEpochSecond(crisisV2Info.getEndTs())) From cdd199bf3a11d70f73a4d0af697882d7eec24243 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Fri, 1 Dec 2023 23:57:16 +0800 Subject: [PATCH 026/168] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=AD=A3=E5=88=99?= =?UTF-8?q?=E8=A1=A8=E8=BE=BE=E5=BC=8F=E3=80=82=E4=BC=98=E5=8C=96=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E7=94=A8=E4=BE=8B=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/common/utils/ArkLevelUtil.java | 2 +- .../common/utils/ArkLevelUtilTest.java | 41 +++++++++++++++---- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java b/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java index e422adc7..81468105 100644 --- a/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java +++ b/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java @@ -9,7 +9,7 @@ public class ArkLevelUtil { private static final Pattern NOT_KEY_INFO = Pattern.compile( // level_、各种难度前缀、season_、前导零、以-或者_划分的后缀 - "^level_|^easy_|^hard_|^tough_|^main_|season_|(? ids = Map.of( - "level_rune_09-01", "level_rune_09-02", - "level_crisis_v2_01-07", "crisis_v2_season_1_1", - "a001_01_perm", "a001_ex05", - "act11d0_ex08#f#", "act11d0_s02", - "act11mini_03#f#", "act11mini_04", - "act17side_01", "act17side_s01_a" + + var ids = Map.ofEntries( + entry("level_rune_09-01", "level_rune_09-02"), + entry("level_crisis_v2_01-07", "crisis_v2_season_1_1"), + entry("a001_01_perm", "a001_ex05"), + entry("act11d0_ex08#f#", "act11d0_s02"), + entry("act11mini_03#f#", "act11mini_04"), + entry("act17side_01", "act17side_s01_a"), + entry("act17side_01_rep", "act17side_02_perm") + ); + + var idsWithInfo = Map.ofEntries( + entry("level_rune_09-01", "rune_9"), + entry("level_crisis_v2_01-07", "crisis_v2_1"), + entry("a001_01_perm", "a1"), + entry("act11d0_ex08#f#", "act11d0"), + entry("act11mini_03#f#", "act11mini"), + entry("act17side_01", "act17side"), + entry("act17side_01_rep", "act17side") ); for (var entity : ids.entrySet()) { - assertEquals(getKeyInfoById(entity.getKey()), getKeyInfoById(entity.getValue())); + var key = entity.getKey(); + var value = entity.getValue(); + var infoOfKey = getKeyInfoById(key); + assertEquals( + infoOfKey, getKeyInfoById(value), + () -> key + " 与 " + value + " 的地图标识不相同" + ); + + var infoOfMap = idsWithInfo.get(key); + assertEquals( + infoOfKey, infoOfMap, + () -> key + " 的地图标识不为 " + infoOfMap + ); } } } \ No newline at end of file From ad09685d8cd7468b9f370731e7a256b17446f9f0 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 2 Dec 2023 14:30:41 +0800 Subject: [PATCH 027/168] =?UTF-8?q?=E5=90=8C=E6=AD=A5GameData=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E5=90=8E=E4=B8=8D=E6=89=A7=E8=A1=8C=E5=90=8E=E7=BB=AD?= =?UTF-8?q?=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/service/ArkGameDataService.java | 50 ++++++++++++------- .../maa/backend/service/ArkLevelService.java | 10 +++- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/ArkGameDataService.java b/src/main/java/plus/maa/backend/service/ArkGameDataService.java index 5ddd79b9..9630e700 100644 --- a/src/main/java/plus/maa/backend/service/ArkGameDataService.java +++ b/src/main/java/plus/maa/backend/service/ArkGameDataService.java @@ -45,13 +45,13 @@ public class ArkGameDataService { private Map arkTowerMap = new ConcurrentHashMap<>(); private Map arkCrisisV2InfoMap = new ConcurrentHashMap<>(); - public void syncGameData() { - syncStage(); - syncZone(); - syncActivity(); - syncCharacter(); - syncTower(); - syncCrisisV2Info(); + public boolean syncGameData() { + return syncStage() && + syncZone() && + syncActivity() && + syncCharacter() && + syncTower() && + syncCrisisV2Info(); } @Nullable @@ -115,13 +115,13 @@ public ArkCrisisV2Info findCrisisV2InfoByKeyInfo(String keyInfo) { return arkCrisisV2InfoMap.get(keyInfo); } - private void syncStage() { + private boolean syncStage() { Request req = new Request.Builder().url(ARK_STAGE).get().build(); try (Response rsp = okHttpClient.newCall(req).execute()) { ResponseBody body = rsp.body(); if (body == null) { log.error("[DATA]获取stage数据失败"); - return; + return false; } JsonNode node = mapper.reader().readTree(body.string()); JsonNode stagesNode = node.get("stages"); @@ -139,16 +139,18 @@ private void syncStage() { log.info("[DATA]获取stage数据成功, 共{}条", levelStageMap.size()); } catch (Exception e) { log.error("[DATA]同步stage数据异常", e); + return false; } + return true; } - private void syncZone() { + private boolean syncZone() { Request req = new Request.Builder().url(ARK_ZONE).get().build(); try (Response rsp = okHttpClient.newCall(req).execute()) { ResponseBody body = rsp.body(); if (body == null) { log.error("[DATA]获取zone数据失败"); - return; + return false; } JsonNode node = mapper.reader().readTree(body.string()); JsonNode zonesNode = node.get("zones"); @@ -158,16 +160,18 @@ private void syncZone() { log.info("[DATA]获取zone数据成功, 共{}条", zoneMap.size()); } catch (Exception e) { log.error("[DATA]同步zone数据异常", e); + return false; } + return true; } - private void syncActivity() { + private boolean syncActivity() { Request req = new Request.Builder().url(ARK_ACTIVITY).get().build(); try (Response rsp = okHttpClient.newCall(req).execute()) { ResponseBody body = rsp.body(); if (body == null) { log.error("[DATA]获取activity数据失败"); - return; + return false; } JsonNode node = mapper.reader().readTree(body.string()); @@ -191,16 +195,18 @@ private void syncActivity() { log.info("[DATA]获取activity数据成功, 共{}条", zoneActivityMap.size()); } catch (Exception e) { log.error("[DATA]同步activity数据异常", e); + return false; } + return true; } - private void syncCharacter() { + private boolean syncCharacter() { Request req = new Request.Builder().url(ARK_CHARACTER).get().build(); try (Response rsp = okHttpClient.newCall(req).execute()) { ResponseBody body = rsp.body(); if (body == null) { log.error("[DATA]获取character数据失败"); - return; + return false; } JsonNode node = mapper.reader().readTree(body.string()); Map characters = mapper.convertValue(node, new TypeReference<>() { @@ -223,16 +229,18 @@ private void syncCharacter() { log.info("[DATA]获取character数据成功, 共{}条", arkCharacterMap.size()); } catch (Exception e) { log.error("[DATA]同步character数据异常", e); + return false; } + return true; } - private void syncTower() { + private boolean syncTower() { Request req = new Request.Builder().url(ARK_TOWER).get().build(); try (Response rsp = okHttpClient.newCall(req).execute()) { ResponseBody body = rsp.body(); if (body == null) { log.error("[DATA]获取tower数据失败"); - return; + return false; } JsonNode node = mapper.reader().readTree(body.string()); JsonNode towerNode = node.get("towers"); @@ -241,16 +249,18 @@ private void syncTower() { log.info("[DATA]获取tower数据成功, 共{}条", arkTowerMap.size()); } catch (Exception e) { log.error("[DATA]同步tower数据异常", e); + return false; } + return true; } - public void syncCrisisV2Info() { + public boolean syncCrisisV2Info() { Request req = new Request.Builder().url(ARK_CRISIS_V2).get().build(); try (Response rsp = okHttpClient.newCall(req).execute()) { ResponseBody body = rsp.body(); if (!rsp.isSuccessful() || body == null) { log.error("[DATA]获取crisisV2Info数据失败"); - return; + return false; } JsonNode node = mapper.reader().readTree(body.charStream()); JsonNode crisisV2InfoNode = node.get("seasonInfoDataMap"); @@ -264,6 +274,8 @@ public void syncCrisisV2Info() { log.info("[DATA]获取crisisV2Info数据成功, 共{}条", arkCrisisV2InfoMap.size()); } catch (Exception e) { log.error("[DATA]同步crisisV2Info数据异常", e); + return false; } + return true; } } diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index c1bf0cd9..f8c62ccf 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -160,7 +160,10 @@ public void runSyncLevelDataTask() { return; } //同步GameData仓库数据 - gameDataService.syncGameData(); + if (!gameDataService.syncGameData()) { + log.error("[LEVEL]GameData仓库数据同步失败"); + return; + } DownloadTask task = new DownloadTask(levelTrees.size(), (t) -> { //仅在全部下载任务成功后更新commit缓存 @@ -250,7 +253,10 @@ public void updateActivitiesOpenStatus() { public void updateCrisisV2OpenStatus() { log.info("[CRISIS-V2-OPEN-STATUS]准备更新危机合约开放状态"); // 同步危机合约信息 - gameDataService.syncCrisisV2Info(); + if (!gameDataService.syncCrisisV2Info()) { + log.error("[CRISIS-V2-OPEN-STATUS]同步危机合约信息失败"); + return; + } final String catOne = ArkLevelType.RUNE.getDisplay(); // 分页修改 From cd6a1bdec83c390241efa167abec4b7e5b3f3727 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Thu, 7 Dec 2023 13:13:51 +0800 Subject: [PATCH 028/168] =?UTF-8?q?Revert=20"=E4=BF=AE=E6=94=B9=20EmailSer?= =?UTF-8?q?vice=20=E6=B3=A8=E5=85=A5=E8=87=AA=E8=BA=AB=E4=BB=A3=E7=90=86?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E6=96=B9=E5=BC=8F=EF=BC=8C=E5=9B=A0=E4=B8=BA?= =?UTF-8?q?=20JUnit=20=E4=B8=8D=E5=85=BC=E5=AE=B9=20@Lazy=EF=BC=8C?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E6=97=B6=E4=BC=9A=E6=8A=A5=E9=94=99"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e6f498ab9fbe091f897d4ccee45af502db4ee701. --- .../maa/backend/service/EmailService.java | 35 +++---------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/EmailService.java b/src/main/java/plus/maa/backend/service/EmailService.java index 96799fc3..b1a6ba5d 100644 --- a/src/main/java/plus/maa/backend/service/EmailService.java +++ b/src/main/java/plus/maa/backend/service/EmailService.java @@ -2,13 +2,14 @@ import cn.hutool.extra.mail.MailAccount; import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.RandomStringUtils; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import plus.maa.backend.common.bo.EmailBusinessObject; import plus.maa.backend.config.external.MaaCopilotProperties; @@ -43,7 +44,9 @@ public class EmailService { private final MailAccount MAIL_ACCOUNT = new MailAccount(); - // 注入自身代理类 + // 注入自身代理类的延迟加载代理类 + @Lazy + @Resource private EmailService emailService; /** @@ -137,32 +140,4 @@ public void sendCommentNotification(String email, CommentNotification commentNot .sendCommentNotification(map); } - - /** - * 注入 EmailService 的代理类 - *

- * 不得为 private,否则静态内部类只会修改内部类作用域内的副本而不是本类 - * - * @param emailService 被注入的 EmailService - */ - void setEmailService(EmailService emailService) { - synchronized (this) { - if (this.emailService == null) { - this.emailService = emailService; - } - } - } - - @Component - @RequiredArgsConstructor - public static class EmailServiceInject { - - private final EmailService emailService; - - @PostConstruct - private void init() { - emailService.setEmailService(emailService); - } - - } } From e7e25c57c6d8ad6287756813d2783ef799e57ace Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Thu, 7 Dec 2023 13:40:31 +0800 Subject: [PATCH 029/168] =?UTF-8?q?=E5=8E=BB=E9=99=A4=20EmailService=20?= =?UTF-8?q?=E4=B8=AD=E7=9A=84=E5=BE=AA=E7=8E=AF=E4=BE=9D=E8=B5=96=EF=BC=8C?= =?UTF-8?q?=E9=81=BF=E5=85=8D=E4=B8=8E=20AOT=20=E7=9A=84=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=80=A7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/config/ThreadPoolConfig.java | 35 +++++++++++++++ .../maa/backend/service/EmailService.java | 45 +++++++++---------- 2 files changed, 57 insertions(+), 23 deletions(-) create mode 100644 src/main/java/plus/maa/backend/config/ThreadPoolConfig.java diff --git a/src/main/java/plus/maa/backend/config/ThreadPoolConfig.java b/src/main/java/plus/maa/backend/config/ThreadPoolConfig.java new file mode 100644 index 00000000..30d82135 --- /dev/null +++ b/src/main/java/plus/maa/backend/config/ThreadPoolConfig.java @@ -0,0 +1,35 @@ +package plus.maa.backend.config; + +import org.springframework.boot.task.TaskExecutorBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Primary; +import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import static org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME; + +@Configuration(proxyBeanMethods = false) +public class ThreadPoolConfig { + + @Lazy + @Primary + @Bean(name = {APPLICATION_TASK_EXECUTOR_BEAN_NAME, + AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME}) + public ThreadPoolTaskExecutor defaultTaskExecutor(TaskExecutorBuilder builder) { + return builder.build(); + } + + @Bean + public ThreadPoolTaskExecutor emailTaskExecutor() { + // 在默认线程池配置的基础上修改了核心线程数和线程名称 + var taskExecutor = new ThreadPoolTaskExecutor(); + // I/O 密集型配置 + taskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2); + taskExecutor.setThreadNamePrefix("email-task-"); + // 动态的核心线程数量 + taskExecutor.setAllowCoreThreadTimeOut(true); + return taskExecutor; + } +} diff --git a/src/main/java/plus/maa/backend/service/EmailService.java b/src/main/java/plus/maa/backend/service/EmailService.java index b1a6ba5d..d2a49004 100644 --- a/src/main/java/plus/maa/backend/service/EmailService.java +++ b/src/main/java/plus/maa/backend/service/EmailService.java @@ -8,7 +8,7 @@ import org.apache.commons.lang3.RandomStringUtils; import org.apache.logging.log4j.util.Strings; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Lazy; +import org.springframework.core.task.AsyncTaskExecutor; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import plus.maa.backend.common.bo.EmailBusinessObject; @@ -44,10 +44,8 @@ public class EmailService { private final MailAccount MAIL_ACCOUNT = new MailAccount(); - // 注入自身代理类的延迟加载代理类 - @Lazy - @Resource - private EmailService emailService; + @Resource(name = "emailTaskExecutor") + private final AsyncTaskExecutor emailTaskExecutor; /** * 初始化邮件账户信息 @@ -82,25 +80,26 @@ public void sendVCode(String email) { // 设置失败,说明 key 已存在 throw new MaaResultException(403, String.format("发送验证码的请求至少需要间隔 %d 秒", timeout)); } - // 调用注入的代理类执行异步任务 - emailService.asyncSendVCode(email); + // 执行异步任务 + asyncSendVCode(email); } - @Async - protected void asyncSendVCode(String email) { - // 6位随机数验证码 - String vcode = RandomStringUtils.random(6, true, true).toUpperCase(); - if (flagNoSend) { - log.debug("vcode is " + vcode); - log.warn("Email not sent, no-send enabled"); - } else { - EmailBusinessObject.builder() - .setMailAccount(MAIL_ACCOUNT) - .setEmail(email) - .sendVerificationCodeMessage(vcode); - } - // 存redis - redisCache.setCache("vCodeEmail:" + email, vcode, expire); + private void asyncSendVCode(String email) { + emailTaskExecutor.execute(() -> { + // 6位随机数验证码 + String vcode = RandomStringUtils.random(6, true, true).toUpperCase(); + if (flagNoSend) { + log.debug("vcode is " + vcode); + log.warn("Email not sent, no-send enabled"); + } else { + EmailBusinessObject.builder() + .setMailAccount(MAIL_ACCOUNT) + .setEmail(email) + .sendVerificationCodeMessage(vcode); + } + // 存redis + redisCache.setCache("vCodeEmail:" + email, vcode, expire); + }); } /** @@ -115,7 +114,7 @@ public void verifyVCode(String email, String vcode) { } } - @Async + @Async("emailTaskExecutor") public void sendCommentNotification(String email, CommentNotification commentNotification) { int limit = 25; From dcec28b31cd473613e984187b331b228e4f3d43b Mon Sep 17 00:00:00 2001 From: dragove Date: Thu, 7 Dec 2023 23:10:36 +0800 Subject: [PATCH 030/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=B1?= =?UTF-8?q?=E4=BA=8Eaot=E6=8F=92=E4=BB=B6=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E7=BC=96=E8=AF=91=E5=90=8Ejar=E5=8C=85=E6=97=A0=E6=B3=95?= =?UTF-8?q?=E7=9B=B4=E6=8E=A5=E8=BF=90=E8=A1=8C=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=88=E6=9A=82=E6=97=B6=E6=B3=A8=E9=87=8Aaot=E6=8F=92?= =?UTF-8?q?=E4=BB=B6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yaml | 1 + build.gradle | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 94cd5841..9baba734 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -80,6 +80,7 @@ jobs: type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', 'main') }} + type=raw,value=dev,enable=${{ github.ref == format('refs/heads/{0}', 'dev') }} type=raw,value={{branch}}-{{sha}} - name: Build and push Docker image diff --git a/build.gradle b/build.gradle index c39cce5d..900e9f1d 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { id 'io.freefair.lombok' version '8.4' id 'org.springdoc.openapi-gradle-plugin' version '1.8.0' id 'org.hidetake.swagger.generator' version '2.19.2' - id 'org.graalvm.buildtools.native' version '0.9.28' +// id 'org.graalvm.buildtools.native' version '0.9.28' } group 'plus.maa' From e01f95acd25c253ebbae8057ed35d5bf4a2e6bd3 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Tue, 12 Dec 2023 00:34:45 +0800 Subject: [PATCH 031/168] =?UTF-8?q?GitHub=20json=20=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E7=9A=84=E5=AD=97=E6=AE=B5=E5=90=8D=E6=A0=B7=E5=BC=8F=E7=BB=9F?= =?UTF-8?q?=E4=B8=80=E9=85=8D=E7=BD=AE=E4=B8=BA=20SnakeCase?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/config/HttpInterfaceConfig.java | 22 +++++++++++++++---- .../entity/github/GithubContent.java | 3 --- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.java b/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.java index 2515e236..1fde03b7 100644 --- a/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.java +++ b/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.java @@ -1,7 +1,12 @@ package plus.maa.backend.config; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.http.codec.json.Jackson2JsonDecoder; +import org.springframework.http.codec.json.Jackson2JsonEncoder; +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.web.reactive.function.client.ExchangeStrategies; import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.support.WebClientAdapter; @@ -13,14 +18,23 @@ public class HttpInterfaceConfig { @Bean GithubRepository githubRepository() { + + ObjectMapper mapper = Jackson2ObjectMapperBuilder.json() + .propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE) + .build(); + WebClient client = WebClient.builder() .baseUrl("https://api.github.com") .exchangeStrategies(ExchangeStrategies .builder() - .codecs(codecs -> codecs - .defaultCodecs() - // 最大 20MB - .maxInMemorySize(20 * 1024 * 1024)) + .codecs(codecs -> { + codecs.defaultCodecs() + .jackson2JsonEncoder(new Jackson2JsonEncoder(mapper)); + codecs.defaultCodecs() + .jackson2JsonDecoder(new Jackson2JsonDecoder(mapper)); + // 最大 20MB + codecs.defaultCodecs().maxInMemorySize(20 * 1024 * 1024); + }) .build()) .defaultHeaders(headers -> { headers.add("Accept", "application/vnd.github+json"); diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java b/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java index 5cd6d80f..4a544fdf 100644 --- a/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java +++ b/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java @@ -1,7 +1,5 @@ package plus.maa.backend.repository.entity.github; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.annotation.JsonNaming; import lombok.Data; import org.apache.commons.lang3.StringUtils; @@ -12,7 +10,6 @@ * created on 2022/12/23 */ @Data -@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) public class GithubContent { // 文件名 From 30116a6b598cb74325bc3e863e7255ed44079a3d Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Tue, 12 Dec 2023 12:21:30 +0800 Subject: [PATCH 032/168] =?UTF-8?q?=E4=BC=98=E5=8C=96=E5=8D=B1=E6=9C=BA?= =?UTF-8?q?=E5=90=88=E7=BA=A6=E5=9C=B0=E5=9B=BE=E4=BF=A1=E6=81=AF=E7=9A=84?= =?UTF-8?q?=20CatTwo=20=E5=AD=97=E6=AE=B5=EF=BC=8C=E4=BD=BF=E5=85=B6?= =?UTF-8?q?=E4=B8=BA=E6=9C=AC=E6=AC=A1=E5=8D=B1=E6=9C=BA=E5=90=88=E7=BA=A6?= =?UTF-8?q?=E7=9A=84=E8=B5=9B=E5=AD=A3=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/service/model/parser/RuneParser.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/plus/maa/backend/service/model/parser/RuneParser.java b/src/main/java/plus/maa/backend/service/model/parser/RuneParser.java index 1e7099fb..2ca223b8 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/RuneParser.java +++ b/src/main/java/plus/maa/backend/service/model/parser/RuneParser.java @@ -1,12 +1,21 @@ package plus.maa.backend.service.model.parser; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import plus.maa.backend.repository.entity.ArkLevel; +import plus.maa.backend.repository.entity.gamedata.ArkCrisisV2Info; import plus.maa.backend.repository.entity.gamedata.ArkTilePos; +import plus.maa.backend.service.ArkGameDataService; import plus.maa.backend.service.model.ArkLevelType; +import java.util.Optional; + @Component +@RequiredArgsConstructor public class RuneParser implements ArkLevelParser { + + private final ArkGameDataService dataService; + @Override public boolean supportType(ArkLevelType type) { return ArkLevelType.RUNE.equals(type); @@ -15,7 +24,12 @@ public boolean supportType(ArkLevelType type) { @Override public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { level.setCatOne(ArkLevelType.RUNE.getDisplay()); - level.setCatTwo(tilePos.getCode()); + level.setCatTwo( + Optional.ofNullable(level.getStageId()) + .map(dataService::findCrisisV2InfoById) + .map(ArkCrisisV2Info::getName) + .orElse(tilePos.getCode()) + ); level.setCatThree(level.getName()); return level; } From 5f372d36332b48c4cdc354d0c7c0de0dfa76ef2d Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Tue, 12 Dec 2023 17:35:54 +0800 Subject: [PATCH 033/168] =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E4=BF=A1=E6=81=AF?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=9C=8D=E5=8A=A1=E5=99=A8=E8=AE=A4=E4=B8=BA?= =?UTF-8?q?=E7=9A=84=E5=85=B3=E9=97=AD=E6=97=B6=E9=97=B4=E3=80=82=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E7=83=AD=E5=BA=A6=E6=83=A9=E7=BD=9A=E4=BB=85=E9=99=90?= =?UTF-8?q?=E9=A6=96=E6=AC=A1=E4=B8=8A=E4=BC=A0=E6=97=B6=E9=97=B4=E4=BA=8E?= =?UTF-8?q?=E5=9C=B0=E5=9B=BE=E5=85=B3=E9=97=AD=E5=89=8D=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/copilot/ArkLevelInfo.java | 9 ++++++++- .../backend/repository/entity/ArkLevel.java | 7 ++++++- .../maa/backend/service/ArkLevelService.java | 18 ++++++++++++++++++ .../backend/task/CopilotScoreRefreshTask.java | 8 +++++++- 4 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java index 27e19731..10579bc3 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java +++ b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java @@ -1,5 +1,6 @@ package plus.maa.backend.controller.response.copilot; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; @@ -8,6 +9,7 @@ import org.jetbrains.annotations.Nullable; import java.io.Serializable; +import java.time.LocalDateTime; /** * @author john180 @@ -26,7 +28,12 @@ public class ArkLevelInfo implements Serializable { private String name; private int width; private int height; - // 当前版本地图是否开放 + // 只是服务器认为的当前版本地图是否开放 @Nullable + @JsonIgnore private Boolean isOpen; + // 非实际意义上的活动地图关闭时间,只是服务器认为的关闭时间 + @Nullable + @JsonIgnore + private LocalDateTime closeTime; } diff --git a/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java b/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java index fd5d9238..beca9be4 100644 --- a/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java +++ b/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java @@ -9,6 +9,8 @@ import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; +import java.time.LocalDateTime; + /** * 地图数据 * @@ -39,7 +41,10 @@ public class ArkLevel { private String name; private int width; private int height; - // 当前版本地图是否开放 + // 只是服务器认为的当前版本地图是否开放 @Nullable private Boolean isOpen; + // 非实际意义上的活动地图关闭时间,只是服务器认为的关闭时间 + @Nullable + private LocalDateTime closeTime; } diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index f8c62ccf..4749bb49 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -34,6 +34,8 @@ import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.Arrays; import java.util.List; import java.util.Optional; @@ -220,6 +222,10 @@ public void updateActivitiesOpenStatus() { // 分页修改 Pageable pageable = Pageable.ofSize(1000); Page arkLevelPage = arkLevelRepo.findAllByCatOne(catOne, pageable); + + // 获取当前时间 + LocalDateTime nowTime = LocalDateTime.now(); + while (arkLevelPage.hasContent()) { arkLevelPage.forEach(arkLevel -> { @@ -227,9 +233,15 @@ public void updateActivitiesOpenStatus() { if (keyInfos.contains(ArkLevelUtil.getKeyInfoById(arkLevel.getStageId()))) { arkLevel.setIsOpen(true); + // 如果一个旧地图重新开放,关闭时间也需要另算 + arkLevel.setCloseTime(null); } else if (arkLevel.getIsOpen() != null) { // 数据可能存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 arkLevel.setIsOpen(false); + // 不能每天都变更关闭时间 + if (arkLevel.getCloseTime() == null) { + arkLevel.setCloseTime(nowTime); + } } }); @@ -265,6 +277,7 @@ public void updateCrisisV2OpenStatus() { // 获取当前时间 Instant nowInstant = Instant.now(); + LocalDateTime nowTime = LocalDateTime.ofInstant(nowInstant, ZoneId.systemDefault()); while (arkCrisisV2Page.hasContent()) { @@ -275,6 +288,11 @@ public void updateCrisisV2OpenStatus() { .map(crisisV2Info -> Instant.ofEpochSecond(crisisV2Info.getEndTs())) .ifPresent(endInstant -> arkCrisisV2.setIsOpen(endInstant.isAfter(nowInstant))); + if (arkCrisisV2.getCloseTime() == null && + Boolean.FALSE.equals(arkCrisisV2.getIsOpen())) { + // 危机合约应该不存在赛季重新开放的问题,只要不每天变动关闭时间即可 + arkCrisisV2.setCloseTime(nowTime); + } }); arkLevelRepo.saveAll(arkCrisisV2Page); diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java index 08f115cd..7a61731d 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java @@ -110,7 +110,13 @@ private void refresh(Collection copilotIdSTRs, Iterable copilot double hotScore = CopilotService.getHotScore(copilot, likeCount, dislikeCount); // 判断关卡是否开放 ArkLevelInfo arkLevelInfo = arkLevelService.findByLevelIdFuzzy(copilot.getStageName()); - if (arkLevelInfo != null && Boolean.FALSE.equals(arkLevelInfo.getIsOpen())) { + // 关卡已关闭,且作业在关闭前上传 + if (arkLevelInfo != null && + arkLevelInfo.getCloseTime() != null && + copilot.getFirstUploadTime() != null && + Boolean.FALSE.equals(arkLevelInfo.getIsOpen()) && + copilot.getFirstUploadTime().isBefore(arkLevelInfo.getCloseTime())) { + // 非开放关卡打入冷宫 hotScore /= 3; } From aba876173247203a50d11c476d8d8b9b73130290 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Tue, 12 Dec 2023 21:15:29 +0800 Subject: [PATCH 034/168] =?UTF-8?q?=E4=BF=AE=E6=94=B9=20findByLevelIdFuzzy?= =?UTF-8?q?=20=E7=9A=84=E8=BF=94=E5=9B=9E=E5=80=BC=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=EF=BC=8C=E8=AF=A5=E6=96=B9=E6=B3=95=E7=9A=84=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=80=BC=E4=BB=8E=E6=9C=AA=E7=94=A8=E4=BA=8E=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E7=BB=99=E5=89=8D=E7=AB=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/response/copilot/ArkLevelInfo.java | 11 ----------- .../plus/maa/backend/service/ArkLevelService.java | 9 ++++----- .../plus/maa/backend/service/CopilotService.java | 9 +++------ .../plus/maa/backend/task/CopilotBackupTask.java | 4 ++-- .../maa/backend/task/CopilotScoreRefreshTask.java | 12 ++++++------ src/main/resources/application.yml | 2 +- 6 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java index 10579bc3..7df5976d 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java +++ b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java @@ -1,15 +1,12 @@ package plus.maa.backend.controller.response.copilot; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonInclude; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.Accessors; -import org.jetbrains.annotations.Nullable; import java.io.Serializable; -import java.time.LocalDateTime; /** * @author john180 @@ -28,12 +25,4 @@ public class ArkLevelInfo implements Serializable { private String name; private int width; private int height; - // 只是服务器认为的当前版本地图是否开放 - @Nullable - @JsonIgnore - private Boolean isOpen; - // 非实际意义上的活动地图关闭时间,只是服务器认为的关闭时间 - @Nullable - @JsonIgnore - private LocalDateTime closeTime; } diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.java index 4749bb49..833c7c09 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.java +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.java @@ -79,7 +79,7 @@ public class ArkLevelService { private final List bypassFileNames = List.of("overview.json"); - @Cacheable("arkLevels") + @Cacheable("arkLevelInfos") public List getArkLevelInfos() { return arkLevelRepo.findAll() .stream() @@ -88,13 +88,12 @@ public List getArkLevelInfos() { } @Cacheable("arkLevel") - public ArkLevelInfo findByLevelIdFuzzy(String levelId) { - ArkLevel level = arkLevelRepo.findByLevelIdFuzzy(levelId).findAny().orElse(null); - return arkLevelConverter.convert(level); + public ArkLevel findByLevelIdFuzzy(String levelId) { + return arkLevelRepo.findByLevelIdFuzzy(levelId).findAny().orElse(null); } - public List queryLevelByKeyword(String keyword) { + public List queryLevelInfosByKeyword(String keyword) { List levels = arkLevelRepo.queryLevelByKeyword(keyword).collect(Collectors.toList()); return arkLevelConverter.convert(levels); } diff --git a/src/main/java/plus/maa/backend/service/CopilotService.java b/src/main/java/plus/maa/backend/service/CopilotService.java index ee088492..ba5d8839 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.java +++ b/src/main/java/plus/maa/backend/service/CopilotService.java @@ -29,10 +29,7 @@ import plus.maa.backend.controller.response.copilot.CopilotInfo; import plus.maa.backend.controller.response.copilot.CopilotPageInfo; import plus.maa.backend.repository.*; -import plus.maa.backend.repository.entity.CommentsArea; -import plus.maa.backend.repository.entity.Copilot; -import plus.maa.backend.repository.entity.MaaUser; -import plus.maa.backend.repository.entity.Rating; +import plus.maa.backend.repository.entity.*; import plus.maa.backend.service.model.RatingCache; import plus.maa.backend.service.model.RatingType; @@ -119,7 +116,7 @@ private CopilotDTO correctCopilot(CopilotDTO copilotDTO) { .setName(action.getName() == null ? null : action.getName().replaceAll("[\"“”]", ""))); } // 使用stageId存储作业关卡信息 - ArkLevelInfo level = levelService.findByLevelIdFuzzy(copilotDTO.getStageName()); + ArkLevel level = levelService.findByLevelIdFuzzy(copilotDTO.getStageName()); if (level != null) { copilotDTO.setStageName(level.getStageId()); } @@ -286,7 +283,7 @@ public CopilotPageInfo queriesCopilot(@Nullable String userId, CopilotQueriesReq //关卡名、关卡类型、关卡编号 if (StringUtils.isNotBlank(request.getLevelKeyword())) { - List levelInfo = levelService.queryLevelByKeyword(request.getLevelKeyword()); + List levelInfo = levelService.queryLevelInfosByKeyword(request.getLevelKeyword()); if (levelInfo.isEmpty()) { andQueries.add(Criteria.where("stageName").regex(caseInsensitive(request.getLevelKeyword()))); } else { diff --git a/src/main/java/plus/maa/backend/task/CopilotBackupTask.java b/src/main/java/plus/maa/backend/task/CopilotBackupTask.java index 19da3794..dd56f9c1 100644 --- a/src/main/java/plus/maa/backend/task/CopilotBackupTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotBackupTask.java @@ -15,8 +15,8 @@ import org.springframework.stereotype.Component; import plus.maa.backend.config.external.CopilotBackup; import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.controller.response.copilot.ArkLevelInfo; import plus.maa.backend.repository.CopilotRepository; +import plus.maa.backend.repository.entity.ArkLevel; import plus.maa.backend.repository.entity.Copilot; import plus.maa.backend.service.ArkLevelService; @@ -107,7 +107,7 @@ public void backupCopilots() { File baseDirectory = git.getRepository().getWorkTree(); List copilots = copilotRepository.findAll(); copilots.forEach(copilot -> { - ArkLevelInfo level = levelService.findByLevelIdFuzzy(copilot.getStageName()); + ArkLevel level = levelService.findByLevelIdFuzzy(copilot.getStageName()); if (Objects.isNull(level)) { return; } diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java index 7a61731d..bc9a4aa4 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java @@ -10,9 +10,9 @@ import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; -import plus.maa.backend.controller.response.copilot.ArkLevelInfo; import plus.maa.backend.repository.CopilotRepository; import plus.maa.backend.repository.RedisCache; +import plus.maa.backend.repository.entity.ArkLevel; import plus.maa.backend.repository.entity.Copilot; import plus.maa.backend.repository.entity.Rating; import plus.maa.backend.service.ArkLevelService; @@ -109,13 +109,13 @@ private void refresh(Collection copilotIdSTRs, Iterable copilot long dislikeCount = dislikeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 0L); double hotScore = CopilotService.getHotScore(copilot, likeCount, dislikeCount); // 判断关卡是否开放 - ArkLevelInfo arkLevelInfo = arkLevelService.findByLevelIdFuzzy(copilot.getStageName()); + ArkLevel level = arkLevelService.findByLevelIdFuzzy(copilot.getStageName()); // 关卡已关闭,且作业在关闭前上传 - if (arkLevelInfo != null && - arkLevelInfo.getCloseTime() != null && + if (level != null && + level.getCloseTime() != null && copilot.getFirstUploadTime() != null && - Boolean.FALSE.equals(arkLevelInfo.getIsOpen()) && - copilot.getFirstUploadTime().isBefore(arkLevelInfo.getCloseTime())) { + Boolean.FALSE.equals(level.getIsOpen()) && + copilot.getFirstUploadTime().isBefore(level.getCloseTime())) { // 非开放关卡打入冷宫 hotScore /= 3; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4ced4110..40a4be83 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -21,7 +21,7 @@ spring: check-template-location: false # 缓存配置,使用caffeine缓存框架,缓存时长为5分钟,最大缓存数量500 cache: - cache-names: arkLevel, arkLevels, copilotPage + cache-names: arkLevel, arkLevelInfos, copilotPage type: caffeine caffeine: spec: maximumSize=500,expireAfterWrite=300s From eeeef6f7ee8b8900b17f6fd515ba145665c99bf5 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Wed, 13 Dec 2023 12:59:34 +0800 Subject: [PATCH 035/168] =?UTF-8?q?/version=20=E6=8E=A5=E5=8F=A3=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=E5=80=BC=E8=BF=94=E5=9B=9E=E7=BC=96=E8=AF=91=E6=97=B6?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=9A=84=20commit=20=E7=9A=84=20abbreviatedI?= =?UTF-8?q?d=20=E4=BB=A5=E5=8F=8A=20dateTime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 24 ++++++++++++++++++- .../maa/backend/config/external/Commit.java | 11 +++++++++ .../maa/backend/config/external/Info.java | 4 ++++ .../backend/controller/SystemController.java | 1 + .../controller/response/MaaSystemInfo.java | 2 ++ src/main/resources/application.yml | 9 ++++++- 6 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 src/main/java/plus/maa/backend/config/external/Commit.java diff --git a/build.gradle b/build.gradle index 900e9f1d..77f330b0 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,5 @@ +import org.apache.tools.ant.filters.ReplaceTokens + plugins { id 'java' id 'org.springframework.boot' version '3.1.5' @@ -6,6 +8,7 @@ plugins { id 'org.springdoc.openapi-gradle-plugin' version '1.8.0' id 'org.hidetake.swagger.generator' version '2.19.2' // id 'org.graalvm.buildtools.native' version '0.9.28' + id 'org.ajoberstar.grgit' version '5.2.1' } group 'plus.maa' @@ -126,4 +129,23 @@ rootProject.afterEvaluate(){ forkedSpringBootRun.configure { doNotTrackState("See https://github.com/springdoc/springdoc-openapi-gradle-plugin/issues/102") } -} \ No newline at end of file +} + +// 配置资源文件拷贝任务 +processResources { + if (grgit == null) { + logger.error('项目中不存在 Git 仓库') + return + } + // 获取当前 commit + def commit = grgit.head() + // 替换配置文件中的占位符 + filesMatching(['**/*.properties', '**/*.yml', '**/*.yaml']) { file -> + { + file.filter(ReplaceTokens, tokens: [ + 'commitAbbreviatedId': commit.abbreviatedId, + 'commitDateTime': commit.dateTime.toString() + ]) + } + } +} diff --git a/src/main/java/plus/maa/backend/config/external/Commit.java b/src/main/java/plus/maa/backend/config/external/Commit.java new file mode 100644 index 00000000..7f0a24a0 --- /dev/null +++ b/src/main/java/plus/maa/backend/config/external/Commit.java @@ -0,0 +1,11 @@ +package plus.maa.backend.config.external; + +import lombok.Data; + +import java.time.ZonedDateTime; + +@Data +public class Commit { + private String abbreviatedId; + private ZonedDateTime dateTime; +} diff --git a/src/main/java/plus/maa/backend/config/external/Info.java b/src/main/java/plus/maa/backend/config/external/Info.java index eca8e46e..92b20132 100644 --- a/src/main/java/plus/maa/backend/config/external/Info.java +++ b/src/main/java/plus/maa/backend/config/external/Info.java @@ -1,5 +1,7 @@ package plus.maa.backend.config.external; +import org.springframework.boot.context.properties.NestedConfigurationProperty; + @lombok.Data public class Info { private String title; @@ -7,4 +9,6 @@ public class Info { private String version; private String domain; private String frontendDomain; + @NestedConfigurationProperty + private Commit commit; } \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/controller/SystemController.java b/src/main/java/plus/maa/backend/controller/SystemController.java index 65827d92..d4243dc8 100644 --- a/src/main/java/plus/maa/backend/controller/SystemController.java +++ b/src/main/java/plus/maa/backend/controller/SystemController.java @@ -38,6 +38,7 @@ public MaaResult getSystemVersion() { systemInfo.setTitle(info.getTitle()); systemInfo.setDescription(info.getDescription()); systemInfo.setVersion(info.getVersion()); + systemInfo.setCommit(info.getCommit()); return MaaResult.success(systemInfo); } diff --git a/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java b/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java index 8f152138..c3496ba8 100644 --- a/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java +++ b/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java @@ -1,6 +1,7 @@ package plus.maa.backend.controller.response; import lombok.Data; +import plus.maa.backend.config.external.Commit; /** * @author AnselYuki @@ -10,4 +11,5 @@ public class MaaSystemInfo { private String title; private String description; private String version; + private Commit commit; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4ced4110..466d3e7d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -40,4 +40,11 @@ logging: logback: rollingpolicy: max-history: 14 - clean-history-on-start: true \ No newline at end of file + clean-history-on-start: true + +maa-copilot: + info: + # 这几个参数应在编译时生成,不宜修改 + commit: + abbreviated-id: @commitAbbreviatedId@ + date-time: @commitDateTime@ \ No newline at end of file From 9a96506d158a52f935ee52793fef04f45d1f729c Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Wed, 13 Dec 2023 14:51:46 +0800 Subject: [PATCH 036/168] =?UTF-8?q?=E8=B0=83=E6=95=B4=20Git=20=E4=BB=93?= =?UTF-8?q?=E5=BA=93=E4=B8=8D=E5=AD=98=E5=9C=A8=E6=97=B6=E7=9A=84=E5=A4=84?= =?UTF-8?q?=E7=90=86=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/build.gradle b/build.gradle index 77f330b0..6907a252 100644 --- a/build.gradle +++ b/build.gradle @@ -133,18 +133,15 @@ rootProject.afterEvaluate(){ // 配置资源文件拷贝任务 processResources { - if (grgit == null) { - logger.error('项目中不存在 Git 仓库') - return - } // 获取当前 commit - def commit = grgit.head() + def commit = grgit?.head() // 替换配置文件中的占位符 filesMatching(['**/*.properties', '**/*.yml', '**/*.yaml']) { file -> { file.filter(ReplaceTokens, tokens: [ - 'commitAbbreviatedId': commit.abbreviatedId, - 'commitDateTime': commit.dateTime.toString() + // commit 不存在时,填充空字符串 + 'commitAbbreviatedId': commit?.abbreviatedId ?: '', + 'commitDateTime' : commit?.dateTime?.toString() ?: '' ]) } } From 9ea4bcb7b87ff8405c0e465a2d4c3213b0cce6ed Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Thu, 21 Dec 2023 20:00:34 +0800 Subject: [PATCH 037/168] =?UTF-8?q?=E4=BC=98=E5=8C=96=20RedisCache=20?= =?UTF-8?q?=E7=9A=84=E5=88=A0=E9=99=A4=E6=80=A7=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/repository/RedisCache.java | 64 +++++++++++++++++-- .../backend/task/CopilotScoreRefreshTask.java | 6 +- 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/main/java/plus/maa/backend/repository/RedisCache.java b/src/main/java/plus/maa/backend/repository/RedisCache.java index 3b21b6e2..88ea5afa 100644 --- a/src/main/java/plus/maa/backend/repository/RedisCache.java +++ b/src/main/java/plus/maa/backend/repository/RedisCache.java @@ -12,10 +12,13 @@ import org.jetbrains.annotations.Nullable; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.ClassPathResource; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.data.redis.RedisSystemException; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.script.RedisScript; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; import java.util.ArrayList; @@ -23,6 +26,7 @@ import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; import java.util.function.Supplier; @@ -50,6 +54,9 @@ public class RedisCache { .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .build(); + + private final AtomicBoolean supportUnlink = new AtomicBoolean(true); + /* 使用 lua 脚本插入数据,维持 ZSet 的相对大小(size <= 实际大小 <= size + 50)以及过期时间 实际大小这么设计是为了避免频繁的 ZREMRANGEBYRANK 操作 @@ -275,7 +282,38 @@ public void setCacheLevelCommit(String commit) { } public void removeCache(String key) { - redisTemplate.delete(key); + removeCache(key, false); + } + + public void removeCache(String key, boolean notUseUnlink) { + removeCache(List.of(key), notUseUnlink); + } + + public void removeCache(Collection keys) { + removeCache(keys, false); + } + + public void removeCache(Collection keys, boolean notUseUnlink) { + + if (!notUseUnlink && supportUnlink.get()) { + try { + redisTemplate.unlink(keys); + return; + } catch (InvalidDataAccessApiUsageException | RedisSystemException e) { + // Redisson、Jedis、Lettuce + Throwable cause = e.getCause(); + if (cause == null || !StringUtils.containsAny( + cause.getMessage(), "unknown command", "not support")) { + throw e; + } + if (supportUnlink.compareAndSet(true, false)) { + log.warn("当前连接的 Redis Service 可能不支持 Unlink 命令,切换为 Del"); + } + } + } + + // 兜底的 Del 命令 + redisTemplate.delete(keys); } /** @@ -294,14 +332,28 @@ public boolean removeKVIfEquals(String key, T value) { } /** - * 模糊删除缓存。 + * 模糊删除缓存。不保证立即删除,不保证完全删除。
+ * 异步,因为 Scan 虽然不会阻塞 Redis,但客户端会阻塞 * * @param pattern 待删除的 Key 表达式,例如 "home:*" 表示删除 Key 以 "home:" 开头的所有缓存 * @author Lixuhuilll */ + @Async public void removeCacheByPattern(String pattern) { + syncRemoveCacheByPattern(pattern); + } + + /** + * 模糊删除缓存。不保证立即删除,不保证完全删除。
+ * 同步调用 Scan,不会长时间阻塞 Redis,但会阻塞客户端,阻塞时间视 Redis 中 key 的数量而定。 + * 删除期间,其他线程或客户端可对 Redis 进行 CURD(因为不阻塞 Redis),因此不保证删除的时机,也不保证完全删除干净 + * + * @param pattern 待删除的 Key 表达式,例如 "home:*" 表示删除 Key 以 "home:" 开头的所有缓存 + * @author Lixuhuilll + */ + public void syncRemoveCacheByPattern(String pattern) { // 批量删除的阈值 - final int batchSize = 10000; + final int batchSize = 2000; // 构造 ScanOptions ScanOptions scanOptions = ScanOptions.scanOptions() .count(batchSize) @@ -309,7 +361,7 @@ public void removeCacheByPattern(String pattern) { .build(); // 保存要删除的键 - List keysToDelete = new ArrayList<>(); + List keysToDelete = new ArrayList<>(batchSize); // try-with-resources 自动关闭 SCAN try (Cursor cursor = redisTemplate.scan(scanOptions)) { @@ -320,7 +372,7 @@ public void removeCacheByPattern(String pattern) { // 如果达到批量删除的阈值,则执行批量删除 if (keysToDelete.size() >= batchSize) { - redisTemplate.delete(keysToDelete); + removeCache(keysToDelete); keysToDelete.clear(); } } @@ -328,7 +380,7 @@ public void removeCacheByPattern(String pattern) { // 删除剩余的键(不足 batchSize 的最后一批) if (!keysToDelete.isEmpty()) { - redisTemplate.delete(keysToDelete); + removeCache(keysToDelete); } } diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java index 08f115cd..d9ae38c9 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java @@ -68,7 +68,7 @@ public void refreshHotScores() { } // 移除首页热度缓存 - redisCache.removeCacheByPattern("home:hot:*"); + redisCache.syncRemoveCacheByPattern("home:hot:*"); } /** @@ -91,9 +91,9 @@ public void refreshTop100HotScores() { refresh(copilotIdSTRs, copilots); // 移除近期评分变化量缓存 - redisCache.removeCacheByPattern("rate:hot:copilotIds"); + redisCache.removeCache("rate:hot:copilotIds"); // 移除首页热度缓存 - redisCache.removeCacheByPattern("home:hot:*"); + redisCache.syncRemoveCacheByPattern("home:hot:*"); } private void refresh(Collection copilotIdSTRs, Iterable copilots) { From c50dcb60887d86fba7b246922d63a3b655d8635e Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Sat, 23 Dec 2023 13:40:55 +0800 Subject: [PATCH 038/168] =?UTF-8?q?fixup!=20/version=20=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=BF=94=E5=9B=9E=E5=80=BC=E8=BF=94=E5=9B=9E=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E6=97=B6=E5=AF=B9=E5=BA=94=E7=9A=84=20commit=20=E7=9A=84=20abb?= =?UTF-8?q?reviatedId=20=E4=BB=A5=E5=8F=8A=20dateTime?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 改进 commit 信息的生成,采用 spring boot 约定的注入方式 --- build.gradle | 20 ++--------- git.properties.gradle | 35 +++++++++++++++++++ .../maa/backend/config/external/Commit.java | 11 ------ .../maa/backend/config/external/Info.java | 4 --- .../backend/controller/SystemController.java | 5 ++- .../controller/response/MaaSystemInfo.java | 4 +-- src/main/resources/application.yml | 7 ---- 7 files changed, 43 insertions(+), 43 deletions(-) create mode 100644 git.properties.gradle delete mode 100644 src/main/java/plus/maa/backend/config/external/Commit.java diff --git a/build.gradle b/build.gradle index 6907a252..c7fa544c 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,3 @@ -import org.apache.tools.ant.filters.ReplaceTokens - plugins { id 'java' id 'org.springframework.boot' version '3.1.5' @@ -11,6 +9,8 @@ plugins { id 'org.ajoberstar.grgit' version '5.2.1' } +apply from: 'git.properties.gradle' + group 'plus.maa' version '1.0-SNAPSHOT' @@ -130,19 +130,3 @@ rootProject.afterEvaluate(){ doNotTrackState("See https://github.com/springdoc/springdoc-openapi-gradle-plugin/issues/102") } } - -// 配置资源文件拷贝任务 -processResources { - // 获取当前 commit - def commit = grgit?.head() - // 替换配置文件中的占位符 - filesMatching(['**/*.properties', '**/*.yml', '**/*.yaml']) { file -> - { - file.filter(ReplaceTokens, tokens: [ - // commit 不存在时,填充空字符串 - 'commitAbbreviatedId': commit?.abbreviatedId ?: '', - 'commitDateTime' : commit?.dateTime?.toString() ?: '' - ]) - } - } -} diff --git a/git.properties.gradle b/git.properties.gradle new file mode 100644 index 00000000..ffea972c --- /dev/null +++ b/git.properties.gradle @@ -0,0 +1,35 @@ +import java.time.ZonedDateTime +import java.time.format.DateTimeFormatter + +apply plugin: 'org.ajoberstar.grgit' + +tasks.named('processResources') { + dependsOn 'generateGitProperties' +} + +tasks.register('generateGitProperties') { + // 不检查是否最新,因为生成的文件中有 build.time,永远不可能最新 + doLast { + def properties = '' + + def commit = grgit?.head() + if (commit == null) { + logger.warn("当前项目不存在 Git 仓库或仓库中没有 Commit") + } else { + def formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ") + properties = """\ + git.branch=${grgit.branch.current().name} + git.build.time=${formatter.format(ZonedDateTime.now())} + git.commit.id=${commit.id} + git.commit.id.abbrev=${commit.abbreviatedId} + git.commit.time=${formatter.format(commit.dateTime)} + """.stripIndent() + } + + copy { + from resources.text.fromString(properties).asFile('UTF-8') + into processResources.destinationDir + rename { 'git.properties' } + } + } +} diff --git a/src/main/java/plus/maa/backend/config/external/Commit.java b/src/main/java/plus/maa/backend/config/external/Commit.java deleted file mode 100644 index 7f0a24a0..00000000 --- a/src/main/java/plus/maa/backend/config/external/Commit.java +++ /dev/null @@ -1,11 +0,0 @@ -package plus.maa.backend.config.external; - -import lombok.Data; - -import java.time.ZonedDateTime; - -@Data -public class Commit { - private String abbreviatedId; - private ZonedDateTime dateTime; -} diff --git a/src/main/java/plus/maa/backend/config/external/Info.java b/src/main/java/plus/maa/backend/config/external/Info.java index 92b20132..eca8e46e 100644 --- a/src/main/java/plus/maa/backend/config/external/Info.java +++ b/src/main/java/plus/maa/backend/config/external/Info.java @@ -1,7 +1,5 @@ package plus.maa.backend.config.external; -import org.springframework.boot.context.properties.NestedConfigurationProperty; - @lombok.Data public class Info { private String title; @@ -9,6 +7,4 @@ public class Info { private String version; private String domain; private String frontendDomain; - @NestedConfigurationProperty - private Commit commit; } \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/controller/SystemController.java b/src/main/java/plus/maa/backend/controller/SystemController.java index d4243dc8..29c86010 100644 --- a/src/main/java/plus/maa/backend/controller/SystemController.java +++ b/src/main/java/plus/maa/backend/controller/SystemController.java @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.boot.info.GitProperties; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -20,7 +21,9 @@ @RestController @RequiredArgsConstructor public class SystemController { + private final MaaCopilotProperties properties; + private final GitProperties gitProperties; @GetMapping("/") @Operation(summary = "Tests if the server is ready.") @@ -38,7 +41,7 @@ public MaaResult getSystemVersion() { systemInfo.setTitle(info.getTitle()); systemInfo.setDescription(info.getDescription()); systemInfo.setVersion(info.getVersion()); - systemInfo.setCommit(info.getCommit()); + systemInfo.setGit(gitProperties); return MaaResult.success(systemInfo); } diff --git a/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java b/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java index c3496ba8..51558746 100644 --- a/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java +++ b/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java @@ -1,7 +1,7 @@ package plus.maa.backend.controller.response; import lombok.Data; -import plus.maa.backend.config.external.Commit; +import org.springframework.boot.info.GitProperties; /** * @author AnselYuki @@ -11,5 +11,5 @@ public class MaaSystemInfo { private String title; private String description; private String version; - private Commit commit; + private GitProperties git; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 466d3e7d..db6bfe52 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -41,10 +41,3 @@ logging: rollingpolicy: max-history: 14 clean-history-on-start: true - -maa-copilot: - info: - # 这几个参数应在编译时生成,不宜修改 - commit: - abbreviated-id: @commitAbbreviatedId@ - date-time: @commitDateTime@ \ No newline at end of file From 93b5529923d11d903fed595ff3f506522f197123 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Mon, 25 Dec 2023 11:18:56 +0800 Subject: [PATCH 039/168] =?UTF-8?q?=E6=94=B9=E4=B8=BA=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E7=8E=B0=E6=88=90=E7=9A=84=E6=8F=92=E4=BB=B6=E7=94=9F=E6=88=90?= =?UTF-8?q?=20git.properties?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 9 +++-- git.properties.gradle | 35 ------------------- .../backend/controller/SystemController.java | 2 ++ 3 files changed, 8 insertions(+), 38 deletions(-) delete mode 100644 git.properties.gradle diff --git a/build.gradle b/build.gradle index c7fa544c..cea70017 100644 --- a/build.gradle +++ b/build.gradle @@ -6,11 +6,9 @@ plugins { id 'org.springdoc.openapi-gradle-plugin' version '1.8.0' id 'org.hidetake.swagger.generator' version '2.19.2' // id 'org.graalvm.buildtools.native' version '0.9.28' - id 'org.ajoberstar.grgit' version '5.2.1' + id 'com.gorylenko.gradle-git-properties' version '2.4.1' } -apply from: 'git.properties.gradle' - group 'plus.maa' version '1.0-SNAPSHOT' @@ -130,3 +128,8 @@ rootProject.afterEvaluate(){ doNotTrackState("See https://github.com/springdoc/springdoc-openapi-gradle-plugin/issues/102") } } + +gitProperties { + failOnNoGitDirectory = false + keys = ["git.branch", "git.commit.id", "git.commit.id.abbrev", "git.commit.time"] +} diff --git a/git.properties.gradle b/git.properties.gradle deleted file mode 100644 index ffea972c..00000000 --- a/git.properties.gradle +++ /dev/null @@ -1,35 +0,0 @@ -import java.time.ZonedDateTime -import java.time.format.DateTimeFormatter - -apply plugin: 'org.ajoberstar.grgit' - -tasks.named('processResources') { - dependsOn 'generateGitProperties' -} - -tasks.register('generateGitProperties') { - // 不检查是否最新,因为生成的文件中有 build.time,永远不可能最新 - doLast { - def properties = '' - - def commit = grgit?.head() - if (commit == null) { - logger.warn("当前项目不存在 Git 仓库或仓库中没有 Commit") - } else { - def formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ") - properties = """\ - git.branch=${grgit.branch.current().name} - git.build.time=${formatter.format(ZonedDateTime.now())} - git.commit.id=${commit.id} - git.commit.id.abbrev=${commit.abbreviatedId} - git.commit.time=${formatter.format(commit.dateTime)} - """.stripIndent() - } - - copy { - from resources.text.fromString(properties).asFile('UTF-8') - into processResources.destinationDir - rename { 'git.properties' } - } - } -} diff --git a/src/main/java/plus/maa/backend/controller/SystemController.java b/src/main/java/plus/maa/backend/controller/SystemController.java index 29c86010..b906d8cb 100644 --- a/src/main/java/plus/maa/backend/controller/SystemController.java +++ b/src/main/java/plus/maa/backend/controller/SystemController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.boot.info.GitProperties; +import org.springframework.lang.Nullable; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -23,6 +24,7 @@ public class SystemController { private final MaaCopilotProperties properties; + @Nullable // 非必须字段,当 Git 仓库不存在时为 null private final GitProperties gitProperties; @GetMapping("/") From df021f201bba66fe9de9b3c09276e5d1cfb4791c Mon Sep 17 00:00:00 2001 From: dragove Date: Tue, 26 Dec 2023 00:44:53 +0800 Subject: [PATCH 040/168] =?UTF-8?q?feat:=20=E8=BF=81=E7=A7=BB=E8=87=AA?= =?UTF-8?q?=E5=A2=9E=20id=20=E7=94=9F=E6=88=90=E7=BB=84=E5=BB=BA=E4=B8=BA?= =?UTF-8?q?=E5=8D=95=E7=8B=AC=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/common/utils/IdComponent.java | 52 +++++++++++++++++++ .../utils/converter/CopilotConverter.java | 3 +- .../backend/repository/entity/Copilot.java | 12 ++++- .../backend/repository/entity/CopilotSet.java | 47 +++++++++++++++++ .../repository/entity/SeqGenerated.java | 18 +++++++ .../maa/backend/service/CopilotService.java | 18 ++----- 6 files changed, 134 insertions(+), 16 deletions(-) create mode 100644 src/main/java/plus/maa/backend/common/utils/IdComponent.java create mode 100644 src/main/java/plus/maa/backend/repository/entity/CopilotSet.java create mode 100644 src/main/java/plus/maa/backend/repository/entity/SeqGenerated.java diff --git a/src/main/java/plus/maa/backend/common/utils/IdComponent.java b/src/main/java/plus/maa/backend/common/utils/IdComponent.java new file mode 100644 index 00000000..a3dc8f41 --- /dev/null +++ b/src/main/java/plus/maa/backend/common/utils/IdComponent.java @@ -0,0 +1,52 @@ +package plus.maa.backend.common.utils; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Sort; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; +import plus.maa.backend.repository.entity.SeqGenerated; + +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicLong; + +@Slf4j +@Component +@RequiredArgsConstructor +public class IdComponent { + private final MongoTemplate mongoTemplate; + private final Map CURRENT_ID_MAP = new ConcurrentHashMap<>(); + + /** + * 获取id数据 + * @param seq 可以生成自增id的数据类型 + * @return 新的id + */ + public Long getId(SeqGenerated seq) { + Class cls = seq.getClass(); + String collectionName = mongoTemplate.getCollectionName(cls); + AtomicLong v = CURRENT_ID_MAP.get(collectionName); + if (v == null) { + synchronized (cls) { + v = CURRENT_ID_MAP.get(collectionName); + if (v == null) { + v = new AtomicLong(getMax(cls, seq.getIdFieldName())); + log.info("初始化获取 collection: {} 的最大 id,id: {}", collectionName, v.get()); + CURRENT_ID_MAP.put(collectionName, v); + } + } + } + return v.incrementAndGet(); + } + + private Long getMax(Class entityClass, String fieldName) { + return Optional.ofNullable(mongoTemplate.findOne( + new Query().with(Sort.by(fieldName).descending()).limit(1), + entityClass)) + .map(SeqGenerated::getGeneratedId) + .orElse(20000L); + } +} diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java index c5bcb239..828d09b1 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java +++ b/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java @@ -52,7 +52,8 @@ public interface CopilotConverter { @Mapping(target = "uploadTime", source = "now") @Mapping(target = "firstUploadTime", source = "now") @Mapping(target = "uploaderId", source = "userId") - Copilot toCopilot(CopilotDTO copilotDto, String userId, LocalDateTime now, Long copilotId, String content); + @Mapping(target = "copilotId", ignore = true) + Copilot toCopilot(CopilotDTO copilotDto, String userId, LocalDateTime now, String content); @Mapping(target = "ratingType", ignore = true) @Mapping(target = "ratingRatio", ignore = true) diff --git a/src/main/java/plus/maa/backend/repository/entity/Copilot.java b/src/main/java/plus/maa/backend/repository/entity/Copilot.java index ce2705ca..56ee9044 100644 --- a/src/main/java/plus/maa/backend/repository/entity/Copilot.java +++ b/src/main/java/plus/maa/backend/repository/entity/Copilot.java @@ -25,7 +25,7 @@ @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) @Accessors(chain = true) @Document("maa_copilot") -public class Copilot implements Serializable { +public class Copilot implements Serializable, SeqGenerated { @Id // 作业id private String id; @@ -85,6 +85,16 @@ public class Copilot implements Serializable { @JsonIgnore private Boolean notification; + @Override + public Long getGeneratedId() { + return copilotId; + } + + @Override + public String getIdFieldName() { + return "copilotId"; + } + @Data @NoArgsConstructor @AllArgsConstructor diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java new file mode 100644 index 00000000..4626edb9 --- /dev/null +++ b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java @@ -0,0 +1,47 @@ +package plus.maa.backend.repository.entity; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import lombok.Data; +import lombok.experimental.Accessors; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +import java.io.Serializable; +import java.util.List; + +/** + * 作业集数据 + */ +@Data +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +@Accessors(chain = true) +@Document("maa_copilot_set") +public class CopilotSet implements Serializable, SeqGenerated { + /** + * 作业集id + */ + @Id + private Long id; + + /** + * 作业id列表 + * 使用 list 保证有序 + * 作业添加时应当保证唯一 + */ + private List copilotIds; + + /** + * 上传者id + */ + private String uploaderId; + + @Override + public Long getGeneratedId() { + return id; + } + + public String getIdFieldName() { + return "id"; + } +} diff --git a/src/main/java/plus/maa/backend/repository/entity/SeqGenerated.java b/src/main/java/plus/maa/backend/repository/entity/SeqGenerated.java new file mode 100644 index 00000000..54ede8eb --- /dev/null +++ b/src/main/java/plus/maa/backend/repository/entity/SeqGenerated.java @@ -0,0 +1,18 @@ +package plus.maa.backend.repository.entity; + +import org.springframework.data.annotation.Transient; + +/** + * 可用于生成id的数据类型 + */ +public interface SeqGenerated { + /** + * 用于生成该类型id的sequenceName + * 方法名这么长是为了防止重名 + */ + @Transient + Long getGeneratedId(); + + @Transient + String getIdFieldName(); +} diff --git a/src/main/java/plus/maa/backend/service/CopilotService.java b/src/main/java/plus/maa/backend/service/CopilotService.java index ba5d8839..96861da7 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.java +++ b/src/main/java/plus/maa/backend/service/CopilotService.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Sets; -import jakarta.annotation.PostConstruct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -18,6 +17,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; +import plus.maa.backend.common.utils.IdComponent; import plus.maa.backend.common.utils.converter.CopilotConverter; import plus.maa.backend.config.external.MaaCopilotProperties; import plus.maa.backend.controller.request.copilot.CopilotCUDRequest; @@ -58,12 +58,12 @@ public class CopilotService { private final ObjectMapper mapper; private final ArkLevelService levelService; private final RedisCache redisCache; + private final IdComponent idComponent; private final UserRepository userRepository; private final CommentsAreaRepository commentsAreaRepository; private final MaaCopilotProperties properties; private final CopilotConverter copilotConverter; - private final AtomicLong copilotIncrementId = new AtomicLong(20000); /* 首页分页查询缓存配置 @@ -76,17 +76,6 @@ public class CopilotService { "id", 300L ); - @PostConstruct - public void init() { - // 初始化copilotId, 从数据库中获取最大的copilotId - // 如果数据库中没有数据, 则从20000开始 - copilotRepository.findFirstByOrderByCopilotIdDesc() - .map(Copilot::getCopilotId) - .ifPresent(last -> copilotIncrementId.set(last + 1)); - - log.info("作业自增ID初始化完成: {}", copilotIncrementId.get()); - } - /** * 并修正前端的冗余部分 * @@ -156,8 +145,9 @@ public Long upload(String loginUserId, String content) { // 将其转换为数据库存储对象 Copilot copilot = copilotConverter.toCopilot( copilotDTO, loginUserId, - LocalDateTime.now(), copilotIncrementId.getAndIncrement(), + LocalDateTime.now(), content); + copilot.setCopilotId(idComponent.getId(copilot)); copilotRepository.insert(copilot); return copilot.getCopilotId(); } From 55f72fcb26b0b2776e5aa867650971ffbc3985df Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 27 Dec 2023 23:07:07 +0800 Subject: [PATCH 041/168] =?UTF-8?q?refactor:=20=E9=87=8D=E6=96=B0=E6=8A=BD?= =?UTF-8?q?=E8=B1=A1=E8=87=AA=E5=A2=9Eid=E5=8A=9F=E8=83=BD=EF=BC=8C?= =?UTF-8?q?=E5=BB=BA=E7=AB=8B=E9=9B=86=E5=90=88=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=EF=BC=8C=E4=BD=BF=E7=94=A8=E5=85=83=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=87=AA=E5=8A=A8=E8=8E=B7=E5=8F=96=E6=9C=80=E5=A4=A7?= =?UTF-8?q?id=E5=B9=B6=E7=94=A8=E4=BA=8E=E7=94=9F=E6=88=90=E4=B9=8B?= =?UTF-8?q?=E5=90=8E=E9=9C=80=E8=A6=81=E4=BD=BF=E7=94=A8=E7=9A=84id?= =?UTF-8?q?=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/common/utils/IdComponent.java | 15 ++++++++------- .../utils/converter/CopilotConverter.java | 3 +-- .../repository/entity/CollectionMeta.java | 13 +++++++++++++ .../maa/backend/repository/entity/Copilot.java | 18 +++++++----------- .../backend/repository/entity/CopilotSet.java | 14 +++++--------- .../repository/entity/SeqGenerated.java | 18 ------------------ .../maa/backend/service/CopilotService.java | 7 ++----- 7 files changed, 36 insertions(+), 52 deletions(-) create mode 100644 src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java delete mode 100644 src/main/java/plus/maa/backend/repository/entity/SeqGenerated.java diff --git a/src/main/java/plus/maa/backend/common/utils/IdComponent.java b/src/main/java/plus/maa/backend/common/utils/IdComponent.java index a3dc8f41..ada31663 100644 --- a/src/main/java/plus/maa/backend/common/utils/IdComponent.java +++ b/src/main/java/plus/maa/backend/common/utils/IdComponent.java @@ -6,12 +6,13 @@ import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.SeqGenerated; +import plus.maa.backend.repository.entity.CollectionMeta; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; @Slf4j @Component @@ -22,18 +23,18 @@ public class IdComponent { /** * 获取id数据 - * @param seq 可以生成自增id的数据类型 + * @param meta 集合元数据 * @return 新的id */ - public Long getId(SeqGenerated seq) { - Class cls = seq.getClass(); + public Long getId(CollectionMeta meta) { + Class cls = meta.entityClass(); String collectionName = mongoTemplate.getCollectionName(cls); AtomicLong v = CURRENT_ID_MAP.get(collectionName); if (v == null) { synchronized (cls) { v = CURRENT_ID_MAP.get(collectionName); if (v == null) { - v = new AtomicLong(getMax(cls, seq.getIdFieldName())); + v = new AtomicLong(getMax(cls, meta.idGetter(), meta.incIdField())); log.info("初始化获取 collection: {} 的最大 id,id: {}", collectionName, v.get()); CURRENT_ID_MAP.put(collectionName, v); } @@ -42,11 +43,11 @@ public Long getId(SeqGenerated seq) { return v.incrementAndGet(); } - private Long getMax(Class entityClass, String fieldName) { + private Long getMax(Class entityClass, Function idGetter, String fieldName) { return Optional.ofNullable(mongoTemplate.findOne( new Query().with(Sort.by(fieldName).descending()).limit(1), entityClass)) - .map(SeqGenerated::getGeneratedId) + .map(idGetter) .orElse(20000L); } } diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java index 828d09b1..8dd9f9f9 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java +++ b/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java @@ -52,8 +52,7 @@ public interface CopilotConverter { @Mapping(target = "uploadTime", source = "now") @Mapping(target = "firstUploadTime", source = "now") @Mapping(target = "uploaderId", source = "userId") - @Mapping(target = "copilotId", ignore = true) - Copilot toCopilot(CopilotDTO copilotDto, String userId, LocalDateTime now, String content); + Copilot toCopilot(CopilotDTO copilotDto, Long copilotId, String userId, LocalDateTime now, String content); @Mapping(target = "ratingType", ignore = true) @Mapping(target = "ratingRatio", ignore = true) diff --git a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java new file mode 100644 index 00000000..bf281519 --- /dev/null +++ b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java @@ -0,0 +1,13 @@ +package plus.maa.backend.repository.entity; + +import java.util.function.Function; + +/** + * mongodb 集合元数据 + * + * @param 集合对应实体数据类型 + * @author dragove + * created on 2023-12-27 + */ +public record CollectionMeta(Function idGetter, String incIdField, Class entityClass) { +} diff --git a/src/main/java/plus/maa/backend/repository/entity/Copilot.java b/src/main/java/plus/maa/backend/repository/entity/Copilot.java index 56ee9044..aae48764 100644 --- a/src/main/java/plus/maa/backend/repository/entity/Copilot.java +++ b/src/main/java/plus/maa/backend/repository/entity/Copilot.java @@ -8,6 +8,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; @@ -25,7 +26,12 @@ @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) @Accessors(chain = true) @Document("maa_copilot") -public class Copilot implements Serializable, SeqGenerated { +public class Copilot implements Serializable { + + @Transient + public static final CollectionMeta META = new CollectionMeta<>(Copilot::getCopilotId, + "copilotId", Copilot.class); + @Id // 作业id private String id; @@ -85,16 +91,6 @@ public class Copilot implements Serializable, SeqGenerated { @JsonIgnore private Boolean notification; - @Override - public Long getGeneratedId() { - return copilotId; - } - - @Override - public String getIdFieldName() { - return "copilotId"; - } - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java index 4626edb9..95fcabec 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java +++ b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java @@ -17,7 +17,11 @@ @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) @Accessors(chain = true) @Document("maa_copilot_set") -public class CopilotSet implements Serializable, SeqGenerated { +public class CopilotSet implements Serializable { + + public static final CollectionMeta META = new CollectionMeta<>(CopilotSet::getId, + "id", CopilotSet.class); + /** * 作业集id */ @@ -36,12 +40,4 @@ public class CopilotSet implements Serializable, SeqGenerated { */ private String uploaderId; - @Override - public Long getGeneratedId() { - return id; - } - - public String getIdFieldName() { - return "id"; - } } diff --git a/src/main/java/plus/maa/backend/repository/entity/SeqGenerated.java b/src/main/java/plus/maa/backend/repository/entity/SeqGenerated.java deleted file mode 100644 index 54ede8eb..00000000 --- a/src/main/java/plus/maa/backend/repository/entity/SeqGenerated.java +++ /dev/null @@ -1,18 +0,0 @@ -package plus.maa.backend.repository.entity; - -import org.springframework.data.annotation.Transient; - -/** - * 可用于生成id的数据类型 - */ -public interface SeqGenerated { - /** - * 用于生成该类型id的sequenceName - * 方法名这么长是为了防止重名 - */ - @Transient - Long getGeneratedId(); - - @Transient - String getIdFieldName(); -} diff --git a/src/main/java/plus/maa/backend/service/CopilotService.java b/src/main/java/plus/maa/backend/service/CopilotService.java index 96861da7..073bdaea 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.java +++ b/src/main/java/plus/maa/backend/service/CopilotService.java @@ -143,11 +143,8 @@ private Pattern caseInsensitive(String s) { public Long upload(String loginUserId, String content) { CopilotDTO copilotDTO = correctCopilot(parseToCopilotDto(content)); // 将其转换为数据库存储对象 - Copilot copilot = copilotConverter.toCopilot( - copilotDTO, loginUserId, - LocalDateTime.now(), - content); - copilot.setCopilotId(idComponent.getId(copilot)); + Copilot copilot = copilotConverter.toCopilot(copilotDTO, + idComponent.getId(Copilot.META), loginUserId, LocalDateTime.now(), content); copilotRepository.insert(copilot); return copilot.getCopilotId(); } From 62161e26e29b5d111e9ee58262d0cf967608589c Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 1 Jan 2024 17:14:56 +0800 Subject: [PATCH 042/168] =?UTF-8?q?feat:=20=E4=BD=9C=E4=B8=9A=E9=9B=86?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=90=8D=E7=A7=B0=E3=80=81=E6=8F=8F=E8=BF=B0?= =?UTF-8?q?=E3=80=81=E7=8A=B6=E6=80=81=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/repository/entity/CopilotSet.java | 18 ++++++++++++ .../service/model/CopilotSetStatus.java | 29 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java index 95fcabec..69ba1c0d 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java +++ b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java @@ -5,6 +5,7 @@ import lombok.Data; import lombok.experimental.Accessors; import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.mapping.Document; import java.io.Serializable; @@ -19,6 +20,7 @@ @Document("maa_copilot_set") public class CopilotSet implements Serializable { + @Transient public static final CollectionMeta META = new CollectionMeta<>(CopilotSet::getId, "id", CopilotSet.class); @@ -28,6 +30,16 @@ public class CopilotSet implements Serializable { @Id private Long id; + /** + * 作业集名称 + */ + private String name; + + /** + * 额外描述 + */ + private String description; + /** * 作业id列表 * 使用 list 保证有序 @@ -40,4 +52,10 @@ public class CopilotSet implements Serializable { */ private String uploaderId; + /** + * 作业状态 + * {@link plus.maa.backend.service.model.CopilotSetStatus} + */ + private Integer status; + } diff --git a/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java b/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java new file mode 100644 index 00000000..d8e1c382 --- /dev/null +++ b/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java @@ -0,0 +1,29 @@ +package plus.maa.backend.service.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * @author dragove + * create on 2024-01-01 + */ +@Getter +@AllArgsConstructor +public enum CopilotSetStatus { + + PUBLIC(1), + PRIVATE(2), + ; + + private final int code; + + /** + * 枚举数量较少,暂时这么写 + * @param code 数据库中的数值 + * @return 枚举对象 + */ + public static CopilotSetStatus get(int code) { + return code == 1 ? PUBLIC : PRIVATE; + } + +} From 330fb127239752570b6d393053d18a3e51c93dcb Mon Sep 17 00:00:00 2001 From: dragove Date: Tue, 2 Jan 2024 00:02:53 +0800 Subject: [PATCH 043/168] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E5=88=9B?= =?UTF-8?q?=E5=BB=BA=E4=BD=9C=E4=B8=9A=E9=9B=86=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 +- .../backend/common/model/CopilotSetType.java | 29 +++++++++++++ .../maa/backend/common/utils/IdComponent.java | 2 +- .../utils/converter/CopilotSetConverter.java | 24 +++++++++++ .../controller/CopilotSetController.java | 41 +++++++++++++++++++ .../copilotset/CopilotSetCreateReq.java | 39 ++++++++++++++++++ .../repository/CopilotSetRepository.java | 13 ++++++ .../repository/entity/CollectionMeta.java | 5 ++- .../backend/repository/entity/CopilotSet.java | 18 ++++++-- .../backend/service/CopilotSetService.java | 32 +++++++++++++++ .../service/model/CopilotSetStatus.java | 18 +++----- 11 files changed, 206 insertions(+), 19 deletions(-) create mode 100644 src/main/java/plus/maa/backend/common/model/CopilotSetType.java create mode 100644 src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java create mode 100644 src/main/java/plus/maa/backend/controller/CopilotSetController.java create mode 100644 src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.java create mode 100644 src/main/java/plus/maa/backend/repository/CopilotSetRepository.java create mode 100644 src/main/java/plus/maa/backend/service/CopilotSetService.java diff --git a/build.gradle b/build.gradle index cea70017..c855d007 100644 --- a/build.gradle +++ b/build.gradle @@ -42,8 +42,8 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-cache' //springdoc相关依赖没有被自动管理,必须保留版本号 - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' - implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' +// implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'com.sun.mail:javax.mail:1.6.2' diff --git a/src/main/java/plus/maa/backend/common/model/CopilotSetType.java b/src/main/java/plus/maa/backend/common/model/CopilotSetType.java new file mode 100644 index 00000000..70300cb6 --- /dev/null +++ b/src/main/java/plus/maa/backend/common/model/CopilotSetType.java @@ -0,0 +1,29 @@ +package plus.maa.backend.common.model; + +import org.springframework.util.Assert; + +import java.util.Collections; +import java.util.List; + +/** + * @author dragove + * create on 2024-01-01 + */ +public interface CopilotSetType { + + List getCopilotIds(); + + default List getDistinctIdsAndCheck() { + List copilotIds = getCopilotIds(); + if (copilotIds == null) { + return Collections.emptyList(); + } + if (copilotIds.isEmpty() || copilotIds.size() == 1) { + return getCopilotIds(); + } + copilotIds = copilotIds.stream().distinct().toList(); + Assert.state(copilotIds.size() <= 1000, "作业集总作业数量不能超过1000条"); + return copilotIds; + } + +} diff --git a/src/main/java/plus/maa/backend/common/utils/IdComponent.java b/src/main/java/plus/maa/backend/common/utils/IdComponent.java index ada31663..62a6ccec 100644 --- a/src/main/java/plus/maa/backend/common/utils/IdComponent.java +++ b/src/main/java/plus/maa/backend/common/utils/IdComponent.java @@ -26,7 +26,7 @@ public class IdComponent { * @param meta 集合元数据 * @return 新的id */ - public Long getId(CollectionMeta meta) { + public long getId(CollectionMeta meta) { Class cls = meta.entityClass(); String collectionName = mongoTemplate.getCollectionName(cls); AtomicLong v = CURRENT_ID_MAP.get(collectionName); diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java new file mode 100644 index 00000000..8bb0c0ad --- /dev/null +++ b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java @@ -0,0 +1,24 @@ +package plus.maa.backend.common.utils.converter; + +import org.mapstruct.Mapper; +import org.mapstruct.Mapping; +import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; +import plus.maa.backend.repository.entity.CopilotSet; + +import java.time.LocalDateTime; + +/** + * @author dragove + * create on 2024-01-01 + */ +@Mapper(componentModel = "spring", imports = { + LocalDateTime.class +}) +public interface CopilotSetConverter { + + @Mapping(target = "copilotIds", expression = "java(createReq.getDistinctIdsAndCheck())") + @Mapping(target = "createTime", expression = "java(LocalDateTime.now())") + @Mapping(target = "updateTime", expression = "java(LocalDateTime.now())") + CopilotSet convert(CopilotSetCreateReq createReq, long id, String creatorId); + +} diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java new file mode 100644 index 00000000..97ab2db7 --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -0,0 +1,41 @@ +package plus.maa.backend.controller; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import plus.maa.backend.config.SpringDocConfig; +import plus.maa.backend.config.security.AuthenticationHelper; +import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; +import plus.maa.backend.controller.response.MaaResult; +import plus.maa.backend.service.CopilotSetService; + +/** + * @author dragove + * create on 2024-01-01 + */ +@Tag(name = "CopilotSet", description = "作业集相关接口") +@RequestMapping("/set") +@RestController +@RequiredArgsConstructor +public class CopilotSetController { + + private final CopilotSetService service; + private final AuthenticationHelper helper; + + @Operation(summary = "创建作业集") + @ApiResponse(description = "作业集id") + @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @PostMapping("/create") + public MaaResult createSet( + @Parameter(description = "作业集新增请求") @RequestBody CopilotSetCreateReq req) { + return MaaResult.success(service.create(req, helper.getUserId())); + } + +} diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.java b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.java new file mode 100644 index 00000000..696d1dc1 --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.java @@ -0,0 +1,39 @@ +package plus.maa.backend.controller.request.copilotset; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.Setter; +import plus.maa.backend.common.model.CopilotSetType; +import plus.maa.backend.service.model.CopilotSetStatus; + +import java.util.List; + +/** + * @author dragove + * create on 2024-01-01 + */ +@Getter +@Setter +@Schema(title = "作业集创建请求") +public class CopilotSetCreateReq implements CopilotSetType { + + @Schema(title = "作业集名称") + @NotBlank(message = "作业集名称不能为空") + private String name; + + @Schema(title = "作业集额外描述") + private String description; + + @NotNull(message = "作业id列表字段不能为null") + @Size(max = 1000, message = "作业集作业列表最大只能为1000") + @Schema(title = "初始关联作业列表") + private List copilotIds; + + @NotNull(message = "作业集公开状态不能为null") + @Schema(title = "作业集公开状态", enumAsRef = true) + private CopilotSetStatus status; + +} diff --git a/src/main/java/plus/maa/backend/repository/CopilotSetRepository.java b/src/main/java/plus/maa/backend/repository/CopilotSetRepository.java new file mode 100644 index 00000000..100e68ca --- /dev/null +++ b/src/main/java/plus/maa/backend/repository/CopilotSetRepository.java @@ -0,0 +1,13 @@ +package plus.maa.backend.repository; + +import org.springframework.data.mongodb.repository.MongoRepository; +import plus.maa.backend.repository.entity.CopilotSet; + +/** + * @author dragove + * create on 2024-01-01 + */ +public interface CopilotSetRepository extends MongoRepository { + + +} diff --git a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java index bf281519..68736d6a 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java +++ b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java @@ -1,5 +1,6 @@ package plus.maa.backend.repository.entity; +import java.io.Serializable; import java.util.function.Function; /** @@ -9,5 +10,7 @@ * @author dragove * created on 2023-12-27 */ -public record CollectionMeta(Function idGetter, String incIdField, Class entityClass) { +public record CollectionMeta(Function idGetter, String incIdField, Class entityClass) + implements Serializable { + } diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java index 69ba1c0d..f7edf61e 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java +++ b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java @@ -7,8 +7,10 @@ import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.mapping.Document; +import plus.maa.backend.service.model.CopilotSetStatus; import java.io.Serializable; +import java.time.LocalDateTime; import java.util.List; /** @@ -28,7 +30,7 @@ public class CopilotSet implements Serializable { * 作业集id */ @Id - private Long id; + private long id; /** * 作业集名称 @@ -50,12 +52,22 @@ public class CopilotSet implements Serializable { /** * 上传者id */ - private String uploaderId; + private String creatorId; + + /** + * 创建时间 + */ + private LocalDateTime createTime; + + /** + * 更新时间 + */ + private LocalDateTime updateTime; /** * 作业状态 * {@link plus.maa.backend.service.model.CopilotSetStatus} */ - private Integer status; + private CopilotSetStatus status; } diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.java b/src/main/java/plus/maa/backend/service/CopilotSetService.java new file mode 100644 index 00000000..be986c54 --- /dev/null +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.java @@ -0,0 +1,32 @@ +package plus.maa.backend.service; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import plus.maa.backend.common.utils.IdComponent; +import plus.maa.backend.common.utils.converter.CopilotSetConverter; +import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; +import plus.maa.backend.repository.CopilotSetRepository; +import plus.maa.backend.repository.entity.CopilotSet; + +/** + * @author dragove + * create on 2024-01-01 + */ +@Slf4j +@Service +@RequiredArgsConstructor +public class CopilotSetService { + + private final IdComponent idComponent; + private final CopilotSetConverter converter; + private final CopilotSetRepository repository; + + public Long create(CopilotSetCreateReq req, String userId) { + long id = idComponent.getId(CopilotSet.META); + CopilotSet newCopilotSet = + converter.convert(req, id, userId); + repository.insert(newCopilotSet); + return id; + } +} diff --git a/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java b/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java index d8e1c382..cc1c7fd0 100644 --- a/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java +++ b/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java @@ -11,19 +11,13 @@ @AllArgsConstructor public enum CopilotSetStatus { - PUBLIC(1), - PRIVATE(2), - ; - - private final int code; - /** - * 枚举数量较少,暂时这么写 - * @param code 数据库中的数值 - * @return 枚举对象 + * 私有,仅查看自己的作业集的时候展示,其他列表页面不展示,但是通过详情接口可查询(无权限控制) + */ + PRIVATE, + /** + * 公开,可以被搜索 */ - public static CopilotSetStatus get(int code) { - return code == 1 ? PUBLIC : PRIVATE; - } + PUBLIC, } From 784cab99fc1f0e0aff72c6a4b3670ca5eb7dee4c Mon Sep 17 00:00:00 2001 From: dragove Date: Tue, 2 Jan 2024 20:29:02 +0800 Subject: [PATCH 044/168] =?UTF-8?q?feat:=20=E5=90=91=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?=E9=9B=86=E4=B8=AD=E6=B7=BB=E5=8A=A0=E4=BD=9C=E4=B8=9Aid?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- .../controller/CopilotSetController.java | 10 +++++++ .../copilotset/CopilotSetAddCopilotsReq.java | 28 +++++++++++++++++++ .../backend/repository/entity/CopilotSet.java | 3 +- .../backend/service/CopilotSetService.java | 19 ++++++++++++- 5 files changed, 59 insertions(+), 3 deletions(-) create mode 100644 src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetAddCopilotsReq.java diff --git a/build.gradle b/build.gradle index c855d007..6afb7328 100644 --- a/build.gradle +++ b/build.gradle @@ -43,7 +43,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-cache' //springdoc相关依赖没有被自动管理,必须保留版本号 implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' -// implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0' + implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0' implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'com.sun.mail:javax.mail:1.6.2' diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index 97ab2db7..5fcd84b6 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.RestController; import plus.maa.backend.config.SpringDocConfig; import plus.maa.backend.config.security.AuthenticationHelper; +import plus.maa.backend.controller.request.copilotset.CopilotSetAddCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; import plus.maa.backend.controller.response.MaaResult; import plus.maa.backend.service.CopilotSetService; @@ -38,4 +39,13 @@ public MaaResult createSet( return MaaResult.success(service.create(req, helper.getUserId())); } + @Operation(summary = "添加作业集作业列表") + @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @PostMapping("/add") + public MaaResult addCopilotIds( + @Parameter(description = "作业集中加入新作业请求") @RequestBody CopilotSetAddCopilotsReq req) { + service.addCopilotIds(req, helper.getUserId()); + return MaaResult.success(); + } + } diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetAddCopilotsReq.java b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetAddCopilotsReq.java new file mode 100644 index 00000000..2686e6a3 --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetAddCopilotsReq.java @@ -0,0 +1,28 @@ +package plus.maa.backend.controller.request.copilotset; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +import java.util.List; + +/** + * @author dragove + * create on 2024-01-02 + */ +@Getter +@Setter +@Schema(title = "作业集新增作业列表请求") +public class CopilotSetAddCopilotsReq { + + @NotNull(message = "作业集id必填") + @Schema(title = "作业集id") + private long id; + + @NotEmpty(message = "添加作业id列表不可为空") + @Schema(title = "新添加到收藏的作业id列表") + private List copilotIds; + +} diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java index f7edf61e..6ebe75b5 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java +++ b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java @@ -7,6 +7,7 @@ import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.mapping.Document; +import plus.maa.backend.common.model.CopilotSetType; import plus.maa.backend.service.model.CopilotSetStatus; import java.io.Serializable; @@ -20,7 +21,7 @@ @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) @Accessors(chain = true) @Document("maa_copilot_set") -public class CopilotSet implements Serializable { +public class CopilotSet implements Serializable, CopilotSetType { @Transient public static final CollectionMeta META = new CollectionMeta<>(CopilotSet::getId, diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.java b/src/main/java/plus/maa/backend/service/CopilotSetService.java index be986c54..5b0a57cd 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.java +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.java @@ -1,10 +1,12 @@ package plus.maa.backend.service; +import cn.hutool.core.lang.Assert; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import plus.maa.backend.common.utils.IdComponent; import plus.maa.backend.common.utils.converter.CopilotSetConverter; +import plus.maa.backend.controller.request.copilotset.CopilotSetAddCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; import plus.maa.backend.repository.CopilotSetRepository; import plus.maa.backend.repository.entity.CopilotSet; @@ -22,11 +24,26 @@ public class CopilotSetService { private final CopilotSetConverter converter; private final CopilotSetRepository repository; - public Long create(CopilotSetCreateReq req, String userId) { + /** + * 创建作业集 + * @param req 作业集创建请求 + * @param userId 创建者用户id + * @return 作业集id + */ + public long create(CopilotSetCreateReq req, String userId) { long id = idComponent.getId(CopilotSet.META); CopilotSet newCopilotSet = converter.convert(req, id, userId); repository.insert(newCopilotSet); return id; } + + public void addCopilotIds(CopilotSetAddCopilotsReq req, String userId) { + CopilotSet copilotSet = repository.findById(req.getId()) + .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); + Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权修改该作业集"); + copilotSet.getCopilotIds().addAll(req.getCopilotIds()); + copilotSet.setCopilotIds(copilotSet.getDistinctIdsAndCheck()); + repository.save(copilotSet); + } } From a3c3f1c6c6d7f3ddd1891cb45ab96611f9386b63 Mon Sep 17 00:00:00 2001 From: dragove Date: Tue, 2 Jan 2024 20:37:02 +0800 Subject: [PATCH 045/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E6=9C=AA=E7=94=9F=E6=95=88=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/controller/CopilotSetController.java | 5 +++-- .../plus/maa/backend/handler/GlobalExceptionHandler.java | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index 5fcd84b6..e989e0a2 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -35,7 +36,7 @@ public class CopilotSetController { @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) @PostMapping("/create") public MaaResult createSet( - @Parameter(description = "作业集新增请求") @RequestBody CopilotSetCreateReq req) { + @Parameter(description = "作业集新增请求") @Valid @RequestBody CopilotSetCreateReq req) { return MaaResult.success(service.create(req, helper.getUserId())); } @@ -43,7 +44,7 @@ public MaaResult createSet( @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) @PostMapping("/add") public MaaResult addCopilotIds( - @Parameter(description = "作业集中加入新作业请求") @RequestBody CopilotSetAddCopilotsReq req) { + @Parameter(description = "作业集中加入新作业请求") @Valid @RequestBody CopilotSetAddCopilotsReq req) { service.addCopilotIds(req, helper.getUserId()); return MaaResult.success(); } diff --git a/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.java b/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.java index 6f72e382..b4ea56bd 100644 --- a/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.java +++ b/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.java @@ -64,9 +64,9 @@ public MaaResult methodArgumentTypeMismatchException(MethodArgumentTypeM public MaaResult methodArgumentNotValidException(MethodArgumentNotValidException e) { FieldError fieldError = e.getBindingResult().getFieldError(); if (fieldError != null) { - return MaaResult.fail(400, String.format("参数校验错误:%s", fieldError.getDefaultMessage())); + return MaaResult.fail(400, String.format("参数校验错误: %s", fieldError.getDefaultMessage())); } - return MaaResult.fail(400, String.format("参数校验错误:%s", e.getMessage())); + return MaaResult.fail(400, String.format("参数校验错误: %s", e.getMessage())); } /** From 4fda5101319b098b2e3609d2370b6b49f86d49da Mon Sep 17 00:00:00 2001 From: dragove Date: Tue, 2 Jan 2024 20:47:14 +0800 Subject: [PATCH 046/168] =?UTF-8?q?feat:=20=E5=BE=80=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?=E9=9B=86=E4=B8=AD=E5=88=A0=E9=99=A4=E4=BD=9C=E4=B8=9A=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CopilotSetController.java | 13 +++++++++-- ...Req.java => CopilotSetModCopilotsReq.java} | 6 ++--- .../backend/service/CopilotSetService.java | 23 +++++++++++++++++-- 3 files changed, 35 insertions(+), 7 deletions(-) rename src/main/java/plus/maa/backend/controller/request/copilotset/{CopilotSetAddCopilotsReq.java => CopilotSetModCopilotsReq.java} (76%) diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index e989e0a2..121292b6 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import plus.maa.backend.config.SpringDocConfig; import plus.maa.backend.config.security.AuthenticationHelper; -import plus.maa.backend.controller.request.copilotset.CopilotSetAddCopilotsReq; +import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; import plus.maa.backend.controller.response.MaaResult; import plus.maa.backend.service.CopilotSetService; @@ -44,9 +44,18 @@ public MaaResult createSet( @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) @PostMapping("/add") public MaaResult addCopilotIds( - @Parameter(description = "作业集中加入新作业请求") @Valid @RequestBody CopilotSetAddCopilotsReq req) { + @Parameter(description = "作业集中加入新作业请求") @Valid @RequestBody CopilotSetModCopilotsReq req) { service.addCopilotIds(req, helper.getUserId()); return MaaResult.success(); } + @Operation(summary = "添加作业集作业列表") + @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @PostMapping("/remove") + public MaaResult removeCopilotIds( + @Parameter(description = "作业集中删除作业请求") @Valid @RequestBody CopilotSetModCopilotsReq req) { + service.removeCopilotIds(req, helper.getUserId()); + return MaaResult.success(); + } + } diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetAddCopilotsReq.java b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.java similarity index 76% rename from src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetAddCopilotsReq.java rename to src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.java index 2686e6a3..ce550f9c 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetAddCopilotsReq.java +++ b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.java @@ -15,14 +15,14 @@ @Getter @Setter @Schema(title = "作业集新增作业列表请求") -public class CopilotSetAddCopilotsReq { +public class CopilotSetModCopilotsReq { @NotNull(message = "作业集id必填") @Schema(title = "作业集id") private long id; - @NotEmpty(message = "添加作业id列表不可为空") - @Schema(title = "新添加到收藏的作业id列表") + @NotEmpty(message = "添加/删除作业id列表不可为空") + @Schema(title = "添加/删除收藏的作业id列表") private List copilotIds; } diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.java b/src/main/java/plus/maa/backend/service/CopilotSetService.java index 5b0a57cd..71018630 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.java +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.java @@ -6,11 +6,14 @@ import org.springframework.stereotype.Service; import plus.maa.backend.common.utils.IdComponent; import plus.maa.backend.common.utils.converter.CopilotSetConverter; -import plus.maa.backend.controller.request.copilotset.CopilotSetAddCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; +import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.repository.CopilotSetRepository; import plus.maa.backend.repository.entity.CopilotSet; +import java.util.HashSet; +import java.util.Set; + /** * @author dragove * create on 2024-01-01 @@ -38,7 +41,10 @@ public long create(CopilotSetCreateReq req, String userId) { return id; } - public void addCopilotIds(CopilotSetAddCopilotsReq req, String userId) { + /** + * 往作业集中加入作业id列表 + */ + public void addCopilotIds(CopilotSetModCopilotsReq req, String userId) { CopilotSet copilotSet = repository.findById(req.getId()) .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权修改该作业集"); @@ -46,4 +52,17 @@ public void addCopilotIds(CopilotSetAddCopilotsReq req, String userId) { copilotSet.setCopilotIds(copilotSet.getDistinctIdsAndCheck()); repository.save(copilotSet); } + + /** + * 往作业集中删除作业id列表 + */ + public void removeCopilotIds(CopilotSetModCopilotsReq req, String userId) { + CopilotSet copilotSet = repository.findById(req.getId()) + .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); + Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权修改该作业集"); + Set removeIds = new HashSet<>(req.getCopilotIds()); + copilotSet.getCopilotIds().removeIf(removeIds::contains); + repository.save(copilotSet); + } + } From 999c4b674ae78069df2da9ce709f7bd676734226 Mon Sep 17 00:00:00 2001 From: dragove Date: Tue, 2 Jan 2024 21:17:28 +0800 Subject: [PATCH 047/168] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E4=BD=9C=E4=B8=9A=E9=9B=86=E4=BF=A1=E6=81=AF=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CopilotSetController.java | 10 ++++++ .../request/CopilotSetUpdateReq.java | 31 +++++++++++++++++++ .../backend/service/CopilotSetService.java | 13 ++++++++ 3 files changed, 54 insertions(+) create mode 100644 src/main/java/plus/maa/backend/controller/request/CopilotSetUpdateReq.java diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index 121292b6..2cbda723 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import plus.maa.backend.config.SpringDocConfig; import plus.maa.backend.config.security.AuthenticationHelper; +import plus.maa.backend.controller.request.CopilotSetUpdateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; import plus.maa.backend.controller.response.MaaResult; @@ -58,4 +59,13 @@ public MaaResult removeCopilotIds( return MaaResult.success(); } + @Operation(summary = "更新作业集信息") + @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @PostMapping("/update") + public MaaResult updateCopilotSet( + @Parameter(description = "更新作业集信息请求") @Valid @RequestBody CopilotSetUpdateReq req) { + service.update(req, helper.getUserId()); + return MaaResult.success(); + } + } diff --git a/src/main/java/plus/maa/backend/controller/request/CopilotSetUpdateReq.java b/src/main/java/plus/maa/backend/controller/request/CopilotSetUpdateReq.java new file mode 100644 index 00000000..a503403e --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/request/CopilotSetUpdateReq.java @@ -0,0 +1,31 @@ +package plus.maa.backend.controller.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; +import plus.maa.backend.service.model.CopilotSetStatus; + +/** + * @author dragove + * create on 2024-01-02 + */ +@Getter +@Setter +@Schema(title = "作业集更新请求") +public class CopilotSetUpdateReq { + @NotNull(message = "作业集id不能为空") + private long id; + + @Schema(title = "作业集名称") + @NotBlank(message = "作业集名称不能为空") + private String name; + + @Schema(title = "作业集额外描述") + private String description; + + @NotNull(message = "作业集公开状态不能为null") + @Schema(title = "作业集公开状态", enumAsRef = true) + private CopilotSetStatus status; +} diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.java b/src/main/java/plus/maa/backend/service/CopilotSetService.java index 71018630..044de575 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.java +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.java @@ -6,6 +6,7 @@ import org.springframework.stereotype.Service; import plus.maa.backend.common.utils.IdComponent; import plus.maa.backend.common.utils.converter.CopilotSetConverter; +import plus.maa.backend.controller.request.CopilotSetUpdateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.repository.CopilotSetRepository; @@ -65,4 +66,16 @@ public void removeCopilotIds(CopilotSetModCopilotsReq req, String userId) { repository.save(copilotSet); } + /** + * 更新作业集信息 + */ + public void update(CopilotSetUpdateReq req, String userId) { + CopilotSet copilotSet = repository.findById(req.getId()) + .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); + Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权修改该作业集"); + copilotSet.setName(req.getName()); + copilotSet.setDescription(req.getDescription()); + copilotSet.setStatus(req.getStatus()); + repository.save(copilotSet); + } } From 74170cd19c08549a5ab14172a79f84e6778e6e45 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Wed, 3 Jan 2024 17:27:28 +0800 Subject: [PATCH 048/168] =?UTF-8?q?=E8=AF=84=E8=AE=BA=E5=93=8D=E5=BA=94?= =?UTF-8?q?=E7=82=B9=E8=B8=A9=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/converter/CommentConverter.java | 10 +++++---- .../response/comments/CommentsInfo.java | 3 ++- .../response/comments/SubCommentsInfo.java | 3 ++- .../repository/entity/CommentsArea.java | 2 ++ .../backend/service/CommentsAreaService.java | 22 ++++++++++++++----- 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java index ba412411..553d99aa 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java +++ b/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java @@ -15,16 +15,18 @@ @Mapper(componentModel = "spring") public interface CommentConverter { - @Mapping(target = "like", source = "likeCount") + @Mapping(target = "like", source = "commentsArea.likeCount") + @Mapping(target = "dislike", source = "commentsArea.dislikeCount") @Mapping(target = "uploader", source = "maaUser.userName") @Mapping(target = "commentId", source = "id") @Mapping(target = "subCommentsInfos", ignore = true) - CommentsInfo toCommentsInfo(CommentsArea commentsArea, String id, int likeCount, MaaUser maaUser); + CommentsInfo toCommentsInfo(CommentsArea commentsArea, String id, MaaUser maaUser); - @Mapping(target = "like", source = "likeCount") + @Mapping(target = "like", source = "commentsArea.likeCount") + @Mapping(target = "dislike", source = "commentsArea.dislikeCount") @Mapping(target = "uploader", source = "maaUser.userName") @Mapping(target = "commentId", source = "id") @Mapping(target = "deleted", source = "delete") - SubCommentsInfo toSubCommentsInfo(CommentsArea commentsArea, String id, int likeCount, MaaUser maaUser, boolean delete); + SubCommentsInfo toSubCommentsInfo(CommentsArea commentsArea, String id, MaaUser maaUser, boolean delete); } diff --git a/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.java b/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.java index f0a8e9be..e41a3193 100644 --- a/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.java +++ b/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.java @@ -26,7 +26,8 @@ public class CommentsInfo { //评论内容 private String message; private LocalDateTime uploadTime; - private int like; + private long like; + private long dislike; private boolean topping; private List subCommentsInfos = new ArrayList<>(); } diff --git a/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.java b/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.java index 5265ce76..ebe24c51 100644 --- a/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.java +++ b/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.java @@ -24,7 +24,8 @@ public class SubCommentsInfo { //评论内容 private String message; private LocalDateTime uploadTime; - private int like; + private long like; + private long dislike; private String fromCommentId; private String mainCommentId; private boolean deleted; diff --git a/src/main/java/plus/maa/backend/repository/entity/CommentsArea.java b/src/main/java/plus/maa/backend/repository/entity/CommentsArea.java index f16b3c0d..6d1a37c1 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CommentsArea.java +++ b/src/main/java/plus/maa/backend/repository/entity/CommentsArea.java @@ -35,6 +35,8 @@ public class CommentsArea implements Serializable { private long likeCount; + private long dislikeCount; + private LocalDateTime uploadTime = LocalDateTime.now(); // 是否将该评论置顶 diff --git a/src/main/java/plus/maa/backend/service/CommentsAreaService.java b/src/main/java/plus/maa/backend/service/CommentsAreaService.java index d5bc14c2..52bda58e 100644 --- a/src/main/java/plus/maa/backend/service/CommentsAreaService.java +++ b/src/main/java/plus/maa/backend/service/CommentsAreaService.java @@ -193,7 +193,9 @@ public void rates(String userId, CommentsRatingDTO commentsRatingDTO) { CommentsArea commentsArea = findCommentsById(commentsRatingDTO.getCommentId()); - long change; + long likeCountChange; + long dislikeCountChange; + Optional ratingOptional = ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COMMENT, commentsArea.getId(), userId); // 判断该用户是否存在评分 if (ratingOptional.isPresent()) { @@ -204,8 +206,10 @@ public void rates(String userId, CommentsRatingDTO commentsRatingDTO) { ratingOptional.get().setRateTime(LocalDateTime.now()); RatingType newRatingType = ratingRepository.save(ratingOptional.get()).getRating(); // 更新评分后更新评论的点赞数 - change = newRatingType == RatingType.LIKE ? 1 : + likeCountChange = newRatingType == RatingType.LIKE ? 1 : (oldRatingType != RatingType.LIKE ? 0 : -1); + dislikeCountChange = newRatingType == RatingType.DISLIKE ? 1 : + (oldRatingType != RatingType.DISLIKE ? 0 : -1); } else { // 如果评分未发生变化则结束 return; @@ -220,15 +224,23 @@ public void rates(String userId, CommentsRatingDTO commentsRatingDTO) { .setRateTime(LocalDateTime.now()); ratingRepository.insert(newRating); - change = newRating.getRating() == RatingType.LIKE ? 1 : 0; + likeCountChange = newRating.getRating() == RatingType.LIKE ? 1 : 0; + dislikeCountChange = newRating.getRating() == RatingType.DISLIKE ? 1 : 0; } // 点赞数不需要在高并发下特别精准,大概就行,但是也得避免特别离谱的数字 - long likeCount = commentsArea.getLikeCount() + change; + long likeCount = commentsArea.getLikeCount() + likeCountChange; if (likeCount < 0) { likeCount = 0; } + + long dislikeCount = commentsArea.getDislikeCount() + dislikeCountChange; + if (dislikeCount < 0) { + dislikeCount = 0; + } + commentsArea.setLikeCount(likeCount); + commentsArea.setDislikeCount(dislikeCount); commentsAreaRepository.save(commentsArea); } @@ -329,7 +341,6 @@ public CommentsAreaInfo queriesCommentsArea(CommentsQueriesDTO request) { .toCommentsInfo( mainComment , mainComment.getId() - , (int) mainComment.getLikeCount() , maaUserMap.getOrDefault( mainComment.getUploaderId() , UNKNOWN_USER @@ -344,7 +355,6 @@ public CommentsAreaInfo queriesCommentsArea(CommentsQueriesDTO request) { .toSubCommentsInfo( subComment , subComment.getId() - , (int) subComment.getLikeCount() //填充评论用户名 , maaUserMap.getOrDefault( subComment.getUploaderId(), From 0504e3ecb415b4f9283c90f3a77922bdacd01719 Mon Sep 17 00:00:00 2001 From: lixuhuilll <676824363@qq.com> Date: Wed, 3 Jan 2024 17:39:36 +0800 Subject: [PATCH 049/168] =?UTF-8?q?=E5=87=8F=E5=B0=91=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E5=99=A8=E4=B8=AD=E4=B8=8D=E5=BF=85=E8=A6=81=E7=9A=84=E5=8F=82?= =?UTF-8?q?=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/utils/converter/CommentConverter.java | 10 +++++----- .../plus/maa/backend/service/CommentsAreaService.java | 3 --- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java index 553d99aa..0f88940b 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java +++ b/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java @@ -18,15 +18,15 @@ public interface CommentConverter { @Mapping(target = "like", source = "commentsArea.likeCount") @Mapping(target = "dislike", source = "commentsArea.dislikeCount") @Mapping(target = "uploader", source = "maaUser.userName") - @Mapping(target = "commentId", source = "id") + @Mapping(target = "commentId", source = "commentsArea.id") @Mapping(target = "subCommentsInfos", ignore = true) - CommentsInfo toCommentsInfo(CommentsArea commentsArea, String id, MaaUser maaUser); + CommentsInfo toCommentsInfo(CommentsArea commentsArea, MaaUser maaUser); @Mapping(target = "like", source = "commentsArea.likeCount") @Mapping(target = "dislike", source = "commentsArea.dislikeCount") @Mapping(target = "uploader", source = "maaUser.userName") - @Mapping(target = "commentId", source = "id") - @Mapping(target = "deleted", source = "delete") - SubCommentsInfo toSubCommentsInfo(CommentsArea commentsArea, String id, MaaUser maaUser, boolean delete); + @Mapping(target = "commentId", source = "commentsArea.id") + @Mapping(target = "deleted", source = "commentsArea.delete") + SubCommentsInfo toSubCommentsInfo(CommentsArea commentsArea, MaaUser maaUser); } diff --git a/src/main/java/plus/maa/backend/service/CommentsAreaService.java b/src/main/java/plus/maa/backend/service/CommentsAreaService.java index 52bda58e..16ac8d5d 100644 --- a/src/main/java/plus/maa/backend/service/CommentsAreaService.java +++ b/src/main/java/plus/maa/backend/service/CommentsAreaService.java @@ -340,7 +340,6 @@ public CommentsAreaInfo queriesCommentsArea(CommentsQueriesDTO request) { commentConverter .toCommentsInfo( mainComment - , mainComment.getId() , maaUserMap.getOrDefault( mainComment.getUploaderId() , UNKNOWN_USER @@ -354,13 +353,11 @@ public CommentsAreaInfo queriesCommentsArea(CommentsQueriesDTO request) { commentConverter .toSubCommentsInfo( subComment - , subComment.getId() //填充评论用户名 , maaUserMap.getOrDefault( subComment.getUploaderId(), UNKNOWN_USER ) - , subComment.isDelete() ) ).toList(); From e434f979e2fe03d31f25190fb6633ddcc523f0f3 Mon Sep 17 00:00:00 2001 From: dragove Date: Fri, 5 Jan 2024 21:48:21 +0800 Subject: [PATCH 050/168] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E9=9B=86=E5=88=A0=E9=99=A4=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CopilotSetController.java | 11 +++++++++++ .../controller/request/CommonIdInput.java | 18 ++++++++++++++++++ .../backend/repository/entity/CopilotSet.java | 7 +++++++ .../maa/backend/service/CopilotSetService.java | 16 ++++++++++++++++ 4 files changed, 52 insertions(+) create mode 100644 src/main/java/plus/maa/backend/controller/request/CommonIdInput.java diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index 2cbda723..66f6f3b5 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import plus.maa.backend.config.SpringDocConfig; import plus.maa.backend.config.security.AuthenticationHelper; +import plus.maa.backend.controller.request.CommonIdInput; import plus.maa.backend.controller.request.CopilotSetUpdateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; @@ -68,4 +69,14 @@ public MaaResult updateCopilotSet( return MaaResult.success(); } + @Operation(summary = "删除作业集") + @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @PostMapping("/delete") + public MaaResult deleteCopilotSet( + @Parameter(description = "删除作业集信息请求") @Valid @RequestBody CommonIdInput req) { + service.delete(req.getId(), helper.getUserId()); + return MaaResult.success(); + } + + } diff --git a/src/main/java/plus/maa/backend/controller/request/CommonIdInput.java b/src/main/java/plus/maa/backend/controller/request/CommonIdInput.java new file mode 100644 index 00000000..535608d3 --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/request/CommonIdInput.java @@ -0,0 +1,18 @@ +package plus.maa.backend.controller.request; + +import jakarta.validation.constraints.NotNull; +import lombok.Getter; +import lombok.Setter; + +/** + * @author dragove + * create on 2024-01-05 + */ +@Getter +@Setter +public class CommonIdInput { + + @NotNull(message = "id必填") + private T id; + +} diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java index 6ebe75b5..c43db05d 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java +++ b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java @@ -1,5 +1,6 @@ package plus.maa.backend.repository.entity; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.databind.PropertyNamingStrategies; import com.fasterxml.jackson.databind.annotation.JsonNaming; import lombok.Data; @@ -71,4 +72,10 @@ public class CopilotSet implements Serializable, CopilotSetType { */ private CopilotSetStatus status; + @JsonIgnore + private boolean delete; + + @JsonIgnore + private LocalDateTime deleteTime; + } diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.java b/src/main/java/plus/maa/backend/service/CopilotSetService.java index 044de575..c2b9fc28 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.java +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.java @@ -12,6 +12,7 @@ import plus.maa.backend.repository.CopilotSetRepository; import plus.maa.backend.repository.entity.CopilotSet; +import java.time.LocalDateTime; import java.util.HashSet; import java.util.Set; @@ -78,4 +79,19 @@ public void update(CopilotSetUpdateReq req, String userId) { copilotSet.setStatus(req.getStatus()); repository.save(copilotSet); } + + /** + * 删除作业集信息(逻辑删除,保留详情接口查询结果) + * @param id 作业集id + * @param userId 登陆用户id + */ + public void delete(long id, String userId) { + log.info("delete copilot set for id: {}, userId: {}", id, userId); + CopilotSet copilotSet = repository.findById(id) + .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); + Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权删除该作业集"); + copilotSet.setDelete(true); + copilotSet.setDeleteTime(LocalDateTime.now()); + repository.save(copilotSet); + } } From b825a02fab0935f8af1be4860292313c1c7ce087 Mon Sep 17 00:00:00 2001 From: dragove Date: Fri, 5 Jan 2024 22:02:23 +0800 Subject: [PATCH 051/168] chore: CommonIdInput -> CommonIdReq --- .../plus/maa/backend/controller/CopilotSetController.java | 4 ++-- .../request/{CommonIdInput.java => CommonIdReq.java} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename src/main/java/plus/maa/backend/controller/request/{CommonIdInput.java => CommonIdReq.java} (89%) diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index 66f6f3b5..dbb11e42 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import plus.maa.backend.config.SpringDocConfig; import plus.maa.backend.config.security.AuthenticationHelper; -import plus.maa.backend.controller.request.CommonIdInput; +import plus.maa.backend.controller.request.CommonIdReq; import plus.maa.backend.controller.request.CopilotSetUpdateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; @@ -73,7 +73,7 @@ public MaaResult updateCopilotSet( @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) @PostMapping("/delete") public MaaResult deleteCopilotSet( - @Parameter(description = "删除作业集信息请求") @Valid @RequestBody CommonIdInput req) { + @Parameter(description = "删除作业集信息请求") @Valid @RequestBody CommonIdReq req) { service.delete(req.getId(), helper.getUserId()); return MaaResult.success(); } diff --git a/src/main/java/plus/maa/backend/controller/request/CommonIdInput.java b/src/main/java/plus/maa/backend/controller/request/CommonIdReq.java similarity index 89% rename from src/main/java/plus/maa/backend/controller/request/CommonIdInput.java rename to src/main/java/plus/maa/backend/controller/request/CommonIdReq.java index 535608d3..c8a6abd5 100644 --- a/src/main/java/plus/maa/backend/controller/request/CommonIdInput.java +++ b/src/main/java/plus/maa/backend/controller/request/CommonIdReq.java @@ -10,7 +10,7 @@ */ @Getter @Setter -public class CommonIdInput { +public class CommonIdReq { @NotNull(message = "id必填") private T id; From ed4582aa2eeb936e699e5f1372b8475ef7a88a34 Mon Sep 17 00:00:00 2001 From: dragove Date: Sat, 6 Jan 2024 20:17:00 +0800 Subject: [PATCH 052/168] =?UTF-8?q?feat:=20=E4=BD=9C=E4=B8=9A=E9=9B=86?= =?UTF-8?q?=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/converter/CopilotSetConverter.java | 6 +++ .../config/security/SecurityConfig.java | 1 + .../controller/CopilotSetController.java | 10 ++++ .../controller/request/CopilotSetQuery.java | 31 ++++++++++++ .../response/CopilotSetPageRes.java | 30 ++++++++++++ .../controller/response/CopilotSetRes.java | 48 +++++++++++++++++++ .../response/user/CopilotSetListRes.java | 39 +++++++++++++++ .../repository/CopilotSetRepository.java | 12 +++++ .../backend/repository/entity/MaaUser.java | 3 ++ .../backend/service/CommentsAreaService.java | 10 ++-- .../backend/service/CopilotSetService.java | 46 ++++++++++++++++-- 11 files changed, 226 insertions(+), 10 deletions(-) create mode 100644 src/main/java/plus/maa/backend/controller/request/CopilotSetQuery.java create mode 100644 src/main/java/plus/maa/backend/controller/response/CopilotSetPageRes.java create mode 100644 src/main/java/plus/maa/backend/controller/response/CopilotSetRes.java create mode 100644 src/main/java/plus/maa/backend/controller/response/user/CopilotSetListRes.java diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java index 8bb0c0ad..81d03374 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java +++ b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java @@ -3,6 +3,7 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; +import plus.maa.backend.controller.response.user.CopilotSetListRes; import plus.maa.backend.repository.entity.CopilotSet; import java.time.LocalDateTime; @@ -16,9 +17,14 @@ }) public interface CopilotSetConverter { + @Mapping(target = "delete", ignore = true) + @Mapping(target = "deleteTime", ignore = true) @Mapping(target = "copilotIds", expression = "java(createReq.getDistinctIdsAndCheck())") @Mapping(target = "createTime", expression = "java(LocalDateTime.now())") @Mapping(target = "updateTime", expression = "java(LocalDateTime.now())") CopilotSet convert(CopilotSetCreateReq createReq, long id, String creatorId); + @Mapping(target = "creator", ignore = true) + CopilotSetListRes convert(CopilotSet copilotSet, String creator); + } diff --git a/src/main/java/plus/maa/backend/config/security/SecurityConfig.java b/src/main/java/plus/maa/backend/config/security/SecurityConfig.java index 0922176b..4850a402 100644 --- a/src/main/java/plus/maa/backend/config/security/SecurityConfig.java +++ b/src/main/java/plus/maa/backend/config/security/SecurityConfig.java @@ -42,6 +42,7 @@ public class SecurityConfig { "/swagger-ui/**", "/arknights/level", "/copilot/query", + "/set/query", "/copilot/get/**", "/copilot/rating", "/comments/query", diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index dbb11e42..bb3235d0 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -14,9 +14,11 @@ import plus.maa.backend.config.SpringDocConfig; import plus.maa.backend.config.security.AuthenticationHelper; import plus.maa.backend.controller.request.CommonIdReq; +import plus.maa.backend.controller.request.CopilotSetQuery; import plus.maa.backend.controller.request.CopilotSetUpdateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; +import plus.maa.backend.controller.response.CopilotSetPageRes; import plus.maa.backend.controller.response.MaaResult; import plus.maa.backend.service.CopilotSetService; @@ -33,6 +35,14 @@ public class CopilotSetController { private final CopilotSetService service; private final AuthenticationHelper helper; + @Operation(summary = "查询作业集列表") + @ApiResponse(description = "作业集id") + @PostMapping("/query") + public MaaResult querySets( + @Parameter(description = "作业集列表查询请求") @Valid @RequestBody CopilotSetQuery req) { + return MaaResult.success(service.query(req)); + } + @Operation(summary = "创建作业集") @ApiResponse(description = "作业集id") @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) diff --git a/src/main/java/plus/maa/backend/controller/request/CopilotSetQuery.java b/src/main/java/plus/maa/backend/controller/request/CopilotSetQuery.java new file mode 100644 index 00000000..bd13920e --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/request/CopilotSetQuery.java @@ -0,0 +1,31 @@ +package plus.maa.backend.controller.request; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; +import lombok.Getter; +import lombok.Setter; + +/** + * @author dragove + * create on 2024-01-06 + */ +@Getter +@Setter +@Schema(title = "作业集列表查询接口参数") +public class CopilotSetQuery { + + @Positive(message = "页码必须为大于0的数字") + @Schema(title = "页码") + private int page = 1; + + @Schema(title = "单页数据量") + @PositiveOrZero(message = "单页数据量必须为大于等于0的数字") + @Max(value = 50, message = "单页大小不得超过50") + private int limit = 10; + + @Schema(title = "查询关键词") + private String keyword; + +} diff --git a/src/main/java/plus/maa/backend/controller/response/CopilotSetPageRes.java b/src/main/java/plus/maa/backend/controller/response/CopilotSetPageRes.java new file mode 100644 index 00000000..10e11603 --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/response/CopilotSetPageRes.java @@ -0,0 +1,30 @@ +package plus.maa.backend.controller.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; +import lombok.experimental.Accessors; +import plus.maa.backend.controller.response.user.CopilotSetListRes; + +import java.util.List; + +/** + * @author dragove + * create on 2024-01-06 + */ +@Getter +@Setter +@Schema(title = "作业集分页返回数据") +@Accessors(chain = true) +public class CopilotSetPageRes { + + @Schema(title = "是否有下一页") + private boolean hasNext; + @Schema(title = "当前页码") + private int page; + @Schema(title = "总数据量") + private long total; + @Schema(title = "作业集列表") + private List data; + +} diff --git a/src/main/java/plus/maa/backend/controller/response/CopilotSetRes.java b/src/main/java/plus/maa/backend/controller/response/CopilotSetRes.java new file mode 100644 index 00000000..0349049b --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/response/CopilotSetRes.java @@ -0,0 +1,48 @@ +package plus.maa.backend.controller.response; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; +import plus.maa.backend.service.model.CopilotSetStatus; + +import java.time.LocalDateTime; +import java.util.List; + +/** + * @author dragove + * create on 2024-01-06 + */ +@Getter +@Setter +@Schema(title = "作业集响应") +public class CopilotSetRes { + + @Schema(title = "作业集id") + private long id; + + @Schema(title = "作业集名称") + private String name; + + @Schema(title = "额外描述") + private String description; + + @Schema(title = "作业id列表") + private List copilotIds; + + @Schema(title = "上传者id") + private String creatorId; + + @Schema(title = "上传者昵称") + private String creator; + + @Schema(title = "创建时间") + private LocalDateTime createTime; + + @Schema(title = "更新时间") + private LocalDateTime updateTime; + + @Schema(title = "作业状态", enumAsRef = true) + private CopilotSetStatus status; + + +} diff --git a/src/main/java/plus/maa/backend/controller/response/user/CopilotSetListRes.java b/src/main/java/plus/maa/backend/controller/response/user/CopilotSetListRes.java new file mode 100644 index 00000000..5b630bee --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/response/user/CopilotSetListRes.java @@ -0,0 +1,39 @@ +package plus.maa.backend.controller.response.user; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.Setter; + +import java.time.LocalDateTime; + +/** + * @author dragove + * create on 2024-01-06 + */ +@Getter +@Setter +@Schema(title = "作业集响应(列表)") +public class CopilotSetListRes { + + @Schema(title = "作业集id") + private long id; + + @Schema(title = "作业集名称") + private String name; + + @Schema(title = "额外描述") + private String description; + + @Schema(title = "上传者id") + private String creatorId; + + @Schema(title = "上传者昵称") + private String creator; + + @Schema(title = "创建时间") + private LocalDateTime createTime; + + @Schema(title = "更新时间") + private LocalDateTime updateTime; + +} diff --git a/src/main/java/plus/maa/backend/repository/CopilotSetRepository.java b/src/main/java/plus/maa/backend/repository/CopilotSetRepository.java index 100e68ca..ab6814ad 100644 --- a/src/main/java/plus/maa/backend/repository/CopilotSetRepository.java +++ b/src/main/java/plus/maa/backend/repository/CopilotSetRepository.java @@ -1,6 +1,9 @@ package plus.maa.backend.repository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.mongodb.repository.MongoRepository; +import org.springframework.data.mongodb.repository.Query; import plus.maa.backend.repository.entity.CopilotSet; /** @@ -9,5 +12,14 @@ */ public interface CopilotSetRepository extends MongoRepository { + @Query(""" + { + "$or": [ + {"name": {'$regex': ?0 ,'$options':'i'}}, + {"description": {'$regex': ?0,'$options':'i' }} + ] + } + """) + Page findByKeyword(String keyword, Pageable pageable); } diff --git a/src/main/java/plus/maa/backend/repository/entity/MaaUser.java b/src/main/java/plus/maa/backend/repository/entity/MaaUser.java index 06561db3..81849409 100644 --- a/src/main/java/plus/maa/backend/repository/entity/MaaUser.java +++ b/src/main/java/plus/maa/backend/repository/entity/MaaUser.java @@ -7,6 +7,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.Accessors; import org.springframework.data.annotation.Id; +import org.springframework.data.annotation.Transient; import org.springframework.data.mongodb.core.index.Indexed; import org.springframework.data.mongodb.core.mapping.Document; import plus.maa.backend.controller.request.user.UserInfoUpdateDTO; @@ -25,6 +26,8 @@ @JsonInclude(JsonInclude.Include.NON_NULL) @Document("maa_user") public class MaaUser implements Serializable { + @Transient + public static final MaaUser UNKNOWN = new MaaUser().setUserName("未知用户:("); @Id private String userId; private String userName; diff --git a/src/main/java/plus/maa/backend/service/CommentsAreaService.java b/src/main/java/plus/maa/backend/service/CommentsAreaService.java index d5bc14c2..e7a1f8b0 100644 --- a/src/main/java/plus/maa/backend/service/CommentsAreaService.java +++ b/src/main/java/plus/maa/backend/service/CommentsAreaService.java @@ -53,8 +53,6 @@ public class CommentsAreaService { private final MaaCopilotProperties maaCopilotProperties; - private final MaaUser UNKNOWN_USER = new MaaUser().setUserName("未知用户:("); - private final CommentConverter commentConverter; @@ -121,8 +119,8 @@ public void addComments(String userId, CommentsAddDTO commentsAddDTO) { CommentNotification commentNotification = new CommentNotification(); - String authorName = maaUserMap.getOrDefault(replyUserId, UNKNOWN_USER).getUserName(); - String reName = maaUserMap.getOrDefault(userId, UNKNOWN_USER).getUserName(); + String authorName = maaUserMap.getOrDefault(replyUserId, MaaUser.UNKNOWN).getUserName(); + String reName = maaUserMap.getOrDefault(userId, MaaUser.UNKNOWN).getUserName(); String title = isCopilotAuthor ? copilot.getDoc().getTitle() : commentsArea.getMessage(); @@ -332,7 +330,7 @@ public CommentsAreaInfo queriesCommentsArea(CommentsQueriesDTO request) { , (int) mainComment.getLikeCount() , maaUserMap.getOrDefault( mainComment.getUploaderId() - , UNKNOWN_USER + , MaaUser.UNKNOWN ) ); @@ -348,7 +346,7 @@ public CommentsAreaInfo queriesCommentsArea(CommentsQueriesDTO request) { //填充评论用户名 , maaUserMap.getOrDefault( subComment.getUploaderId(), - UNKNOWN_USER + MaaUser.UNKNOWN ) , subComment.isDelete() ) diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.java b/src/main/java/plus/maa/backend/service/CopilotSetService.java index c2b9fc28..9518f81f 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.java +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.java @@ -3,18 +3,25 @@ import cn.hutool.core.lang.Assert; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; import org.springframework.stereotype.Service; import plus.maa.backend.common.utils.IdComponent; import plus.maa.backend.common.utils.converter.CopilotSetConverter; +import plus.maa.backend.controller.request.CopilotSetQuery; import plus.maa.backend.controller.request.CopilotSetUpdateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; +import plus.maa.backend.controller.response.CopilotSetPageRes; import plus.maa.backend.repository.CopilotSetRepository; +import plus.maa.backend.repository.UserRepository; import plus.maa.backend.repository.entity.CopilotSet; +import plus.maa.backend.repository.entity.MaaUser; import java.time.LocalDateTime; -import java.util.HashSet; -import java.util.Set; +import java.util.*; /** * @author dragove @@ -28,10 +35,13 @@ public class CopilotSetService { private final IdComponent idComponent; private final CopilotSetConverter converter; private final CopilotSetRepository repository; + private final UserRepository userRepository; + private final Sort DEFAULT_SORT = Sort.by("id").descending(); /** * 创建作业集 - * @param req 作业集创建请求 + * + * @param req 作业集创建请求 * @param userId 创建者用户id * @return 作业集id */ @@ -82,7 +92,8 @@ public void update(CopilotSetUpdateReq req, String userId) { /** * 删除作业集信息(逻辑删除,保留详情接口查询结果) - * @param id 作业集id + * + * @param id 作业集id * @param userId 登陆用户id */ public void delete(long id, String userId) { @@ -94,4 +105,31 @@ public void delete(long id, String userId) { copilotSet.setDeleteTime(LocalDateTime.now()); repository.save(copilotSet); } + + public CopilotSetPageRes query(CopilotSetQuery req) { + PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getLimit(), DEFAULT_SORT); + + String keyword = req.getKeyword(); + Page copilotSets; + if (StringUtils.isBlank(keyword)) { + copilotSets = repository.findAll(pageRequest); + } else { + copilotSets = repository.findByKeyword(keyword, pageRequest); + } + + List userIds = copilotSets.stream().map(CopilotSet::getCreatorId) + .filter(Objects::nonNull) + .distinct() + .toList(); + Map userById = userRepository.findByUsersId(userIds); + return new CopilotSetPageRes() + .setPage(copilotSets.getNumber() + 1) + .setTotal(copilotSets.getTotalElements()) + .setHasNext(copilotSets.getTotalPages() > req.getPage()) + .setData(copilotSets.stream().map(cs -> { + MaaUser user = userById.getOrDefault(cs.getCreatorId(), MaaUser.UNKNOWN); + return converter.convert(cs, user.getUserName()); + }).toList()); + + } } From 688c2d6f77a60fb998c8efb05cafe1732fc046b5 Mon Sep 17 00:00:00 2001 From: dragove Date: Sat, 6 Jan 2024 20:26:59 +0800 Subject: [PATCH 053/168] =?UTF-8?q?feat:=20=E4=BD=9C=E4=B8=9A=E9=9B=86?= =?UTF-8?q?=E8=AF=A6=E6=83=85=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/converter/CopilotSetConverter.java | 3 +++ .../backend/config/security/SecurityConfig.java | 1 + .../backend/controller/CopilotSetController.java | 16 +++++++++++----- .../maa/backend/repository/UserRepository.java | 3 +++ .../maa/backend/service/CopilotSetService.java | 8 ++++++++ 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java index 81d03374..3057af84 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java +++ b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java @@ -3,6 +3,7 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; +import plus.maa.backend.controller.response.CopilotSetRes; import plus.maa.backend.controller.response.user.CopilotSetListRes; import plus.maa.backend.repository.entity.CopilotSet; @@ -27,4 +28,6 @@ public interface CopilotSetConverter { @Mapping(target = "creator", ignore = true) CopilotSetListRes convert(CopilotSet copilotSet, String creator); + CopilotSetRes convertDetail(CopilotSet copilotSet, String creator); + } diff --git a/src/main/java/plus/maa/backend/config/security/SecurityConfig.java b/src/main/java/plus/maa/backend/config/security/SecurityConfig.java index 4850a402..43466348 100644 --- a/src/main/java/plus/maa/backend/config/security/SecurityConfig.java +++ b/src/main/java/plus/maa/backend/config/security/SecurityConfig.java @@ -43,6 +43,7 @@ public class SecurityConfig { "/arknights/level", "/copilot/query", "/set/query", + "/set/get", "/copilot/get/**", "/copilot/rating", "/comments/query", diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index bb3235d0..015b7fdc 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -7,18 +7,16 @@ import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import plus.maa.backend.config.SpringDocConfig; import plus.maa.backend.config.security.AuthenticationHelper; import plus.maa.backend.controller.request.CommonIdReq; import plus.maa.backend.controller.request.CopilotSetQuery; import plus.maa.backend.controller.request.CopilotSetUpdateReq; -import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; +import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.controller.response.CopilotSetPageRes; +import plus.maa.backend.controller.response.CopilotSetRes; import plus.maa.backend.controller.response.MaaResult; import plus.maa.backend.service.CopilotSetService; @@ -43,6 +41,14 @@ public MaaResult querySets( return MaaResult.success(service.query(req)); } + @Operation(summary = "查询作业集列表") + @ApiResponse(description = "作业集id") + @GetMapping("/get") + public MaaResult getSet(@RequestParam @Parameter(description = "作业id") long id) { + return MaaResult.success(service.get(id)); + } + + @Operation(summary = "创建作业集") @ApiResponse(description = "作业集id") @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) diff --git a/src/main/java/plus/maa/backend/repository/UserRepository.java b/src/main/java/plus/maa/backend/repository/UserRepository.java index 35112d39..d9a4fde5 100644 --- a/src/main/java/plus/maa/backend/repository/UserRepository.java +++ b/src/main/java/plus/maa/backend/repository/UserRepository.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -20,6 +21,8 @@ public interface UserRepository extends MongoRepository { */ MaaUser findByEmail(String email); + Optional findByUserId(String userId); + default Map findByUsersId(List userId) { return findAllById(userId) .stream().collect(Collectors.toMap(MaaUser::getUserId, Function.identity())); diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.java b/src/main/java/plus/maa/backend/service/CopilotSetService.java index 9518f81f..84cda80a 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.java +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.java @@ -15,6 +15,7 @@ import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; import plus.maa.backend.controller.response.CopilotSetPageRes; +import plus.maa.backend.controller.response.CopilotSetRes; import plus.maa.backend.repository.CopilotSetRepository; import plus.maa.backend.repository.UserRepository; import plus.maa.backend.repository.entity.CopilotSet; @@ -132,4 +133,11 @@ public CopilotSetPageRes query(CopilotSetQuery req) { }).toList()); } + + public CopilotSetRes get(long id) { + return repository.findById(id).map($ -> { + String userName = userRepository.findByUserId($.getCreatorId()).orElse(MaaUser.UNKNOWN).getUserName(); + return converter.convertDetail($, userName); + }).orElseThrow(() -> new IllegalArgumentException("作业不存在")); + } } From 9583a1748c3b5c9c892c18ec254e5c2eed1a3d8d Mon Sep 17 00:00:00 2001 From: dragove Date: Sat, 6 Jan 2024 20:49:55 +0800 Subject: [PATCH 054/168] =?UTF-8?q?feat:=20=E4=BD=9C=E4=B8=9A=E5=88=97?= =?UTF-8?q?=E8=A1=A8=E6=9F=A5=E8=AF=A2=E6=8E=A5=E5=8F=A3=EF=BC=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E6=94=AF=E6=8C=81=E6=A0=B9=E6=8D=AE=E4=BD=9C=E4=B8=9A?= =?UTF-8?q?id=E5=88=97=E8=A1=A8=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/copilot/CopilotQueriesRequest.java | 13 +++++++++++++ .../maa/backend/service/CopilotService.java | 17 ++++++++++++----- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.java b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.java index 81adcc70..1ec5133c 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.java +++ b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + /** * @author LoMu * Date 2022-12-26 2:48 @@ -25,6 +27,7 @@ public class CopilotQueriesRequest { private boolean desc = true; private String orderBy; private String language; + private List copilotIds; /* * 这里为了正确接收前端的下划线风格,手动写了三个 setter 用于起别名 @@ -33,17 +36,27 @@ public class CopilotQueriesRequest { * (吐槽一下,同样是Get请求,怎么CommentsQueries是驼峰命名,到了CopilotQueries就成了下划线命名) */ @JsonIgnore + @SuppressWarnings("unused") public void setLevel_keyword(String levelKeyword) { this.levelKeyword = levelKeyword; } @JsonIgnore + @SuppressWarnings("unused") public void setUploader_id(String uploaderId) { this.uploaderId = uploaderId; } @JsonIgnore + @SuppressWarnings("unused") public void setOrder_by(String orderBy) { this.orderBy = orderBy; } + + @JsonIgnore + @SuppressWarnings("unused") + public void setCopilot_ids(List copilotIds) { + this.copilotIds = copilotIds; + } + } diff --git a/src/main/java/plus/maa/backend/service/CopilotService.java b/src/main/java/plus/maa/backend/service/CopilotService.java index 073bdaea..00dd697f 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.java +++ b/src/main/java/plus/maa/backend/service/CopilotService.java @@ -1,5 +1,6 @@ package plus.maa.backend.service; +import cn.hutool.core.collection.CollectionUtil; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Sets; @@ -201,7 +202,7 @@ public Optional getCopilotById(String userIdOrIpAddress, Long id) { // 新评分系统 RatingType ratingType = ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COPILOT, - Long.toString(copilot.getCopilotId()), userIdOrIpAddress) + Long.toString(copilot.getCopilotId()), userIdOrIpAddress) .map(Rating::getRating) .orElse(null); // 用户点进作业会显示点赞信息 @@ -225,7 +226,8 @@ public CopilotPageInfo queriesCopilot(@Nullable String userId, CopilotQueriesReq AtomicReference setKey = new AtomicReference<>(); // 只缓存默认状态下热度和访问量排序的结果,并且最多只缓存前三页 if (request.getPage() <= 3 && request.getDocument() == null && request.getLevelKeyword() == null && - request.getUploaderId() == null && request.getOperator() == null) { + request.getUploaderId() == null && request.getOperator() == null && + CollectionUtil.isEmpty(request.getCopilotIds())) { Optional cacheOptional = Optional.ofNullable(request.getOrderBy()) .filter(StringUtils::isNotBlank) @@ -279,6 +281,11 @@ public CopilotPageInfo queriesCopilot(@Nullable String userId, CopilotQueriesReq } } + // 作业id列表 + if (CollectionUtil.isNotEmpty(request.getCopilotIds())) { + andQueries.add(Criteria.where("copilotId").in(request.getCopilotIds())); + } + //标题、描述、神秘代码 if (StringUtils.isNotBlank(request.getDocument())) { orQueries.add(Criteria.where("doc.title").regex(caseInsensitive(request.getDocument()))); @@ -341,9 +348,9 @@ public CopilotPageInfo queriesCopilot(@Nullable String userId, CopilotQueriesReq // 新版评分系统 // 反正目前首页和搜索不会直接展示当前用户有没有点赞,干脆直接不查,要用户点进作业才显示自己是否点赞 List infos = copilots.stream().map(copilot -> - formatCopilot(copilot, null, - maaUsers.get(copilot.getUploaderId()).getUserName(), - commentsCount.get(copilot.getCopilotId()))) + formatCopilot(copilot, null, + maaUsers.get(copilot.getUploaderId()).getUserName(), + commentsCount.get(copilot.getCopilotId()))) .toList(); // 计算页面 From 5fd1b7e9bf400fd7338292d77ca200054c92f5be Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 14 Jan 2024 15:24:32 +0800 Subject: [PATCH 055/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=9F?= =?UTF-8?q?=E6=88=90=E6=96=87=E6=A1=A3=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6afb7328..cea70017 100644 --- a/build.gradle +++ b/build.gradle @@ -42,7 +42,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-cache' //springdoc相关依赖没有被自动管理,必须保留版本号 - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0' + implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0' implementation 'com.squareup.okhttp3:okhttp:4.10.0' From 673a709fa7fbfa06fd433425bd96bd9710569cb0 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Sat, 20 Jan 2024 16:30:27 +0800 Subject: [PATCH 056/168] refactor: extract security requirement annotation --- .../plus/maa/backend/config/doc/RequireJwt.java | 15 +++++++++++++++ .../backend/config/{ => doc}/SpringDocConfig.java | 10 +++++----- .../controller/CommentsAreaController.java | 13 ++++++------- .../maa/backend/controller/CopilotController.java | 11 +++++------ .../backend/controller/CopilotSetController.java | 13 ++++++------- .../maa/backend/controller/UserController.java | 7 +++---- .../backend/controller/file/FileController.java | 15 +++++++-------- 7 files changed, 47 insertions(+), 37 deletions(-) create mode 100644 src/main/java/plus/maa/backend/config/doc/RequireJwt.java rename src/main/java/plus/maa/backend/config/{ => doc}/SpringDocConfig.java (93%) diff --git a/src/main/java/plus/maa/backend/config/doc/RequireJwt.java b/src/main/java/plus/maa/backend/config/doc/RequireJwt.java new file mode 100644 index 00000000..ea8626bb --- /dev/null +++ b/src/main/java/plus/maa/backend/config/doc/RequireJwt.java @@ -0,0 +1,15 @@ +package plus.maa.backend.config.doc; + +import io.swagger.v3.oas.annotations.security.SecurityRequirement; + +import java.lang.annotation.*; + +/** + * 指示需要 Jwt 认证 + */ +@Target({ElementType.METHOD, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +@SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_JWT) +public @interface RequireJwt { +} diff --git a/src/main/java/plus/maa/backend/config/SpringDocConfig.java b/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.java similarity index 93% rename from src/main/java/plus/maa/backend/config/SpringDocConfig.java rename to src/main/java/plus/maa/backend/config/doc/SpringDocConfig.java index 4c59d80a..bb3d9ccc 100644 --- a/src/main/java/plus/maa/backend/config/SpringDocConfig.java +++ b/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.java @@ -1,4 +1,4 @@ -package plus.maa.backend.config; +package plus.maa.backend.config.doc; import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.v3.core.jackson.ModelResolver; @@ -38,7 +38,7 @@ public class SpringDocConfig { @Value("${maa-copilot.jwt.header}") private String securitySchemeHeader; - public static final String SECURITY_SCHEME_NAME = "Bearer"; + public static final String SECURITY_SCHEME_JWT = "Jwt"; @Bean public OpenAPI emergencyLogistics() { @@ -48,7 +48,7 @@ public OpenAPI emergencyLogistics() { .description("GitHub repo") .url("https://github.com/MaaAssistantArknights/MaaBackendCenter")) .components(new Components() - .addSecuritySchemes(SECURITY_SCHEME_NAME, + .addSecuritySchemes(SECURITY_SCHEME_JWT, new SecurityScheme() .type(SecurityScheme.Type.HTTP) .scheme("bearer") @@ -68,13 +68,13 @@ public OperationCustomizer currentUserOperationCustomizer() { if (parameter.hasParameterAnnotation(CurrentUser.class)) { var security = Optional.ofNullable(operation.getSecurity()); // 已有 security scheme - if (security.stream().flatMap(List::stream).anyMatch(s -> s.containsKey(SECURITY_SCHEME_NAME))) { + if (security.stream().flatMap(List::stream).anyMatch(s -> s.containsKey(SECURITY_SCHEME_JWT))) { break; } // 添加 security scheme operation.setSecurity(security.orElseGet(ArrayList::new)); - operation.getSecurity().add(new SecurityRequirement().addList(SECURITY_SCHEME_NAME)); + operation.getSecurity().add(new SecurityRequirement().addList(SECURITY_SCHEME_JWT)); break; } } diff --git a/src/main/java/plus/maa/backend/controller/CommentsAreaController.java b/src/main/java/plus/maa/backend/controller/CommentsAreaController.java index ba4770a3..affbbd2c 100644 --- a/src/main/java/plus/maa/backend/controller/CommentsAreaController.java +++ b/src/main/java/plus/maa/backend/controller/CommentsAreaController.java @@ -3,7 +3,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; @@ -11,7 +10,7 @@ import org.springframework.web.bind.annotation.*; import plus.maa.backend.common.annotation.JsonSchema; import plus.maa.backend.common.annotation.SensitiveWordDetection; -import plus.maa.backend.config.SpringDocConfig; +import plus.maa.backend.config.doc.RequireJwt; import plus.maa.backend.config.security.AuthenticationHelper; import plus.maa.backend.controller.request.comments.*; import plus.maa.backend.controller.response.MaaResult; @@ -35,7 +34,7 @@ public class CommentsAreaController { @PostMapping("/add") @Operation(summary = "发送评论") @ApiResponse(description = "发送评论结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt public MaaResult sendComments( @Parameter(description = "评论") @Valid @RequestBody CommentsAddDTO comments ) { @@ -55,7 +54,7 @@ public MaaResult queriesCommentsArea( @PostMapping("/delete") @Operation(summary = "删除评论") @ApiResponse(description = "评论删除结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt public MaaResult deleteComments( @Parameter(description = "评论删除对象") @Valid @RequestBody CommentsDeleteDTO comments ) { @@ -66,7 +65,7 @@ public MaaResult deleteComments( @JsonSchema @Operation(summary = "为评论点赞") @ApiResponse(description = "点赞结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/rating") public MaaResult ratesComments( @Parameter(description = "评论点赞对象") @Valid @RequestBody CommentsRatingDTO commentsRatingDTO @@ -77,7 +76,7 @@ public MaaResult ratesComments( @Operation(summary = "为评论置顶/取消置顶") @ApiResponse(description = "置顶/取消置顶结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/topping") public MaaResult toppingComments( @Parameter(description = "评论置顶对象") @Valid @RequestBody CommentsToppingDTO commentsToppingDTO @@ -87,7 +86,7 @@ public MaaResult toppingComments( } @Operation(summary = "设置通知接收状态") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @GetMapping("/status") public MaaResult modifyStatus(@RequestParam @NotBlank String id, @RequestParam boolean status) { commentsAreaService.notificationStatus(authHelper.getUserId(), id, status); diff --git a/src/main/java/plus/maa/backend/controller/CopilotController.java b/src/main/java/plus/maa/backend/controller/CopilotController.java index 9f1c1dba..ffdd6daf 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotController.java @@ -3,7 +3,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; @@ -13,7 +12,7 @@ import org.springframework.web.bind.annotation.*; import plus.maa.backend.common.annotation.JsonSchema; import plus.maa.backend.common.annotation.SensitiveWordDetection; -import plus.maa.backend.config.SpringDocConfig; +import plus.maa.backend.config.doc.RequireJwt; import plus.maa.backend.config.security.AuthenticationHelper; import plus.maa.backend.controller.request.copilot.CopilotCUDRequest; import plus.maa.backend.controller.request.copilot.CopilotQueriesRequest; @@ -39,7 +38,7 @@ public class CopilotController { @Operation(summary = "上传作业") @ApiResponse(description = "上传作业结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @JsonSchema @SensitiveWordDetection("#request.content != null ? #objectMapper.readTree(#request.content).get('doc')?.toString() : null") @PostMapping("/upload") @@ -51,7 +50,7 @@ public MaaResult uploadCopilot( @Operation(summary = "删除作业") @ApiResponse(description = "删除作业结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/delete") public MaaResult deleteCopilot( @Parameter(description = "作业操作请求") @RequestBody CopilotCUDRequest request @@ -85,7 +84,7 @@ public MaaResult queriesCopilot( @Operation(summary = "更新作业") @ApiResponse(description = "更新结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @JsonSchema @SensitiveWordDetection("#copilotCUDRequest.content != null ? #objectMapper.readTree(#copilotCUDRequest.content).get('doc')?.toString() : null") @PostMapping("/update") @@ -107,7 +106,7 @@ public MaaResult ratesCopilotOperation( return MaaResult.success("评分成功"); } - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @Operation(summary = "修改通知状态") @ApiResponse(description = "success") @GetMapping("/status") diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.java index 015b7fdc..152862a1 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.java +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.java @@ -3,12 +3,11 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; -import plus.maa.backend.config.SpringDocConfig; +import plus.maa.backend.config.doc.RequireJwt; import plus.maa.backend.config.security.AuthenticationHelper; import plus.maa.backend.controller.request.CommonIdReq; import plus.maa.backend.controller.request.CopilotSetQuery; @@ -51,7 +50,7 @@ public MaaResult getSet(@RequestParam @Parameter(description = " @Operation(summary = "创建作业集") @ApiResponse(description = "作业集id") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/create") public MaaResult createSet( @Parameter(description = "作业集新增请求") @Valid @RequestBody CopilotSetCreateReq req) { @@ -59,7 +58,7 @@ public MaaResult createSet( } @Operation(summary = "添加作业集作业列表") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/add") public MaaResult addCopilotIds( @Parameter(description = "作业集中加入新作业请求") @Valid @RequestBody CopilotSetModCopilotsReq req) { @@ -68,7 +67,7 @@ public MaaResult addCopilotIds( } @Operation(summary = "添加作业集作业列表") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/remove") public MaaResult removeCopilotIds( @Parameter(description = "作业集中删除作业请求") @Valid @RequestBody CopilotSetModCopilotsReq req) { @@ -77,7 +76,7 @@ public MaaResult removeCopilotIds( } @Operation(summary = "更新作业集信息") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/update") public MaaResult updateCopilotSet( @Parameter(description = "更新作业集信息请求") @Valid @RequestBody CopilotSetUpdateReq req) { @@ -86,7 +85,7 @@ public MaaResult updateCopilotSet( } @Operation(summary = "删除作业集") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/delete") public MaaResult deleteCopilotSet( @Parameter(description = "删除作业集信息请求") @Valid @RequestBody CommonIdReq req) { diff --git a/src/main/java/plus/maa/backend/controller/UserController.java b/src/main/java/plus/maa/backend/controller/UserController.java index 0c91e9f8..c9c0abd3 100644 --- a/src/main/java/plus/maa/backend/controller/UserController.java +++ b/src/main/java/plus/maa/backend/controller/UserController.java @@ -3,7 +3,6 @@ import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.Data; @@ -14,7 +13,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import plus.maa.backend.config.SpringDocConfig; +import plus.maa.backend.config.doc.RequireJwt; import plus.maa.backend.config.external.MaaCopilotProperties; import plus.maa.backend.config.security.AuthenticationHelper; import plus.maa.backend.controller.request.user.*; @@ -52,7 +51,7 @@ public class UserController { */ @Operation(summary = "修改当前用户密码", description = "根据原密码") @ApiResponse(description = "修改密码结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/update/password") public MaaResult updatePassword( @Parameter(description = "修改密码请求") @RequestBody @Valid PasswordUpdateDTO updateDTO @@ -69,7 +68,7 @@ public MaaResult updatePassword( */ @Operation(summary = "更新用户详细信息") @ApiResponse(description = "更新结果") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/update/info") public MaaResult updateInfo( @Parameter(description = "更新用户详细信息请求") @Valid @RequestBody UserInfoUpdateDTO updateDTO diff --git a/src/main/java/plus/maa/backend/controller/file/FileController.java b/src/main/java/plus/maa/backend/controller/file/FileController.java index c8b0b8c0..6b20d577 100644 --- a/src/main/java/plus/maa/backend/controller/file/FileController.java +++ b/src/main/java/plus/maa/backend/controller/file/FileController.java @@ -6,7 +6,6 @@ import io.swagger.v3.oas.annotations.media.Content; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -14,7 +13,7 @@ import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import plus.maa.backend.common.annotation.AccessLimit; -import plus.maa.backend.config.SpringDocConfig; +import plus.maa.backend.config.doc.RequireJwt; import plus.maa.backend.config.security.AuthenticationHelper; import plus.maa.backend.controller.response.MaaResult; import plus.maa.backend.service.FileService; @@ -55,7 +54,7 @@ public MaaResult uploadFile( responseCode = "200", content = @Content(mediaType = "application/zip", schema = @Schema(type = "string", format = "binary")) ) - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @AccessLimit @GetMapping("/download") public void downloadSpecifiedDateFile( @@ -72,7 +71,7 @@ public void downloadSpecifiedDateFile( responseCode = "200", content = @Content(mediaType = "application/zip", schema = @Schema(type = "string", format = "binary")) ) - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/download") public void downloadFile(@RequestBody @Valid ImageDownloadDTO imageDownloadDTO, @@ -81,7 +80,7 @@ public void downloadFile(@RequestBody @Valid } @Operation(summary = "设置上传文件功能状态") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/upload_ability") public MaaResult setUploadAbility(@RequestBody UploadAbility request) { fileService.setUploadEnabled(request.enabled); @@ -89,14 +88,14 @@ public MaaResult setUploadAbility(@RequestBody UploadAbility request) { } @Operation(summary = "获取上传文件功能状态") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @GetMapping("/upload_ability") public MaaResult getUploadAbility() { return MaaResult.success(new UploadAbility(fileService.isUploadEnabled())); } @Operation(summary = "关闭uploadfile接口") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/disable") public MaaResult disable(@RequestBody boolean status) { if (!status) { @@ -106,7 +105,7 @@ public MaaResult disable(@RequestBody boolean status) { } @Operation(summary = "开启uploadfile接口") - @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_NAME) + @RequireJwt @PostMapping("/enable") public MaaResult enable(@RequestBody boolean status) { if (!status) { From 06f6aec339a8eb80775415427d43d4ebd976b77e Mon Sep 17 00:00:00 2001 From: Handiwork Date: Thu, 25 Jan 2024 22:15:46 +0800 Subject: [PATCH 057/168] Rename .java to .kt --- .../plus/maa/backend/{MainApplication.java => MainApplication.kt} | 0 .../backend/config/external/{ArkLevelGit.java => ArkLevelGit.kt} | 0 .../plus/maa/backend/config/external/{Cache.java => Cache.kt} | 0 .../plus/maa/backend/config/external/{Copilot.java => Copilot.kt} | 0 .../config/external/{CopilotBackup.java => CopilotBackup.kt} | 0 .../plus/maa/backend/config/external/{Github.java => Github.kt} | 0 .../java/plus/maa/backend/config/external/{Info.java => Info.kt} | 0 .../java/plus/maa/backend/config/external/{Jwt.java => Jwt.kt} | 0 .../{MaaCopilotProperties.java => MaaCopilotProperties.kt} | 0 .../java/plus/maa/backend/config/external/{Mail.java => Mail.kt} | 0 .../config/external/{SensitiveWord.java => SensitiveWord.kt} | 0 .../maa/backend/config/external/{TaskCron.java => TaskCron.kt} | 0 .../plus/maa/backend/config/external/{Vcode.java => Vcode.kt} | 0 .../controller/{SystemController.java => SystemController.kt} | 0 .../backend/controller/response/{MaaResult.java => MaaResult.kt} | 0 15 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/{MainApplication.java => MainApplication.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{ArkLevelGit.java => ArkLevelGit.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{Cache.java => Cache.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{Copilot.java => Copilot.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{CopilotBackup.java => CopilotBackup.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{Github.java => Github.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{Info.java => Info.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{Jwt.java => Jwt.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{MaaCopilotProperties.java => MaaCopilotProperties.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{Mail.java => Mail.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{SensitiveWord.java => SensitiveWord.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{TaskCron.java => TaskCron.kt} (100%) rename src/main/java/plus/maa/backend/config/external/{Vcode.java => Vcode.kt} (100%) rename src/main/java/plus/maa/backend/controller/{SystemController.java => SystemController.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/{MaaResult.java => MaaResult.kt} (100%) diff --git a/src/main/java/plus/maa/backend/MainApplication.java b/src/main/java/plus/maa/backend/MainApplication.kt similarity index 100% rename from src/main/java/plus/maa/backend/MainApplication.java rename to src/main/java/plus/maa/backend/MainApplication.kt diff --git a/src/main/java/plus/maa/backend/config/external/ArkLevelGit.java b/src/main/java/plus/maa/backend/config/external/ArkLevelGit.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/ArkLevelGit.java rename to src/main/java/plus/maa/backend/config/external/ArkLevelGit.kt diff --git a/src/main/java/plus/maa/backend/config/external/Cache.java b/src/main/java/plus/maa/backend/config/external/Cache.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Cache.java rename to src/main/java/plus/maa/backend/config/external/Cache.kt diff --git a/src/main/java/plus/maa/backend/config/external/Copilot.java b/src/main/java/plus/maa/backend/config/external/Copilot.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Copilot.java rename to src/main/java/plus/maa/backend/config/external/Copilot.kt diff --git a/src/main/java/plus/maa/backend/config/external/CopilotBackup.java b/src/main/java/plus/maa/backend/config/external/CopilotBackup.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/CopilotBackup.java rename to src/main/java/plus/maa/backend/config/external/CopilotBackup.kt diff --git a/src/main/java/plus/maa/backend/config/external/Github.java b/src/main/java/plus/maa/backend/config/external/Github.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Github.java rename to src/main/java/plus/maa/backend/config/external/Github.kt diff --git a/src/main/java/plus/maa/backend/config/external/Info.java b/src/main/java/plus/maa/backend/config/external/Info.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Info.java rename to src/main/java/plus/maa/backend/config/external/Info.kt diff --git a/src/main/java/plus/maa/backend/config/external/Jwt.java b/src/main/java/plus/maa/backend/config/external/Jwt.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Jwt.java rename to src/main/java/plus/maa/backend/config/external/Jwt.kt diff --git a/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java b/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.java rename to src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.kt diff --git a/src/main/java/plus/maa/backend/config/external/Mail.java b/src/main/java/plus/maa/backend/config/external/Mail.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Mail.java rename to src/main/java/plus/maa/backend/config/external/Mail.kt diff --git a/src/main/java/plus/maa/backend/config/external/SensitiveWord.java b/src/main/java/plus/maa/backend/config/external/SensitiveWord.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/SensitiveWord.java rename to src/main/java/plus/maa/backend/config/external/SensitiveWord.kt diff --git a/src/main/java/plus/maa/backend/config/external/TaskCron.java b/src/main/java/plus/maa/backend/config/external/TaskCron.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/TaskCron.java rename to src/main/java/plus/maa/backend/config/external/TaskCron.kt diff --git a/src/main/java/plus/maa/backend/config/external/Vcode.java b/src/main/java/plus/maa/backend/config/external/Vcode.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Vcode.java rename to src/main/java/plus/maa/backend/config/external/Vcode.kt diff --git a/src/main/java/plus/maa/backend/controller/SystemController.java b/src/main/java/plus/maa/backend/controller/SystemController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/SystemController.java rename to src/main/java/plus/maa/backend/controller/SystemController.kt diff --git a/src/main/java/plus/maa/backend/controller/response/MaaResult.java b/src/main/java/plus/maa/backend/controller/response/MaaResult.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/MaaResult.java rename to src/main/java/plus/maa/backend/controller/response/MaaResult.kt From 857bb859b412b317caf86a7deb431761ae13896c Mon Sep 17 00:00:00 2001 From: Handiwork Date: Thu, 25 Jan 2024 22:15:46 +0800 Subject: [PATCH 058/168] feat: add kotlin support --- build.gradle | 27 ++++++-- .../java/plus/maa/backend/MainApplication.kt | 27 ++++---- .../backend/config/external/ArkLevelGit.kt | 13 ++-- .../plus/maa/backend/config/external/Cache.kt | 10 +-- .../maa/backend/config/external/Copilot.kt | 22 +++--- .../backend/config/external/CopilotBackup.kt | 41 +++++++---- .../maa/backend/config/external/Github.kt | 16 ++--- .../plus/maa/backend/config/external/Info.kt | 18 ++--- .../plus/maa/backend/config/external/Jwt.kt | 48 +++++++------ .../config/external/MaaCopilotProperties.kt | 68 +++++++++++-------- .../plus/maa/backend/config/external/Mail.kt | 28 +++----- .../backend/config/external/SensitiveWord.kt | 13 ++-- .../maa/backend/config/external/TaskCron.kt | 12 ++-- .../plus/maa/backend/config/external/Vcode.kt | 15 ++-- .../backend/controller/SystemController.kt | 68 +++++++++---------- .../backend/controller/response/MaaResult.kt | 52 +++++++------- .../controller/response/MaaSystemInfo.java | 15 ---- .../maa/backend/task/CopilotBackupTask.java | 4 +- src/main/resources/application-template.yml | 3 +- 19 files changed, 256 insertions(+), 244 deletions(-) delete mode 100644 src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java diff --git a/build.gradle b/build.gradle index cea70017..af0def8a 100644 --- a/build.gradle +++ b/build.gradle @@ -7,6 +7,9 @@ plugins { id 'org.hidetake.swagger.generator' version '2.19.2' // id 'org.graalvm.buildtools.native' version '0.9.28' id 'com.gorylenko.gradle-git-properties' version '2.4.1' + id 'org.jetbrains.kotlin.jvm' version '1.9.22' + id "org.jetbrains.kotlin.plugin.spring" version "1.9.22" + id "org.jetbrains.kotlin.kapt" version "1.9.22" } group 'plus.maa' @@ -25,13 +28,12 @@ repositories { ext { // 统一管理版本号 hutoolVersion = '5.8.22' + mapstructVersion = '1.5.5.Final' } dependencies { - annotationProcessor 'com.github.therapi:therapi-runtime-javadoc-scribe:0.13.0' - annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.3.Final' - annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' + kapt 'org.springframework.boot:spring-boot-configuration-processor' implementation 'org.springframework.boot:spring-boot-starter-test' implementation 'org.springframework.boot:spring-boot-starter-web' @@ -41,9 +43,16 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-mongodb' implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-cache' + //springdoc相关依赖没有被自动管理,必须保留版本号 implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0' + kapt 'com.github.therapi:therapi-runtime-javadoc-scribe:0.15.0' + + // kotlin + implementation "com.fasterxml.jackson.module:jackson-module-kotlin" + implementation "org.jetbrains.kotlin:kotlin-reflect" + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'com.sun.mail:javax.mail:1.6.2' @@ -52,7 +61,11 @@ dependencies { implementation "cn.hutool:hutool-jwt:$hutoolVersion" implementation "cn.hutool:hutool-dfa:$hutoolVersion" - implementation 'org.mapstruct:mapstruct:1.5.5.Final' + // mapstruct and lombok + implementation "org.mapstruct:mapstruct:${mapstructVersion}" + kapt "org.projectlombok:lombok-mapstruct-binding:0.2.0" + kapt "org.mapstruct:mapstruct-processor:${mapstructVersion}" + implementation 'org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r' implementation 'org.eclipse.jgit:org.eclipse.jgit.ssh.apache.agent:6.6.0.202305301015-r' implementation 'org.freemarker:freemarker:2.3.32' @@ -66,6 +79,10 @@ dependencies { } +kapt { + keepJavacAnnotationProcessors = true +} + test { useJUnitPlatform() } @@ -122,7 +139,7 @@ swaggerSources { } } -rootProject.afterEvaluate(){ +rootProject.afterEvaluate() { def forkedSpringBootRun = project.tasks.named("forkedSpringBootRun") forkedSpringBootRun.configure { doNotTrackState("See https://github.com/springdoc/springdoc-openapi-gradle-plugin/issues/102") diff --git a/src/main/java/plus/maa/backend/MainApplication.kt b/src/main/java/plus/maa/backend/MainApplication.kt index 91038693..4c5d416b 100644 --- a/src/main/java/plus/maa/backend/MainApplication.kt +++ b/src/main/java/plus/maa/backend/MainApplication.kt @@ -1,24 +1,21 @@ -package plus.maa.backend; +package plus.maa.backend -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.boot.context.properties.ConfigurationPropertiesScan; -import org.springframework.cache.annotation.EnableCaching; -import org.springframework.scheduling.annotation.EnableAsync; -import org.springframework.scheduling.annotation.EnableScheduling; -import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.context.properties.ConfigurationPropertiesScan +import org.springframework.boot.runApplication +import org.springframework.cache.annotation.EnableCaching +import org.springframework.scheduling.annotation.EnableAsync +import org.springframework.scheduling.annotation.EnableScheduling +import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity -/** - * @author AnselYuki - */ @EnableAsync @EnableCaching @EnableScheduling @SpringBootApplication @ConfigurationPropertiesScan @EnableMethodSecurity -public class MainApplication { - public static void main(String[] args) { - SpringApplication.run(MainApplication.class, args); - } +class MainApplication + +fun main(args: Array) { + runApplication(*args) } diff --git a/src/main/java/plus/maa/backend/config/external/ArkLevelGit.kt b/src/main/java/plus/maa/backend/config/external/ArkLevelGit.kt index d8a860e1..8ecabc50 100644 --- a/src/main/java/plus/maa/backend/config/external/ArkLevelGit.kt +++ b/src/main/java/plus/maa/backend/config/external/ArkLevelGit.kt @@ -1,9 +1,8 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class ArkLevelGit { - private String repository; - private String localRepository; - private String jsonPath; -} +data class ArkLevelGit( + var repository: String = "https://github.com/MaaAssistantArknights/MaaAssistantArknights.git", + var localRepository: String = "./MaaAssistantArknights", + var jsonPath: String = "resource/Arknights-Tile-Pos/", +) diff --git a/src/main/java/plus/maa/backend/config/external/Cache.kt b/src/main/java/plus/maa/backend/config/external/Cache.kt index 4f2e7ede..99060b2b 100644 --- a/src/main/java/plus/maa/backend/config/external/Cache.kt +++ b/src/main/java/plus/maa/backend/config/external/Cache.kt @@ -1,6 +1,6 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class Cache { - private long defaultExpire; -} + +data class Cache ( + var defaultExpire: Long = 0 +) diff --git a/src/main/java/plus/maa/backend/config/external/Copilot.kt b/src/main/java/plus/maa/backend/config/external/Copilot.kt index 9d06b5dd..110702b5 100644 --- a/src/main/java/plus/maa/backend/config/external/Copilot.kt +++ b/src/main/java/plus/maa/backend/config/external/Copilot.kt @@ -1,14 +1,12 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -import lombok.Data; -@Data -public class Copilot { - - /** - * 作业评分总数少于指定值时显示评分不足 - *

- * 默认值:50 - */ - private int minValueShowNotEnoughRating = 50; -} +data class Copilot( + /** + * 作业评分总数少于指定值时显示评分不足 + * + * + * 默认值:50 + */ + var minValueShowNotEnoughRating: Int = 50 +) diff --git a/src/main/java/plus/maa/backend/config/external/CopilotBackup.kt b/src/main/java/plus/maa/backend/config/external/CopilotBackup.kt index 845627c4..c8acf580 100644 --- a/src/main/java/plus/maa/backend/config/external/CopilotBackup.kt +++ b/src/main/java/plus/maa/backend/config/external/CopilotBackup.kt @@ -1,16 +1,29 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class CopilotBackup { - // 是禁用备份功能 - private boolean disabled; - // 本地备份地址 - private String dir; - // 远程备份地址 - private String uri; - // git 用户名 - private String username; - // git 邮箱 - private String email; -} +data class CopilotBackup( + /** + * 是否禁用备份功能 + */ + var disabled: Boolean = false, + + /** + * 本地备份地址 + * */ + var dir: String = "/home/dove/copilotBak", + + /** + * 远程备份地址 + */ + var uri: String = "git@github.com:dragove/maa-copilot-store.git", + + /** + * git 用户名 + */ + var username: String = "dragove", + + /** + * git 邮箱 + */ + var email: String = "dragove@qq.com", +) diff --git a/src/main/java/plus/maa/backend/config/external/Github.kt b/src/main/java/plus/maa/backend/config/external/Github.kt index 6f6d9d07..a5bfe359 100644 --- a/src/main/java/plus/maa/backend/config/external/Github.kt +++ b/src/main/java/plus/maa/backend/config/external/Github.kt @@ -1,9 +1,9 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class Github { - /** - * GitHub api token - */ - private String token; -} \ No newline at end of file + +data class Github( + /** + * GitHub api token + */ + var token: String = "github_pat_xxx" +) \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/config/external/Info.kt b/src/main/java/plus/maa/backend/config/external/Info.kt index eca8e46e..5aef2129 100644 --- a/src/main/java/plus/maa/backend/config/external/Info.kt +++ b/src/main/java/plus/maa/backend/config/external/Info.kt @@ -1,10 +1,10 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class Info { - private String title; - private String description; - private String version; - private String domain; - private String frontendDomain; -} \ No newline at end of file + +data class Info( + var title: String = "MAA Copilot Center API", + var description: String = "MAA Copilot Backend Center", + var version: String = "v1.0.0", + var domain: String = "https://prts.maa.plus", + var frontendDomain: String = "https://prts.plus", +) diff --git a/src/main/java/plus/maa/backend/config/external/Jwt.kt b/src/main/java/plus/maa/backend/config/external/Jwt.kt index 94f6f578..dccdaef3 100644 --- a/src/main/java/plus/maa/backend/config/external/Jwt.kt +++ b/src/main/java/plus/maa/backend/config/external/Jwt.kt @@ -1,26 +1,24 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class Jwt { - /** - * Header name - */ - private String header; - /** - * 默认的JwtToken过期时间,以秒为单位 - */ - private long expire = 21600; - - /* - * 默认的 Refresh Token 过期时间,以秒为单位 - */ - private long refreshExpire = 30 * 24 * 60 * 60; - /** - * JwtToken的加密密钥 - */ - private String secret; - /** - * Jwt 最大同时登录设备数 - */ - private int maxLogin = 1; -} \ No newline at end of file +data class Jwt( + /** + * Header name + */ + var header: String = "Authorization", + /** + * 默认的JwtToken过期时间,以秒为单位 + */ + var expire: Long = 21600, + /* + * 默认的 Refresh Token 过期时间,以秒为单位 + */ + var refreshExpire: Long = (30 * 24 * 60 * 60).toLong(), + /** + * JwtToken的加密密钥 + */ + var secret: String = "", + /** + * Jwt 最大同时登录设备数 + */ + var maxLogin: Int = 1, +) \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.kt b/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.kt index 7ecc8141..797456b8 100644 --- a/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.kt +++ b/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.kt @@ -1,34 +1,42 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.NestedConfigurationProperty; -import org.springframework.stereotype.Component; +import org.springframework.boot.context.properties.ConfigurationProperties +import org.springframework.boot.context.properties.NestedConfigurationProperty +import org.springframework.stereotype.Component -@Data @Component @ConfigurationProperties("maa-copilot") -public class MaaCopilotProperties { - @NestedConfigurationProperty - private Jwt jwt; - @NestedConfigurationProperty - private Github github; - @NestedConfigurationProperty - private Info info; - @NestedConfigurationProperty - private Vcode vcode; - @NestedConfigurationProperty - private Cache cache; - @NestedConfigurationProperty - private ArkLevelGit arkLevelGit; - @NestedConfigurationProperty - private TaskCron taskCron; - @NestedConfigurationProperty - private CopilotBackup backup; - @NestedConfigurationProperty - private Mail mail; - @NestedConfigurationProperty - private SensitiveWord sensitiveWord; - @NestedConfigurationProperty - private Copilot copilot = new Copilot(); -} +data class MaaCopilotProperties( + @NestedConfigurationProperty + var jwt: Jwt = Jwt(), + + @NestedConfigurationProperty + var github: Github = Github(), + + @NestedConfigurationProperty + var info: Info = Info(), + + @NestedConfigurationProperty + var vcode: Vcode = Vcode(), + + @NestedConfigurationProperty + var cache: Cache = Cache(), + + @NestedConfigurationProperty + var arkLevelGit: ArkLevelGit = ArkLevelGit(), + + @NestedConfigurationProperty + var taskCron: TaskCron = TaskCron(), + + @NestedConfigurationProperty + var backup: CopilotBackup = CopilotBackup(), + + @NestedConfigurationProperty + var mail: Mail = Mail(), + + @NestedConfigurationProperty + var sensitiveWord: SensitiveWord = SensitiveWord(), + + @NestedConfigurationProperty + var copilot: Copilot = Copilot() +) \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/config/external/Mail.kt b/src/main/java/plus/maa/backend/config/external/Mail.kt index 8cafbbd3..14d1c4bf 100644 --- a/src/main/java/plus/maa/backend/config/external/Mail.kt +++ b/src/main/java/plus/maa/backend/config/external/Mail.kt @@ -1,19 +1,13 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -import lombok.Data; -/** - * @author LoMu - * Date 2023-03-04 14:49 - */ -@Data -public class Mail { - private String host; - private Integer port; - private String from; - private String user; - private String pass; - private Boolean starttls; - private Boolean ssl; - private Boolean notification; -} +data class Mail( + var host: String = "smtp.qq.com", + var port: Int = 465, + var from: String = "2842775752@qq.com", + var user: String = "2842775752", + var pass: String = "123456789", + var starttls: Boolean = true, + var ssl: Boolean = false, + var notification: Boolean = true, +) diff --git a/src/main/java/plus/maa/backend/config/external/SensitiveWord.kt b/src/main/java/plus/maa/backend/config/external/SensitiveWord.kt index 535ca52a..587a2206 100644 --- a/src/main/java/plus/maa/backend/config/external/SensitiveWord.kt +++ b/src/main/java/plus/maa/backend/config/external/SensitiveWord.kt @@ -1,6 +1,9 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class SensitiveWord { - private String path; -} + +data class SensitiveWord( + /** + * 敏感词文件路径,默认为 `classpath:sensitive-word.txt` + */ + var path: String = "classpath:sensitive-word.txt" +) diff --git a/src/main/java/plus/maa/backend/config/external/TaskCron.kt b/src/main/java/plus/maa/backend/config/external/TaskCron.kt index 09f8f210..c301b45e 100644 --- a/src/main/java/plus/maa/backend/config/external/TaskCron.kt +++ b/src/main/java/plus/maa/backend/config/external/TaskCron.kt @@ -1,8 +1,6 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class TaskCron { - - private String arkLevel; - -} +data class TaskCron( + var arkLevel: String = "-", + var copilotUpdate: String = "-" +) diff --git a/src/main/java/plus/maa/backend/config/external/Vcode.kt b/src/main/java/plus/maa/backend/config/external/Vcode.kt index 34690eee..da90495b 100644 --- a/src/main/java/plus/maa/backend/config/external/Vcode.kt +++ b/src/main/java/plus/maa/backend/config/external/Vcode.kt @@ -1,9 +1,8 @@ -package plus.maa.backend.config.external; +package plus.maa.backend.config.external -@lombok.Data -public class Vcode { - /** - * 默认的验证码失效时间,以秒为单位 - */ - private long expire; -} \ No newline at end of file +data class Vcode( + /** + * 默认的验证码失效时间,以秒为单位 + */ + var expire: Long = 0 +) \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/controller/SystemController.kt b/src/main/java/plus/maa/backend/controller/SystemController.kt index b906d8cb..dfd7c14c 100644 --- a/src/main/java/plus/maa/backend/controller/SystemController.kt +++ b/src/main/java/plus/maa/backend/controller/SystemController.kt @@ -1,18 +1,12 @@ -package plus.maa.backend.controller; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; -import org.springframework.boot.info.GitProperties; -import org.springframework.lang.Nullable; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.controller.response.MaaResult; -import plus.maa.backend.controller.response.MaaSystemInfo; +package plus.maa.backend.controller +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.boot.info.GitProperties +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.controller.response.MaaResult /** * @author AnselYuki @@ -20,31 +14,35 @@ import plus.maa.backend.controller.response.MaaSystemInfo; @Tag(name = "System", description = "系统管理接口") @RequestMapping("") @RestController -@RequiredArgsConstructor -public class SystemController { - - private final MaaCopilotProperties properties; - @Nullable // 非必须字段,当 Git 仓库不存在时为 null - private final GitProperties gitProperties; +class SystemController( + private val properties: MaaCopilotProperties, + private val gitProperties: GitProperties? +) { + /** + * Tests if the server is ready. + * @return 系统启动信息 + */ @GetMapping("/") - @Operation(summary = "Tests if the server is ready.") - @ApiResponse(description = "系统启动信息") - public MaaResult test() { - return MaaResult.success("Maa Copilot Server is Running", null); + fun test(): MaaResult { + return MaaResult.success("Maa Copilot Server is Running", null) } + /** + * Gets the current version of the server. + * @return 系统版本信息 + */ @GetMapping("version") - @Operation(summary = "Gets the current version of the server.") - @ApiResponse(description = "系统版本信息") - public MaaResult getSystemVersion() { - var systemInfo = new MaaSystemInfo(); - var info = properties.getInfo(); - systemInfo.setTitle(info.getTitle()); - systemInfo.setDescription(info.getDescription()); - systemInfo.setVersion(info.getVersion()); - systemInfo.setGit(gitProperties); - return MaaResult.success(systemInfo); + fun getSystemVersion(): MaaResult { + val info = properties.info + val systemInfo = MaaSystemInfo(info.title, info.description, info.version, gitProperties!!) + return MaaResult.success(systemInfo) } -} + data class MaaSystemInfo( + val title: String, + val description: String, + val version: String, + val git: GitProperties, + ) +} \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/controller/response/MaaResult.kt b/src/main/java/plus/maa/backend/controller/response/MaaResult.kt index de2cb5da..bf74c443 100644 --- a/src/main/java/plus/maa/backend/controller/response/MaaResult.kt +++ b/src/main/java/plus/maa/backend/controller/response/MaaResult.kt @@ -1,32 +1,36 @@ -package plus.maa.backend.controller.response; +package plus.maa.backend.controller.response -import com.fasterxml.jackson.annotation.JsonInclude; - -import java.io.Serializable; +import com.fasterxml.jackson.annotation.JsonInclude /** * @author AnselYuki */ @JsonInclude(JsonInclude.Include.NON_NULL) -public record MaaResult(int statusCode, String message, T data) implements Serializable { - public static MaaResult success(T data) { - return success(null, data); - } - - public static MaaResult success() { - return success(null, null); - } - - public static MaaResult success(String msg, T data) { - return new MaaResult<>(200, msg, data); +data class MaaResult(val statusCode: Int, val message: String?, val data: T) { + companion object { + @JvmStatic + fun success(data: T): MaaResult { + return success(null, data) + } + + @JvmStatic + fun success(): MaaResult { + return success(null, null) + } + + @JvmStatic + fun success(msg: String?, data: T): MaaResult { + return MaaResult(200, msg, data) + } + + @JvmStatic + fun fail(code: Int, msg: String?): MaaResult { + return fail(code, msg, null) + } + + @JvmStatic + fun fail(code: Int, msg: String?, data: T): MaaResult { + return MaaResult(code, msg, data) + } } - - public static MaaResult fail(int code, String msg) { - return fail(code, msg, null); - } - - public static MaaResult fail(int code, String msg, T data) { - return new MaaResult<>(code, msg, data); - } - } \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java b/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java deleted file mode 100644 index 51558746..00000000 --- a/src/main/java/plus/maa/backend/controller/response/MaaSystemInfo.java +++ /dev/null @@ -1,15 +0,0 @@ -package plus.maa.backend.controller.response; - -import lombok.Data; -import org.springframework.boot.info.GitProperties; - -/** - * @author AnselYuki - */ -@Data -public class MaaSystemInfo { - private String title; - private String description; - private String version; - private GitProperties git; -} diff --git a/src/main/java/plus/maa/backend/task/CopilotBackupTask.java b/src/main/java/plus/maa/backend/task/CopilotBackupTask.java index dd56f9c1..1a3d21f9 100644 --- a/src/main/java/plus/maa/backend/task/CopilotBackupTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotBackupTask.java @@ -62,7 +62,7 @@ public class CopilotBackupTask { @PostConstruct public void initGit() { CopilotBackup backup = config.getBackup(); - if (backup.isDisabled()) { + if (backup.getDisabled()) { return; } File repoDir = new File(backup.getDir()); @@ -95,7 +95,7 @@ public void initGit() { */ @Scheduled(cron = "${maa-copilot.task-cron.copilot-update:-}") public void backupCopilots() { - if (config.getBackup().isDisabled() || Objects.isNull(git)) { + if (config.getBackup().getDisabled() || Objects.isNull(git)) { return; } try { diff --git a/src/main/resources/application-template.yml b/src/main/resources/application-template.yml index 6d8ae4f3..5d160c0d 100644 --- a/src/main/resources/application-template.yml +++ b/src/main/resources/application-template.yml @@ -63,7 +63,8 @@ maa-copilot: notification: true copilot: min-value-show-not-enough-rating: 50 - + sensitive-word: + path: "classpath:sensitive-word.txt" springdoc: From ad07463f7afaa57c9c0707195c2d904cdc1ad65e Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Mon, 5 Feb 2024 15:25:26 +0800 Subject: [PATCH 059/168] Rename .java to .kt --- .../maa/backend/common/{MaaStatusCode.java => MaaStatusCode.kt} | 0 .../entity/gamedata/{ArkCharacter.java => ArkCharacter.kt} | 0 .../repository/entity/gamedata/{ArkStage.java => ArkStage.kt} | 0 .../service/{ArkGameDataService.java => ArkGameDataService.kt} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/common/{MaaStatusCode.java => MaaStatusCode.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/gamedata/{ArkCharacter.java => ArkCharacter.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/gamedata/{ArkStage.java => ArkStage.kt} (100%) rename src/main/java/plus/maa/backend/service/{ArkGameDataService.java => ArkGameDataService.kt} (100%) diff --git a/src/main/java/plus/maa/backend/common/MaaStatusCode.java b/src/main/java/plus/maa/backend/common/MaaStatusCode.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/MaaStatusCode.java rename to src/main/java/plus/maa/backend/common/MaaStatusCode.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.java rename to src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.java rename to src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt diff --git a/src/main/java/plus/maa/backend/service/ArkGameDataService.java b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/ArkGameDataService.java rename to src/main/java/plus/maa/backend/service/ArkGameDataService.kt From c62efd6d181a09efe52e22dc82c663d6ef632c5c Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Mon, 5 Feb 2024 15:25:27 +0800 Subject: [PATCH 060/168] refactor: migrate ArkGameDataService and some data types to kt --- build.gradle | 3 + .../plus/maa/backend/common/MaaStatusCode.kt | 10 +- .../response/MaaResultException.java | 4 +- .../entity/gamedata/ArkCharacter.kt | 20 +- .../repository/entity/gamedata/ArkStage.kt | 26 +- .../maa/backend/service/ArkGameDataService.kt | 416 +++++++++--------- 6 files changed, 227 insertions(+), 252 deletions(-) diff --git a/build.gradle b/build.gradle index af0def8a..33fc5dd3 100644 --- a/build.gradle +++ b/build.gradle @@ -54,6 +54,9 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-reflect" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + // kotlin-logging + implementation 'io.github.oshai:kotlin-logging-jvm:5.1.0' + implementation 'com.squareup.okhttp3:okhttp:4.10.0' implementation 'com.sun.mail:javax.mail:1.6.2' // 双引号才能使用变量 diff --git a/src/main/java/plus/maa/backend/common/MaaStatusCode.kt b/src/main/java/plus/maa/backend/common/MaaStatusCode.kt index 58e1cdbd..4e86edb8 100644 --- a/src/main/java/plus/maa/backend/common/MaaStatusCode.kt +++ b/src/main/java/plus/maa/backend/common/MaaStatusCode.kt @@ -1,12 +1,9 @@ -package plus.maa.backend.common; - -import lombok.AllArgsConstructor; +package plus.maa.backend.common /** * @author AnselYuki */ -@AllArgsConstructor -public enum MaaStatusCode { +enum class MaaStatusCode(val code:Int,val message:String) { /** * MAA自定义状态码 */ @@ -15,8 +12,5 @@ public enum MaaStatusCode { MAA_USER_NOT_ENABLED(10003, "用户未启用"), MAA_USER_EXISTS(10004, "用户已存在"), MAA_REGISTRATION_CODE_NOT_FOUND(10011, "注册验证码错误"), - ; - public final int code; - public final String message; } diff --git a/src/main/java/plus/maa/backend/controller/response/MaaResultException.java b/src/main/java/plus/maa/backend/controller/response/MaaResultException.java index 5d98c3f9..9c385452 100644 --- a/src/main/java/plus/maa/backend/controller/response/MaaResultException.java +++ b/src/main/java/plus/maa/backend/controller/response/MaaResultException.java @@ -21,7 +21,7 @@ public MaaResultException(String msg) { } public MaaResultException(MaaStatusCode statusCode) { - this.code = statusCode.code; - this.msg = statusCode.message; + this.code = statusCode.getCode(); + this.msg = statusCode.getMessage(); } } diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt index 91da06ee..8457fdd9 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt @@ -1,15 +1,9 @@ -package plus.maa.backend.repository.entity.gamedata; +package plus.maa.backend.repository.entity.gamedata -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class ArkCharacter { - private String id; - private String name; - private String profession; - private int rarity; +data class ArkCharacter ( + val name: String, + val profession: String, + val rarity: Int +) { + var id: String? = null } diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt index a2cc37e4..071112a9 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt @@ -1,28 +1,24 @@ -package plus.maa.backend.repository.entity.gamedata; +package plus.maa.backend.repository.entity.gamedata -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class ArkStage { +data class ArkStage( /** - * 关卡ID, 需转换为全小写后使用
+ * 关卡ID, 需转换为全小写后使用

* 例: Activities/ACT5D0/level_act5d0_ex08 */ - private String levelId; + val levelId: String, + /** * 例: act14d7_zone2 */ - private String zoneId; + val zoneId: String, + /** * 例: act5d0_ex08 */ - private String stageId; + val stageId: String, + /** * 例: CB-EX8 */ - private String code; -} + val code: String +) \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt index 9630e700..391984ca 100644 --- a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt +++ b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt @@ -1,108 +1,93 @@ -package plus.maa.backend.service; +package plus.maa.backend.service -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okhttp3.ResponseBody; -import org.jetbrains.annotations.Nullable; -import org.springframework.stereotype.Service; -import org.springframework.util.ObjectUtils; -import plus.maa.backend.common.utils.ArkLevelUtil; -import plus.maa.backend.repository.entity.gamedata.*; +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.json.JsonMapper +import io.github.oshai.kotlinlogging.KotlinLogging +import okhttp3.OkHttpClient +import okhttp3.Request +import org.springframework.stereotype.Service +import org.springframework.util.ObjectUtils +import plus.maa.backend.common.utils.ArkLevelUtil +import plus.maa.backend.repository.entity.gamedata.* +import java.util.* +import java.util.concurrent.ConcurrentHashMap -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; +private val log = KotlinLogging.logger {} /** * @author john180 */ -@Slf4j @Service -@RequiredArgsConstructor -public class ArkGameDataService { - private static final String ARK_STAGE = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/stage_table.json"; - private static final String ARK_ZONE = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/zone_table.json"; - private static final String ARK_ACTIVITY = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/activity_table.json"; - private static final String ARK_CHARACTER = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/character_table.json"; - private static final String ARK_TOWER = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/climb_tower_table.json"; - private static final String ARK_CRISIS_V2 = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/crisis_v2_table.json"; - private final OkHttpClient okHttpClient; - private final ObjectMapper mapper = JsonMapper.builder() - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .build(); - private Map stageMap = new ConcurrentHashMap<>(); - private Map levelStageMap = new ConcurrentHashMap<>(); - private Map zoneMap = new ConcurrentHashMap<>(); - private Map zoneActivityMap = new ConcurrentHashMap<>(); - private Map arkCharacterMap = new ConcurrentHashMap<>(); - private Map arkTowerMap = new ConcurrentHashMap<>(); - private Map arkCrisisV2InfoMap = new ConcurrentHashMap<>(); +class ArkGameDataService(private val okHttpClient: OkHttpClient) { - public boolean syncGameData() { + companion object { + private const val ARK_STAGE = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/stage_table.json" + private const val ARK_ZONE = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/zone_table.json" + private const val ARK_ACTIVITY = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/activity_table.json" + private const val ARK_CHARACTER = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/character_table.json" + private const val ARK_TOWER = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/climb_tower_table.json" + private const val ARK_CRISIS_V2 = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/crisis_v2_table.json" + } + + private final val mapper = JsonMapper.builder() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build() + private val stageMap = ConcurrentHashMap() + private val levelStageMap = ConcurrentHashMap() + private val zoneMap = ConcurrentHashMap() + private val zoneActivityMap = ConcurrentHashMap() + private val arkCharacterMap = ConcurrentHashMap() + private val arkTowerMap = ConcurrentHashMap() + private val arkCrisisV2InfoMap = ConcurrentHashMap() + + fun syncGameData(): Boolean{ return syncStage() && syncZone() && syncActivity() && syncCharacter() && syncTower() && - syncCrisisV2Info(); + syncCrisisV2Info() } - @Nullable - public ArkStage findStage(String levelId, String code, String stageId) { - ArkStage stage = levelStageMap.get(levelId.toLowerCase()); - if (stage != null && stage.getCode().equalsIgnoreCase(code)) { - return stage; + fun findStage(levelId:String,code:String,stageId:String):ArkStage? { + val stage = levelStageMap[levelId.lowercase(Locale.getDefault())] + if (stage != null && stage.code.equals(code, ignoreCase = true)) { + return stage } - return stageMap.get(stageId); + return stageMap[stageId] } - @Nullable - public ArkZone findZone(String levelId, String code, String stageId) { - ArkStage stage = findStage(levelId, code, stageId); + fun findZone(levelId: String, code: String, stageId: String): ArkZone? { + val stage = findStage(levelId, code, stageId) if (stage == null) { - log.error("[DATA]stage不存在:{}, Level: {}", stageId, levelId); - return null; + log.error { "${"[DATA]stage不存在:{}, Level: {}"} $stageId $levelId" } + return null } - ArkZone zone = zoneMap.get(stage.getZoneId()); + val zone = zoneMap[stage.zoneId] if (zone == null) { - log.error("[DATA]zone不存在:{}, Level: {}", stage.getZoneId(), levelId); + log.error { "${"[DATA]zone不存在:{}, Level: {}"} ${stage.zoneId} $levelId" } } - return zone; + return zone } - @Nullable - public ArkTower findTower(String zoneId) { - return arkTowerMap.get(zoneId); - } + fun findTower(zoneId: String) = arkTowerMap[zoneId] - @Nullable - public ArkCharacter findCharacter(String characterId) { - String[] ids = characterId.split("_"); - return arkCharacterMap.get(ids[ids.length - 1]); - } - @Nullable - public ArkActivity findActivityByZoneId(String zoneId) { - return zoneActivityMap.get(zoneId); + fun findCharacter(characterId: String): ArkCharacter? { + val ids = characterId.split("_") + return arkCharacterMap[ids[ids.size - 1]] } + fun findActivityByZoneId(zoneId: String) = zoneActivityMap[zoneId] + /** * 通过 stageId 或者 seasonId 提取危机合约信息 * * @param id stageId 或者 seasonId * @return 危机合约信息,包含合约名、开始时间、结束时间等 */ - @Nullable - public ArkCrisisV2Info findCrisisV2InfoById(String id) { - return findCrisisV2InfoByKeyInfo(ArkLevelUtil.getKeyInfoById(id)); - } + fun findCrisisV2InfoById(id: String) = findCrisisV2InfoByKeyInfo(ArkLevelUtil.getKeyInfoById(id)) /** * 通过地图系列的唯一标识提取危机合约信息 @@ -110,172 +95,175 @@ public class ArkGameDataService { * @param keyInfo 地图系列的唯一标识 * @return 危机合约信息,包含合约名、开始时间、结束时间等 */ - @Nullable - public ArkCrisisV2Info findCrisisV2InfoByKeyInfo(String keyInfo) { - return arkCrisisV2InfoMap.get(keyInfo); - } + fun findCrisisV2InfoByKeyInfo(keyInfo: String) = arkCrisisV2InfoMap[keyInfo] - private boolean syncStage() { - Request req = new Request.Builder().url(ARK_STAGE).get().build(); - try (Response rsp = okHttpClient.newCall(req).execute()) { - ResponseBody body = rsp.body(); - if (body == null) { - log.error("[DATA]获取stage数据失败"); - return false; - } - JsonNode node = mapper.reader().readTree(body.string()); - JsonNode stagesNode = node.get("stages"); - Map temp = mapper.convertValue(stagesNode, new TypeReference<>() { - }); - stageMap = new ConcurrentHashMap<>(); - levelStageMap = new ConcurrentHashMap<>(); - temp.forEach((k, v) -> { - stageMap.put(k, v); - if (!ObjectUtils.isEmpty(v.getLevelId())) { - levelStageMap.put(v.getLevelId().toLowerCase(), v); - } - }); + private fun syncStage(): Boolean { + val req = Request.Builder().url(ARK_STAGE).get().build() - log.info("[DATA]获取stage数据成功, 共{}条", levelStageMap.size()); - } catch (Exception e) { - log.error("[DATA]同步stage数据异常", e); - return false; + okHttpClient.newCall(req).execute().use { rsp -> + try { + val body = rsp.body + if(body == null) { + log.error { "[DATA]获取stage数据失败" } + return false + } + val node = mapper.reader().readTree(body.string()) + val stagesNode = node.get("stages") + val temp = mapper.convertValue(stagesNode, object : TypeReference>() {}) + stageMap.clear() + levelStageMap.clear() + temp.forEach { (k, v) -> + stageMap[k] = v + if (!ObjectUtils.isEmpty(v.levelId)) { + levelStageMap[v.levelId.lowercase(Locale.getDefault())] = v + } + } + log.info { "${"[DATA]获取stage数据成功, 共{}条"} ${levelStageMap.size}" } + } catch (e: Exception) { + log.error(e) { "[DATA]同步stage数据异常" } + return false + } } - return true; + return true } - private boolean syncZone() { - Request req = new Request.Builder().url(ARK_ZONE).get().build(); - try (Response rsp = okHttpClient.newCall(req).execute()) { - ResponseBody body = rsp.body(); - if (body == null) { - log.error("[DATA]获取zone数据失败"); - return false; + private fun syncZone(): Boolean { + val req = Request.Builder().url(ARK_ZONE).get().build() + okHttpClient.newCall(req).execute().use { rsp -> + try { + val body = rsp.body + if(body == null) { + log.error { "[DATA]获取zone数据失败" } + return false + } + val node = mapper.reader().readTree(body.string()) + val zonesNode = node.get("zones") + val temp = mapper.convertValue(zonesNode, object : TypeReference>() {}) + zoneMap.clear() + zoneMap.putAll(temp) + log.info { "${"[DATA]获取zone数据成功, 共{}条"} ${zoneMap.size}" } + } catch (e: Exception) { + log.error(e) { "[DATA]同步zone数据异常" } + return false } - JsonNode node = mapper.reader().readTree(body.string()); - JsonNode zonesNode = node.get("zones"); - Map temp = mapper.convertValue(zonesNode, new TypeReference<>() { - }); - zoneMap = new ConcurrentHashMap<>(temp); - log.info("[DATA]获取zone数据成功, 共{}条", zoneMap.size()); - } catch (Exception e) { - log.error("[DATA]同步zone数据异常", e); - return false; } - return true; - } - private boolean syncActivity() { - Request req = new Request.Builder().url(ARK_ACTIVITY).get().build(); - try (Response rsp = okHttpClient.newCall(req).execute()) { - ResponseBody body = rsp.body(); - if (body == null) { - log.error("[DATA]获取activity数据失败"); - return false; - } - JsonNode node = mapper.reader().readTree(body.string()); + return true + } - //zoneId转换活动Id - JsonNode zonesNode = node.get("zoneToActivity"); - Map zoneToActivity = mapper.convertValue(zonesNode, new TypeReference<>() { - }); - //活动信息 - JsonNode baseInfoNode = node.get("basicInfo"); - Map baseInfos = mapper.convertValue(baseInfoNode, new TypeReference<>() { - }); - Map temp = new ConcurrentHashMap<>(); - zoneToActivity.forEach((zoneId, actId) -> { - ArkActivity act = baseInfos.get(actId); - if (act != null) { - temp.put(zoneId, act); + private fun syncActivity(): Boolean { + val req = Request.Builder().url(ARK_ACTIVITY).get().build() + okHttpClient.newCall(req).execute().use { rsp -> + try { + val body = rsp.body + if(body == null) { + log.error { "[DATA]获取activity数据失败" } + return false } - }); - zoneActivityMap = temp; - - log.info("[DATA]获取activity数据成功, 共{}条", zoneActivityMap.size()); - } catch (Exception e) { - log.error("[DATA]同步activity数据异常", e); - return false; + val node = mapper.reader().readTree(body.string()) + val zonesNode = node.get("zoneToActivity") + val zoneToActivity = mapper.convertValue(zonesNode, object : TypeReference>() {}) + val baseInfoNode = node.get("basicInfo") + val baseInfos = mapper.convertValue(baseInfoNode, object : TypeReference>() {}) + val temp = ConcurrentHashMap() + zoneToActivity.forEach { (zoneId, actId) -> + val act = baseInfos[actId] + if (act != null) { + temp[zoneId] = act + } + } + zoneActivityMap.clear() + zoneActivityMap.putAll(temp) + log.info { "${"[DATA]获取activity数据成功, 共{}条"} ${zoneActivityMap.size}" } + } catch (e: Exception) { + log.error(e) { "[DATA]同步activity数据异常" } + return false + } } - return true; + + return true } - private boolean syncCharacter() { - Request req = new Request.Builder().url(ARK_CHARACTER).get().build(); - try (Response rsp = okHttpClient.newCall(req).execute()) { - ResponseBody body = rsp.body(); - if (body == null) { - log.error("[DATA]获取character数据失败"); - return false; - } - JsonNode node = mapper.reader().readTree(body.string()); - Map characters = mapper.convertValue(node, new TypeReference<>() { - }); - characters.forEach((id, c) -> c.setId(id)); - Map temp = new ConcurrentHashMap<>(); - characters.values().forEach(c -> { - if (ObjectUtils.isEmpty(c.getId())) { - return; + private fun syncCharacter(): Boolean { + val req = Request.Builder().url(ARK_CHARACTER).get().build() + okHttpClient.newCall(req).execute().use { rsp -> + try { + val body = rsp.body + if(body == null) { + log.error { "[DATA]获取character数据失败" } + return false } - String[] ids = c.getId().split("_"); - if (ids.length != 3) { - //不是干员 - return; + val node = mapper.reader().readTree(body.string()) + val characters = mapper.convertValue(node, object : TypeReference>() {}) + characters.forEach { (id, c) -> c.id = id } + arkCharacterMap.clear() + characters.values.forEach { c -> + if (c.id.isNullOrBlank()) { + return@forEach + } + val ids = c.id!!.split("_") + if (ids.size != 3) { + // 不是干员 + return@forEach + } + arkCharacterMap[ids[2]] = c } - temp.put(ids[2], c); - }); - arkCharacterMap = temp; - - log.info("[DATA]获取character数据成功, 共{}条", arkCharacterMap.size()); - } catch (Exception e) { - log.error("[DATA]同步character数据异常", e); - return false; + log.info { "${"[DATA]获取character数据成功, 共{}条"} ${arkCharacterMap.size}" } + } catch (e: Exception) { + log.error(e) { "[DATA]同步character数据异常" } + return false + } } - return true; + + return true } - private boolean syncTower() { - Request req = new Request.Builder().url(ARK_TOWER).get().build(); - try (Response rsp = okHttpClient.newCall(req).execute()) { - ResponseBody body = rsp.body(); - if (body == null) { - log.error("[DATA]获取tower数据失败"); - return false; + private fun syncTower(): Boolean { + val req = Request.Builder().url(ARK_TOWER).get().build() + okHttpClient.newCall(req).execute().use { rsp -> + try { + val body = rsp.body + if(body == null) { + log.error { "[DATA]获取tower数据失败" } + return false + } + val node = mapper.reader().readTree(body.string()) + val towerNode = node.get("towers") + arkTowerMap.clear() + arkTowerMap.putAll(mapper.convertValue(towerNode, object : TypeReference>() {})) + log.info { "${"[DATA]获取tower数据成功, 共{}条"} ${arkTowerMap.size}" } + } catch (e: Exception) { + log.error(e) { "[DATA]同步tower数据异常" } + return false } - JsonNode node = mapper.reader().readTree(body.string()); - JsonNode towerNode = node.get("towers"); - arkTowerMap = mapper.convertValue(towerNode, new TypeReference<>() { - }); - log.info("[DATA]获取tower数据成功, 共{}条", arkTowerMap.size()); - } catch (Exception e) { - log.error("[DATA]同步tower数据异常", e); - return false; } - return true; + + return true } - public boolean syncCrisisV2Info() { - Request req = new Request.Builder().url(ARK_CRISIS_V2).get().build(); - try (Response rsp = okHttpClient.newCall(req).execute()) { - ResponseBody body = rsp.body(); - if (!rsp.isSuccessful() || body == null) { - log.error("[DATA]获取crisisV2Info数据失败"); - return false; + fun syncCrisisV2Info(): Boolean { + val req = Request.Builder().url(ARK_CRISIS_V2).get().build() + okHttpClient.newCall(req).execute().use { rsp -> + try { + val body = rsp.body + if(body == null) { + log.error { "[DATA]获取crisisV2Info数据失败" } + return false + } + val node = mapper.reader().readTree(body.string()) + val crisisV2InfoNode = node.get("seasonInfoDataMap") + val crisisV2InfoMap = mapper.convertValue(crisisV2InfoNode, object : TypeReference>() {}) + val temp = ConcurrentHashMap() + crisisV2InfoMap.forEach { (k, v) -> temp[ArkLevelUtil.getKeyInfoById(k)] = v } + arkCrisisV2InfoMap.clear() + arkCrisisV2InfoMap.putAll(temp) + log.info { "${"[DATA]获取crisisV2Info数据成功, 共{}条"} ${arkCrisisV2InfoMap.size}" } + } catch (e: Exception) { + log.error(e) { "[DATA]同步crisisV2Info数据异常" } + return false } - JsonNode node = mapper.reader().readTree(body.charStream()); - JsonNode crisisV2InfoNode = node.get("seasonInfoDataMap"); - Map crisisV2InfoMap = mapper.convertValue(crisisV2InfoNode, new TypeReference<>() { - }); - Map temp = new ConcurrentHashMap<>(); - - crisisV2InfoMap.forEach((k, v) -> temp.put(ArkLevelUtil.getKeyInfoById(k), v)); - arkCrisisV2InfoMap = temp; - - log.info("[DATA]获取crisisV2Info数据成功, 共{}条", arkCrisisV2InfoMap.size()); - } catch (Exception e) { - log.error("[DATA]同步crisisV2Info数据异常", e); - return false; } - return true; + + return true } } From 42bc972a13ca5b67ae1de409ac647dd6f60797ae Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Mon, 5 Feb 2024 16:12:02 +0800 Subject: [PATCH 061/168] fix: null in ArkStage deserialization --- .../repository/entity/gamedata/ArkStage.kt | 2 +- .../maa/backend/service/ArkGameDataService.kt | 111 +++++++++--------- 2 files changed, 59 insertions(+), 54 deletions(-) diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt index 071112a9..4d29f519 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt @@ -5,7 +5,7 @@ data class ArkStage( * 关卡ID, 需转换为全小写后使用

* 例: Activities/ACT5D0/level_act5d0_ex08 */ - val levelId: String, + val levelId: String?, /** * 例: act14d7_zone2 diff --git a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt index 391984ca..967b0a94 100644 --- a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt +++ b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt @@ -2,12 +2,11 @@ package plus.maa.backend.service import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.module.kotlin.jacksonMapperBuilder import io.github.oshai.kotlinlogging.KotlinLogging import okhttp3.OkHttpClient import okhttp3.Request import org.springframework.stereotype.Service -import org.springframework.util.ObjectUtils import plus.maa.backend.common.utils.ArkLevelUtil import plus.maa.backend.repository.entity.gamedata.* import java.util.* @@ -22,15 +21,21 @@ private val log = KotlinLogging.logger {} class ArkGameDataService(private val okHttpClient: OkHttpClient) { companion object { - private const val ARK_STAGE = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/stage_table.json" - private const val ARK_ZONE = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/zone_table.json" - private const val ARK_ACTIVITY = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/activity_table.json" - private const val ARK_CHARACTER = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/character_table.json" - private const val ARK_TOWER = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/climb_tower_table.json" - private const val ARK_CRISIS_V2 = "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/crisis_v2_table.json" + private const val ARK_STAGE = + "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/stage_table.json" + private const val ARK_ZONE = + "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/zone_table.json" + private const val ARK_ACTIVITY = + "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/activity_table.json" + private const val ARK_CHARACTER = + "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/character_table.json" + private const val ARK_TOWER = + "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/climb_tower_table.json" + private const val ARK_CRISIS_V2 = + "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/crisis_v2_table.json" } - private final val mapper = JsonMapper.builder() + private final val mapper = jacksonMapperBuilder() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) .build() private val stageMap = ConcurrentHashMap() @@ -41,7 +46,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { private val arkTowerMap = ConcurrentHashMap() private val arkCrisisV2InfoMap = ConcurrentHashMap() - fun syncGameData(): Boolean{ + fun syncGameData(): Boolean { return syncStage() && syncZone() && syncActivity() && @@ -50,7 +55,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { syncCrisisV2Info() } - fun findStage(levelId:String,code:String,stageId:String):ArkStage? { + fun findStage(levelId: String, code: String, stageId: String): ArkStage? { val stage = levelStageMap[levelId.lowercase(Locale.getDefault())] if (stage != null && stage.code.equals(code, ignoreCase = true)) { return stage @@ -99,11 +104,10 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { private fun syncStage(): Boolean { val req = Request.Builder().url(ARK_STAGE).get().build() - - okHttpClient.newCall(req).execute().use { rsp -> - try { + try { + okHttpClient.newCall(req).execute().use { rsp -> val body = rsp.body - if(body == null) { + if (body == null) { log.error { "[DATA]获取stage数据失败" } return false } @@ -114,25 +118,25 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { levelStageMap.clear() temp.forEach { (k, v) -> stageMap[k] = v - if (!ObjectUtils.isEmpty(v.levelId)) { - levelStageMap[v.levelId.lowercase(Locale.getDefault())] = v + v.levelId?.let { + levelStageMap[it.lowercase(Locale.getDefault())] = v } } log.info { "${"[DATA]获取stage数据成功, 共{}条"} ${levelStageMap.size}" } - } catch (e: Exception) { - log.error(e) { "[DATA]同步stage数据异常" } - return false } + } catch (e: Exception) { + log.error(e) { "[DATA]同步stage数据异常" } + return false } return true } private fun syncZone(): Boolean { val req = Request.Builder().url(ARK_ZONE).get().build() - okHttpClient.newCall(req).execute().use { rsp -> - try { + try { + okHttpClient.newCall(req).execute().use { rsp -> val body = rsp.body - if(body == null) { + if (body == null) { log.error { "[DATA]获取zone数据失败" } return false } @@ -142,10 +146,10 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { zoneMap.clear() zoneMap.putAll(temp) log.info { "${"[DATA]获取zone数据成功, 共{}条"} ${zoneMap.size}" } - } catch (e: Exception) { - log.error(e) { "[DATA]同步zone数据异常" } - return false } + } catch (e: Exception) { + log.error(e) { "[DATA]同步zone数据异常" } + return false } return true @@ -153,10 +157,10 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { private fun syncActivity(): Boolean { val req = Request.Builder().url(ARK_ACTIVITY).get().build() - okHttpClient.newCall(req).execute().use { rsp -> - try { + try { + okHttpClient.newCall(req).execute().use { rsp -> val body = rsp.body - if(body == null) { + if (body == null) { log.error { "[DATA]获取activity数据失败" } return false } @@ -168,17 +172,17 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { val temp = ConcurrentHashMap() zoneToActivity.forEach { (zoneId, actId) -> val act = baseInfos[actId] - if (act != null) { - temp[zoneId] = act + act?.let { + temp[zoneId] = it } } zoneActivityMap.clear() zoneActivityMap.putAll(temp) log.info { "${"[DATA]获取activity数据成功, 共{}条"} ${zoneActivityMap.size}" } - } catch (e: Exception) { - log.error(e) { "[DATA]同步activity数据异常" } - return false } + } catch (e: Exception) { + log.error(e) { "[DATA]同步activity数据异常" } + return false } return true @@ -186,10 +190,10 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { private fun syncCharacter(): Boolean { val req = Request.Builder().url(ARK_CHARACTER).get().build() - okHttpClient.newCall(req).execute().use { rsp -> - try { + try { + okHttpClient.newCall(req).execute().use { rsp -> val body = rsp.body - if(body == null) { + if (body == null) { log.error { "[DATA]获取character数据失败" } return false } @@ -209,10 +213,10 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { arkCharacterMap[ids[2]] = c } log.info { "${"[DATA]获取character数据成功, 共{}条"} ${arkCharacterMap.size}" } - } catch (e: Exception) { - log.error(e) { "[DATA]同步character数据异常" } - return false } + } catch (e: Exception) { + log.error(e) { "[DATA]同步character数据异常" } + return false } return true @@ -220,10 +224,10 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { private fun syncTower(): Boolean { val req = Request.Builder().url(ARK_TOWER).get().build() - okHttpClient.newCall(req).execute().use { rsp -> - try { + try { + okHttpClient.newCall(req).execute().use { rsp -> val body = rsp.body - if(body == null) { + if (body == null) { log.error { "[DATA]获取tower数据失败" } return false } @@ -232,10 +236,10 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { arkTowerMap.clear() arkTowerMap.putAll(mapper.convertValue(towerNode, object : TypeReference>() {})) log.info { "${"[DATA]获取tower数据成功, 共{}条"} ${arkTowerMap.size}" } - } catch (e: Exception) { - log.error(e) { "[DATA]同步tower数据异常" } - return false } + } catch (e: Exception) { + log.error(e) { "[DATA]同步tower数据异常" } + return false } return true @@ -243,25 +247,26 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { fun syncCrisisV2Info(): Boolean { val req = Request.Builder().url(ARK_CRISIS_V2).get().build() - okHttpClient.newCall(req).execute().use { rsp -> - try { + try { + okHttpClient.newCall(req).execute().use { rsp -> val body = rsp.body - if(body == null) { + if (body == null) { log.error { "[DATA]获取crisisV2Info数据失败" } return false } val node = mapper.reader().readTree(body.string()) val crisisV2InfoNode = node.get("seasonInfoDataMap") - val crisisV2InfoMap = mapper.convertValue(crisisV2InfoNode, object : TypeReference>() {}) + val crisisV2InfoMap = + mapper.convertValue(crisisV2InfoNode, object : TypeReference>() {}) val temp = ConcurrentHashMap() crisisV2InfoMap.forEach { (k, v) -> temp[ArkLevelUtil.getKeyInfoById(k)] = v } arkCrisisV2InfoMap.clear() arkCrisisV2InfoMap.putAll(temp) log.info { "${"[DATA]获取crisisV2Info数据成功, 共{}条"} ${arkCrisisV2InfoMap.size}" } - } catch (e: Exception) { - log.error(e) { "[DATA]同步crisisV2Info数据异常" } - return false } + } catch (e: Exception) { + log.error(e) { "[DATA]同步crisisV2Info数据异常" } + return false } return true From 2180ef5054f696f18871b848d96076a898ae7ede Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Mon, 5 Feb 2024 18:33:45 +0800 Subject: [PATCH 062/168] Rename .java to .kt --- .../{CommentsAreaRepository.java => CommentsAreaRepository.kt} | 0 .../repository/entity/gamedata/{ArkTilePos.java => ArkTilePos.kt} | 0 .../{ArkLevelParserService.java => ArkLevelParserService.kt} | 0 .../backend/service/{ArkLevelService.java => ArkLevelService.kt} | 0 .../service/{CommentsAreaService.java => CommentsAreaService.kt} | 0 .../backend/service/{CopilotService.java => CopilotService.kt} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/repository/{CommentsAreaRepository.java => CommentsAreaRepository.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/gamedata/{ArkTilePos.java => ArkTilePos.kt} (100%) rename src/main/java/plus/maa/backend/service/{ArkLevelParserService.java => ArkLevelParserService.kt} (100%) rename src/main/java/plus/maa/backend/service/{ArkLevelService.java => ArkLevelService.kt} (100%) rename src/main/java/plus/maa/backend/service/{CommentsAreaService.java => CommentsAreaService.kt} (100%) rename src/main/java/plus/maa/backend/service/{CopilotService.java => CopilotService.kt} (100%) diff --git a/src/main/java/plus/maa/backend/repository/CommentsAreaRepository.java b/src/main/java/plus/maa/backend/repository/CommentsAreaRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/CommentsAreaRepository.java rename to src/main/java/plus/maa/backend/repository/CommentsAreaRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.java rename to src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt diff --git a/src/main/java/plus/maa/backend/service/ArkLevelParserService.java b/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/ArkLevelParserService.java rename to src/main/java/plus/maa/backend/service/ArkLevelParserService.kt diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.java b/src/main/java/plus/maa/backend/service/ArkLevelService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/ArkLevelService.java rename to src/main/java/plus/maa/backend/service/ArkLevelService.kt diff --git a/src/main/java/plus/maa/backend/service/CommentsAreaService.java b/src/main/java/plus/maa/backend/service/CommentsAreaService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/CommentsAreaService.java rename to src/main/java/plus/maa/backend/service/CommentsAreaService.kt diff --git a/src/main/java/plus/maa/backend/service/CopilotService.java b/src/main/java/plus/maa/backend/service/CopilotService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/CopilotService.java rename to src/main/java/plus/maa/backend/service/CopilotService.kt From 944354883ce437a01512bcccd4f2d80aa850dcc2 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Mon, 5 Feb 2024 18:33:45 +0800 Subject: [PATCH 063/168] refactor: more services in kotlin --- build.gradle | 1 + .../repository/CommentsAreaRepository.kt | 55 +- .../repository/entity/gamedata/ArkTilePos.kt | 50 +- .../maa/backend/service/ArkGameDataService.kt | 2 +- .../backend/service/ArkLevelParserService.kt | 70 +- .../maa/backend/service/ArkLevelService.kt | 540 +++++++------ .../backend/service/CommentsAreaService.kt | 499 ++++++------ .../maa/backend/service/CopilotService.kt | 721 +++++++++--------- .../backend/task/CopilotScoreRefreshTask.java | 8 +- 9 files changed, 972 insertions(+), 974 deletions(-) diff --git a/build.gradle b/build.gradle index 33fc5dd3..e7c34fdc 100644 --- a/build.gradle +++ b/build.gradle @@ -2,6 +2,7 @@ plugins { id 'java' id 'org.springframework.boot' version '3.1.5' id 'io.spring.dependency-management' version '1.1.3' + id 'org.jetbrains.kotlin.plugin.lombok' version '1.9.22' id 'io.freefair.lombok' version '8.4' id 'org.springdoc.openapi-gradle-plugin' version '1.8.0' id 'org.hidetake.swagger.generator' version '2.19.2' diff --git a/src/main/java/plus/maa/backend/repository/CommentsAreaRepository.kt b/src/main/java/plus/maa/backend/repository/CommentsAreaRepository.kt index 60b5ded9..9857195a 100644 --- a/src/main/java/plus/maa/backend/repository/CommentsAreaRepository.kt +++ b/src/main/java/plus/maa/backend/repository/CommentsAreaRepository.kt @@ -1,44 +1,37 @@ -package plus.maa.backend.repository; +package plus.maa.backend.repository -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; -import plus.maa.backend.repository.entity.CommentsArea; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Stream; +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.mongodb.repository.MongoRepository +import org.springframework.stereotype.Repository +import plus.maa.backend.repository.entity.CommentsArea /** * @author LoMu * Date 2023-02-17 15:06 */ - @Repository -public interface CommentsAreaRepository extends MongoRepository { - - - List findByMainCommentId(String commentsId); - - Page findByCopilotIdAndDeleteAndMainCommentIdExists( - Long copilotId, - boolean delete, - boolean exists, - Pageable pageable - ); - - Page findByCopilotIdAndUploaderIdAndDeleteAndMainCommentIdExists(Long copilotId, - String uploaderId, - boolean delete, - boolean exists, - Pageable pageable); +interface CommentsAreaRepository : MongoRepository { + fun findByMainCommentId(commentsId: String): List - Stream findByCopilotIdInAndDelete(Collection copilotIds, boolean delete); + fun findByCopilotIdAndDeleteAndMainCommentIdExists( + copilotId: Long, + delete: Boolean, + exists: Boolean, + pageable: Pageable + ): Page - List findByMainCommentIdIn(List ids); + fun findByCopilotIdAndUploaderIdAndDeleteAndMainCommentIdExists( + copilotId: Long, + uploaderId: String, + delete: Boolean, + exists: Boolean, + pageable: Pageable + ): Page - Long countByCopilotIdAndDelete(Long copilotId, boolean delete); + fun findByCopilotIdInAndDelete(copilotIds: Collection, delete: Boolean): List + fun findByMainCommentIdIn(ids: List): List + fun countByCopilotIdAndDelete(copilotId: Long, delete: Boolean): Long } diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt index 76628c0f..9c3bab81 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt @@ -1,10 +1,7 @@ -package plus.maa.backend.repository.entity.gamedata; +package plus.maa.backend.repository.entity.gamedata -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Data; - -import java.util.List; +import com.fasterxml.jackson.databind.PropertyNamingStrategies.LowerCamelCaseStrategy +import com.fasterxml.jackson.databind.annotation.JsonNaming /** * 地图格子数据 @@ -12,26 +9,23 @@ import java.util.List; * @author dragove * created on 2022/12/23 */ -@Data -@JsonNaming(PropertyNamingStrategies.LowerCamelCaseStrategy.class) -public class ArkTilePos { - - private String code; - private Integer height; - private Integer width; - private String levelId; - private String name; - private String stageId; - private List> tiles; - private List> view; - - @Data - @JsonNaming(PropertyNamingStrategies.LowerCamelCaseStrategy.class) - public static class Tile { - private String tileKey; - private Integer heightType; - private Integer buildableType; - private Boolean isStart; - private Boolean isEnd; - } +@JsonNaming(LowerCamelCaseStrategy::class) +data class ArkTilePos( + val code: String? = null, + val height: Int = 0, + val width: Int = 0, + val levelId: String? = null, + val name: String? = null, + val stageId: String? = null, + private val tiles: List>? = null, + private val view: List>? = null, +) { + @JsonNaming(LowerCamelCaseStrategy::class) + data class Tile( + private val tileKey: String? = null, + private val heightType: Int? = null, + private val buildableType: Int? = null, + private val isStart: Boolean? = null, + private val isEnd: Boolean? = null, + ) } diff --git a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt index 967b0a94..f04d0332 100644 --- a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt +++ b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt @@ -92,7 +92,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { * @param id stageId 或者 seasonId * @return 危机合约信息,包含合约名、开始时间、结束时间等 */ - fun findCrisisV2InfoById(id: String) = findCrisisV2InfoByKeyInfo(ArkLevelUtil.getKeyInfoById(id)) + fun findCrisisV2InfoById(id: String?) = findCrisisV2InfoByKeyInfo(ArkLevelUtil.getKeyInfoById(id)) /** * 通过地图系列的唯一标识提取危机合约信息 diff --git a/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt b/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt index abfd520b..067715bf 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt +++ b/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt @@ -1,59 +1,55 @@ -package plus.maa.backend.service; +package plus.maa.backend.service -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.lang.Nullable; -import org.springframework.stereotype.Service; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.service.model.ArkLevelType; -import plus.maa.backend.service.model.parser.ArkLevelParser; +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.lang.Nullable +import org.springframework.stereotype.Service +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.model.ArkLevelType +import plus.maa.backend.service.model.parser.ArkLevelParser -import java.util.List; +private val log = KotlinLogging.logger { } /** * @author john180 */ -@Slf4j @Service -@RequiredArgsConstructor -public class ArkLevelParserService { - private final List parsers; +class ArkLevelParserService(private val parsers: List) { /** * 具体地图信息生成规则见 - * GameDataParser - * 尚未全部实现
+ * [GameDataParser](https://github.com/MaaAssistantArknights/MaaCopilotServer/blob/main/src/MaaCopilotServer.GameData/GameDataParser.cs) + * 尚未全部实现

* TODO 完成剩余字段实现 */ @Nullable - public ArkLevel parseLevel(ArkTilePos tilePos, String sha) { - ArkLevel level = ArkLevel.builder() - .levelId(tilePos.getLevelId()) - .stageId(tilePos.getStageId()) - .sha(sha) - .catThree(tilePos.getCode()) - .name(tilePos.getName()) - .width(tilePos.getWidth()) - .height(tilePos.getHeight()) - .build(); - return parseLevel(level, tilePos); + fun parseLevel(tilePos: ArkTilePos, sha: String?): ArkLevel? { + val level = ArkLevel.builder() + .levelId(tilePos.levelId) + .stageId(tilePos.stageId) + .sha(sha) + .catThree(tilePos.code) + .name(tilePos.name) + .width(tilePos.width) + .height(tilePos.height) + .build(); + return parseLevel(level, tilePos) } - private ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - ArkLevelType type = ArkLevelType.fromLevelId(level.getLevelId()); + private fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + val type = ArkLevelType.fromLevelId(level.levelId) if (ArkLevelType.UNKNOWN == type) { - log.warn("[PARSER]未知关卡类型:{}", level.getLevelId()); - return null; + log.warn { "${"[PARSER]未知关卡类型:{}"} ${level.levelId}" } + return null } - ArkLevelParser parser = parsers.stream() - .filter(p -> p.supportType(type)) - .findFirst() - .orElse(null); + val parser = parsers.stream() + .filter { p: ArkLevelParser? -> p!!.supportType(type) } + .findFirst() + .orElse(null) if (parser == null) { //类型存在但无对应Parser直接跳过 - return ArkLevel.EMPTY; + return ArkLevel.EMPTY } - return parser.parseLevel(level, tilePos); + return parser.parseLevel(level, tilePos) } } diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.kt b/src/main/java/plus/maa/backend/service/ArkLevelService.kt index 833c7c09..150add99 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.kt +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.kt @@ -1,398 +1,376 @@ -package plus.maa.backend.service; - -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.Data; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import okhttp3.*; -import org.jetbrains.annotations.NotNull; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.cache.annotation.Cacheable; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; -import org.springframework.util.CollectionUtils; -import plus.maa.backend.common.utils.ArkLevelUtil; -import plus.maa.backend.common.utils.converter.ArkLevelConverter; -import plus.maa.backend.controller.response.copilot.ArkLevelInfo; -import plus.maa.backend.repository.ArkLevelRepository; -import plus.maa.backend.repository.GithubRepository; -import plus.maa.backend.repository.RedisCache; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.ArkLevelSha; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.repository.entity.gamedata.MaaArkStage; -import plus.maa.backend.repository.entity.github.GithubCommit; -import plus.maa.backend.repository.entity.github.GithubContent; -import plus.maa.backend.repository.entity.github.GithubTree; -import plus.maa.backend.repository.entity.github.GithubTrees; -import plus.maa.backend.service.model.ArkLevelType; - -import java.io.IOException; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.Arrays; -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Consumer; -import java.util.stream.Collectors; +package plus.maa.backend.service + +import com.fasterxml.jackson.core.type.TypeReference +import com.fasterxml.jackson.databind.ObjectMapper +import io.github.oshai.kotlinlogging.KotlinLogging +import okhttp3.* +import org.springframework.beans.factory.annotation.Value +import org.springframework.cache.annotation.Cacheable +import org.springframework.data.domain.Pageable +import org.springframework.scheduling.annotation.Async +import org.springframework.stereotype.Service +import org.springframework.util.CollectionUtils +import plus.maa.backend.common.utils.ArkLevelUtil +import plus.maa.backend.common.utils.converter.ArkLevelConverter +import plus.maa.backend.controller.response.copilot.ArkLevelInfo +import plus.maa.backend.repository.ArkLevelRepository +import plus.maa.backend.repository.GithubRepository +import plus.maa.backend.repository.RedisCache +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.ArkLevelSha +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.repository.entity.gamedata.MaaArkStage +import plus.maa.backend.repository.entity.github.GithubContent +import plus.maa.backend.repository.entity.github.GithubTree +import plus.maa.backend.repository.entity.github.GithubTrees +import plus.maa.backend.service.model.ArkLevelType +import java.io.IOException +import java.net.URLEncoder +import java.nio.charset.StandardCharsets +import java.time.Instant +import java.time.LocalDateTime +import java.time.ZoneId +import java.util.* +import java.util.concurrent.atomic.AtomicInteger + +private val log = KotlinLogging.logger { } /** * @author dragove * created on 2022/12/23 */ -@Slf4j @Service -@RequiredArgsConstructor -public class ArkLevelService { +class ArkLevelService( /** - * Github api调用token 从 tokens 获取 + * GitHub api调用token 从 [tokens](https://github.com/settings/tokens) 获取 */ - @Value("${maa-copilot.github.token:}") - private String githubToken; + @Value("\${maa-copilot.github.token:}") + private val githubToken: String, /** * maa 主仓库,一般不变 */ - @Value("${maa-copilot.github.repo:MaaAssistantArknights/MaaAssistantArknights/dev}") - private String maaRepoAndBranch; + @Value("\${maa-copilot.github.repo:MaaAssistantArknights/MaaAssistantArknights/dev}") + private val maaRepoAndBranch: String, /** * 地图数据所在路径 */ - @Value("${maa-copilot.github.repo.tile.path:resource/Arknights-Tile-Pos}") - private String tilePosPath; - - private final GithubRepository githubRepo; - private final RedisCache redisCache; - private final ArkLevelRepository arkLevelRepo; - private final ArkLevelParserService parserService; - private final ArkGameDataService gameDataService; - private final ObjectMapper mapper = new ObjectMapper(); - private final OkHttpClient okHttpClient; - private final ArkLevelConverter arkLevelConverter; - - private final List bypassFileNames = List.of("overview.json"); - - @Cacheable("arkLevelInfos") - public List getArkLevelInfos() { - return arkLevelRepo.findAll() - .stream() - .map(arkLevelConverter::convert) - .collect(Collectors.toList()); - } + @Value("\${maa-copilot.github.repo.tile.path:resource/Arknights-Tile-Pos}") + private val tilePosPath: String, + + private val githubRepo: GithubRepository, + private val redisCache: RedisCache, + private val arkLevelRepo: ArkLevelRepository, + private val parserService: ArkLevelParserService, + private val gameDataService: ArkGameDataService, + private val mapper: ObjectMapper, + private val okHttpClient: OkHttpClient, + private val arkLevelConverter: ArkLevelConverter +) { + private val bypassFileNames = listOf("overview.json") + + @get:Cacheable("arkLevelInfos") + val arkLevelInfos: List + get() = arkLevelRepo.findAll() + .map { arkLevel: ArkLevel? -> arkLevelConverter.convert(arkLevel) } + .toList() @Cacheable("arkLevel") - public ArkLevel findByLevelIdFuzzy(String levelId) { - return arkLevelRepo.findByLevelIdFuzzy(levelId).findAny().orElse(null); + fun findByLevelIdFuzzy(levelId: String?): ArkLevel { + return arkLevelRepo.findByLevelIdFuzzy(levelId).findAny().orElse(null) } - - public List queryLevelInfosByKeyword(String keyword) { - List levels = arkLevelRepo.queryLevelByKeyword(keyword).collect(Collectors.toList()); - return arkLevelConverter.convert(levels); + fun queryLevelInfosByKeyword(keyword: String?): List { + val levels = arkLevelRepo.queryLevelByKeyword(keyword).toList() + return arkLevelConverter.convert(levels) } /** * 地图数据更新任务 */ @Async - public void runSyncLevelDataTask() { - log.info("[LEVEL]开始同步地图数据"); + fun runSyncLevelDataTask() { + log.info { "[LEVEL]开始同步地图数据" } //获取地图文件夹最新的commit, 用于判断是否需要更新 - List commits = githubRepo.getCommits(githubToken); + val commits = githubRepo.getCommits(githubToken) if (CollectionUtils.isEmpty(commits)) { - log.info("[LEVEL]获取地图数据最新commit失败"); - return; + log.info { "[LEVEL]获取地图数据最新commit失败" } + return } //与缓存的commit比较,如果相同则不更新 - GithubCommit commit = commits.get(0); - String lastCommit = redisCache.getCacheLevelCommit(); - if (lastCommit != null && lastCommit.equals(commit.getSha())) { - log.info("[LEVEL]地图数据已是最新"); - return; + val commit = commits[0] + val lastCommit = redisCache.cacheLevelCommit + if (lastCommit != null && lastCommit == commit!!.sha) { + log.info { "[LEVEL]地图数据已是最新" } + return } //获取根目录文件列表 - GithubTrees trees; - List files = Arrays.stream(tilePosPath.split("/")).toList(); - trees = githubRepo.getTrees(githubToken, commit.getSha()); + var trees: GithubTrees? + val files = Arrays.stream(tilePosPath.split("/".toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray()).toList() + trees = githubRepo.getTrees(githubToken, commit!!.sha) //根据路径获取文件列表 - for (String file : files) { - if (trees == null || CollectionUtils.isEmpty(trees.getTree())) { - log.info("[LEVEL]地图数据获取失败"); - return; + for (file in files) { + if (trees == null || CollectionUtils.isEmpty(trees.tree)) { + log.info { "[LEVEL]地图数据获取失败" } + return } - GithubTree tree = trees.getTree().stream() - .filter(t -> t.getPath().equals(file) && t.getType().equals("tree")) - .findFirst() - .orElse(null); + val tree = trees.tree.stream() + .filter { t: GithubTree -> t.path == file && t.type == "tree" } + .findFirst() + .orElse(null) if (tree == null) { - log.info("[LEVEL]地图数据获取失败, 未找到文件夹{}", file); - return; + log.info { "[LEVEL]地图数据获取失败, 未找到文件夹$file" } + return } - trees = githubRepo.getTrees(githubToken, tree.getSha()); + trees = githubRepo.getTrees(githubToken, tree.sha) } - if (trees == null || CollectionUtils.isEmpty(trees.getTree())) { - log.info("[LEVEL]地图数据获取失败, 未找到文件夹{}", tilePosPath); - return; + if (trees == null || CollectionUtils.isEmpty(trees.tree)) { + log.info { "[LEVEL]地图数据获取失败, 未找到文件夹$tilePosPath" } + return } //根据后缀筛选地图文件列表 - List levelTrees = trees.getTree().stream() - .filter(t -> t.getType().equals("blob") && t.getPath().endsWith(".json")) - .collect(Collectors.toList()); - log.info("[LEVEL]已发现{}份地图数据", levelTrees.size()); + val levelTrees = trees.tree + .filter { t: GithubTree -> t.type == "blob" && t.path.endsWith(".json") } + .toMutableList() + log.info { "[LEVEL]已发现${levelTrees.size}份地图数据" } //根据sha筛选无需更新的地图 - List shaList = arkLevelRepo.findAllShaBy().stream().map(ArkLevelSha::getSha).toList(); - levelTrees.removeIf(t -> shaList.contains(t.getSha())); + val shaList = arkLevelRepo.findAllShaBy().stream().map { obj: ArkLevelSha -> obj.sha }.toList() + levelTrees.removeIf { t: GithubTree -> shaList.contains(t.sha) } // 排除overview文件、肉鸽、训练关卡和 Guide? 不知道是啥 - levelTrees.removeIf(t -> t.getPath().equals("overview.json") || - t.getPath().contains("roguelike") || - t.getPath().startsWith("tr_") || - t.getPath().startsWith("guide_")); - levelTrees.removeIf(t -> t.getPath().contains("roguelike")); - log.info("[LEVEL]{}份地图数据需要更新", levelTrees.size()); + levelTrees.removeIf { t: GithubTree -> + t.path == "overview.json" || + t.path.contains("roguelike") || + t.path.startsWith("tr_") || + t.path.startsWith("guide_") + } + levelTrees.removeIf { t: GithubTree -> t.path.contains("roguelike") } + log.info { "[LEVEL]${levelTrees.size}份地图数据需要更新" } if (levelTrees.isEmpty()) { - return; + return } //同步GameData仓库数据 if (!gameDataService.syncGameData()) { - log.error("[LEVEL]GameData仓库数据同步失败"); - return; + log.error { "[LEVEL]GameData仓库数据同步失败" } + return } - DownloadTask task = new DownloadTask(levelTrees.size(), (t) -> { + val task = DownloadTask(total = levelTrees.size, finishCallback = { t: DownloadTask -> //仅在全部下载任务成功后更新commit缓存 - if (t.isAllSuccess()) { - redisCache.setCacheLevelCommit(commit.getSha()); + if (t.isAllSuccess) { + redisCache.cacheLevelCommit = commit.sha } - }); - levelTrees.forEach(tree -> download(task, tree)); + }) + levelTrees.forEach { tree -> download(task, tree) } } /** * 更新活动地图开放状态 */ - public void updateActivitiesOpenStatus() { - log.info("[ACTIVITIES-OPEN-STATUS]准备更新活动地图开放状态"); - GithubContent stages = githubRepo.getContents(githubToken, "resource").stream() - .filter(content -> content.isFile() && "stages.json".equals(content.getName())) - .findFirst() - .orElse(null); + fun updateActivitiesOpenStatus() { + log.info { "[ACTIVITIES-OPEN-STATUS]准备更新活动地图开放状态" } + val stages = githubRepo.getContents(githubToken, "resource").stream() + .filter { content: GithubContent -> content.isFile && "stages.json" == content.name } + .findFirst() + .orElse(null) if (stages == null) { - log.info("[ACTIVITIES-OPEN-STATUS]活动地图开放状态数据不存在"); - return; + log.info { "[ACTIVITIES-OPEN-STATUS]活动地图开放状态数据不存在" } + return } - String lastStagesSha = redisCache.getCache("level:stages:sha", String.class); - if (lastStagesSha != null && lastStagesSha.equals(stages.getSha())) { - log.info("[ACTIVITIES-OPEN-STATUS]活动地图开放状态已是最新"); - return; + val lastStagesSha = redisCache.getCache("level:stages:sha", String::class.java) + if (lastStagesSha != null && lastStagesSha == stages.sha) { + log.info { "[ACTIVITIES-OPEN-STATUS]活动地图开放状态已是最新" } + return } - log.info("[ACTIVITIES-OPEN-STATUS]开始更新活动地图开放状态"); + log.info { "[ACTIVITIES-OPEN-STATUS]开始更新活动地图开放状态" } // 就一个文件,直接在当前线程下载数据 - try (Response response = okHttpClient - .newCall(new Request.Builder().url(stages.getDownloadUrl()).build()) - .execute()) { + try { + okHttpClient + .newCall(Request.Builder().url(stages.downloadUrl).build()) + .execute().use { response -> + if (!response.isSuccessful || response.body == null) { + log.error { "[ACTIVITIES-OPEN-STATUS]活动地图开放状态下载失败" } + return + } + val body = response.body!!.byteStream() + val stagesList: List = + mapper.readValue(body, object : TypeReference>() { + }) + + val keyInfos = stagesList + .map { it.stageId } // 提取地图系列的唯一标识 + .map { id: String? -> ArkLevelUtil.getKeyInfoById(id) } + .toSet() + + // 修改活动地图 + val catOne = ArkLevelType.ACTIVITIES.display + // 分页修改 + var pageable = Pageable.ofSize(1000) + var arkLevelPage = arkLevelRepo.findAllByCatOne(catOne, pageable) + + // 获取当前时间 + val nowTime = LocalDateTime.now() + + while (arkLevelPage.hasContent()) { + arkLevelPage.forEach{ arkLevel: ArkLevel -> + // 只考虑地图系列的唯一标识 + if (keyInfos.contains(ArkLevelUtil.getKeyInfoById(arkLevel.stageId))) { + arkLevel.isOpen = true + // 如果一个旧地图重新开放,关闭时间也需要另算 + arkLevel.closeTime = null + } else if (arkLevel.isOpen != null) { + // 数据可能存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 + arkLevel.isOpen = false + // 不能每天都变更关闭时间 + if (arkLevel.closeTime == null) { + arkLevel.closeTime = nowTime + } + } + } - if (!response.isSuccessful() || response.body() == null) { - log.error("[ACTIVITIES-OPEN-STATUS]活动地图开放状态下载失败"); - return; - } + arkLevelRepo.saveAll(arkLevelPage) - var body = response.body().charStream(); - List stagesList = mapper.readValue(body, new TypeReference<>() { - }); - - Set keyInfos = stagesList.stream() - .map(MaaArkStage::getStageId) - // 提取地图系列的唯一标识 - .map(ArkLevelUtil::getKeyInfoById) - .collect(Collectors.toUnmodifiableSet()); - - // 修改活动地图 - final String catOne = ArkLevelType.ACTIVITIES.getDisplay(); - // 分页修改 - Pageable pageable = Pageable.ofSize(1000); - Page arkLevelPage = arkLevelRepo.findAllByCatOne(catOne, pageable); - - // 获取当前时间 - LocalDateTime nowTime = LocalDateTime.now(); - - while (arkLevelPage.hasContent()) { - - arkLevelPage.forEach(arkLevel -> { - // 只考虑地图系列的唯一标识 - if (keyInfos.contains(ArkLevelUtil.getKeyInfoById(arkLevel.getStageId()))) { - - arkLevel.setIsOpen(true); - // 如果一个旧地图重新开放,关闭时间也需要另算 - arkLevel.setCloseTime(null); - } else if (arkLevel.getIsOpen() != null) { - // 数据可能存在部分缺失,因此地图此前必须被匹配过,才会认为其关闭 - arkLevel.setIsOpen(false); - // 不能每天都变更关闭时间 - if (arkLevel.getCloseTime() == null) { - arkLevel.setCloseTime(nowTime); + if (!arkLevelPage.hasNext()) { + // 没有下一页了,跳出循环 + break } + pageable = arkLevelPage.nextPageable() + arkLevelPage = arkLevelRepo.findAllByCatOne(catOne, pageable) } - }); - arkLevelRepo.saveAll(arkLevelPage); - - if (!arkLevelPage.hasNext()) { - // 没有下一页了,跳出循环 - break; + redisCache.setData("level:stages:sha", stages.sha) + log.info { "[ACTIVITIES-OPEN-STATUS]活动地图开放状态更新完成" } } - pageable = arkLevelPage.nextPageable(); - arkLevelPage = arkLevelRepo.findAllByCatOne(catOne, pageable); - } - - redisCache.setData("level:stages:sha", stages.getSha()); - log.info("[ACTIVITIES-OPEN-STATUS]活动地图开放状态更新完成"); - } catch (Exception e) { - log.error("[ACTIVITIES-OPEN-STATUS]活动地图开放状态更新失败", e); + } catch (e: Exception) { + log.error(e) { "[ACTIVITIES-OPEN-STATUS]活动地图开放状态更新失败" } } } - public void updateCrisisV2OpenStatus() { - log.info("[CRISIS-V2-OPEN-STATUS]准备更新危机合约开放状态"); + fun updateCrisisV2OpenStatus() { + log.info { "[CRISIS-V2-OPEN-STATUS]准备更新危机合约开放状态" } // 同步危机合约信息 if (!gameDataService.syncCrisisV2Info()) { - log.error("[CRISIS-V2-OPEN-STATUS]同步危机合约信息失败"); - return; + log.error { "[CRISIS-V2-OPEN-STATUS]同步危机合约信息失败" } + return } - final String catOne = ArkLevelType.RUNE.getDisplay(); + val catOne = ArkLevelType.RUNE.display // 分页修改 - Pageable pageable = Pageable.ofSize(1000); - Page arkCrisisV2Page = arkLevelRepo.findAllByCatOne(catOne, pageable); + var pageable = Pageable.ofSize(1000) + var arkCrisisV2Page = arkLevelRepo.findAllByCatOne(catOne, pageable) // 获取当前时间 - Instant nowInstant = Instant.now(); - LocalDateTime nowTime = LocalDateTime.ofInstant(nowInstant, ZoneId.systemDefault()); + val nowInstant = Instant.now() + val nowTime = LocalDateTime.ofInstant(nowInstant, ZoneId.systemDefault()) while (arkCrisisV2Page.hasContent()) { - - arkCrisisV2Page.forEach(arkCrisisV2 -> { + arkCrisisV2Page.forEach { arkCrisisV2: ArkLevel -> // 危机合约信息比较准,因此未匹配一律视为已关闭 - arkCrisisV2.setIsOpen(false); - Optional.ofNullable(gameDataService.findCrisisV2InfoById(arkCrisisV2.getStageId())) - .map(crisisV2Info -> Instant.ofEpochSecond(crisisV2Info.getEndTs())) - .ifPresent(endInstant -> arkCrisisV2.setIsOpen(endInstant.isAfter(nowInstant))); - - if (arkCrisisV2.getCloseTime() == null && - Boolean.FALSE.equals(arkCrisisV2.getIsOpen())) { + arkCrisisV2.isOpen = false + gameDataService.findCrisisV2InfoById(arkCrisisV2.stageId)?.let { crisisV2Info -> + val instant = Instant.ofEpochSecond(crisisV2Info.endTs) + arkCrisisV2.isOpen = instant.isAfter(nowInstant) + } + if (arkCrisisV2.closeTime == null && java.lang.Boolean.FALSE == arkCrisisV2.isOpen) { // 危机合约应该不存在赛季重新开放的问题,只要不每天变动关闭时间即可 - arkCrisisV2.setCloseTime(nowTime); + arkCrisisV2.closeTime = nowTime } - }); + } - arkLevelRepo.saveAll(arkCrisisV2Page); + arkLevelRepo.saveAll(arkCrisisV2Page) if (!arkCrisisV2Page.hasNext()) { // 没有下一页了,跳出循环 - break; + break } - pageable = arkCrisisV2Page.nextPageable(); - arkCrisisV2Page = arkLevelRepo.findAllByCatOne(catOne, pageable); + pageable = arkCrisisV2Page.nextPageable() + arkCrisisV2Page = arkLevelRepo.findAllByCatOne(catOne, pageable) } - log.info("[CRISIS-V2-OPEN-STATUS]危机合约开放状态更新完毕"); + log.info { "[CRISIS-V2-OPEN-STATUS]危机合约开放状态更新完毕" } } /** * 下载地图数据 */ - private void download(DownloadTask task, GithubTree tree) { - String fileName = URLEncoder.encode(tree.getPath(), StandardCharsets.UTF_8); + private fun download(task: DownloadTask, tree: GithubTree) { + val fileName = URLEncoder.encode(tree.path, StandardCharsets.UTF_8) if (bypassFileNames.contains(fileName)) { - task.success(); - return; + task.success() + return } - String url = String.format("https://raw.githubusercontent.com/%s/%s/%s", maaRepoAndBranch, tilePosPath, fileName); - okHttpClient.newCall(new Request.Builder().url(url).build()).enqueue(new Callback() { - @Override - public void onFailure(@NotNull Call call, @NotNull IOException e) { - log.error("[LEVEL]下载地图数据失败:" + tree.getPath(), e); + val url = String.format("https://raw.githubusercontent.com/%s/%s/%s", maaRepoAndBranch, tilePosPath, fileName) + okHttpClient.newCall(Request.Builder().url(url).build()).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + log.error(e) { "[LEVEL]下载地图数据失败:" + tree.path } } - @Override - public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { - try (ResponseBody rspBody = response.body()) { - if (!response.isSuccessful() || rspBody == null) { - task.fail(); - log.error("[LEVEL]下载地图数据失败:" + tree.getPath()); - return; + @Throws(IOException::class) + override fun onResponse(call: Call, response: Response) { + response.body.use { rspBody -> + if (!response.isSuccessful || rspBody == null) { + task.fail() + log.error { "[LEVEL]下载地图数据失败:" + tree.path } + return } - ArkTilePos tilePos = mapper.readValue(rspBody.string(), ArkTilePos.class); - ArkLevel level = parserService.parseLevel(tilePos, tree.getSha()); + val tilePos = mapper.readValue(rspBody.string(), ArkTilePos::class.java) + val level = parserService.parseLevel(tilePos, tree.sha) if (level == null) { - task.fail(); - log.info("[LEVEL]地图数据解析失败:" + tree.getPath()); - return; - } else if (level == ArkLevel.EMPTY) { - task.pass(); - return; + task.fail() + log.info { "[LEVEL]地图数据解析失败:" + tree.path } + return + } else if (level === ArkLevel.EMPTY) { + task.pass() + return } - arkLevelRepo.save(level); + arkLevelRepo.save(level) - task.success(); - log.info("[LEVEL]下载地图数据 {} 成功, 进度{}/{}, 用时:{}s", tilePos.getName(), task.getCurrent(), task.getTotal(), task.getDuration()); + task.success() + log.info { "[LEVEL]下载地图数据 ${tilePos.name} 成功, 进度${task.current}/${task.total}, 用时:${task.duration}s" } } } - }); + }) } - @Data - @RequiredArgsConstructor - private static class DownloadTask { - private final long startTime = System.currentTimeMillis(); - private final AtomicInteger success = new AtomicInteger(0); - private final AtomicInteger fail = new AtomicInteger(0); - private final AtomicInteger pass = new AtomicInteger(0); - private final int total; - private final Consumer finishCallback; - - public void success() { - success.incrementAndGet(); - checkFinish(); + private class DownloadTask( + private val startTime: Long = System.currentTimeMillis(), + private val success: AtomicInteger = AtomicInteger(0), + private val fail: AtomicInteger = AtomicInteger(0), + private val pass: AtomicInteger = AtomicInteger(0), + val total: Int = 0, + private val finishCallback: ((DownloadTask) -> Unit)? = null + ) { + fun success() { + success.incrementAndGet() + checkFinish() } - public void fail() { - fail.incrementAndGet(); - checkFinish(); + fun fail() { + fail.incrementAndGet() + checkFinish() } - public void pass() { - pass.incrementAndGet(); - checkFinish(); + fun pass() { + pass.incrementAndGet() + checkFinish() } - public int getCurrent() { - return success.get() + fail.get() + pass.get(); - } + val current: Int + get() = success.get() + fail.get() + pass.get() - public int getDuration() { - return (int) (System.currentTimeMillis() - startTime) / 1000; - } + val duration: Int + get() = (System.currentTimeMillis() - startTime).toInt() / 1000 - public boolean isAllSuccess() { - return success.get() + pass.get() == total; - } + val isAllSuccess: Boolean + get() = success.get() + pass.get() == total - private void checkFinish() { + private fun checkFinish() { if (success.get() + fail.get() + pass.get() != total) { - return; + return } - finishCallback.accept(this); - log.info("[LEVEL]地图数据下载完成, 成功:{}, 失败:{}, 跳过:{} 总用时{}s", success.get(), fail.get(), pass.get(), getDuration()); + finishCallback!!.invoke(this) + log.info { "[LEVEL]地图数据下载完成, 成功:${success.get()}, 失败:${fail.get()}, 跳过:${pass.get()} 总用时${duration}s" } } } - } diff --git a/src/main/java/plus/maa/backend/service/CommentsAreaService.kt b/src/main/java/plus/maa/backend/service/CommentsAreaService.kt index 22084fd9..b0e4ed10 100644 --- a/src/main/java/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/java/plus/maa/backend/service/CommentsAreaService.kt @@ -1,59 +1,50 @@ -package plus.maa.backend.service; - - -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Service; -import org.springframework.util.Assert; -import plus.maa.backend.common.utils.converter.CommentConverter; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.controller.request.comments.CommentsAddDTO; -import plus.maa.backend.controller.request.comments.CommentsQueriesDTO; -import plus.maa.backend.controller.request.comments.CommentsRatingDTO; -import plus.maa.backend.controller.request.comments.CommentsToppingDTO; -import plus.maa.backend.controller.response.comments.CommentsAreaInfo; -import plus.maa.backend.controller.response.comments.CommentsInfo; -import plus.maa.backend.controller.response.comments.SubCommentsInfo; -import plus.maa.backend.repository.CommentsAreaRepository; -import plus.maa.backend.repository.CopilotRepository; -import plus.maa.backend.repository.RatingRepository; -import plus.maa.backend.repository.UserRepository; -import plus.maa.backend.repository.entity.CommentsArea; -import plus.maa.backend.repository.entity.Copilot; -import plus.maa.backend.repository.entity.MaaUser; -import plus.maa.backend.repository.entity.Rating; -import plus.maa.backend.service.model.CommentNotification; -import plus.maa.backend.service.model.RatingType; - -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.util.*; +package plus.maa.backend.service + +import lombok.RequiredArgsConstructor +import org.apache.commons.lang3.StringUtils +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Pageable +import org.springframework.data.domain.Sort +import org.springframework.stereotype.Service +import org.springframework.util.Assert +import plus.maa.backend.common.utils.converter.CommentConverter +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.controller.request.comments.CommentsAddDTO +import plus.maa.backend.controller.request.comments.CommentsQueriesDTO +import plus.maa.backend.controller.request.comments.CommentsRatingDTO +import plus.maa.backend.controller.request.comments.CommentsToppingDTO +import plus.maa.backend.controller.response.comments.CommentsAreaInfo +import plus.maa.backend.repository.CommentsAreaRepository +import plus.maa.backend.repository.CopilotRepository +import plus.maa.backend.repository.RatingRepository +import plus.maa.backend.repository.UserRepository +import plus.maa.backend.repository.entity.CommentsArea +import plus.maa.backend.repository.entity.Copilot +import plus.maa.backend.repository.entity.MaaUser +import plus.maa.backend.repository.entity.Rating +import plus.maa.backend.service.model.CommentNotification +import plus.maa.backend.service.model.RatingType +import java.time.LocalDateTime +import java.time.format.DateTimeFormatter +import java.util.* +import java.util.function.Consumer + /** * @author LoMu * Date 2023-02-17 15:00 */ - @Service @RequiredArgsConstructor -public class CommentsAreaService { - private final CommentsAreaRepository commentsAreaRepository; - - private final RatingRepository ratingRepository; - - private final CopilotRepository copilotRepository; - - private final UserRepository userRepository; - - private final EmailService emailService; - - private final MaaCopilotProperties maaCopilotProperties; - - private final CommentConverter commentConverter; +class CommentsAreaService( + private val commentsAreaRepository: CommentsAreaRepository, + private val ratingRepository: RatingRepository, + private val copilotRepository: CopilotRepository, + private val userRepository: UserRepository, + private val emailService: EmailService, + private val maaCopilotProperties: MaaCopilotProperties, + private val commentConverter: CommentConverter, +) { /** @@ -63,78 +54,76 @@ public class CommentsAreaService { * @param userId 登录用户 id * @param commentsAddDTO CommentsRequest */ - public void addComments(String userId, CommentsAddDTO commentsAddDTO) { - long copilotId = Long.parseLong(commentsAddDTO.getCopilotId()); - String message = commentsAddDTO.getMessage(); - Optional copilotOptional = copilotRepository.findByCopilotId(copilotId); - Assert.isTrue(StringUtils.isNotBlank(message), "评论不可为空"); - Assert.isTrue(copilotOptional.isPresent(), "作业表不存在"); + fun addComments(userId: String, commentsAddDTO: CommentsAddDTO) { + val copilotId = commentsAddDTO.copilotId.toLong() + val message = commentsAddDTO.message + val copilotOptional = copilotRepository.findByCopilotId(copilotId) + Assert.isTrue(StringUtils.isNotBlank(message), "评论不可为空") + Assert.isTrue(copilotOptional.isPresent, "作业表不存在") - String fromCommentsId = null; - String mainCommentsId = null; + var fromCommentsId: String? = null + var mainCommentsId: String? = null - CommentsArea commentsArea = null; - Boolean isCopilotAuthor = null; + var commentsArea: CommentsArea? = null + var isCopilotAuthor: Boolean? = null //代表这是一条回复评论 - if (StringUtils.isNoneBlank(commentsAddDTO.getFromCommentId())) { - - Optional commentsAreaOptional = commentsAreaRepository.findById(commentsAddDTO.getFromCommentId()); - Assert.isTrue(commentsAreaOptional.isPresent(), "回复的评论不存在"); - commentsArea = commentsAreaOptional.get(); - Assert.isTrue(!commentsArea.isDelete(), "回复的评论不存在"); - - mainCommentsId = StringUtils - .isNoneBlank(commentsArea.getMainCommentId()) ? - commentsArea.getMainCommentId() : commentsArea.getId(); - - fromCommentsId = StringUtils - .isNoneBlank(commentsArea.getId()) ? - commentsArea.getId() : null; - - if (Objects.isNull(commentsArea.getNotification()) || commentsArea.getNotification()) { - isCopilotAuthor = false; + if (StringUtils.isNoneBlank(commentsAddDTO.fromCommentId)) { + val commentsAreaOptional = commentsAreaRepository.findById(commentsAddDTO.fromCommentId) + Assert.isTrue(commentsAreaOptional.isPresent, "回复的评论不存在") + commentsArea = commentsAreaOptional.get() + Assert.isTrue(!commentsArea.isDelete, "回复的评论不存在") + + mainCommentsId = if (StringUtils + .isNoneBlank(commentsArea.mainCommentId) + ) commentsArea.mainCommentId else commentsArea.id + + fromCommentsId = if (StringUtils + .isNoneBlank(commentsArea.id) + ) commentsArea.id else null + + if (Objects.isNull(commentsArea.notification) || commentsArea.notification) { + isCopilotAuthor = false } - } else { - isCopilotAuthor = true; + isCopilotAuthor = true } //判断是否需要通知 - if (Objects.nonNull(isCopilotAuthor) && maaCopilotProperties.getMail().getNotification()) { - Copilot copilot = copilotOptional.get(); + if (Objects.nonNull(isCopilotAuthor) && maaCopilotProperties.mail.notification) { + val copilot = copilotOptional.get() //通知作业作者或是评论作者 - String replyUserId = isCopilotAuthor ? copilot.getUploaderId() : commentsArea.getUploaderId(); + val replyUserId = if (isCopilotAuthor!!) copilot.uploaderId else commentsArea!!.uploaderId - Map maaUserMap = userRepository.findByUsersId(List.of(userId, replyUserId)); + val maaUserMap = userRepository.findByUsersId(listOf(userId, replyUserId)) //防止通知自己 - if (!Objects.equals(replyUserId, userId)) { - LocalDateTime time = LocalDateTime.now(); - String timeStr = time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); - CommentNotification commentNotification = new CommentNotification(); + if (replyUserId != userId) { + val time = LocalDateTime.now() + val timeStr = time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + val commentNotification = CommentNotification() - String authorName = maaUserMap.getOrDefault(replyUserId, MaaUser.UNKNOWN).getUserName(); - String reName = maaUserMap.getOrDefault(userId, MaaUser.UNKNOWN).getUserName(); + val authorName = maaUserMap.getOrDefault(replyUserId, MaaUser.UNKNOWN).userName + val reName = maaUserMap.getOrDefault(userId, MaaUser.UNKNOWN).userName - String title = isCopilotAuthor ? copilot.getDoc().getTitle() : commentsArea.getMessage(); + val title = if (isCopilotAuthor) copilot.doc.title else commentsArea!!.message commentNotification - .setTitle(title) - .setDate(timeStr) - .setAuthorName(authorName) - .setReName(reName) - .setReMessage(message); + .setTitle(title) + .setDate(timeStr) + .setAuthorName(authorName) + .setReName(reName) + .setReMessage(message) - MaaUser maaUser = maaUserMap.get(replyUserId); + val maaUser = maaUserMap[replyUserId] if (Objects.nonNull(maaUser)) { - emailService.sendCommentNotification(maaUser.getEmail(), commentNotification); + emailService.sendCommentNotification(maaUser!!.email, commentNotification) } } } @@ -142,41 +131,42 @@ public class CommentsAreaService { //创建评论表 commentsAreaRepository.insert( - new CommentsArea().setCopilotId(copilotId) - .setUploaderId(userId) - .setFromCommentId(fromCommentsId) - .setMainCommentId(mainCommentsId) - .setMessage(message) - .setNotification(commentsAddDTO.isNotification()) - ); - + CommentsArea().setCopilotId(copilotId) + .setUploaderId(userId) + .setFromCommentId(fromCommentsId) + .setMainCommentId(mainCommentsId) + .setMessage(message) + .setNotification(commentsAddDTO.isNotification) + ) } - public void deleteComments(String userId, String commentsId) { - CommentsArea commentsArea = findCommentsById(commentsId); + fun deleteComments(userId: String, commentsId: String) { + val commentsArea = findCommentsById(commentsId) //允许作者删除评论 - copilotRepository.findByCopilotId(commentsArea.getCopilotId()) - .ifPresent(copilot -> - Assert.isTrue( - Objects.equals(userId, copilot.getUploaderId()) - || Objects.equals(userId, commentsArea.getUploaderId()), - "您无法删除不属于您的评论") - ); - LocalDateTime now = LocalDateTime.now(); - commentsArea.setDelete(true); - commentsArea.setDeleteTime(now); + copilotRepository.findByCopilotId(commentsArea.copilotId) + .ifPresent { copilot: Copilot -> + Assert.isTrue( + userId == copilot.uploaderId || userId == commentsArea.uploaderId, + "您无法删除不属于您的评论" + ) + } + val now = LocalDateTime.now() + commentsArea.setDelete(true) + commentsArea.setDeleteTime(now) //删除所有回复 - if (StringUtils.isBlank(commentsArea.getMainCommentId())) { - List commentsAreaList = commentsAreaRepository.findByMainCommentId(commentsArea.getId()); - commentsAreaList.forEach(ca -> + if (StringUtils.isBlank(commentsArea.mainCommentId)) { + val commentsAreaList = commentsAreaRepository.findByMainCommentId(commentsArea.id) + commentsAreaList.forEach( + Consumer { ca: CommentsArea -> ca.setDeleteTime(now) - .setDelete(true) - ); - commentsAreaRepository.saveAll(commentsAreaList); + .setDelete(true) + } + ) + commentsAreaRepository.saveAll(commentsAreaList) } - commentsAreaRepository.save(commentsArea); + commentsAreaRepository.save(commentsArea) } @@ -186,61 +176,62 @@ public class CommentsAreaService { * @param userId 登录用户 id * @param commentsRatingDTO CommentsRatingDTO */ - public void rates(String userId, CommentsRatingDTO commentsRatingDTO) { - String rating = commentsRatingDTO.getRating(); + fun rates(userId: String?, commentsRatingDTO: CommentsRatingDTO) { + val rating = commentsRatingDTO.rating - CommentsArea commentsArea = findCommentsById(commentsRatingDTO.getCommentId()); + val commentsArea = findCommentsById(commentsRatingDTO.commentId) - long likeCountChange; - long dislikeCountChange; + val likeCountChange: Long + val dislikeCountChange: Long - Optional ratingOptional = ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COMMENT, commentsArea.getId(), userId); + val ratingOptional = + ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COMMENT, commentsArea.id, userId) // 判断该用户是否存在评分 - if (ratingOptional.isPresent()) { + if (ratingOptional.isPresent) { // 如果评分发生变化则更新 - if (!Objects.equals(ratingOptional.get().getRating(), RatingType.fromRatingType(rating))) { - RatingType oldRatingType = ratingOptional.get().getRating(); - ratingOptional.get().setRating(RatingType.fromRatingType(rating)); - ratingOptional.get().setRateTime(LocalDateTime.now()); - RatingType newRatingType = ratingRepository.save(ratingOptional.get()).getRating(); + if (ratingOptional.get().rating != RatingType.fromRatingType(rating)) { + val oldRatingType = ratingOptional.get().rating + ratingOptional.get().setRating(RatingType.fromRatingType(rating)) + ratingOptional.get().setRateTime(LocalDateTime.now()) + val newRatingType = ratingRepository.save(ratingOptional.get()).rating // 更新评分后更新评论的点赞数 - likeCountChange = newRatingType == RatingType.LIKE ? 1 : - (oldRatingType != RatingType.LIKE ? 0 : -1); - dislikeCountChange = newRatingType == RatingType.DISLIKE ? 1 : - (oldRatingType != RatingType.DISLIKE ? 0 : -1); + likeCountChange = + (if (newRatingType == RatingType.LIKE) 1 else (if (oldRatingType != RatingType.LIKE) 0 else -1)).toLong() + dislikeCountChange = + (if (newRatingType == RatingType.DISLIKE) 1 else (if (oldRatingType != RatingType.DISLIKE) 0 else -1)).toLong() } else { // 如果评分未发生变化则结束 - return; + return } } else { // 不存在评分则创建 - Rating newRating = new Rating() - .setType(Rating.KeyType.COMMENT) - .setKey(commentsArea.getId()) - .setUserId(userId) - .setRating(RatingType.fromRatingType(rating)) - .setRateTime(LocalDateTime.now()); - - ratingRepository.insert(newRating); - likeCountChange = newRating.getRating() == RatingType.LIKE ? 1 : 0; - dislikeCountChange = newRating.getRating() == RatingType.DISLIKE ? 1 : 0; + val newRating = Rating() + .setType(Rating.KeyType.COMMENT) + .setKey(commentsArea.id) + .setUserId(userId) + .setRating(RatingType.fromRatingType(rating)) + .setRateTime(LocalDateTime.now()) + + ratingRepository.insert(newRating) + likeCountChange = (if (newRating.rating == RatingType.LIKE) 1 else 0).toLong() + dislikeCountChange = (if (newRating.rating == RatingType.DISLIKE) 1 else 0).toLong() } // 点赞数不需要在高并发下特别精准,大概就行,但是也得避免特别离谱的数字 - long likeCount = commentsArea.getLikeCount() + likeCountChange; + var likeCount = commentsArea.likeCount + likeCountChange if (likeCount < 0) { - likeCount = 0; + likeCount = 0 } - long dislikeCount = commentsArea.getDislikeCount() + dislikeCountChange; + var dislikeCount = commentsArea.dislikeCount + dislikeCountChange if (dislikeCount < 0) { - dislikeCount = 0; + dislikeCount = 0 } - commentsArea.setLikeCount(likeCount); - commentsArea.setDislikeCount(dislikeCount); + commentsArea.setLikeCount(likeCount) + commentsArea.setDislikeCount(dislikeCount) - commentsAreaRepository.save(commentsArea); + commentsAreaRepository.save(commentsArea) } /** @@ -249,19 +240,19 @@ public class CommentsAreaService { * @param userId 登录用户 id * @param commentsToppingDTO CommentsToppingDTO */ - public void topping(String userId, CommentsToppingDTO commentsToppingDTO) { - CommentsArea commentsArea = findCommentsById(commentsToppingDTO.getCommentId()); - Assert.isTrue(!commentsArea.isDelete(), "评论不存在"); + fun topping(userId: String, commentsToppingDTO: CommentsToppingDTO) { + val commentsArea = findCommentsById(commentsToppingDTO.commentId) + Assert.isTrue(!commentsArea.isDelete, "评论不存在") // 只允许作者置顶评论 - copilotRepository.findByCopilotId(commentsArea.getCopilotId()) - .ifPresent(copilot -> { - Assert.isTrue( - Objects.equals(userId, copilot.getUploaderId()), - "只有作者才能置顶评论"); - commentsArea.setTopping(commentsToppingDTO.isTopping()); - commentsAreaRepository.save(commentsArea); - } - ); + copilotRepository.findByCopilotId(commentsArea.copilotId) + .ifPresent { copilot: Copilot -> + Assert.isTrue( + userId == copilot.uploaderId, + "只有作者才能置顶评论" + ) + commentsArea.setTopping(commentsToppingDTO.isTopping) + commentsAreaRepository.save(commentsArea) + } } /** @@ -270,120 +261,128 @@ public class CommentsAreaService { * @param request CommentsQueriesDTO * @return CommentsAreaInfo */ - public CommentsAreaInfo queriesCommentsArea(CommentsQueriesDTO request) { - Sort.Order toppingOrder = Sort.Order.desc("topping"); + fun queriesCommentsArea(request: CommentsQueriesDTO): CommentsAreaInfo { + val toppingOrder = Sort.Order.desc("topping") - Sort.Order sortOrder = new Sort.Order( - request.isDesc() ? Sort.Direction.DESC : Sort.Direction.ASC, - Optional.ofNullable(request.getOrderBy()) - .filter(StringUtils::isNotBlank) - .map(ob -> switch (ob) { - case "hot" -> "likeCount"; - case "id" -> "uploadTime"; - default -> request.getOrderBy(); - }).orElse("likeCount")); + val sortOrder = Sort.Order( + if (request.isDesc) Sort.Direction.DESC else Sort.Direction.ASC, + Optional.ofNullable(request.orderBy) + .filter { cs: String? -> StringUtils.isNotBlank(cs) } + .map { ob: String? -> + when (ob) { + "hot" -> "likeCount" + "id" -> "uploadTime" + else -> request.orderBy + } + }.orElse("likeCount") + ) - int page = request.getPage() > 0 ? request.getPage() : 1; - int limit = request.getLimit() > 0 ? request.getLimit() : 10; + val page = if (request.page > 0) request.page else 1 + val limit = if (request.limit > 0) request.limit else 10 - Pageable pageable = PageRequest.of(page - 1, limit, Sort.by(toppingOrder, sortOrder)); + val pageable: Pageable = PageRequest.of(page - 1, limit, Sort.by(toppingOrder, sortOrder)) //主评论 - - Page mainCommentsList; - - if (StringUtils.isNotBlank(request.getJustSeeId())) { - mainCommentsList = commentsAreaRepository.findByCopilotIdAndUploaderIdAndDeleteAndMainCommentIdExists(request.getCopilotId(), request.getJustSeeId(), false, false, pageable); + val mainCommentsList = if (StringUtils.isNotBlank(request.justSeeId)) { + commentsAreaRepository.findByCopilotIdAndUploaderIdAndDeleteAndMainCommentIdExists( + request.copilotId, + request.justSeeId, + false, + false, + pageable + ) } else { - mainCommentsList = commentsAreaRepository.findByCopilotIdAndDeleteAndMainCommentIdExists(request.getCopilotId(), false, false, pageable); + commentsAreaRepository.findByCopilotIdAndDeleteAndMainCommentIdExists( + request.copilotId, + false, + false, + pageable + ) } - long count = mainCommentsList.getTotalElements(); + val count = mainCommentsList.totalElements - int pageNumber = mainCommentsList.getTotalPages(); + val pageNumber = mainCommentsList.totalPages // 判断是否存在下一页 - boolean hasNext = count - (long) page * limit > 0; + val hasNext = count - page.toLong() * limit > 0 //获取子评论 - List subCommentsList = commentsAreaRepository.findByMainCommentIdIn( - mainCommentsList.stream() - .map(CommentsArea::getId) - .toList() - ); + val subCommentsList = commentsAreaRepository.findByMainCommentIdIn( + mainCommentsList.stream() + .map { obj: CommentsArea -> obj.id } + .toList() + ) //将已删除评论内容替换为空 - subCommentsList.forEach(comment -> { - if (comment.isDelete()) { - comment.setMessage(""); + subCommentsList.forEach(Consumer { comment: CommentsArea -> + if (comment.isDelete) { + comment.setMessage("") } - }); + }) //所有评论 - List allComments = new ArrayList<>(mainCommentsList.stream().toList()); - allComments.addAll(subCommentsList); + val allComments: MutableList = ArrayList(mainCommentsList.stream().toList()) + allComments.addAll(subCommentsList) //获取所有评论用户 - List userId = allComments.stream().map(CommentsArea::getUploaderId).distinct().toList(); - Map maaUserMap = userRepository.findByUsersId(userId); + val userId = allComments.stream().map { obj: CommentsArea -> obj.uploaderId }.distinct().toList() + val maaUserMap = userRepository.findByUsersId(userId) //转换主评论数据并填充用户名 - List commentsInfos = mainCommentsList.stream().map(mainComment -> { - CommentsInfo commentsInfo = + val commentsInfos = mainCommentsList.stream().map { mainComment: CommentsArea -> + val commentsInfo = + commentConverter + .toCommentsInfo( + mainComment, + maaUserMap.getOrDefault( + mainComment.uploaderId, + MaaUser.UNKNOWN + ) + ) + val subCommentsInfoList = subCommentsList.stream() + .filter { comment: CommentsArea -> commentsInfo.commentId == comment.mainCommentId } //转换子评论数据并填充用户名 + .map { subComment: CommentsArea -> commentConverter - .toCommentsInfo( - mainComment - , maaUserMap.getOrDefault( - mainComment.getUploaderId() - , MaaUser.UNKNOWN - ) - ); - - List subCommentsInfoList = subCommentsList.stream() - .filter(comment -> Objects.equals(commentsInfo.getCommentId(), comment.getMainCommentId())) - //转换子评论数据并填充用户名 - .map(subComment -> - commentConverter - .toSubCommentsInfo( - subComment - //填充评论用户名 - , maaUserMap.getOrDefault( - subComment.getUploaderId(), - MaaUser.UNKNOWN - ) - ) - ).toList(); - - - commentsInfo.setSubCommentsInfos(subCommentsInfoList); - return commentsInfo; - }).toList(); - - return new CommentsAreaInfo().setHasNext(hasNext) - .setPage(pageNumber) - .setTotal(count) - .setData(commentsInfos); + .toSubCommentsInfo( + subComment, //填充评论用户名 + maaUserMap.getOrDefault( + subComment.uploaderId, + MaaUser.UNKNOWN + ) + ) + }.toList() + + + commentsInfo.setSubCommentsInfos(subCommentsInfoList) + commentsInfo + }.toList() + + return CommentsAreaInfo().setHasNext(hasNext) + .setPage(pageNumber) + .setTotal(count) + .setData(commentsInfos) } - private CommentsArea findCommentsById(String commentsId) { - Optional commentsArea = commentsAreaRepository.findById(commentsId); - Assert.isTrue(commentsArea.isPresent(), "评论不存在"); - return commentsArea.get(); + private fun findCommentsById(commentsId: String): CommentsArea { + val commentsArea = commentsAreaRepository.findById(commentsId) + Assert.isTrue(commentsArea.isPresent, "评论不存在") + return commentsArea.get() } - public void notificationStatus(String userId, String id, boolean status) { - Optional commentsAreaOptional = commentsAreaRepository.findById(id); - Assert.isTrue(commentsAreaOptional.isPresent(), "评论不存在"); - CommentsArea commentsArea = commentsAreaOptional.get(); - Assert.isTrue(Objects.equals(userId, commentsArea.getUploaderId()), "您没有权限修改"); - commentsArea.setNotification(status); - commentsAreaRepository.save(commentsArea); + fun notificationStatus(userId: String, id: String, status: Boolean) { + val commentsAreaOptional = commentsAreaRepository.findById(id) + Assert.isTrue(commentsAreaOptional.isPresent, "评论不存在") + val commentsArea = commentsAreaOptional.get() + Assert.isTrue(userId == commentsArea.uploaderId, "您没有权限修改") + commentsArea.setNotification(status) + commentsAreaRepository.save(commentsArea) } } diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/java/plus/maa/backend/service/CopilotService.kt index 00dd697f..b3f8ffe2 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotService.kt @@ -1,116 +1,114 @@ -package plus.maa.backend.service; - -import cn.hutool.core.collection.CollectionUtil; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.common.collect.Sets; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.Nullable; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.data.mongodb.core.query.Update; -import org.springframework.stereotype.Service; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import plus.maa.backend.common.utils.IdComponent; -import plus.maa.backend.common.utils.converter.CopilotConverter; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.controller.request.copilot.CopilotCUDRequest; -import plus.maa.backend.controller.request.copilot.CopilotDTO; -import plus.maa.backend.controller.request.copilot.CopilotQueriesRequest; -import plus.maa.backend.controller.request.copilot.CopilotRatingReq; -import plus.maa.backend.controller.response.MaaResultException; -import plus.maa.backend.controller.response.copilot.ArkLevelInfo; -import plus.maa.backend.controller.response.copilot.CopilotInfo; -import plus.maa.backend.controller.response.copilot.CopilotPageInfo; -import plus.maa.backend.repository.*; -import plus.maa.backend.repository.entity.*; -import plus.maa.backend.service.model.RatingCache; -import plus.maa.backend.service.model.RatingType; - -import java.math.BigDecimal; -import java.math.RoundingMode; -import java.time.LocalDateTime; -import java.time.temporal.ChronoUnit; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.AtomicReference; -import java.util.regex.Pattern; -import java.util.stream.Collectors; +package plus.maa.backend.service + +import cn.hutool.core.collection.CollectionUtil +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.ObjectMapper +import com.google.common.collect.Sets +import io.github.oshai.kotlinlogging.KotlinLogging +import org.apache.commons.lang3.StringUtils +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Pageable +import org.springframework.data.domain.Sort +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.core.query.Criteria +import org.springframework.data.mongodb.core.query.Query +import org.springframework.data.mongodb.core.query.Update +import org.springframework.stereotype.Service +import org.springframework.util.Assert +import org.springframework.util.ObjectUtils +import plus.maa.backend.common.utils.IdComponent +import plus.maa.backend.common.utils.converter.CopilotConverter +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.controller.request.copilot.CopilotCUDRequest +import plus.maa.backend.controller.request.copilot.CopilotDTO +import plus.maa.backend.controller.request.copilot.CopilotQueriesRequest +import plus.maa.backend.controller.request.copilot.CopilotRatingReq +import plus.maa.backend.controller.response.MaaResultException +import plus.maa.backend.controller.response.copilot.ArkLevelInfo +import plus.maa.backend.controller.response.copilot.CopilotInfo +import plus.maa.backend.controller.response.copilot.CopilotPageInfo +import plus.maa.backend.repository.* +import plus.maa.backend.repository.entity.Copilot +import plus.maa.backend.repository.entity.Copilot.OperationGroup +import plus.maa.backend.repository.entity.Rating +import plus.maa.backend.service.model.RatingCache +import plus.maa.backend.service.model.RatingType +import java.math.BigDecimal +import java.math.RoundingMode +import java.time.LocalDateTime +import java.time.temporal.ChronoUnit +import java.util.* +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicLong +import java.util.concurrent.atomic.AtomicReference +import java.util.function.Consumer +import java.util.regex.Pattern +import java.util.stream.Collectors +import kotlin.collections.component1 +import kotlin.math.ceil +import kotlin.math.ln +import kotlin.math.max + +private val log = KotlinLogging.logger { } /** * @author LoMu * Date 2022-12-25 19:57 */ -@Slf4j @Service -@RequiredArgsConstructor -public class CopilotService { - private final CopilotRepository copilotRepository; - private final RatingRepository ratingRepository; - private final MongoTemplate mongoTemplate; - private final ObjectMapper mapper; - private final ArkLevelService levelService; - private final RedisCache redisCache; - private final IdComponent idComponent; - private final UserRepository userRepository; - private final CommentsAreaRepository commentsAreaRepository; - private final MaaCopilotProperties properties; - - private final CopilotConverter copilotConverter; - - /* - 首页分页查询缓存配置 - 格式为:需要缓存的 orderBy 类型(也就是榜单类型) -> 缓存时间 - (Map.of()返回的是不可变对象,无需担心线程安全问题) - */ - private static final Map HOME_PAGE_CACHE_CONFIG = Map.of( - "hot", 3600 * 24L, - "views", 3600L, - "id", 300L - ); +class CopilotService( + private val copilotRepository: CopilotRepository, + private val ratingRepository: RatingRepository, + private val mongoTemplate: MongoTemplate, + private val mapper: ObjectMapper, + private val levelService: ArkLevelService, + private val redisCache: RedisCache, + private val idComponent: IdComponent, + private val userRepository: UserRepository, + private val commentsAreaRepository: CommentsAreaRepository, + private val properties: MaaCopilotProperties, + private val copilotConverter: CopilotConverter +) { + /** * 并修正前端的冗余部分 * * @param copilotDTO copilotDTO */ - private CopilotDTO correctCopilot(CopilotDTO copilotDTO) { - + private fun correctCopilot(copilotDTO: CopilotDTO): CopilotDTO { // 去除name的冗余部分 // todo 优化空处理代码美观程度 - if (copilotDTO.getGroups() != null) { - copilotDTO.getGroups().forEach( - group -> { - if (group.getOpers() != null) { - group.getOpers().forEach(oper -> oper - .setName(oper.getName() == null ? null : oper.getName().replaceAll("[\"“”]", ""))); - } - }); + + if (copilotDTO.groups != null) { + copilotDTO.groups.forEach( + Consumer { group: Copilot.Groups -> + if (group.opers != null) { + group.opers.forEach(Consumer { oper: OperationGroup -> + oper + .setName(if (oper.name == null) null else oper.name.replace("[\"“”]".toRegex(), "")) + }) + } + }) } - if (copilotDTO.getOpers() != null) { - copilotDTO.getOpers().forEach(operator -> operator - .setName(operator.getName() == null ? null : operator.getName().replaceAll("[\"“”]", ""))); + if (copilotDTO.opers != null) { + copilotDTO.opers.forEach(Consumer { operator: Copilot.Operators -> + operator + .setName(if (operator.name == null) null else operator.name.replace("[\"“”]".toRegex(), "")) + }) } // actions name 不是必须 - if (copilotDTO.getActions() != null) { - copilotDTO.getActions().forEach(action -> action - .setName(action.getName() == null ? null : action.getName().replaceAll("[\"“”]", ""))); + if (copilotDTO.actions != null) { + copilotDTO.actions.forEach(Consumer { action: Copilot.Action -> + action + .setName(if (action.name == null) null else action.name.replace("[\"“”]".toRegex(), "")) + }) } // 使用stageId存储作业关卡信息 - ArkLevel level = levelService.findByLevelIdFuzzy(copilotDTO.getStageName()); - if (level != null) { - copilotDTO.setStageName(level.getStageId()); - } - return copilotDTO; + val level = levelService.findByLevelIdFuzzy(copilotDTO.stageName) + copilotDTO.stageName = level.stageId + return copilotDTO } /** @@ -119,19 +117,19 @@ public class CopilotService { * @param content content * @return CopilotDTO */ - private CopilotDTO parseToCopilotDto(String content) { - Assert.notNull(content, "作业内容不可为空"); + private fun parseToCopilotDto(content: String): CopilotDTO { + Assert.notNull(content, "作业内容不可为空") try { - return mapper.readValue(content, CopilotDTO.class); - } catch (JsonProcessingException e) { - log.error("解析copilot失败", e); - throw new MaaResultException("解析copilot失败"); + return mapper.readValue(content, CopilotDTO::class.java) + } catch (e: JsonProcessingException) { + log.error(e) { "解析copilot失败" } + throw MaaResultException("解析copilot失败") } } - private Pattern caseInsensitive(String s) { - return Pattern.compile(s, Pattern.CASE_INSENSITIVE); + private fun caseInsensitive(s: String): Pattern { + return Pattern.compile(s, Pattern.CASE_INSENSITIVE) } @@ -141,74 +139,82 @@ public class CopilotService { * @param content 前端编辑json作业内容 * @return 返回_id */ - public Long upload(String loginUserId, String content) { - CopilotDTO copilotDTO = correctCopilot(parseToCopilotDto(content)); + fun upload(loginUserId: String?, content: String): Long { + val copilotDTO = correctCopilot(parseToCopilotDto(content)) // 将其转换为数据库存储对象 - Copilot copilot = copilotConverter.toCopilot(copilotDTO, - idComponent.getId(Copilot.META), loginUserId, LocalDateTime.now(), content); - copilotRepository.insert(copilot); - return copilot.getCopilotId(); + val copilot = copilotConverter.toCopilot( + copilotDTO, + idComponent.getId(Copilot.META), loginUserId, LocalDateTime.now(), content + ) + copilotRepository.insert(copilot) + return copilot.copilotId } /** * 根据作业id删除作业 */ - public void delete(String loginUserId, CopilotCUDRequest request) { - copilotRepository.findByCopilotId(request.getId()).ifPresent(copilot -> { - Assert.state(Objects.equals(copilot.getUploaderId(), loginUserId), "您无法修改不属于您的作业"); - copilot.setDelete(true); - copilotRepository.save(copilot); + fun delete(loginUserId: String, request: CopilotCUDRequest) { + copilotRepository.findByCopilotId(request.id).ifPresent { copilot: Copilot -> + Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") + copilot.setDelete(true) + copilotRepository.save(copilot) /* * 删除作业时,如果被删除的项在 Redis 首页缓存中存在,则清空对应的首页缓存 * 新增作业就不必,因为新作业显然不会那么快就登上热度榜和浏览量榜 */ - for (var kv : HOME_PAGE_CACHE_CONFIG.entrySet()) { - String key = String.format("home:%s:copilotIds", kv.getKey()); - String pattern = String.format("home:%s:*", kv.getKey()); - if (redisCache.valueMemberInSet(key, copilot.getCopilotId())) { - redisCache.removeCacheByPattern(pattern); + for ((key1) in HOME_PAGE_CACHE_CONFIG) { + val key = String.format("home:%s:copilotIds", key1) + val pattern = String.format("home:%s:*", key1) + if (redisCache.valueMemberInSet(key, copilot.copilotId)) { + redisCache.removeCacheByPattern(pattern) } } - }); + } } /** * 指定查询 */ - public Optional getCopilotById(String userIdOrIpAddress, Long id) { + fun getCopilotById(userIdOrIpAddress: String, id: Long): Optional { // 根据ID获取作业, 如作业不存在则抛出异常返回 - Optional copilotOptional = copilotRepository.findByCopilotIdAndDeleteIsFalse(id); - return copilotOptional.map(copilot -> { + val copilotOptional = copilotRepository.findByCopilotIdAndDeleteIsFalse(id) + return copilotOptional.map { copilot: Copilot -> // 60分钟内限制同一个用户对访问量的增加 - RatingCache cache = redisCache.getCache("views:" + userIdOrIpAddress, RatingCache.class); - if (Objects.isNull(cache) || Objects.isNull(cache.getCopilotIds()) || - !cache.getCopilotIds().contains(id)) { - Query query = Query.query(Criteria.where("copilotId").is(id)); - Update update = new Update(); + val cache = redisCache.getCache("views:$userIdOrIpAddress", RatingCache::class.java) + if (Objects.isNull(cache) || Objects.isNull(cache!!.copilotIds) || + !cache.copilotIds.contains(id) + ) { + val query = Query.query(Criteria.where("copilotId").`is`(id)) + val update = Update() // 增加一次views - update.inc("views"); - mongoTemplate.updateFirst(query, update, Copilot.class); + update.inc("views") + mongoTemplate.updateFirst(query, update, Copilot::class.java) if (Objects.isNull(cache)) { - redisCache.setCache("views:" + userIdOrIpAddress, new RatingCache(Sets.newHashSet(id))); + redisCache.setCache("views:$userIdOrIpAddress", RatingCache(Sets.newHashSet(id))) } else { - redisCache.updateCache("views:" + userIdOrIpAddress, RatingCache.class, cache, - updateCache -> { - updateCache.getCopilotIds().add(id); - return updateCache; - }, 60, TimeUnit.MINUTES); + redisCache.updateCache( + "views:$userIdOrIpAddress", RatingCache::class.java, cache, + { updateCache: RatingCache? -> + updateCache!!.copilotIds.add(id) + updateCache + }, 60, TimeUnit.MINUTES + ) } } - Map maaUser = userRepository.findByUsersId(List.of(copilot.getUploaderId())); + val maaUser = userRepository.findByUsersId(listOf(copilot.uploaderId)) // 新评分系统 - RatingType ratingType = ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COPILOT, - Long.toString(copilot.getCopilotId()), userIdOrIpAddress) - .map(Rating::getRating) - .orElse(null); - // 用户点进作业会显示点赞信息 - return formatCopilot(copilot, ratingType, maaUser.get(copilot.getUploaderId()).getUserName(), - commentsAreaRepository.countByCopilotIdAndDelete(copilot.getCopilotId(), false)); - }); + val ratingType = ratingRepository.findByTypeAndKeyAndUserId( + Rating.KeyType.COPILOT, + copilot.copilotId.toString(), userIdOrIpAddress + ) + .map { obj: Rating -> obj.rating } + .orElse(null) + formatCopilot( + copilot, ratingType, maaUser[copilot.uploaderId]!!.userName, + commentsAreaRepository.countByCopilotIdAndDelete(copilot.copilotId, false) + ) + } } /** @@ -219,161 +225,172 @@ public class CopilotService { * @param request 模糊查询 * @return CopilotPageInfo */ - public CopilotPageInfo queriesCopilot(@Nullable String userId, CopilotQueriesRequest request) { - - AtomicLong cacheTimeout = new AtomicLong(); - AtomicReference cacheKey = new AtomicReference<>(); - AtomicReference setKey = new AtomicReference<>(); + fun queriesCopilot(userId: String?, request: CopilotQueriesRequest): CopilotPageInfo { + val cacheTimeout = AtomicLong() + val cacheKey = AtomicReference() + val setKey = AtomicReference() // 只缓存默认状态下热度和访问量排序的结果,并且最多只缓存前三页 - if (request.getPage() <= 3 && request.getDocument() == null && request.getLevelKeyword() == null && - request.getUploaderId() == null && request.getOperator() == null && - CollectionUtil.isEmpty(request.getCopilotIds())) { - - Optional cacheOptional = Optional.ofNullable(request.getOrderBy()) - .filter(StringUtils::isNotBlank) - .map(HOME_PAGE_CACHE_CONFIG::get) - .map(t -> { - cacheTimeout.set(t); - setKey.set(String.format("home:%s:copilotIds", request.getOrderBy())); - cacheKey.set(String.format("home:%s:%s", request.getOrderBy(), request.hashCode())); - return redisCache.getCache(cacheKey.get(), CopilotPageInfo.class); - }); + if (request.page <= 3 && request.document == null && request.levelKeyword == null && request.uploaderId == null && request.operator == null && + CollectionUtil.isEmpty(request.copilotIds) + ) { + val cacheOptional = Optional.ofNullable(request.orderBy) + .filter { cs: String? -> StringUtils.isNotBlank(cs) } + .map { key: String? -> HOME_PAGE_CACHE_CONFIG[key] } + .map { t: Long? -> + cacheTimeout.set(t!!) + setKey.set(String.format("home:%s:copilotIds", request.orderBy)) + cacheKey.set(String.format("home:%s:%s", request.orderBy, request.hashCode())) + redisCache.getCache(cacheKey.get(), CopilotPageInfo::class.java) + } // 如果缓存存在则直接返回 - if (cacheOptional.isPresent()) { - return cacheOptional.get(); + if (cacheOptional.isPresent) { + return cacheOptional.get() } } - Sort.Order sortOrder = new Sort.Order( - request.isDesc() ? Sort.Direction.DESC : Sort.Direction.ASC, - Optional.ofNullable(request.getOrderBy()) - .filter(StringUtils::isNotBlank) - .map(ob -> switch (ob) { - case "hot" -> "hotScore"; - case "id" -> "copilotId"; - default -> request.getOrderBy(); - }).orElse("copilotId")); + val sortOrder = Sort.Order( + if (request.isDesc) Sort.Direction.DESC else Sort.Direction.ASC, + Optional.ofNullable(request.orderBy) + .filter { cs: String? -> StringUtils.isNotBlank(cs) } + .map { ob: String? -> + when (ob) { + "hot" -> "hotScore" + "id" -> "copilotId" + else -> request.orderBy + } + }.orElse("copilotId") + ) // 判断是否有值 无值则为默认 - int page = request.getPage() > 0 ? request.getPage() : 1; - int limit = request.getLimit() > 0 ? request.getLimit() : 10; + val page = if (request.page > 0) request.page else 1 + val limit = if (request.limit > 0) request.limit else 10 - Pageable pageable = PageRequest.of(page - 1, limit, Sort.by(sortOrder)); + val pageable: Pageable = PageRequest.of(page - 1, limit, Sort.by(sortOrder)) - Query queryObj = new Query(); - Criteria criteriaObj = new Criteria(); + val queryObj = Query() + val criteriaObj = Criteria() - Set andQueries = new HashSet<>(); - Set norQueries = new HashSet<>(); - Set orQueries = new HashSet<>(); + val andQueries: MutableSet = HashSet() + val norQueries: MutableSet = HashSet() + val orQueries: MutableSet = HashSet() - andQueries.add(Criteria.where("delete").is(false)); + andQueries.add(Criteria.where("delete").`is`(false)) //关卡名、关卡类型、关卡编号 - if (StringUtils.isNotBlank(request.getLevelKeyword())) { - List levelInfo = levelService.queryLevelInfosByKeyword(request.getLevelKeyword()); + if (StringUtils.isNotBlank(request.levelKeyword)) { + val levelInfo = levelService.queryLevelInfosByKeyword(request.levelKeyword) if (levelInfo.isEmpty()) { - andQueries.add(Criteria.where("stageName").regex(caseInsensitive(request.getLevelKeyword()))); + andQueries.add(Criteria.where("stageName").regex(caseInsensitive(request.levelKeyword))) } else { - andQueries.add(Criteria.where("stageName").in(levelInfo.stream() - .map(ArkLevelInfo::getStageId).collect(Collectors.toSet()))); + andQueries.add( + Criteria.where("stageName").`in`( + levelInfo.stream() + .map { obj: ArkLevelInfo -> obj.stageId }.collect(Collectors.toSet()) + ) + ) } } // 作业id列表 - if (CollectionUtil.isNotEmpty(request.getCopilotIds())) { - andQueries.add(Criteria.where("copilotId").in(request.getCopilotIds())); + if (CollectionUtil.isNotEmpty(request.copilotIds)) { + andQueries.add(Criteria.where("copilotId").`in`(request.copilotIds)) } //标题、描述、神秘代码 - if (StringUtils.isNotBlank(request.getDocument())) { - orQueries.add(Criteria.where("doc.title").regex(caseInsensitive(request.getDocument()))); - orQueries.add(Criteria.where("doc.details").regex(caseInsensitive(request.getDocument()))); + if (StringUtils.isNotBlank(request.document)) { + orQueries.add(Criteria.where("doc.title").regex(caseInsensitive(request.document))) + orQueries.add(Criteria.where("doc.details").regex(caseInsensitive(request.document))) } //包含或排除干员 - String oper = request.getOperator(); + var oper = request.operator if (StringUtils.isNotBlank(oper)) { - oper = oper.replaceAll("[“\"”]", ""); - String[] operators = oper.split(","); - for (String operator : operators) { + oper = oper.replace("[“\"”]".toRegex(), "") + val operators = oper.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + for (operator in operators) { if (operator.startsWith("~")) { - String exclude = operator.substring(1); + val exclude = operator.substring(1) // 排除查询指定干员 - norQueries.add(Criteria.where("opers.name").regex(exclude)); + norQueries.add(Criteria.where("opers.name").regex(exclude)) } else { // 模糊匹配查询指定干员 - andQueries.add(Criteria.where("opers.name").regex(operator)); + andQueries.add(Criteria.where("opers.name").regex(operator)) } } } //查看自己 - if (StringUtils.isNotBlank(request.getUploaderId())) { - if ("me".equals(request.getUploaderId())) { + if (StringUtils.isNotBlank(request.uploaderId)) { + if ("me" == request.uploaderId) { if (!ObjectUtils.isEmpty(userId)) { - andQueries.add(Criteria.where("uploaderId").is(userId)); + andQueries.add(Criteria.where("uploaderId").`is`(userId)) } } else { - andQueries.add(Criteria.where("uploaderId").is(request.getUploaderId())); + andQueries.add(Criteria.where("uploaderId").`is`(request.uploaderId)) } } // 封装查询 - if (!andQueries.isEmpty()) { - criteriaObj.andOperator(andQueries); + if (andQueries.isNotEmpty()) { + criteriaObj.andOperator(andQueries) } - if (!norQueries.isEmpty()) { - criteriaObj.norOperator(norQueries); + if (norQueries.isNotEmpty()) { + criteriaObj.norOperator(norQueries) } - if (!orQueries.isEmpty()) { - criteriaObj.orOperator(orQueries); + if (orQueries.isNotEmpty()) { + criteriaObj.orOperator(orQueries) } - queryObj.addCriteria(criteriaObj); + queryObj.addCriteria(criteriaObj) // 查询总数 - long count = mongoTemplate.count(queryObj, Copilot.class); + val count = mongoTemplate.count(queryObj, Copilot::class.java) // 分页排序查询 - List copilots = mongoTemplate.find(queryObj.with(pageable), Copilot.class); + val copilots = mongoTemplate.find(queryObj.with(pageable), Copilot::class.java) // 填充前端所需信息 - Set copilotIds = copilots.stream().map(Copilot::getCopilotId).collect(Collectors.toSet()); - Map maaUsers = userRepository.findByUsersId(copilots.stream().map(Copilot::getUploaderId).toList()); - Map commentsCount = commentsAreaRepository.findByCopilotIdInAndDelete(copilotIds, false) - .collect(Collectors.groupingBy(CommentsArea::getCopilotId, Collectors.counting())); + val copilotIds = copilots.map { + it.copilotId + }.toSet() + val maaUsers = userRepository.findByUsersId(copilots.map { it.uploaderId }.toList()) + val commentsCount = commentsAreaRepository.findByCopilotIdInAndDelete(copilotIds,false) + .groupBy { it.copilotId } + .mapValues { it.value.size.toLong() } // 新版评分系统 // 反正目前首页和搜索不会直接展示当前用户有没有点赞,干脆直接不查,要用户点进作业才显示自己是否点赞 - List infos = copilots.stream().map(copilot -> - formatCopilot(copilot, null, - maaUsers.get(copilot.getUploaderId()).getUserName(), - commentsCount.get(copilot.getCopilotId()))) - .toList(); + val infos = copilots.stream().map { copilot: Copilot -> + formatCopilot( + copilot, null, + maaUsers[copilot.uploaderId]!!.userName, + commentsCount[copilot.copilotId] + ) + } + .toList() // 计算页面 - int pageNumber = (int) Math.ceil((double) count / limit); + val pageNumber = ceil(count.toDouble() / limit).toInt() // 判断是否存在下一页 - boolean hasNext = count - (long) page * limit > 0; + val hasNext = count - page.toLong() * limit > 0 // 封装数据 - CopilotPageInfo data = new CopilotPageInfo() - .setTotal(count) - .setHasNext(hasNext) - .setData(infos) - .setPage(pageNumber); + val data = CopilotPageInfo() + .setTotal(count) + .setHasNext(hasNext) + .setData(infos) + .setPage(pageNumber) // 决定是否缓存 if (cacheKey.get() != null) { // 记录存在的作业id - redisCache.addSet(setKey.get(), copilotIds, cacheTimeout.get()); + redisCache.addSet(setKey.get(), copilotIds, cacheTimeout.get()) // 缓存数据 - redisCache.setCache(cacheKey.get(), data, cacheTimeout.get()); + redisCache.setCache(cacheKey.get(), data, cacheTimeout.get()) } - return data; + return data } /** @@ -381,16 +398,16 @@ public class CopilotService { * * @param copilotCUDRequest 作业_id content */ - public void update(String loginUserId, CopilotCUDRequest copilotCUDRequest) { - String content = copilotCUDRequest.getContent(); - Long id = copilotCUDRequest.getId(); - copilotRepository.findByCopilotId(id).ifPresent(copilot -> { - CopilotDTO copilotDTO = correctCopilot(parseToCopilotDto(content)); - Assert.state(Objects.equals(copilot.getUploaderId(), loginUserId), "您无法修改不属于您的作业"); - copilot.setUploadTime(LocalDateTime.now()); - copilotConverter.updateCopilotFromDto(copilotDTO, content, copilot); - copilotRepository.save(copilot); - }); + fun update(loginUserId: String, copilotCUDRequest: CopilotCUDRequest) { + val content = copilotCUDRequest.content + val id = copilotCUDRequest.id + copilotRepository.findByCopilotId(id).ifPresent { copilot: Copilot -> + val copilotDTO = correctCopilot(parseToCopilotDto(content)) + Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") + copilot.setUploadTime(LocalDateTime.now()) + copilotConverter.updateCopilotFromDto(copilotDTO, content, copilot) + copilotRepository.save(copilot) + } } /** @@ -399,140 +416,164 @@ public class CopilotService { * @param request 评分 * @param userIdOrIpAddress 用于已登录用户作出评分 */ - public void rates(String userIdOrIpAddress, CopilotRatingReq request) { - String rating = request.getRating(); + fun rates(userIdOrIpAddress: String?, request: CopilotRatingReq) { + val rating = request.rating - Assert.isTrue(copilotRepository.existsCopilotsByCopilotId(request.getId()), "作业id不存在"); + Assert.isTrue(copilotRepository.existsCopilotsByCopilotId(request.id), "作业id不存在") - int likeCountChange = 0; - int dislikeCountChange = 0; - Optional ratingOptional = ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COPILOT, - Long.toString(request.getId()), userIdOrIpAddress); + var likeCountChange = 0 + var dislikeCountChange = 0 + val ratingOptional = ratingRepository.findByTypeAndKeyAndUserId( + Rating.KeyType.COPILOT, + request.id.toString(), userIdOrIpAddress + ) // 如果评分存在则更新评分 - if (ratingOptional.isPresent()) { - Rating rating1 = ratingOptional.get(); + if (ratingOptional.isPresent) { + val rating1 = ratingOptional.get() // 如果评分相同,则不做任何操作 - if (Objects.equals(rating1.getRating(), RatingType.fromRatingType(rating))) { - return; + if (rating1.rating == RatingType.fromRatingType(rating)) { + return } // 如果评分不同则更新评分 - RatingType oldRatingType = rating1.getRating(); - rating1.setRating(RatingType.fromRatingType(rating)); - rating1.setRateTime(LocalDateTime.now()); - ratingRepository.save(rating1); + val oldRatingType = rating1.rating + rating1.setRating(RatingType.fromRatingType(rating)) + rating1.setRateTime(LocalDateTime.now()) + ratingRepository.save(rating1) // 计算评分变化 - likeCountChange = rating1.getRating() == RatingType.LIKE ? 1 : - (oldRatingType != RatingType.LIKE ? 0 : -1); - dislikeCountChange = rating1.getRating() == RatingType.DISLIKE ? 1 : - (oldRatingType != RatingType.DISLIKE ? 0 : -1); + likeCountChange = + if (rating1.rating == RatingType.LIKE) 1 else (if (oldRatingType != RatingType.LIKE) 0 else -1) + dislikeCountChange = + if (rating1.rating == RatingType.DISLIKE) 1 else (if (oldRatingType != RatingType.DISLIKE) 0 else -1) } // 不存在评分 则添加新的评分 - if (ratingOptional.isEmpty()) { - Rating newRating = new Rating() - .setType(Rating.KeyType.COPILOT) - .setKey(Long.toString(request.getId())) - .setUserId(userIdOrIpAddress) - .setRating(RatingType.fromRatingType(rating)) - .setRateTime(LocalDateTime.now()); - - ratingRepository.insert(newRating); + if (ratingOptional.isEmpty) { + val newRating = Rating() + .setType(Rating.KeyType.COPILOT) + .setKey(request.id.toString()) + .setUserId(userIdOrIpAddress) + .setRating(RatingType.fromRatingType(rating)) + .setRateTime(LocalDateTime.now()) + + ratingRepository.insert(newRating) // 计算评分变化 - likeCountChange = newRating.getRating() == RatingType.LIKE ? 1 : 0; - dislikeCountChange = newRating.getRating() == RatingType.DISLIKE ? 1 : 0; + likeCountChange = if (newRating.rating == RatingType.LIKE) 1 else 0 + dislikeCountChange = if (newRating.rating == RatingType.DISLIKE) 1 else 0 } // 获取只包含评分的作业 - Query query = Query.query(Criteria - .where("copilotId").is(request.getId()) - .and("delete").is(false) - ); + var query = Query.query( + Criteria + .where("copilotId").`is`(request.id) + .and("delete").`is`(false) + ) // 排除 _id,防止误 save 该不完整作业后原有数据丢失 - query.fields().include("likeCount", "dislikeCount").exclude("_id"); - Copilot copilot = mongoTemplate.findOne(query, Copilot.class); - Assert.notNull(copilot, "作业不存在"); + query.fields().include("likeCount", "dislikeCount").exclude("_id") + val copilot = mongoTemplate.findOne(query, Copilot::class.java) + Assert.notNull(copilot, "作业不存在") // 计算评分相关 - long likeCount = copilot.getLikeCount() + likeCountChange; - likeCount = likeCount < 0 ? 0 : likeCount; - long ratingCount = likeCount + copilot.getDislikeCount() + dislikeCountChange; - ratingCount = ratingCount < 0 ? 0 : ratingCount; + var likeCount = copilot!!.likeCount + likeCountChange + likeCount = if (likeCount < 0) 0 else likeCount + var ratingCount = likeCount + copilot.dislikeCount + dislikeCountChange + ratingCount = if (ratingCount < 0) 0 else ratingCount - double rawRatingLevel = ratingCount != 0 ? (double) likeCount / ratingCount : 0; - BigDecimal bigDecimal = new BigDecimal(rawRatingLevel); + val rawRatingLevel = if (ratingCount != 0L) likeCount.toDouble() / ratingCount else 0.0 + val bigDecimal = BigDecimal(rawRatingLevel) // 只取一位小数点 - double ratingLevel = bigDecimal.setScale(1, RoundingMode.HALF_UP).doubleValue(); + val ratingLevel = bigDecimal.setScale(1, RoundingMode.HALF_UP).toDouble() // 更新数据 - query = Query.query(Criteria - .where("copilotId").is(request.getId()) - .and("delete").is(false) - ); - Update update = new Update(); - update.set("likeCount", likeCount); - update.set("dislikeCount", ratingCount - likeCount); - update.set("ratingLevel", (int) (ratingLevel * 10)); - update.set("ratingRatio", ratingLevel); - mongoTemplate.updateFirst(query, update, Copilot.class); + query = Query.query( + Criteria + .where("copilotId").`is`(request.id) + .and("delete").`is`(false) + ) + val update = Update() + update["likeCount"] = likeCount + update["dislikeCount"] = ratingCount - likeCount + update["ratingLevel"] = (ratingLevel * 10).toInt() + update["ratingRatio"] = ratingLevel + mongoTemplate.updateFirst(query, update, Copilot::class.java) // 记录近期评分变化量前 100 的作业 id - redisCache.incZSet("rate:hot:copilotIds", - Long.toString(request.getId()), - 1, 100, 3600 * 3); - } - - public static double getHotScore(Copilot copilot, long lastWeekLike, long lastWeekDislike) { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime uploadTime = copilot.getUploadTime(); - // 基于时间的基础分 - double base = 6d; - // 相比上传时间过了多少周 - long pastedWeeks = ChronoUnit.WEEKS.between(uploadTime, now) + 1; - base = base / Math.log(pastedWeeks + 1); - // 上一周好评率 - long ups = Math.max(lastWeekLike, 1); - long downs = Math.max(lastWeekDislike, 0); - double greatRate = (double) ups / (ups + downs); - if ((ups + downs) >= 5 && downs >= ups) { - // 将信赖就差评过多的作业打入地狱 - base = base * greatRate; - } - // 上一周好评率 * (上一周评分数 / 10) * (浏览数 / 10) / 过去的周数 - double s = greatRate * (copilot.getViews() / 10d) - * Math.max((ups + downs) / 10d, 1) / pastedWeeks; - double order = Math.log(Math.max(s, 1)); - return order + s / 1000d + base; + redisCache.incZSet( + "rate:hot:copilotIds", + request.id.toString(), + 1.0, 100, (3600 * 3).toLong() + ) } /** - * 将数据库内容转换为前端所需格式
+ * 将数据库内容转换为前端所需格式

* 新版评分系统 */ - private CopilotInfo formatCopilot(Copilot copilot, @Nullable RatingType ratingType, String userName, - Long commentsCount) { - CopilotInfo info = copilotConverter.toCopilotInfo(copilot, userName, copilot.getCopilotId(), - commentsCount); - - info.setRatingRatio(copilot.getRatingRatio()); - info.setRatingLevel(copilot.getRatingLevel()); + private fun formatCopilot( + copilot: Copilot, ratingType: RatingType?, userName: String, + commentsCount: Long? + ): CopilotInfo { + val info = copilotConverter.toCopilotInfo( + copilot, userName, copilot.copilotId, + commentsCount + ) + + info.ratingRatio = copilot.ratingRatio + info.ratingLevel = copilot.ratingLevel if (ratingType != null) { - info.setRatingType(ratingType.getDisplay()); + info.ratingType = ratingType.display } // 评分数少于一定数量 - info.setNotEnoughRating(copilot.getLikeCount() + copilot.getDislikeCount() <= properties.getCopilot().getMinValueShowNotEnoughRating()); + info.isNotEnoughRating = + copilot.likeCount + copilot.dislikeCount <= properties.copilot.minValueShowNotEnoughRating - info.setAvailable(true); + info.isAvailable = true // 兼容客户端, 将作业ID替换为数字ID - copilot.setId(Long.toString(copilot.getCopilotId())); - return info; + copilot.setId(copilot.copilotId.toString()) + return info + } + + fun notificationStatus(userId: String, copilotId: Long?, status: Boolean) { + val copilotOptional = copilotRepository.findByCopilotId(copilotId) + Assert.isTrue(copilotOptional.isPresent, "copilot不存在") + val copilot = copilotOptional.get() + Assert.isTrue(userId == copilot.uploaderId, "您没有权限修改") + copilot.setNotification(status) + copilotRepository.save(copilot) } - public void notificationStatus(String userId, Long copilotId, boolean status) { - Optional copilotOptional = copilotRepository.findByCopilotId(copilotId); - Assert.isTrue(copilotOptional.isPresent(), "copilot不存在"); - Copilot copilot = copilotOptional.get(); - Assert.isTrue(Objects.equals(userId, copilot.getUploaderId()), "您没有权限修改"); - copilot.setNotification(status); - copilotRepository.save(copilot); + companion object { + /* + 首页分页查询缓存配置 + 格式为:需要缓存的 orderBy 类型(也就是榜单类型) -> 缓存时间 + (Map.of()返回的是不可变对象,无需担心线程安全问题) + */ + private val HOME_PAGE_CACHE_CONFIG: Map = java.util.Map.of( + "hot", 3600 * 24L, + "views", 3600L, + "id", 300L + ) + + fun getHotScore(copilot: Copilot, lastWeekLike: Long, lastWeekDislike: Long): Double { + val now = LocalDateTime.now() + val uploadTime = copilot.uploadTime + // 基于时间的基础分 + var base = 6.0 + // 相比上传时间过了多少周 + val pastedWeeks = ChronoUnit.WEEKS.between(uploadTime, now) + 1 + base /= ln((pastedWeeks + 1).toDouble()) + // 上一周好评率 + val ups = max(lastWeekLike.toDouble(), 1.0).toLong() + val downs = max(lastWeekDislike.toDouble(), 0.0).toLong() + val greatRate = ups.toDouble() / (ups + downs) + if ((ups + downs) >= 5 && downs >= ups) { + // 将信赖就差评过多的作业打入地狱 + base *= greatRate + } + // 上一周好评率 * (上一周评分数 / 10) * (浏览数 / 10) / 过去的周数 + val s = (greatRate * (copilot.views / 10.0) + * max((ups + downs) / 10.0, 1.0)) / pastedWeeks + val order = ln(max(s, 1.0)) + return order + s / 1000.0 + base + } } } \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java index 5ffc74e1..2d2cf8f3 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java @@ -107,15 +107,11 @@ private void refresh(Collection copilotIdSTRs, Iterable copilot for (Copilot copilot : copilots) { long likeCount = likeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 1L); long dislikeCount = dislikeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 0L); - double hotScore = CopilotService.getHotScore(copilot, likeCount, dislikeCount); + double hotScore = CopilotService.Companion.getHotScore(copilot, likeCount, dislikeCount); // 判断关卡是否开放 ArkLevel level = arkLevelService.findByLevelIdFuzzy(copilot.getStageName()); // 关卡已关闭,且作业在关闭前上传 - if (level != null && - level.getCloseTime() != null && - copilot.getFirstUploadTime() != null && - Boolean.FALSE.equals(level.getIsOpen()) && - copilot.getFirstUploadTime().isBefore(level.getCloseTime())) { + if (level.getCloseTime() != null && copilot.getFirstUploadTime() != null && Boolean.FALSE.equals(level.getIsOpen()) && copilot.getFirstUploadTime().isBefore(level.getCloseTime())) { // 非开放关卡打入冷宫 hotScore /= 3; From 0fb82fc12945a3e6525bf66f3ac77fe742e0f3d1 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Mon, 5 Feb 2024 18:38:13 +0800 Subject: [PATCH 064/168] fix: log format corrected --- .../maa/backend/service/ArkGameDataService.kt | 16 ++++++++-------- .../maa/backend/service/ArkLevelParserService.kt | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt index f04d0332..989ab167 100644 --- a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt +++ b/src/main/java/plus/maa/backend/service/ArkGameDataService.kt @@ -66,12 +66,12 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { fun findZone(levelId: String, code: String, stageId: String): ArkZone? { val stage = findStage(levelId, code, stageId) if (stage == null) { - log.error { "${"[DATA]stage不存在:{}, Level: {}"} $stageId $levelId" } + log.error { "[DATA]stage不存在:$stageId, Level: $levelId" } return null } val zone = zoneMap[stage.zoneId] if (zone == null) { - log.error { "${"[DATA]zone不存在:{}, Level: {}"} ${stage.zoneId} $levelId" } + log.error { "[DATA]zone不存在:${stage.zoneId}, Level: $levelId" } } return zone } @@ -122,7 +122,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { levelStageMap[it.lowercase(Locale.getDefault())] = v } } - log.info { "${"[DATA]获取stage数据成功, 共{}条"} ${levelStageMap.size}" } + log.info { "[DATA]获取stage数据成功, 共${levelStageMap.size}条" } } } catch (e: Exception) { log.error(e) { "[DATA]同步stage数据异常" } @@ -145,7 +145,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { val temp = mapper.convertValue(zonesNode, object : TypeReference>() {}) zoneMap.clear() zoneMap.putAll(temp) - log.info { "${"[DATA]获取zone数据成功, 共{}条"} ${zoneMap.size}" } + log.info { "[DATA]获取zone数据成功, 共${zoneMap.size}条" } } } catch (e: Exception) { log.error(e) { "[DATA]同步zone数据异常" } @@ -178,7 +178,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { } zoneActivityMap.clear() zoneActivityMap.putAll(temp) - log.info { "${"[DATA]获取activity数据成功, 共{}条"} ${zoneActivityMap.size}" } + log.info { "[DATA]获取activity数据成功, 共${zoneActivityMap.size}条" } } } catch (e: Exception) { log.error(e) { "[DATA]同步activity数据异常" } @@ -212,7 +212,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { } arkCharacterMap[ids[2]] = c } - log.info { "${"[DATA]获取character数据成功, 共{}条"} ${arkCharacterMap.size}" } + log.info { "[DATA]获取character数据成功, 共${arkCharacterMap.size}条" } } } catch (e: Exception) { log.error(e) { "[DATA]同步character数据异常" } @@ -235,7 +235,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { val towerNode = node.get("towers") arkTowerMap.clear() arkTowerMap.putAll(mapper.convertValue(towerNode, object : TypeReference>() {})) - log.info { "${"[DATA]获取tower数据成功, 共{}条"} ${arkTowerMap.size}" } + log.info { "[DATA]获取tower数据成功, 共${arkTowerMap.size}条" } } } catch (e: Exception) { log.error(e) { "[DATA]同步tower数据异常" } @@ -262,7 +262,7 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { crisisV2InfoMap.forEach { (k, v) -> temp[ArkLevelUtil.getKeyInfoById(k)] = v } arkCrisisV2InfoMap.clear() arkCrisisV2InfoMap.putAll(temp) - log.info { "${"[DATA]获取crisisV2Info数据成功, 共{}条"} ${arkCrisisV2InfoMap.size}" } + log.info { "[DATA]获取crisisV2Info数据成功, 共${arkCrisisV2InfoMap.size}条" } } } catch (e: Exception) { log.error(e) { "[DATA]同步crisisV2Info数据异常" } diff --git a/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt b/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt index 067715bf..199954ab 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt +++ b/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt @@ -39,7 +39,7 @@ class ArkLevelParserService(private val parsers: List) { private fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { val type = ArkLevelType.fromLevelId(level.levelId) if (ArkLevelType.UNKNOWN == type) { - log.warn { "${"[PARSER]未知关卡类型:{}"} ${level.levelId}" } + log.warn { "[PARSER]未知关卡类型:${level.levelId}" } return null } val parser = parsers.stream() From 1e45e818c8cb4b5498becfa791cfc507b5ad8297 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Mon, 5 Feb 2024 20:41:59 +0800 Subject: [PATCH 065/168] Rename .java to .kt --- .../service/{CopilotSetService.java => CopilotSetService.kt} | 0 .../maa/backend/service/{EmailService.java => EmailService.kt} | 0 .../plus/maa/backend/service/{FileService.java => FileService.kt} | 0 .../{UserDetailServiceImpl.java => UserDetailServiceImpl.kt} | 0 .../plus/maa/backend/service/{UserService.java => UserService.kt} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/service/{CopilotSetService.java => CopilotSetService.kt} (100%) rename src/main/java/plus/maa/backend/service/{EmailService.java => EmailService.kt} (100%) rename src/main/java/plus/maa/backend/service/{FileService.java => FileService.kt} (100%) rename src/main/java/plus/maa/backend/service/{UserDetailServiceImpl.java => UserDetailServiceImpl.kt} (100%) rename src/main/java/plus/maa/backend/service/{UserService.java => UserService.kt} (100%) diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.java b/src/main/java/plus/maa/backend/service/CopilotSetService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/CopilotSetService.java rename to src/main/java/plus/maa/backend/service/CopilotSetService.kt diff --git a/src/main/java/plus/maa/backend/service/EmailService.java b/src/main/java/plus/maa/backend/service/EmailService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/EmailService.java rename to src/main/java/plus/maa/backend/service/EmailService.kt diff --git a/src/main/java/plus/maa/backend/service/FileService.java b/src/main/java/plus/maa/backend/service/FileService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/FileService.java rename to src/main/java/plus/maa/backend/service/FileService.kt diff --git a/src/main/java/plus/maa/backend/service/UserDetailServiceImpl.java b/src/main/java/plus/maa/backend/service/UserDetailServiceImpl.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/UserDetailServiceImpl.java rename to src/main/java/plus/maa/backend/service/UserDetailServiceImpl.kt diff --git a/src/main/java/plus/maa/backend/service/UserService.java b/src/main/java/plus/maa/backend/service/UserService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/UserService.java rename to src/main/java/plus/maa/backend/service/UserService.kt From caddcae2a212c399e5dfe6e3c3400dba0b0e7c83 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Mon, 5 Feb 2024 20:41:59 +0800 Subject: [PATCH 066/168] refactor: more services rewritten in kotlin --- .../maa/backend/service/CopilotSetService.kt | 182 ++++++----- .../plus/maa/backend/service/EmailService.kt | 166 +++++----- .../plus/maa/backend/service/FileService.kt | 301 +++++++++--------- .../backend/service/UserDetailServiceImpl.kt | 51 ++- .../plus/maa/backend/service/UserService.kt | 239 +++++++------- 5 files changed, 460 insertions(+), 479 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.kt b/src/main/java/plus/maa/backend/service/CopilotSetService.kt index 84cda80a..5433d1d8 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.kt @@ -1,43 +1,41 @@ -package plus.maa.backend.service; +package plus.maa.backend.service -import cn.hutool.core.lang.Assert; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Service; -import plus.maa.backend.common.utils.IdComponent; -import plus.maa.backend.common.utils.converter.CopilotSetConverter; -import plus.maa.backend.controller.request.CopilotSetQuery; -import plus.maa.backend.controller.request.CopilotSetUpdateReq; -import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; -import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; -import plus.maa.backend.controller.response.CopilotSetPageRes; -import plus.maa.backend.controller.response.CopilotSetRes; -import plus.maa.backend.repository.CopilotSetRepository; -import plus.maa.backend.repository.UserRepository; -import plus.maa.backend.repository.entity.CopilotSet; -import plus.maa.backend.repository.entity.MaaUser; +import cn.hutool.core.lang.Assert +import io.github.oshai.kotlinlogging.KotlinLogging +import org.apache.commons.lang3.StringUtils +import org.springframework.data.domain.PageRequest +import org.springframework.data.domain.Sort +import org.springframework.stereotype.Service +import plus.maa.backend.common.utils.IdComponent +import plus.maa.backend.common.utils.converter.CopilotSetConverter +import plus.maa.backend.controller.request.CopilotSetQuery +import plus.maa.backend.controller.request.CopilotSetUpdateReq +import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq +import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq +import plus.maa.backend.controller.response.CopilotSetPageRes +import plus.maa.backend.controller.response.CopilotSetRes +import plus.maa.backend.repository.CopilotSetRepository +import plus.maa.backend.repository.UserRepository +import plus.maa.backend.repository.entity.CopilotSet +import plus.maa.backend.repository.entity.MaaUser +import java.time.LocalDateTime +import java.util.* -import java.time.LocalDateTime; -import java.util.*; +private val log = KotlinLogging.logger { } /** * @author dragove * create on 2024-01-01 */ -@Slf4j @Service -@RequiredArgsConstructor -public class CopilotSetService { +class CopilotSetService( + private val idComponent: IdComponent, + private val converter: CopilotSetConverter, + private val repository: CopilotSetRepository, + private val userRepository: UserRepository, +) { - private final IdComponent idComponent; - private final CopilotSetConverter converter; - private final CopilotSetRepository repository; - private final UserRepository userRepository; - private final Sort DEFAULT_SORT = Sort.by("id").descending(); + private val DEFAULT_SORT: Sort = Sort.by("id").descending() /** * 创建作业集 @@ -46,49 +44,49 @@ public class CopilotSetService { * @param userId 创建者用户id * @return 作业集id */ - public long create(CopilotSetCreateReq req, String userId) { - long id = idComponent.getId(CopilotSet.META); - CopilotSet newCopilotSet = - converter.convert(req, id, userId); - repository.insert(newCopilotSet); - return id; + fun create(req: CopilotSetCreateReq?, userId: String?): Long { + val id = idComponent.getId(CopilotSet.META) + val newCopilotSet = + converter.convert(req, id, userId) + repository.insert(newCopilotSet) + return id } /** * 往作业集中加入作业id列表 */ - public void addCopilotIds(CopilotSetModCopilotsReq req, String userId) { - CopilotSet copilotSet = repository.findById(req.getId()) - .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); - Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权修改该作业集"); - copilotSet.getCopilotIds().addAll(req.getCopilotIds()); - copilotSet.setCopilotIds(copilotSet.getDistinctIdsAndCheck()); - repository.save(copilotSet); + fun addCopilotIds(req: CopilotSetModCopilotsReq, userId: String) { + val copilotSet = repository.findById(req.id) + .orElseThrow { IllegalArgumentException("作业集不存在") } + Assert.state(copilotSet.creatorId == userId, "您不是该作业集的创建者,无权修改该作业集") + copilotSet.copilotIds.addAll(req.copilotIds) + copilotSet.setCopilotIds(copilotSet.distinctIdsAndCheck) + repository.save(copilotSet) } /** * 往作业集中删除作业id列表 */ - public void removeCopilotIds(CopilotSetModCopilotsReq req, String userId) { - CopilotSet copilotSet = repository.findById(req.getId()) - .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); - Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权修改该作业集"); - Set removeIds = new HashSet<>(req.getCopilotIds()); - copilotSet.getCopilotIds().removeIf(removeIds::contains); - repository.save(copilotSet); + fun removeCopilotIds(req: CopilotSetModCopilotsReq, userId: String) { + val copilotSet = repository.findById(req.id) + .orElseThrow { IllegalArgumentException("作业集不存在") } + Assert.state(copilotSet.creatorId == userId, "您不是该作业集的创建者,无权修改该作业集") + val removeIds: Set = HashSet(req.copilotIds) + copilotSet.copilotIds.removeIf { o: Long -> removeIds.contains(o) } + repository.save(copilotSet) } /** * 更新作业集信息 */ - public void update(CopilotSetUpdateReq req, String userId) { - CopilotSet copilotSet = repository.findById(req.getId()) - .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); - Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权修改该作业集"); - copilotSet.setName(req.getName()); - copilotSet.setDescription(req.getDescription()); - copilotSet.setStatus(req.getStatus()); - repository.save(copilotSet); + fun update(req: CopilotSetUpdateReq, userId: String) { + val copilotSet = repository.findById(req.id) + .orElseThrow { IllegalArgumentException("作业集不存在") } + Assert.state(copilotSet.creatorId == userId, "您不是该作业集的创建者,无权修改该作业集") + copilotSet.setName(req.name) + copilotSet.setDescription(req.description) + copilotSet.setStatus(req.status) + repository.save(copilotSet) } /** @@ -97,47 +95,45 @@ public class CopilotSetService { * @param id 作业集id * @param userId 登陆用户id */ - public void delete(long id, String userId) { - log.info("delete copilot set for id: {}, userId: {}", id, userId); - CopilotSet copilotSet = repository.findById(id) - .orElseThrow(() -> new IllegalArgumentException("作业集不存在")); - Assert.state(copilotSet.getCreatorId().equals(userId), "您不是该作业集的创建者,无权删除该作业集"); - copilotSet.setDelete(true); - copilotSet.setDeleteTime(LocalDateTime.now()); - repository.save(copilotSet); + fun delete(id: Long, userId: String) { + log.info { "delete copilot set for id: $id, userId: $userId" } + val copilotSet = repository.findById(id) + .orElseThrow { IllegalArgumentException("作业集不存在") } + Assert.state(copilotSet.creatorId == userId, "您不是该作业集的创建者,无权删除该作业集") + copilotSet.setDelete(true) + copilotSet.setDeleteTime(LocalDateTime.now()) + repository.save(copilotSet) } - public CopilotSetPageRes query(CopilotSetQuery req) { - PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getLimit(), DEFAULT_SORT); + fun query(req: CopilotSetQuery): CopilotSetPageRes { + val pageRequest = PageRequest.of(req.page - 1, req.limit, DEFAULT_SORT) - String keyword = req.getKeyword(); - Page copilotSets; - if (StringUtils.isBlank(keyword)) { - copilotSets = repository.findAll(pageRequest); + val keyword = req.keyword + val copilotSets = if (StringUtils.isBlank(keyword)) { + repository.findAll(pageRequest) } else { - copilotSets = repository.findByKeyword(keyword, pageRequest); + repository.findByKeyword(keyword, pageRequest) } - List userIds = copilotSets.stream().map(CopilotSet::getCreatorId) - .filter(Objects::nonNull) - .distinct() - .toList(); - Map userById = userRepository.findByUsersId(userIds); - return new CopilotSetPageRes() - .setPage(copilotSets.getNumber() + 1) - .setTotal(copilotSets.getTotalElements()) - .setHasNext(copilotSets.getTotalPages() > req.getPage()) - .setData(copilotSets.stream().map(cs -> { - MaaUser user = userById.getOrDefault(cs.getCreatorId(), MaaUser.UNKNOWN); - return converter.convert(cs, user.getUserName()); - }).toList()); - + val userIds = copilotSets.stream().map { obj: CopilotSet -> obj.creatorId } + .filter { obj: String? -> Objects.nonNull(obj) } + .distinct() + .toList() + val userById = userRepository.findByUsersId(userIds) + return CopilotSetPageRes() + .setPage(copilotSets.number + 1) + .setTotal(copilotSets.totalElements) + .setHasNext(copilotSets.totalPages > req.page) + .setData(copilotSets.stream().map { cs: CopilotSet -> + val user = userById.getOrDefault(cs.creatorId, MaaUser.UNKNOWN) + converter.convert(cs, user.userName) + }.toList()) } - public CopilotSetRes get(long id) { - return repository.findById(id).map($ -> { - String userName = userRepository.findByUserId($.getCreatorId()).orElse(MaaUser.UNKNOWN).getUserName(); - return converter.convertDetail($, userName); - }).orElseThrow(() -> new IllegalArgumentException("作业不存在")); + fun get(id: Long): CopilotSetRes { + return repository.findById(id).map { copilotSet: CopilotSet -> + val userName = userRepository.findByUserId(copilotSet.creatorId).orElse(MaaUser.UNKNOWN).userName + converter.convertDetail(copilotSet, userName) + }.orElseThrow { IllegalArgumentException("作业不存在") } } } diff --git a/src/main/java/plus/maa/backend/service/EmailService.kt b/src/main/java/plus/maa/backend/service/EmailService.kt index d2a49004..69e9f6dd 100644 --- a/src/main/java/plus/maa/backend/service/EmailService.kt +++ b/src/main/java/plus/maa/backend/service/EmailService.kt @@ -1,68 +1,62 @@ -package plus.maa.backend.service; - -import cn.hutool.extra.mail.MailAccount; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.RandomStringUtils; -import org.apache.logging.log4j.util.Strings; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.task.AsyncTaskExecutor; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Service; -import plus.maa.backend.common.bo.EmailBusinessObject; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.config.external.Mail; -import plus.maa.backend.controller.response.MaaResultException; -import plus.maa.backend.repository.RedisCache; -import plus.maa.backend.service.model.CommentNotification; - -import java.util.HashMap; -import java.util.Map; +package plus.maa.backend.service + +import cn.hutool.extra.mail.MailAccount +import io.github.oshai.kotlinlogging.KotlinLogging +import jakarta.annotation.PostConstruct +import jakarta.annotation.Resource +import org.apache.commons.lang3.RandomStringUtils +import org.apache.logging.log4j.util.Strings +import org.springframework.beans.factory.annotation.Value +import org.springframework.core.task.AsyncTaskExecutor +import org.springframework.scheduling.annotation.Async +import org.springframework.stereotype.Service +import plus.maa.backend.common.bo.EmailBusinessObject +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.controller.response.MaaResultException +import plus.maa.backend.repository.RedisCache +import plus.maa.backend.service.model.CommentNotification +import java.util.* + +private val log = KotlinLogging.logger { } /** * @author LoMu * Date 2022-12-24 11:05 */ @Service -@Slf4j -@RequiredArgsConstructor -public class EmailService { - @Value("${maa-copilot.vcode.expire:600}") - private int expire; - - @Value("${maa-copilot.info.domain}") - private String domain; - - private final MaaCopilotProperties maaCopilotProperties; +class EmailService( + @Value("\${maa-copilot.vcode.expire:600}") + private val expire:Int, + @Value("\${maa-copilot.info.domain}") + private val domain: String, + private val maaCopilotProperties: MaaCopilotProperties, + @Value("\${debug.email.no-send:false}") + private val flagNoSend:Boolean = false, + private val redisCache: RedisCache, + @Resource(name = "emailTaskExecutor") + private val emailTaskExecutor: AsyncTaskExecutor +) { - @Value("${debug.email.no-send:false}") - private boolean flagNoSend; + private val mainAccount = MailAccount() - private final RedisCache redisCache; - private final MailAccount MAIL_ACCOUNT = new MailAccount(); - - @Resource(name = "emailTaskExecutor") - private final AsyncTaskExecutor emailTaskExecutor; /** * 初始化邮件账户信息 */ @PostConstruct - private void initMailAccount() { - Mail mail = maaCopilotProperties.getMail(); - MAIL_ACCOUNT - .setHost(mail.getHost()) - .setPort(mail.getPort()) - .setFrom(mail.getFrom()) - .setUser(mail.getUser()) - .setPass(mail.getPass()) - .setSslEnable(mail.getSsl()) - .setStarttlsEnable(mail.getStarttls()); - - log.info("邮件账户信息初始化完成: {}", MAIL_ACCOUNT); + private fun initMailAccount() { + val mail = maaCopilotProperties.mail + mainAccount + .setHost(mail.host) + .setPort(mail.port) + .setFrom(mail.from) + .setUser(mail.user) + .setPass(mail.pass) + .setSslEnable(mail.ssl) + .setStarttlsEnable(mail.starttls) + + log.info { "邮件账户信息初始化完成: $mainAccount" } } /** @@ -72,34 +66,33 @@ public class EmailService { * * @param email 邮箱 */ - - public void sendVCode(String email) { + fun sendVCode(email: String) { // 一个过期周期最多重发十条,记录已发送的邮箱以及间隔时间 - final int timeout = expire / 10; - if (!redisCache.setCacheIfAbsent("HasBeenSentVCode:" + email , timeout, timeout)) { + val timeout = expire / 10 + if (!redisCache.setCacheIfAbsent("HasBeenSentVCode:$email", timeout, timeout.toLong())) { // 设置失败,说明 key 已存在 - throw new MaaResultException(403, String.format("发送验证码的请求至少需要间隔 %d 秒", timeout)); + throw MaaResultException(403, String.format("发送验证码的请求至少需要间隔 %d 秒", timeout)) } // 执行异步任务 - asyncSendVCode(email); + asyncSendVCode(email) } - private void asyncSendVCode(String email) { - emailTaskExecutor.execute(() -> { + private fun asyncSendVCode(email: String) { + emailTaskExecutor.execute { // 6位随机数验证码 - String vcode = RandomStringUtils.random(6, true, true).toUpperCase(); + val vcode = RandomStringUtils.random(6, true, true).uppercase(Locale.getDefault()) if (flagNoSend) { - log.debug("vcode is " + vcode); - log.warn("Email not sent, no-send enabled"); + log.debug { "vcode is $vcode" } + log.warn { "Email not sent, no-send enabled" } } else { EmailBusinessObject.builder() - .setMailAccount(MAIL_ACCOUNT) - .setEmail(email) - .sendVerificationCodeMessage(vcode); + .setMailAccount(mainAccount) + .setEmail(email) + .sendVerificationCodeMessage(vcode) } // 存redis - redisCache.setCache("vCodeEmail:" + email, vcode, expire); - }); + redisCache.setCache("vCodeEmail:$email", vcode, expire.toLong()) + } } /** @@ -108,35 +101,34 @@ public class EmailService { * @param vcode 验证码 * @throws MaaResultException 验证码错误 */ - public void verifyVCode(String email, String vcode) { - if (!redisCache.removeKVIfEquals("vCodeEmail:" + email, vcode.toUpperCase())) { - throw new MaaResultException(401, "验证码错误"); + fun verifyVCode(email: String, vcode: String) { + if (!redisCache.removeKVIfEquals("vCodeEmail:$email", vcode.uppercase(Locale.getDefault()))) { + throw MaaResultException(401, "验证码错误") } } @Async("emailTaskExecutor") - public void sendCommentNotification(String email, CommentNotification commentNotification) { - int limit = 25; + fun sendCommentNotification(email: String?, commentNotification: CommentNotification) { + val limit = 25 - String title = commentNotification.getTitle(); + var title = commentNotification.title if (Strings.isNotBlank(title)) { - if (title.length() > limit) { - title = title.substring(0, limit) + "...."; + if (title.length > limit) { + title = title.substring(0, limit) + "...." } } - Map map = new HashMap<>(); - map.put("authorName", commentNotification.getAuthorName()); - map.put("forntEndLink", maaCopilotProperties.getInfo().getFrontendDomain()); - map.put("reName", commentNotification.getReName()); - map.put("date", commentNotification.getDate()); - map.put("title", title); - map.put("reMessage", commentNotification.getReMessage()); + val map: MutableMap = HashMap() + map["authorName"] = commentNotification.authorName + map["forntEndLink"] = maaCopilotProperties.info.frontendDomain + map["reName"] = commentNotification.reName + map["date"] = commentNotification.date + map["title"] = title + map["reMessage"] = commentNotification.reMessage EmailBusinessObject.builder() - .setTitle("收到新回复 来自用户@" + commentNotification.getReName() + " Re: " + map.get("title")) - .setMailAccount(MAIL_ACCOUNT) - .setEmail(email) - .sendCommentNotification(map); - + .setTitle("收到新回复 来自用户@" + commentNotification.reName + " Re: " + map["title"]) + .setMailAccount(mainAccount) + .setEmail(email) + .sendCommentNotification(map) } } diff --git a/src/main/java/plus/maa/backend/service/FileService.kt b/src/main/java/plus/maa/backend/service/FileService.kt index 481fc4b6..201e4204 100644 --- a/src/main/java/plus/maa/backend/service/FileService.kt +++ b/src/main/java/plus/maa/backend/service/FileService.kt @@ -1,225 +1,228 @@ -package plus.maa.backend.service; - - -import com.mongodb.client.gridfs.GridFSFindIterable; -import com.mongodb.client.gridfs.model.GridFSFile; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import org.apache.commons.lang3.StringUtils; -import org.bson.Document; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.data.mongodb.gridfs.GridFsCriteria; -import org.springframework.data.mongodb.gridfs.GridFsOperations; -import org.springframework.stereotype.Service; -import org.springframework.util.Assert; -import org.springframework.web.multipart.MultipartException; -import org.springframework.web.multipart.MultipartFile; -import plus.maa.backend.controller.file.ImageDownloadDTO; -import plus.maa.backend.controller.response.MaaResultException; -import plus.maa.backend.repository.RedisCache; - -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.*; -import java.util.concurrent.TimeUnit; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipOutputStream; +package plus.maa.backend.service + +import com.mongodb.client.gridfs.GridFSFindIterable +import jakarta.servlet.http.HttpServletResponse +import org.apache.commons.lang3.StringUtils +import org.bson.Document +import org.springframework.data.mongodb.core.query.Criteria +import org.springframework.data.mongodb.core.query.Query +import org.springframework.data.mongodb.gridfs.GridFsCriteria +import org.springframework.data.mongodb.gridfs.GridFsOperations +import org.springframework.stereotype.Service +import org.springframework.util.Assert +import org.springframework.web.multipart.MultipartException +import org.springframework.web.multipart.MultipartFile +import plus.maa.backend.controller.file.ImageDownloadDTO +import plus.maa.backend.controller.response.MaaResultException +import plus.maa.backend.repository.RedisCache +import java.io.IOException +import java.text.ParseException +import java.text.SimpleDateFormat +import java.util.* +import java.util.concurrent.TimeUnit +import java.util.regex.Pattern +import java.util.zip.ZipEntry +import java.util.zip.ZipOutputStream + /** * @author LoMu * Date 2023-04-16 23:21 */ - -@RequiredArgsConstructor @Service -public class FileService { - private final GridFsOperations gridFsOperations; - private final RedisCache redisCache; - - public void uploadFile(MultipartFile file, - String type, - String version, - String classification, - String label, - String ip) { - +class FileService( + private val gridFsOperations: GridFsOperations, + private val redisCache: RedisCache +) { + + fun uploadFile( + file: MultipartFile, + type: String?, + version: String, + classification: String?, + label: String?, + ip: String? + ) { //redis持久化 - if (redisCache.getCache("NotEnable:UploadFile", String.class) != null) { - throw new MaaResultException(403, "closed uploadfile"); + + var version = version + if (redisCache.getCache("NotEnable:UploadFile", String::class.java) != null) { + throw MaaResultException(403, "closed uploadfile") } //文件小于1024Bytes不接收 - if (file.getSize() < 1024) { - throw new MultipartException("Minimum upload size exceeded"); + if (file.size < 1024) { + throw MultipartException("Minimum upload size exceeded") } - Assert.notNull(file.getOriginalFilename(), "文件名不可为空"); + Assert.notNull(file.originalFilename, "文件名不可为空") - String antecedentVersion = null; + var antecedentVersion: String? = null if (version.contains("-")) { - String[] split = version.split("-"); - version = split[0]; - antecedentVersion = split[1]; + val split = version.split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + version = split[0] + antecedentVersion = split[1] } - Document document = new Document(); - document.put("version", version); - document.put("antecedentVersion", antecedentVersion); - document.put("label", label); - document.put("classification", classification); - document.put("type", type); - document.put("ip", ip); + val document = Document() + document["version"] = version + document["antecedentVersion"] = antecedentVersion + document["label"] = label + document["classification"] = classification + document["type"] = type + document["ip"] = ip - int index = file.getOriginalFilename().lastIndexOf("."); - String fileType = ""; + val index = file.originalFilename!!.lastIndexOf(".") + var fileType = "" if (index != -1) { - fileType = file.getOriginalFilename().substring(index); + fileType = file.originalFilename!!.substring(index) } - String fileName = "Maa-" + UUID.randomUUID().toString().replaceAll("-", "") + fileType; + val fileName = "Maa-" + UUID.randomUUID().toString().replace("-".toRegex(), "") + fileType try { - gridFsOperations.store(file.getInputStream(), fileName, document); - } catch (IOException e) { - throw new RuntimeException(e); + gridFsOperations.store(file.inputStream, fileName, document) + } catch (e: IOException) { + throw RuntimeException(e) } } - public void downloadDateFile(String date, String beLocated, boolean delete, HttpServletResponse response) { - SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); - Date d; - Query query; + fun downloadDateFile(date: String?, beLocated: String, delete: Boolean, response: HttpServletResponse) { + val formatter = SimpleDateFormat("yyyy-MM-dd") + val query: Query - if (StringUtils.isBlank(date)) { - d = new Date(System.currentTimeMillis()); + val d = if (StringUtils.isBlank(date)) { + Date(System.currentTimeMillis()) } else { try { - d = formatter.parse(date); - } catch (ParseException e) { - throw new RuntimeException(e); + formatter.parse(date) + } catch (e: ParseException) { + throw RuntimeException(e) } } - if (StringUtils.isBlank(beLocated) || Objects.equals("after", beLocated.toLowerCase())) { - query = new Query(Criteria.where("metadata").gte(d)); + query = if (StringUtils.isBlank(beLocated) || "after" == beLocated.lowercase(Locale.getDefault())) { + Query(Criteria.where("metadata").gte(d)) } else { - query = new Query(Criteria.where("uploadDate").lte(d)); + Query(Criteria.where("uploadDate").lte(d)) } - GridFSFindIterable files = gridFsOperations.find(query); + val files = gridFsOperations.find(query) - response.addHeader("Content-Disposition", "attachment;filename=" + System.currentTimeMillis() + ".zip"); + response.addHeader("Content-Disposition", "attachment;filename=" + System.currentTimeMillis() + ".zip") - gzip(response, files); + gzip(response, files) if (delete) { - gridFsOperations.delete(query); + gridFsOperations.delete(query) } } - public void downloadFile(ImageDownloadDTO imageDownloadDTO, HttpServletResponse response) { - Query query = new Query(); - Set criteriaSet = new HashSet<>(); + fun downloadFile(imageDownloadDTO: ImageDownloadDTO, response: HttpServletResponse) { + val query = Query() + val criteriaSet: MutableSet = HashSet() //图片类型 - criteriaSet.add(GridFsCriteria.whereMetaData("type").regex(Pattern.compile(imageDownloadDTO.getType(), Pattern.CASE_INSENSITIVE))); + criteriaSet.add( + GridFsCriteria.whereMetaData("type").regex(Pattern.compile(imageDownloadDTO.type, Pattern.CASE_INSENSITIVE)) + ) //指定下载某个类型的图片 - if (StringUtils.isNotBlank(imageDownloadDTO.getClassification())) { - criteriaSet.add(GridFsCriteria.whereMetaData("classification").regex(Pattern.compile(imageDownloadDTO.getClassification(), Pattern.CASE_INSENSITIVE))); + if (StringUtils.isNotBlank(imageDownloadDTO.classification)) { + criteriaSet.add( + GridFsCriteria.whereMetaData("classification") + .regex(Pattern.compile(imageDownloadDTO.classification, Pattern.CASE_INSENSITIVE)) + ) } //指定版本或指定范围版本 - if (!Objects.isNull(imageDownloadDTO.getVersion())) { - List version = imageDownloadDTO.getVersion(); - - if (version.size() == 1) { - String antecedentVersion = null; - if (version.get(0).contains("-")) { - String[] split = version.get(0).split("-"); - antecedentVersion = split[1]; + if (!Objects.isNull(imageDownloadDTO.version)) { + val version = imageDownloadDTO.version + + if (version.size == 1) { + var antecedentVersion: String? = null + if (version[0].contains("-")) { + val split = version[0].split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + antecedentVersion = split[1] } - criteriaSet.add(GridFsCriteria.whereMetaData("version").is(version.get(0)).and("antecedentVersion").is(antecedentVersion)); - - } else if (version.size() == 2) { - criteriaSet.add(GridFsCriteria.whereMetaData("version").gte(version.get(0)).lte(version.get(1))); + criteriaSet.add( + GridFsCriteria.whereMetaData("version").`is`(version[0]).and("antecedentVersion") + .`is`(antecedentVersion) + ) + } else if (version.size == 2) { + criteriaSet.add(GridFsCriteria.whereMetaData("version").gte(version[0]).lte(version[1])) } } - if (StringUtils.isNotBlank(imageDownloadDTO.getLabel())) { - criteriaSet.add(GridFsCriteria.whereMetaData("label").regex(Pattern.compile(imageDownloadDTO.getLabel(), Pattern.CASE_INSENSITIVE))); + if (StringUtils.isNotBlank(imageDownloadDTO.label)) { + criteriaSet.add( + GridFsCriteria.whereMetaData("label") + .regex(Pattern.compile(imageDownloadDTO.label, Pattern.CASE_INSENSITIVE)) + ) } - Criteria criteria = new Criteria().andOperator(criteriaSet); - query.addCriteria(criteria); + val criteria = Criteria().andOperator(criteriaSet) + query.addCriteria(criteria) - GridFSFindIterable gridFSFiles = gridFsOperations.find(query); + val gridFSFiles = gridFsOperations.find(query) - response.addHeader("Content-Disposition", "attachment;filename=" + "Maa-" + imageDownloadDTO.getType() + ".zip"); + response.addHeader("Content-Disposition", "attachment;filename=" + "Maa-" + imageDownloadDTO.type + ".zip") - gzip(response, gridFSFiles); + gzip(response, gridFSFiles) - if (imageDownloadDTO.isDelete()) { - gridFsOperations.delete(query); + if (imageDownloadDTO.isDelete) { + gridFsOperations.delete(query) } - - } - - public String disable() { - setUploadEnabled(false); - return "已关闭"; } - public String enable() { - setUploadEnabled(true); - return "已启用"; + fun disable(): String { + isUploadEnabled = false + return "已关闭" } - public boolean isUploadEnabled() { - return redisCache.getCache("NotEnable:UploadFile", String.class) == null; + fun enable(): String { + isUploadEnabled = true + return "已启用" } - /** - * 设置上传功能状态 - * @param enabled 是否开启 - */ - public void setUploadEnabled(boolean enabled) { - // Fixme: redis recovery solution should be added, or change to another storage - if (enabled) { - redisCache.removeCache("NotEnable:UploadFile"); - } else { - redisCache.setCache("NotEnable:UploadFile", "1", 0, TimeUnit.DAYS); + var isUploadEnabled: Boolean + get() = redisCache.getCache("NotEnable:UploadFile", String::class.java) == null + /** + * 设置上传功能状态 + * @param enabled 是否开启 + */ + set(enabled) { + // Fixme: redis recovery solution should be added, or change to another storage + if (enabled) { + redisCache.removeCache("NotEnable:UploadFile") + } else { + redisCache.setCache("NotEnable:UploadFile", "1", 0, TimeUnit.DAYS) + } } - } - - private void gzip(HttpServletResponse response, GridFSFindIterable files) { - try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) { - for (GridFSFile file : files) { - - ZipEntry zipEntry = new ZipEntry(file.getFilename()); - try (InputStream inputStream = gridFsOperations.getResource(file).getInputStream()) { - //添加压缩文件 - zipOutputStream.putNextEntry(zipEntry); - - byte[] bytes = new byte[1024]; - int len; - while ((len = inputStream.read(bytes)) != -1) { - zipOutputStream.write(bytes, 0, len); - zipOutputStream.flush(); + private fun gzip(response: HttpServletResponse, files: GridFSFindIterable) { + try { + ZipOutputStream(response.outputStream).use { zipOutputStream -> + for (file in files) { + val zipEntry = ZipEntry(file.filename) + gridFsOperations.getResource(file).inputStream.use { inputStream -> + //添加压缩文件 + zipOutputStream.putNextEntry(zipEntry) + + val bytes = ByteArray(1024) + var len: Int + while ((inputStream.read(bytes).also { len = it }) != -1) { + zipOutputStream.write(bytes, 0, len) + zipOutputStream.flush() + } } } } - - } catch (IOException e) { - throw new RuntimeException(e); + } catch (e: IOException) { + throw RuntimeException(e) } } } diff --git a/src/main/java/plus/maa/backend/service/UserDetailServiceImpl.kt b/src/main/java/plus/maa/backend/service/UserDetailServiceImpl.kt index b3f116ca..3890afd7 100644 --- a/src/main/java/plus/maa/backend/service/UserDetailServiceImpl.kt +++ b/src/main/java/plus/maa/backend/service/UserDetailServiceImpl.kt @@ -1,26 +1,20 @@ -package plus.maa.backend.service; +package plus.maa.backend.service -import lombok.RequiredArgsConstructor; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Service; -import plus.maa.backend.repository.UserRepository; -import plus.maa.backend.repository.entity.MaaUser; -import plus.maa.backend.service.model.LoginUser; - -import java.util.ArrayList; -import java.util.Collection; +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.core.userdetails.UserDetailsService +import org.springframework.security.core.userdetails.UsernameNotFoundException +import org.springframework.stereotype.Service +import plus.maa.backend.repository.UserRepository +import plus.maa.backend.repository.entity.MaaUser +import plus.maa.backend.service.model.LoginUser /** * @author AnselYuki */ @Service -@RequiredArgsConstructor -public class UserDetailServiceImpl implements UserDetailsService { - private final UserRepository userRepository; +class UserDetailServiceImpl(private val userRepository: UserRepository) : UserDetailsService { /** * 查询用户信息 @@ -29,23 +23,20 @@ public class UserDetailServiceImpl implements UserDetailsService { * @return 用户详细信息 * @throws UsernameNotFoundException 用户名未找到 */ - @Override - public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException { - MaaUser user = userRepository.findByEmail(email); - if (user == null) { - throw new UsernameNotFoundException("用户不存在"); - } + @Throws(UsernameNotFoundException::class) + override fun loadUserByUsername(email: String): UserDetails { + val user = userRepository.findByEmail(email) ?: throw UsernameNotFoundException("用户不存在") - var permissions = collectAuthoritiesFor(user); + val permissions = collectAuthoritiesFor(user) //数据封装成UserDetails返回 - return new LoginUser(user, permissions); + return LoginUser(user, permissions) } - public Collection collectAuthoritiesFor(MaaUser user) { - var authorities = new ArrayList(); - for (int i = 0; i <= user.getStatus(); i++) { - authorities.add(new SimpleGrantedAuthority(Integer.toString(i))); + fun collectAuthoritiesFor(user: MaaUser): Collection { + val authorities = ArrayList() + for (i in 0..user.status) { + authorities.add(SimpleGrantedAuthority(i.toString())) } - return authorities; + return authorities } } diff --git a/src/main/java/plus/maa/backend/service/UserService.kt b/src/main/java/plus/maa/backend/service/UserService.kt index 9c80e178..a3623155 100644 --- a/src/main/java/plus/maa/backend/service/UserService.kt +++ b/src/main/java/plus/maa/backend/service/UserService.kt @@ -1,30 +1,25 @@ -package plus.maa.backend.service; - -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.jetbrains.annotations.NotNull; -import org.springframework.beans.BeanUtils; -import org.springframework.dao.DuplicateKeyException; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import plus.maa.backend.common.MaaStatusCode; -import plus.maa.backend.common.utils.converter.MaaUserConverter; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.controller.request.user.*; -import plus.maa.backend.controller.response.MaaResultException; -import plus.maa.backend.controller.response.user.MaaLoginRsp; -import plus.maa.backend.controller.response.user.MaaUserInfo; -import plus.maa.backend.repository.UserRepository; -import plus.maa.backend.repository.entity.MaaUser; -import plus.maa.backend.service.jwt.JwtExpiredException; -import plus.maa.backend.service.jwt.JwtInvalidException; -import plus.maa.backend.service.jwt.JwtService; - -import java.util.ArrayList; -import java.util.NoSuchElementException; -import java.util.Objects; -import java.util.UUID; +package plus.maa.backend.service + +import lombok.RequiredArgsConstructor +import lombok.Setter +import lombok.extern.slf4j.Slf4j +import org.springframework.beans.BeanUtils +import org.springframework.dao.DuplicateKeyException +import org.springframework.security.crypto.password.PasswordEncoder +import org.springframework.stereotype.Service +import plus.maa.backend.common.MaaStatusCode +import plus.maa.backend.common.utils.converter.MaaUserConverter +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.controller.request.user.* +import plus.maa.backend.controller.response.MaaResultException +import plus.maa.backend.controller.response.user.MaaLoginRsp +import plus.maa.backend.controller.response.user.MaaUserInfo +import plus.maa.backend.repository.UserRepository +import plus.maa.backend.repository.entity.MaaUser +import plus.maa.backend.service.jwt.JwtExpiredException +import plus.maa.backend.service.jwt.JwtInvalidException +import plus.maa.backend.service.jwt.JwtService +import java.util.* /** * @author AnselYuki @@ -33,14 +28,15 @@ import java.util.UUID; @Slf4j @Service @RequiredArgsConstructor -public class UserService { - private final UserRepository userRepository; - private final EmailService emailService; - private final PasswordEncoder passwordEncoder; - private final UserDetailServiceImpl userDetailService; - private final JwtService jwtService; - private final MaaUserConverter maaUserConverter; - private final MaaCopilotProperties properties; +class UserService( + private val userRepository: UserRepository, + private val emailService: EmailService, + private val passwordEncoder: PasswordEncoder, + private val userDetailService: UserDetailServiceImpl, + private val jwtService: JwtService, + private val maaUserConverter: MaaUserConverter, + private val properties: MaaCopilotProperties +) { /** * 登录方法 @@ -48,35 +44,35 @@ public class UserService { * @param loginDTO 登录参数 * @return 携带了token的封装类 */ - public MaaLoginRsp login(LoginDTO loginDTO) { - var user = userRepository.findByEmail(loginDTO.getEmail()); - if (user == null || !passwordEncoder.matches(loginDTO.getPassword(), user.getPassword())) { - throw new MaaResultException(401, "用户不存在或者密码错误"); + fun login(loginDTO: LoginDTO): MaaLoginRsp { + val user = userRepository.findByEmail(loginDTO.email) + if (user == null || !passwordEncoder.matches(loginDTO.password, user.password)) { + throw MaaResultException(401, "用户不存在或者密码错误") } // 未激活的用户 - if (Objects.equals(user.getStatus(), 0)) { - throw new MaaResultException(MaaStatusCode.MAA_USER_NOT_ENABLED); + if (user.status == 0) { + throw MaaResultException(MaaStatusCode.MAA_USER_NOT_ENABLED) } - var jwtId = UUID.randomUUID().toString(); - var jwtIds = user.getRefreshJwtIds(); - jwtIds.add(jwtId); - while (jwtIds.size() > properties.getJwt().getMaxLogin()) jwtIds.remove(0); - userRepository.save(user); - - var authorities = userDetailService.collectAuthoritiesFor(user); - var authToken = jwtService.issueAuthToken(user.getUserId(), null, authorities); - var refreshToken = jwtService.issueRefreshToken(user.getUserId(), jwtId); - - return new MaaLoginRsp( - authToken.getValue(), - authToken.getExpiresAt(), - authToken.getNotBefore(), - refreshToken.getValue(), - refreshToken.getExpiresAt(), - refreshToken.getNotBefore(), - maaUserConverter.convert(user) - ); + val jwtId = UUID.randomUUID().toString() + val jwtIds = user.refreshJwtIds + jwtIds.add(jwtId) + while (jwtIds.size > properties.jwt.maxLogin) jwtIds.removeAt(0) + userRepository.save(user) + + val authorities = userDetailService.collectAuthoritiesFor(user) + val authToken = jwtService.issueAuthToken(user.userId, null, authorities) + val refreshToken = jwtService.issueRefreshToken(user.userId, jwtId) + + return MaaLoginRsp( + authToken.value, + authToken.expiresAt, + authToken.notBefore, + refreshToken.value, + refreshToken.expiresAt, + refreshToken.notBefore, + maaUserConverter.convert(user) + ) } /** @@ -85,14 +81,14 @@ public class UserService { * @param userId 当前用户 * @param rawPassword 新密码 */ - public void modifyPassword(String userId, String rawPassword) { - var userResult = userRepository.findById(userId); - if (userResult.isEmpty()) return; - var maaUser = userResult.get(); + fun modifyPassword(userId: String, rawPassword: String?) { + val userResult = userRepository.findById(userId) + if (userResult.isEmpty) return + val maaUser = userResult.get() // 修改密码的逻辑,应当使用与 authentication provider 一致的编码器 - maaUser.setPassword(passwordEncoder.encode(rawPassword)); - maaUser.setRefreshJwtIds(new ArrayList<>()); - userRepository.save(maaUser); + maaUser.setPassword(passwordEncoder.encode(rawPassword)) + maaUser.setRefreshJwtIds(ArrayList()) + userRepository.save(maaUser) } /** @@ -101,24 +97,24 @@ public class UserService { * @param registerDTO 传入用户参数 * @return 返回注册成功的用户摘要(脱敏) */ - public MaaUserInfo register(RegisterDTO registerDTO) { - String encode = passwordEncoder.encode(registerDTO.getPassword()); + fun register(registerDTO: RegisterDTO): MaaUserInfo { + val encode = passwordEncoder.encode(registerDTO.password) // 校验验证码 - emailService.verifyVCode(registerDTO.getEmail(), registerDTO.getRegistrationToken()); + emailService.verifyVCode(registerDTO.email, registerDTO.registrationToken) - MaaUser user = new MaaUser(); - BeanUtils.copyProperties(registerDTO, user); - user.setPassword(encode); - user.setStatus(1); - MaaUserInfo userInfo; + val user = MaaUser() + BeanUtils.copyProperties(registerDTO, user) + user.setPassword(encode) + user.setStatus(1) + val userInfo: MaaUserInfo try { - MaaUser save = userRepository.save(user); - userInfo = new MaaUserInfo(save); - } catch (DuplicateKeyException e) { - throw new MaaResultException(MaaStatusCode.MAA_USER_EXISTS); + val save = userRepository.save(user) + userInfo = MaaUserInfo(save) + } catch (e: DuplicateKeyException) { + throw MaaResultException(MaaStatusCode.MAA_USER_EXISTS) } - return userInfo; + return userInfo } /** @@ -127,11 +123,11 @@ public class UserService { * @param userId 用户id * @param updateDTO 更新参数 */ - public void updateUserInfo(@NotNull String userId, UserInfoUpdateDTO updateDTO) { - userRepository.findById(userId).ifPresent((maaUser) -> { - maaUser.updateAttribute(updateDTO); - userRepository.save(maaUser); - }); + fun updateUserInfo(userId: String, updateDTO: UserInfoUpdateDTO?) { + userRepository.findById(userId).ifPresent { maaUser: MaaUser -> + maaUser.updateAttribute(updateDTO) + userRepository.save(maaUser) + } } /** @@ -139,38 +135,42 @@ public class UserService { * * @param token token */ - public MaaLoginRsp refreshToken(String token) { + fun refreshToken(token: String?): MaaLoginRsp { try { - var old = jwtService.verifyAndParseRefreshToken(token); + val old = jwtService.verifyAndParseRefreshToken(token) - var userId = old.getSubject(); - var user = userRepository.findById(userId).orElseThrow(); + val userId = old.subject + val user = userRepository.findById(userId).orElseThrow() - var refreshJwtIds = user.getRefreshJwtIds(); - int idIndex = refreshJwtIds.indexOf(old.getJwtId()); - if (idIndex < 0) throw new MaaResultException(401, "invalid token"); + val refreshJwtIds = user.refreshJwtIds + val idIndex = refreshJwtIds.indexOf(old.jwtId) + if (idIndex < 0) throw MaaResultException(401, "invalid token") - var jwtId = UUID.randomUUID().toString(); - refreshJwtIds.set(idIndex, jwtId); + val jwtId = UUID.randomUUID().toString() + refreshJwtIds[idIndex] = jwtId - userRepository.save(user); + userRepository.save(user) - var refreshToken = jwtService.newRefreshToken(old, jwtId); + val refreshToken = jwtService.newRefreshToken(old, jwtId) - var authorities = userDetailService.collectAuthoritiesFor(user); - var authToken = jwtService.issueAuthToken(userId, null, authorities); + val authorities = userDetailService.collectAuthoritiesFor(user) + val authToken = jwtService.issueAuthToken(userId, null, authorities) - return new MaaLoginRsp( - authToken.getValue(), - authToken.getExpiresAt(), - authToken.getNotBefore(), - refreshToken.getValue(), - refreshToken.getExpiresAt(), - refreshToken.getNotBefore(), - maaUserConverter.convert(user) - ); - } catch (JwtInvalidException | JwtExpiredException | NoSuchElementException e) { - throw new MaaResultException(401, e.getMessage()); + return MaaLoginRsp( + authToken.value, + authToken.expiresAt, + authToken.notBefore, + refreshToken.value, + refreshToken.expiresAt, + refreshToken.notBefore, + maaUserConverter.convert(user) + ) + } catch (e: JwtInvalidException) { + throw MaaResultException(401, e.message) + } catch (e: JwtExpiredException) { + throw MaaResultException(401, e.message) + } catch (e: NoSuchElementException) { + throw MaaResultException(401, e.message) } } @@ -179,10 +179,10 @@ public class UserService { * * @param passwordResetDTO 通过邮箱修改密码请求 */ - public void modifyPasswordByActiveCode(PasswordResetDTO passwordResetDTO) { - emailService.verifyVCode(passwordResetDTO.getEmail(), passwordResetDTO.getActiveCode()); - var maaUser = userRepository.findByEmail(passwordResetDTO.getEmail()); - modifyPassword(maaUser.getUserId(), passwordResetDTO.getPassword()); + fun modifyPasswordByActiveCode(passwordResetDTO: PasswordResetDTO) { + emailService.verifyVCode(passwordResetDTO.email, passwordResetDTO.activeCode) + val maaUser = userRepository.findByEmail(passwordResetDTO.email) + modifyPassword(maaUser.userId, passwordResetDTO.password) } /** @@ -190,24 +190,23 @@ public class UserService { * * @param email 用户邮箱 */ - public void checkUserExistByEmail(String email) { + fun checkUserExistByEmail(email: String?) { if (null == userRepository.findByEmail(email)) { - throw new MaaResultException(MaaStatusCode.MAA_USER_NOT_FOUND); + throw MaaResultException(MaaStatusCode.MAA_USER_NOT_FOUND) } } /** * 注册时发送验证码 */ - public void sendRegistrationToken(SendRegistrationTokenDTO regDTO) { + fun sendRegistrationToken(regDTO: SendRegistrationTokenDTO) { // 判断用户是否存在 - MaaUser maaUser = userRepository.findByEmail(regDTO.getEmail()); + val maaUser = userRepository.findByEmail(regDTO.email) if (maaUser != null) { // 用户已存在 - throw new MaaResultException(MaaStatusCode.MAA_USER_EXISTS); + throw MaaResultException(MaaStatusCode.MAA_USER_EXISTS) } // 发送验证码 - emailService.sendVCode(regDTO.getEmail()); + emailService.sendVCode(regDTO.email) } - } From a5c418bd2531f5593e26224bd3b9f8ed8f0699ac Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Tue, 6 Feb 2024 07:55:35 +0800 Subject: [PATCH 067/168] perf: add @JvmStatic annotation for companion object val --- src/main/java/plus/maa/backend/service/CopilotService.kt | 1 + .../java/plus/maa/backend/task/CopilotScoreRefreshTask.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/java/plus/maa/backend/service/CopilotService.kt index b3f8ffe2..92e99928 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotService.kt @@ -553,6 +553,7 @@ class CopilotService( "id", 300L ) + @JvmStatic fun getHotScore(copilot: Copilot, lastWeekLike: Long, lastWeekDislike: Long): Double { val now = LocalDateTime.now() val uploadTime = copilot.uploadTime diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java index 2d2cf8f3..3ec19cb1 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java +++ b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java @@ -107,7 +107,7 @@ private void refresh(Collection copilotIdSTRs, Iterable copilot for (Copilot copilot : copilots) { long likeCount = likeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 1L); long dislikeCount = dislikeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 0L); - double hotScore = CopilotService.Companion.getHotScore(copilot, likeCount, dislikeCount); + double hotScore = CopilotService.getHotScore(copilot, likeCount, dislikeCount); // 判断关卡是否开放 ArkLevel level = arkLevelService.findByLevelIdFuzzy(copilot.getStageName()); // 关卡已关闭,且作业在关闭前上传 From 3e2769677c7d1d541e4a221039e1c0c1c5eee6ec Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Tue, 6 Feb 2024 14:24:17 +0800 Subject: [PATCH 068/168] Rename .java to .kt --- .../backend/task/{ArkLevelSyncTask.java => ArkLevelSyncTask.kt} | 0 .../backend/task/{CopilotBackupTask.java => CopilotBackupTask.kt} | 0 .../{CopilotScoreRefreshTask.java => CopilotScoreRefreshTask.kt} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/task/{ArkLevelSyncTask.java => ArkLevelSyncTask.kt} (100%) rename src/main/java/plus/maa/backend/task/{CopilotBackupTask.java => CopilotBackupTask.kt} (100%) rename src/main/java/plus/maa/backend/task/{CopilotScoreRefreshTask.java => CopilotScoreRefreshTask.kt} (100%) diff --git a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt similarity index 100% rename from src/main/java/plus/maa/backend/task/ArkLevelSyncTask.java rename to src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt diff --git a/src/main/java/plus/maa/backend/task/CopilotBackupTask.java b/src/main/java/plus/maa/backend/task/CopilotBackupTask.kt similarity index 100% rename from src/main/java/plus/maa/backend/task/CopilotBackupTask.java rename to src/main/java/plus/maa/backend/task/CopilotBackupTask.kt diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt similarity index 100% rename from src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.java rename to src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt From 6bec42d71bd89eb659483b5ef9b604cb31a77429 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Tue, 6 Feb 2024 14:24:17 +0800 Subject: [PATCH 069/168] refactor: migrate tasks to kotlin --- .../maa/backend/service/ArkLevelService.kt | 2 +- .../plus/maa/backend/task/ArkLevelSyncTask.kt | 30 +-- .../maa/backend/task/CopilotBackupTask.kt | 244 +++++++++--------- .../backend/task/CopilotScoreRefreshTask.kt | 166 ++++++------ 4 files changed, 213 insertions(+), 229 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.kt b/src/main/java/plus/maa/backend/service/ArkLevelService.kt index 150add99..943f0230 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.kt +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.kt @@ -75,7 +75,7 @@ class ArkLevelService( .toList() @Cacheable("arkLevel") - fun findByLevelIdFuzzy(levelId: String?): ArkLevel { + fun findByLevelIdFuzzy(levelId: String?): ArkLevel? { return arkLevelRepo.findByLevelIdFuzzy(levelId).findAny().orElse(null) } diff --git a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt index 3921d258..1157507c 100644 --- a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt +++ b/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt @@ -1,23 +1,22 @@ -package plus.maa.backend.task; +package plus.maa.backend.task -import lombok.RequiredArgsConstructor; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import plus.maa.backend.service.ArkLevelService; +import lombok.RequiredArgsConstructor +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Component +import plus.maa.backend.service.ArkLevelService @Component -@RequiredArgsConstructor -public class ArkLevelSyncTask { - - private final ArkLevelService arkLevelService; +class ArkLevelSyncTask( + private val arkLevelService: ArkLevelService +) { /** * 地图数据同步定时任务,每10分钟执行一次 * 应用启动时自动同步一次 */ - @Scheduled(cron = "${maa-copilot.task-cron.ark-level:-}") - public void syncArkLevels() { - arkLevelService.runSyncLevelDataTask(); + @Scheduled(cron = "\${maa-copilot.task-cron.ark-level:-}") + fun syncArkLevels() { + arkLevelService.runSyncLevelDataTask() } /** @@ -25,9 +24,8 @@ public class ArkLevelSyncTask { * 4:00、4:15 各执行一次,避免网络波动导致更新失败 */ @Scheduled(cron = "0 0-15/15 4 * * ?") - public void updateOpenStatus() { - arkLevelService.updateActivitiesOpenStatus(); - arkLevelService.updateCrisisV2OpenStatus(); + fun updateOpenStatus() { + arkLevelService.updateActivitiesOpenStatus() + arkLevelService.updateCrisisV2OpenStatus() } - } diff --git a/src/main/java/plus/maa/backend/task/CopilotBackupTask.kt b/src/main/java/plus/maa/backend/task/CopilotBackupTask.kt index 1a3d21f9..5511cbd4 100644 --- a/src/main/java/plus/maa/backend/task/CopilotBackupTask.kt +++ b/src/main/java/plus/maa/backend/task/CopilotBackupTask.kt @@ -1,184 +1,180 @@ -package plus.maa.backend.task; - -import jakarta.annotation.PostConstruct; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.eclipse.jgit.api.Git; -import org.eclipse.jgit.api.Status; -import org.eclipse.jgit.api.TransportConfigCallback; -import org.eclipse.jgit.api.errors.GitAPIException; -import org.eclipse.jgit.lib.PersonIdent; -import org.eclipse.jgit.transport.SshTransport; -import org.eclipse.jgit.transport.sshd.SshdSessionFactoryBuilder; -import org.eclipse.jgit.util.FS; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import plus.maa.backend.config.external.CopilotBackup; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.repository.CopilotRepository; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.Copilot; -import plus.maa.backend.service.ArkLevelService; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.LocalDate; -import java.util.List; -import java.util.Objects; -import java.util.stream.Stream; +package plus.maa.backend.task + +import io.github.oshai.kotlinlogging.KotlinLogging +import jakarta.annotation.PostConstruct +import org.eclipse.jgit.api.Git +import org.eclipse.jgit.api.TransportConfigCallback +import org.eclipse.jgit.api.errors.GitAPIException +import org.eclipse.jgit.lib.PersonIdent +import org.eclipse.jgit.transport.SshTransport +import org.eclipse.jgit.transport.Transport +import org.eclipse.jgit.transport.sshd.SshdSessionFactoryBuilder +import org.eclipse.jgit.util.FS +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Component +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.repository.CopilotRepository +import plus.maa.backend.repository.entity.Copilot +import plus.maa.backend.service.ArkLevelService +import java.io.File +import java.io.IOException +import java.nio.file.Files +import java.time.LocalDate +import java.util.* + +private val log = KotlinLogging.logger { } /** * CopilotBackupTask */ -@Slf4j @Component -@RequiredArgsConstructor -public class CopilotBackupTask { - - private final MaaCopilotProperties config; +class CopilotBackupTask( + private val config: MaaCopilotProperties, + private val copilotRepository: CopilotRepository, + private val levelService: ArkLevelService, +) { - private final CopilotRepository copilotRepository; - - private final ArkLevelService levelService; - - private Git git; - private static final File DEFAULT_SSH_DIR = new File(FS.DETECTED.userHome(), "/.ssh"); - - private static final TransportConfigCallback sshCallback = transport -> { - if (transport instanceof SshTransport sshTransport) { - sshTransport.setSshSessionFactory(new SshdSessionFactoryBuilder() - .setPreferredAuthentications("publickey") - .setHomeDirectory(FS.DETECTED.userHome()) - .setSshDirectory(DEFAULT_SSH_DIR) - .build(null)); - } - }; + private lateinit var git: Git /** * 初始化Git对象,如果目录已经存在且存在文件,则直接当作git仓库,如果不存在则clone仓库 */ @PostConstruct - public void initGit() { - CopilotBackup backup = config.getBackup(); - if (backup.getDisabled()) { - return; + fun initGit() { + val backup = config.backup + if (backup.disabled) { + return } - File repoDir = new File(backup.getDir()); + val repoDir = File(backup.dir) if (repoDir.mkdirs()) { - log.info("directory not exist, created: {}", backup.getDir()); + log.info { "directory not exist, created: ${backup.dir}" } } else { - log.info("directory already exists, dir: {}", backup.getDir()); + log.info { "directory already exists, dir: ${backup.dir}" } } - if (!repoDir.isDirectory()) { - return; + if (!repoDir.isDirectory) { + return } - try (Stream fileList = Files.list(repoDir.toPath())) { - if (fileList.findFirst().isEmpty()) { - // 不存在文件则初始化 - git = Git.cloneRepository() - .setURI(backup.getUri()) + try { + Files.list(repoDir.toPath()).use { fileList -> + git = if (fileList.findFirst().isEmpty) { + // 不存在文件则初始化 + Git.cloneRepository() + .setURI(backup.uri) .setDirectory(repoDir) .setTransportConfigCallback(sshCallback) - .call(); - } else { - git = Git.open(repoDir); + .call() + } else { + Git.open(repoDir) + } } - } catch (IOException | GitAPIException e) { - log.error("init copilot backup repo failed, repoDir: {}", repoDir, e); + } catch (e: IOException) { + log.error { "init copilot backup repo failed, repoDir: $repoDir, $e"} + } catch (e: GitAPIException) { + log.error { "init copilot backup repo failed, repoDir: $repoDir, $e" } } } /** * copilot数据同步定时任务,每天执行一次 */ - @Scheduled(cron = "${maa-copilot.task-cron.copilot-update:-}") - public void backupCopilots() { - if (config.getBackup().getDisabled() || Objects.isNull(git)) { - return; + @Scheduled(cron = "\${maa-copilot.task-cron.copilot-update:-}") + fun backupCopilots() { + if (config.backup.disabled || Objects.isNull(git)) { + return } try { - git.pull().call(); - } catch (GitAPIException e) { - log.error("git pull execute failed, msg: {}", e.getMessage(), e); + git.pull().call() + } catch (e: GitAPIException) { + log.error { "git pull execute failed, msg: ${e.message}, $e" } } - File baseDirectory = git.getRepository().getWorkTree(); - List copilots = copilotRepository.findAll(); - copilots.forEach(copilot -> { - ArkLevel level = levelService.findByLevelIdFuzzy(copilot.getStageName()); - if (Objects.isNull(level)) { - return; - } + val baseDirectory = git.repository.workTree + val copilots = copilotRepository.findAll() + copilots.forEach{ copilot: Copilot -> + val level = levelService.findByLevelIdFuzzy(copilot.stageName) ?: return@forEach // 暂时使用 copilotId 作为文件名 - File filePath = new File(String.join(File.separator, baseDirectory.getPath(), level.getCatOne(), - level.getCatTwo(), level.getCatThree(), copilot.getCopilotId() + ".json")); - String content = copilot.getContent(); - if (Objects.isNull(content)) { - return; - } - if (copilot.isDelete()) { + val filePath = File( + java.lang.String.join( + File.separator, baseDirectory.path, level.catOne, + level.catTwo, level.catThree, copilot.copilotId.toString() + ".json" + ) + ) + val content = copilot.content ?: return@forEach + if (copilot.isDelete) { // 删除文件 - deleteCopilot(filePath); + deleteCopilot(filePath) } else { // 创建或者修改文件 - upsertCopilot(filePath, content); + upsertCopilot(filePath, content) } - }); + } - doCommitAndPush(); + doCommitAndPush() } - private void upsertCopilot(File file, String content) { + private fun upsertCopilot(file: File, content: String) { if (!file.exists()) { - if (!file.getParentFile().mkdirs()) { - log.warn("folder may exists, mkdir failed"); + if (!file.parentFile.mkdirs()) { + log.warn { "folder may exists, mkdir failed" } } } try { - Files.writeString(file.toPath(), content); - } catch (IOException e) { - log.error("write file failed, path: {}, message: {}", file.getPath(), e.getMessage(), e); + Files.writeString(file.toPath(), content) + } catch (e: IOException) { + log.error { "write file failed, path: ${file.path}, message: ${e.message}, $e" } } } - private void deleteCopilot(File file) { + private fun deleteCopilot(file: File) { if (file.exists()) { if (file.delete()) { - log.info("delete copilot file: {}", file.getPath()); + log.info { "delete copilot file: ${file.path}" } } else { - log.error("delete copilot failed, file: {}", file.getPath()); + log.error { "delete copilot failed, file: ${file.path}" } } } else { - log.info("file does not exists, no need to delete"); + log.info { "file does not exists, no need to delete" } } } - private void doCommitAndPush() { + private fun doCommitAndPush() { try { - Status status = git.status().call(); - if (status.getAdded().isEmpty() && - status.getChanged().isEmpty() && - status.getRemoved().isEmpty() && - status.getUntracked().isEmpty() && - status.getModified().isEmpty() && - status.getAdded().isEmpty()) { - log.info("copilot backup with no new added or changes"); - return; + val status = git.status().call() + if (status.added.isEmpty() && + status.changed.isEmpty() && + status.removed.isEmpty() && + status.untracked.isEmpty() && + status.modified.isEmpty() && + status.added.isEmpty() + ) { + log.info { "copilot backup with no new added or changes" } + return } - git.add().addFilepattern(".").call(); - CopilotBackup backup = config.getBackup(); - PersonIdent committer = new PersonIdent(backup.getUsername(), backup.getEmail()); + git.add().addFilepattern(".").call() + val backup = config.backup + val committer = PersonIdent(backup.username, backup.email) git.commit().setCommitter(committer) - .setMessage(LocalDate.now().toString()) - .call(); + .setMessage(LocalDate.now().toString()) + .call() git.push() - .setTransportConfigCallback(sshCallback) - .call(); - } catch (GitAPIException e) { - log.error("git committing failed, msg: {}", e.getMessage(), e); + .setTransportConfigCallback(sshCallback) + .call() + } catch (e: GitAPIException) { + log.error { "git committing failed, msg: ${e.message}, $e" } } } + companion object { + private val DEFAULT_SSH_DIR = File(FS.DETECTED.userHome(), "/.ssh") + + private val sshCallback = TransportConfigCallback { transport: Transport -> + if (transport is SshTransport) { + transport.sshSessionFactory = SshdSessionFactoryBuilder() + .setPreferredAuthentications("publickey") + .setHomeDirectory(FS.DETECTED.userHome()) + .setSshDirectory(DEFAULT_SSH_DIR) + .build(null) + } + } + } } diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt index 3ec19cb1..efa4012d 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt +++ b/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt @@ -1,31 +1,21 @@ -package plus.maa.backend.task; +package plus.maa.backend.task -import lombok.AccessLevel; -import lombok.RequiredArgsConstructor; -import lombok.experimental.FieldDefaults; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.aggregation.Aggregation; -import org.springframework.data.mongodb.core.query.Criteria; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.CopilotRepository; -import plus.maa.backend.repository.RedisCache; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.Copilot; -import plus.maa.backend.repository.entity.Rating; -import plus.maa.backend.service.ArkLevelService; -import plus.maa.backend.service.CopilotService; -import plus.maa.backend.service.model.RatingCount; -import plus.maa.backend.service.model.RatingType; - -import java.time.LocalDateTime; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; +import org.springframework.data.domain.Pageable +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.core.aggregation.Aggregation +import org.springframework.data.mongodb.core.query.Criteria +import org.springframework.scheduling.annotation.Scheduled +import org.springframework.stereotype.Component +import plus.maa.backend.repository.CopilotRepository +import plus.maa.backend.repository.RedisCache +import plus.maa.backend.repository.entity.Copilot +import plus.maa.backend.repository.entity.Rating +import plus.maa.backend.service.ArkLevelService +import plus.maa.backend.service.CopilotService.Companion.getHotScore +import plus.maa.backend.service.model.RatingCount +import plus.maa.backend.service.model.RatingType +import java.time.LocalDateTime +import kotlin.String /** * 作业热度值刷入任务,每日执行,用于计算基于时间的热度值 @@ -34,107 +24,107 @@ import java.util.stream.Collectors; * created on 2023.05.03 */ @Component -@RequiredArgsConstructor -@FieldDefaults(makeFinal = true, level = AccessLevel.PRIVATE) -public class CopilotScoreRefreshTask { - - ArkLevelService arkLevelService; - RedisCache redisCache; - CopilotRepository copilotRepository; - MongoTemplate mongoTemplate; - +class CopilotScoreRefreshTask( + private val arkLevelService: ArkLevelService, + private val redisCache: RedisCache, + private val copilotRepository: CopilotRepository, + private val mongoTemplate: MongoTemplate +) { /** * 热度值刷入任务,每日四点三十执行(实际可能会更晚,因为需要等待之前启动的定时任务完成) */ @Scheduled(cron = "0 30 4 * * ?") - public void refreshHotScores() { + fun refreshHotScores() { // 分页获取所有未删除的作业 - Pageable pageable = Pageable.ofSize(1000); - Page copilots = copilotRepository.findAllByDeleteIsFalse(pageable); + var pageable = Pageable.ofSize(1000) + var copilots = copilotRepository.findAllByDeleteIsFalse(pageable) // 循环读取直到没有未删除的作业为止 while (copilots.hasContent()) { - List copilotIdSTRs = copilots.stream() - .map(copilot -> Long.toString(copilot.getCopilotId())) - .collect(Collectors.toList()); - refresh(copilotIdSTRs, copilots); + val copilotIdSTRs = copilots.map { copilot -> + copilot.copilotId.toString() + }.toList() + refresh(copilotIdSTRs, copilots) // 获取下一页 if (!copilots.hasNext()) { // 没有下一页了,跳出循环 - break; + break } - pageable = copilots.nextPageable(); - copilots = copilotRepository.findAllByDeleteIsFalse(pageable); + pageable = copilots.nextPageable() + copilots = copilotRepository.findAllByDeleteIsFalse(pageable) } // 移除首页热度缓存 - redisCache.syncRemoveCacheByPattern("home:hot:*"); + redisCache.syncRemoveCacheByPattern("home:hot:*") } /** * 刷入评分变更数 Top 100 的热度值,每日八点到二十点每三小时执行一次 */ @Scheduled(cron = "0 0 8-20/3 * * ?") - public void refreshTop100HotScores() { - Set copilotIdSTRs = redisCache.getZSetReverse("rate:hot:copilotIds", 0, 99); - if (copilotIdSTRs == null || copilotIdSTRs.isEmpty()) { - return; + fun refreshTop100HotScores() { + val copilotIdSTRs = redisCache.getZSetReverse("rate:hot:copilotIds", 0, 99) + if (copilotIdSTRs.isNullOrEmpty()) { + return } - List copilots = copilotRepository.findByCopilotIdInAndDeleteIsFalse( - copilotIdSTRs.stream().map(Long::parseLong).collect(Collectors.toList()) - ); + val copilots = copilotRepository.findByCopilotIdInAndDeleteIsFalse( + copilotIdSTRs.map { s: String? -> s!!.toLong() } + ) if (copilots == null || copilots.isEmpty()) { - return; + return } - refresh(copilotIdSTRs, copilots); + refresh(copilotIdSTRs, copilots) // 移除近期评分变化量缓存 - redisCache.removeCache("rate:hot:copilotIds"); + redisCache.removeCache("rate:hot:copilotIds") // 移除首页热度缓存 - redisCache.syncRemoveCacheByPattern("home:hot:*"); + redisCache.syncRemoveCacheByPattern("home:hot:*") } - private void refresh(Collection copilotIdSTRs, Iterable copilots) { + private fun refresh(copilotIdSTRs: Collection, copilots: Iterable) { // 批量获取最近七天的点赞和点踩数量 - LocalDateTime now = LocalDateTime.now(); - List likeCounts = counts(copilotIdSTRs, RatingType.LIKE, now.minusDays(7)); - List dislikeCounts = counts(copilotIdSTRs, RatingType.DISLIKE, now.minusDays(7)); - Map likeCountMap = likeCounts.stream().collect(Collectors.toMap(RatingCount::getKey, RatingCount::getCount)); - Map dislikeCountMap = dislikeCounts.stream().collect(Collectors.toMap(RatingCount::getKey, RatingCount::getCount)); + val now = LocalDateTime.now() + val likeCounts = counts(copilotIdSTRs, RatingType.LIKE, now.minusDays(7)) + val dislikeCounts = counts(copilotIdSTRs, RatingType.DISLIKE, now.minusDays(7)) + val likeCountMap = likeCounts.associate { it.key to it.count } + val dislikeCountMap = dislikeCounts.associate { it.key to it.count } // 计算热度值 - for (Copilot copilot : copilots) { - long likeCount = likeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 1L); - long dislikeCount = dislikeCountMap.getOrDefault(Long.toString(copilot.getCopilotId()), 0L); - double hotScore = CopilotService.getHotScore(copilot, likeCount, dislikeCount); + for (copilot in copilots) { + val likeCount = likeCountMap.getOrDefault(copilot.copilotId.toString(), 1L) + val dislikeCount = dislikeCountMap.getOrDefault(copilot.copilotId.toString(), 0L) + var hotScore = getHotScore(copilot, likeCount, dislikeCount) // 判断关卡是否开放 - ArkLevel level = arkLevelService.findByLevelIdFuzzy(copilot.getStageName()); + val level = arkLevelService.findByLevelIdFuzzy(copilot.stageName) // 关卡已关闭,且作业在关闭前上传 - if (level.getCloseTime() != null && copilot.getFirstUploadTime() != null && Boolean.FALSE.equals(level.getIsOpen()) && copilot.getFirstUploadTime().isBefore(level.getCloseTime())) { - + if (level!!.closeTime != null && copilot.firstUploadTime != null && false == level.isOpen && copilot.firstUploadTime.isBefore( + level.closeTime + ) + ) { // 非开放关卡打入冷宫 - hotScore /= 3; + + hotScore /= 3.0 } - copilot.setHotScore(hotScore); + copilot.setHotScore(hotScore) } // 批量更新热度值 - copilotRepository.saveAll(copilots); + copilotRepository.saveAll(copilots) } - private List counts(Collection keys, RatingType rating, LocalDateTime startTime) { - Aggregation aggregation = Aggregation.newAggregation( - Aggregation.match(Criteria - .where("type").is(Rating.KeyType.COPILOT) - .and("key").in(keys) - .and("rating").is(rating) - .and("rateTime").gte(startTime) - ), - Aggregation.group("key").count().as("count") - .first("key").as("key"), - Aggregation.project("key", "count") - ).withOptions(Aggregation.newAggregationOptions().allowDiskUse(true).build()); // 放弃内存优化,使用磁盘优化,免得内存炸了 - return mongoTemplate.aggregate(aggregation, Rating.class, RatingCount.class).getMappedResults(); + private fun counts(keys: Collection, rating: RatingType, startTime: LocalDateTime): List { + val aggregation = Aggregation.newAggregation( + Aggregation.match( + Criteria + .where("type").`is`(Rating.KeyType.COPILOT) + .and("key").`in`(keys) + .and("rating").`is`(rating) + .and("rateTime").gte(startTime) + ), + Aggregation.group("key").count().`as`("count") + .first("key").`as`("key"), + Aggregation.project("key", "count") + ).withOptions(Aggregation.newAggregationOptions().allowDiskUse(true).build()) // 放弃内存优化,使用磁盘优化,免得内存炸了 + return mongoTemplate.aggregate(aggregation, Rating::class.java, RatingCount::class.java).mappedResults } - } From 630c434fd545e3bddcc483b73bd67fea503dd5cc Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Tue, 6 Feb 2024 21:25:33 +0800 Subject: [PATCH 070/168] fix: NoSuchMethodError with lombok --- .../backend/repository/entity/Copilot.java | 1 - .../maa/backend/service/CopilotService.kt | 34 ++++++++----------- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/main/java/plus/maa/backend/repository/entity/Copilot.java b/src/main/java/plus/maa/backend/repository/entity/Copilot.java index aae48764..3ebda8f1 100644 --- a/src/main/java/plus/maa/backend/repository/entity/Copilot.java +++ b/src/main/java/plus/maa/backend/repository/entity/Copilot.java @@ -24,7 +24,6 @@ @NoArgsConstructor @AllArgsConstructor @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) -@Accessors(chain = true) @Document("maa_copilot") public class Copilot implements Serializable { diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/java/plus/maa/backend/service/CopilotService.kt index 92e99928..329d8daf 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotService.kt @@ -70,7 +70,6 @@ class CopilotService( private val copilotConverter: CopilotConverter ) { - /** * 并修正前端的冗余部分 * @@ -78,36 +77,32 @@ class CopilotService( */ private fun correctCopilot(copilotDTO: CopilotDTO): CopilotDTO { // 去除name的冗余部分 - // todo 优化空处理代码美观程度 - if (copilotDTO.groups != null) { - copilotDTO.groups.forEach( - Consumer { group: Copilot.Groups -> + copilotDTO.groups.forEach{ group: Copilot.Groups -> if (group.opers != null) { - group.opers.forEach(Consumer { oper: OperationGroup -> - oper - .setName(if (oper.name == null) null else oper.name.replace("[\"“”]".toRegex(), "")) - }) + group.opers.forEach{ oper: OperationGroup -> + oper.name = oper.name?.replace("[\"“”]".toRegex(), "") + } } - }) + } } if (copilotDTO.opers != null) { copilotDTO.opers.forEach(Consumer { operator: Copilot.Operators -> - operator - .setName(if (operator.name == null) null else operator.name.replace("[\"“”]".toRegex(), "")) + operator.name = operator.name?.replace("[\"“”]".toRegex(), "") }) } // actions name 不是必须 if (copilotDTO.actions != null) { copilotDTO.actions.forEach(Consumer { action: Copilot.Action -> - action - .setName(if (action.name == null) null else action.name.replace("[\"“”]".toRegex(), "")) + action.name = if (action.name == null) null else action.name.replace("[\"“”]".toRegex(), "") }) } // 使用stageId存储作业关卡信息 val level = levelService.findByLevelIdFuzzy(copilotDTO.stageName) - copilotDTO.stageName = level.stageId + level?.stageId?.let { + copilotDTO.stageName = it + } return copilotDTO } @@ -156,7 +151,7 @@ class CopilotService( fun delete(loginUserId: String, request: CopilotCUDRequest) { copilotRepository.findByCopilotId(request.id).ifPresent { copilot: Copilot -> Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") - copilot.setDelete(true) + copilot.isDelete = true copilotRepository.save(copilot) /* * 删除作业时,如果被删除的项在 Redis 首页缓存中存在,则清空对应的首页缓存 @@ -349,7 +344,6 @@ class CopilotService( // 分页排序查询 val copilots = mongoTemplate.find(queryObj.with(pageable), Copilot::class.java) - // 填充前端所需信息 val copilotIds = copilots.map { it.copilotId @@ -404,7 +398,7 @@ class CopilotService( copilotRepository.findByCopilotId(id).ifPresent { copilot: Copilot -> val copilotDTO = correctCopilot(parseToCopilotDto(content)) Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") - copilot.setUploadTime(LocalDateTime.now()) + copilot.uploadTime = LocalDateTime.now() copilotConverter.updateCopilotFromDto(copilotDTO, content, copilot) copilotRepository.save(copilot) } @@ -528,7 +522,7 @@ class CopilotService( info.isAvailable = true // 兼容客户端, 将作业ID替换为数字ID - copilot.setId(copilot.copilotId.toString()) + copilot.id = copilot.copilotId.toString() return info } @@ -537,7 +531,7 @@ class CopilotService( Assert.isTrue(copilotOptional.isPresent, "copilot不存在") val copilot = copilotOptional.get() Assert.isTrue(userId == copilot.uploaderId, "您没有权限修改") - copilot.setNotification(status) + copilot.notification = status copilotRepository.save(copilot) } From d600f7f3980cea4166882ef42269f733f6a49fa7 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Tue, 6 Feb 2024 21:27:46 +0800 Subject: [PATCH 071/168] perf: remove some uses of java Stream and Collector --- .../java/plus/maa/backend/service/CopilotService.kt | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/java/plus/maa/backend/service/CopilotService.kt index 329d8daf..11d22056 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotService.kt @@ -41,9 +41,7 @@ import java.util.* import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicLong import java.util.concurrent.atomic.AtomicReference -import java.util.function.Consumer import java.util.regex.Pattern -import java.util.stream.Collectors import kotlin.collections.component1 import kotlin.math.ceil import kotlin.math.ln @@ -87,16 +85,16 @@ class CopilotService( } } if (copilotDTO.opers != null) { - copilotDTO.opers.forEach(Consumer { operator: Copilot.Operators -> + copilotDTO.opers.forEach{ operator: Copilot.Operators -> operator.name = operator.name?.replace("[\"“”]".toRegex(), "") - }) + } } // actions name 不是必须 if (copilotDTO.actions != null) { - copilotDTO.actions.forEach(Consumer { action: Copilot.Action -> + copilotDTO.actions.forEach{ action: Copilot.Action -> action.name = if (action.name == null) null else action.name.replace("[\"“”]".toRegex(), "") - }) + } } // 使用stageId存储作业关卡信息 val level = levelService.findByLevelIdFuzzy(copilotDTO.stageName) @@ -280,8 +278,7 @@ class CopilotService( } else { andQueries.add( Criteria.where("stageName").`in`( - levelInfo.stream() - .map { obj: ArkLevelInfo -> obj.stageId }.collect(Collectors.toSet()) + levelInfo.map { obj: ArkLevelInfo -> obj.stageId }.toSet() ) ) } From 3b47527d750ea904c8ed351930dfa81b4ba7871a Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 07:54:07 +0800 Subject: [PATCH 072/168] Rename .java to .kt --- .../controller/{CopilotController.java => CopilotController.kt} | 0 .../repository/{ArkLevelRepository.java => ArkLevelRepository.kt} | 0 .../repository/{CopilotRepository.java => CopilotRepository.kt} | 0 .../backend/service/session/{UserSession.java => UserSession.kt} | 0 .../session/{UserSessionService.java => UserSessionService.kt} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/{CopilotController.java => CopilotController.kt} (100%) rename src/main/java/plus/maa/backend/repository/{ArkLevelRepository.java => ArkLevelRepository.kt} (100%) rename src/main/java/plus/maa/backend/repository/{CopilotRepository.java => CopilotRepository.kt} (100%) rename src/main/java/plus/maa/backend/service/session/{UserSession.java => UserSession.kt} (100%) rename src/main/java/plus/maa/backend/service/session/{UserSessionService.java => UserSessionService.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/CopilotController.java b/src/main/java/plus/maa/backend/controller/CopilotController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/CopilotController.java rename to src/main/java/plus/maa/backend/controller/CopilotController.kt diff --git a/src/main/java/plus/maa/backend/repository/ArkLevelRepository.java b/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/ArkLevelRepository.java rename to src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/CopilotRepository.java b/src/main/java/plus/maa/backend/repository/CopilotRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/CopilotRepository.java rename to src/main/java/plus/maa/backend/repository/CopilotRepository.kt diff --git a/src/main/java/plus/maa/backend/service/session/UserSession.java b/src/main/java/plus/maa/backend/service/session/UserSession.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/session/UserSession.java rename to src/main/java/plus/maa/backend/service/session/UserSession.kt diff --git a/src/main/java/plus/maa/backend/service/session/UserSessionService.java b/src/main/java/plus/maa/backend/service/session/UserSessionService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/session/UserSessionService.java rename to src/main/java/plus/maa/backend/service/session/UserSessionService.kt From 45ecb41957d54f59bb9a67a72760d2df2a258f01 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 07:54:08 +0800 Subject: [PATCH 073/168] refactor: migrate CopilotController and some services to kotlin --- .../backend/controller/CopilotController.kt | 123 +++++++++--------- .../backend/repository/ArkLevelRepository.kt | 59 ++++----- .../backend/repository/CopilotRepository.kt | 31 ++--- .../maa/backend/service/ArkLevelService.kt | 6 +- .../backend/service/CommentsAreaService.kt | 10 +- .../maa/backend/service/CopilotService.kt | 14 +- .../backend/service/session/UserSession.kt | 5 +- .../service/session/UserSessionService.kt | 64 ++++----- 8 files changed, 146 insertions(+), 166 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/CopilotController.kt b/src/main/java/plus/maa/backend/controller/CopilotController.kt index ffdd6daf..adb80c95 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotController.kt +++ b/src/main/java/plus/maa/backend/controller/CopilotController.kt @@ -1,40 +1,40 @@ -package plus.maa.backend.controller; +package plus.maa.backend.controller -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpHeaders; -import org.springframework.web.bind.annotation.*; -import plus.maa.backend.common.annotation.JsonSchema; -import plus.maa.backend.common.annotation.SensitiveWordDetection; -import plus.maa.backend.config.doc.RequireJwt; -import plus.maa.backend.config.security.AuthenticationHelper; -import plus.maa.backend.controller.request.copilot.CopilotCUDRequest; -import plus.maa.backend.controller.request.copilot.CopilotQueriesRequest; -import plus.maa.backend.controller.request.copilot.CopilotRatingReq; -import plus.maa.backend.controller.response.MaaResult; -import plus.maa.backend.controller.response.copilot.CopilotInfo; -import plus.maa.backend.controller.response.copilot.CopilotPageInfo; -import plus.maa.backend.service.CopilotService; +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.servlet.http.HttpServletResponse +import jakarta.validation.Valid +import jakarta.validation.constraints.NotBlank +import org.springframework.http.HttpHeaders +import org.springframework.web.bind.annotation.* +import plus.maa.backend.common.annotation.JsonSchema +import plus.maa.backend.common.annotation.SensitiveWordDetection +import plus.maa.backend.config.doc.RequireJwt +import plus.maa.backend.config.security.AuthenticationHelper +import plus.maa.backend.controller.request.copilot.CopilotCUDRequest +import plus.maa.backend.controller.request.copilot.CopilotQueriesRequest +import plus.maa.backend.controller.request.copilot.CopilotRatingReq +import plus.maa.backend.controller.response.MaaResult +import plus.maa.backend.controller.response.MaaResult.Companion.fail +import plus.maa.backend.controller.response.MaaResult.Companion.success +import plus.maa.backend.controller.response.copilot.CopilotInfo +import plus.maa.backend.controller.response.copilot.CopilotPageInfo +import plus.maa.backend.service.CopilotService /** * @author LoMu * Date 2022-12-25 17:08 */ - -@RequiredArgsConstructor @RestController @RequestMapping("/copilot") @Tag(name = "CopilotController", description = "作业本体管理接口") -public class CopilotController { - private final CopilotService copilotService; - private final AuthenticationHelper helper; - private final HttpServletResponse response; +class CopilotController( + private val copilotService: CopilotService, + private val helper: AuthenticationHelper, + private val response: HttpServletResponse +) { @Operation(summary = "上传作业") @ApiResponse(description = "上传作业结果") @@ -42,44 +42,44 @@ public class CopilotController { @JsonSchema @SensitiveWordDetection("#request.content != null ? #objectMapper.readTree(#request.content).get('doc')?.toString() : null") @PostMapping("/upload") - public MaaResult uploadCopilot( - @Parameter(description = "作业操作请求") @RequestBody CopilotCUDRequest request - ) { - return MaaResult.success(copilotService.upload(helper.requireUserId(), request.getContent())); + fun uploadCopilot( + @Parameter(description = "作业操作请求") @RequestBody request: CopilotCUDRequest + ): MaaResult { + return success(copilotService.upload(helper.requireUserId(), request.content)) } @Operation(summary = "删除作业") @ApiResponse(description = "删除作业结果") @RequireJwt @PostMapping("/delete") - public MaaResult deleteCopilot( - @Parameter(description = "作业操作请求") @RequestBody CopilotCUDRequest request - ) { - copilotService.delete(helper.requireUserId(), request); - return MaaResult.success(); + fun deleteCopilot( + @Parameter(description = "作业操作请求") @RequestBody request: CopilotCUDRequest? + ): MaaResult { + copilotService.delete(helper.requireUserId(), request!!) + return success() } @Operation(summary = "获取作业") @ApiResponse(description = "作业信息") @GetMapping("/get/{id}") - public MaaResult getCopilotById( - @Parameter(description = "作业id") @PathVariable("id") Long id - ) { - var userIdOrIpAddress = helper.getUserIdOrIpAddress(); - return copilotService.getCopilotById(userIdOrIpAddress, id).map(MaaResult::success) - .orElse(MaaResult.fail(404, "数据不存在")); + fun getCopilotById( + @Parameter(description = "作业id") @PathVariable("id") id: Long + ): MaaResult { + val userIdOrIpAddress = helper.userIdOrIpAddress + return copilotService.getCopilotById(userIdOrIpAddress, id)?.let { success(it) } + ?: fail(404, "作业不存在") } @Operation(summary = "分页查询作业,提供登录凭据时查询用户自己的作业") @ApiResponse(description = "作业信息") @GetMapping("/query") - public MaaResult queriesCopilot( - @Parameter(description = "作业查询请求") @Valid CopilotQueriesRequest parsed - ) { + fun queriesCopilot( + @Parameter(description = "作业查询请求") parsed: @Valid CopilotQueriesRequest + ): MaaResult { // 三秒防抖,缓解前端重复请求问题 - response.setHeader(HttpHeaders.CACHE_CONTROL, "private, max-age=3, must-revalidate"); - return MaaResult.success(copilotService.queriesCopilot(helper.getUserId(), parsed)); + response.setHeader(HttpHeaders.CACHE_CONTROL, "private, max-age=3, must-revalidate") + return success(copilotService.queriesCopilot(helper.userId, parsed)) } @Operation(summary = "更新作业") @@ -88,31 +88,30 @@ public class CopilotController { @JsonSchema @SensitiveWordDetection("#copilotCUDRequest.content != null ? #objectMapper.readTree(#copilotCUDRequest.content).get('doc')?.toString() : null") @PostMapping("/update") - public MaaResult updateCopilot( - @Parameter(description = "作业操作请求") @RequestBody CopilotCUDRequest copilotCUDRequest - ) { - copilotService.update(helper.requireUserId(), copilotCUDRequest); - return MaaResult.success(); + fun updateCopilot( + @Parameter(description = "作业操作请求") @RequestBody copilotCUDRequest: CopilotCUDRequest + ): MaaResult { + copilotService.update(helper.requireUserId(), copilotCUDRequest) + return success() } @Operation(summary = "为作业评分") @ApiResponse(description = "评分结果") @JsonSchema @PostMapping("/rating") - public MaaResult ratesCopilotOperation( - @Parameter(description = "作业评分请求") @RequestBody CopilotRatingReq copilotRatingReq - ) { - copilotService.rates(helper.getUserIdOrIpAddress(), copilotRatingReq); - return MaaResult.success("评分成功"); + fun ratesCopilotOperation( + @Parameter(description = "作业评分请求") @RequestBody copilotRatingReq: CopilotRatingReq + ): MaaResult { + copilotService.rates(helper.userIdOrIpAddress, copilotRatingReq) + return success("评分成功") } @RequireJwt @Operation(summary = "修改通知状态") @ApiResponse(description = "success") @GetMapping("/status") - public MaaResult modifyStatus(@RequestParam @NotBlank Long id, @RequestParam boolean status) { - copilotService.notificationStatus(helper.getUserId(), id, status); - return MaaResult.success("success"); + fun modifyStatus(@RequestParam id: @NotBlank Long, @RequestParam status: Boolean): MaaResult { + copilotService.notificationStatus(helper.userId, id, status) + return success("success") } - } diff --git a/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt b/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt index f49891eb..2b08150b 100644 --- a/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt +++ b/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt @@ -1,54 +1,55 @@ -package plus.maa.backend.repository; +package plus.maa.backend.repository -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.data.mongodb.repository.Query; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.ArkLevelSha; - -import java.util.Collection; -import java.util.List; -import java.util.stream.Stream; +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.mongodb.repository.MongoRepository +import org.springframework.data.mongodb.repository.Query +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.ArkLevelSha /** * @author john180 */ -public interface ArkLevelRepository extends MongoRepository { - List findAllShaBy(); +interface ArkLevelRepository : MongoRepository { + fun findAllShaBy(): List - Page findAllByCatOne(String catOne, Pageable pageable); + fun findAllByCatOne(catOne: String, pageable: Pageable): Page - @Query(""" + @Query( + """ { - "$or": [ + "${'$'}or": [ {"levelId": ?0}, {"stageId": ?0}, {"catThree": ?0} ] } - """) - Stream findByLevelIdFuzzy(String levelId); + + """ + ) + fun findByLevelIdFuzzy(levelId: String): List /** * 用于前端查询 关卡名、关卡类型、关卡编号 */ - @Query(""" + @Query( + """ { - "$or": [ - {"stageId": {'$regex': ?0 ,'$options':'i'}}, - {"catThree": {'$regex': ?0 ,'$options':'i'}}, - {"catTwo": {'$regex': ?0 ,'$options':'i'}}, - {"catOne": {'$regex': ?0 ,'$options':'i'}}, - {"name": {'$regex': ?0,'$options':'i' }} + "${'$'}or": [ + {"stageId": {'${'$'}regex': ?0 ,'${'$'}options':'i'}}, + {"catThree": {'${'$'}regex': ?0 ,'${'$'}options':'i'}}, + {"catTwo": {'${'$'}regex': ?0 ,'${'$'}options':'i'}}, + {"catOne": {'${'$'}regex': ?0 ,'${'$'}options':'i'}}, + {"name": {'${'$'}regex': ?0,'${'$'}options':'i' }} ] } - """) - Stream queryLevelByKeyword(String keyword); + + """ + ) + fun queryLevelByKeyword(keyword: String): List /** * 根据stageId列表查询 */ - List findByStageIdIn(Collection stageIds); - + fun findByStageIdIn(stageIds: Collection): List } diff --git a/src/main/java/plus/maa/backend/repository/CopilotRepository.kt b/src/main/java/plus/maa/backend/repository/CopilotRepository.kt index 15b729be..7d168828 100644 --- a/src/main/java/plus/maa/backend/repository/CopilotRepository.kt +++ b/src/main/java/plus/maa/backend/repository/CopilotRepository.kt @@ -1,31 +1,24 @@ -package plus.maa.backend.repository; +package plus.maa.backend.repository -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.repository.MongoRepository; -import plus.maa.backend.repository.entity.Copilot; - -import java.util.Collection; -import java.util.List; -import java.util.Optional; +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.mongodb.repository.MongoRepository +import plus.maa.backend.repository.entity.Copilot /** * @author LoMu * Date 2022-12-27 10:28 */ +interface CopilotRepository : MongoRepository { + fun findAllByDeleteIsFalse(pageable: Pageable): Page -public interface CopilotRepository extends MongoRepository { - - Page findAllByDeleteIsFalse(Pageable pageable); - - Optional findFirstByOrderByCopilotIdDesc(); - - Optional findByCopilotIdAndDeleteIsFalse(Long copilotId); + fun findFirstByOrderByCopilotIdDesc(): Copilot? - List findByCopilotIdInAndDeleteIsFalse(Collection copilotIds); + fun findByCopilotIdAndDeleteIsFalse(copilotId: Long): Copilot? - Optional findByCopilotId(Long copilotId); + fun findByCopilotIdInAndDeleteIsFalse(copilotIds: Collection): List - boolean existsCopilotsByCopilotId(Long copilotId); + fun findByCopilotId(copilotId: Long): Copilot? + fun existsCopilotsByCopilotId(copilotId: Long): Boolean } diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.kt b/src/main/java/plus/maa/backend/service/ArkLevelService.kt index 943f0230..3387e23b 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.kt +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.kt @@ -75,11 +75,11 @@ class ArkLevelService( .toList() @Cacheable("arkLevel") - fun findByLevelIdFuzzy(levelId: String?): ArkLevel? { - return arkLevelRepo.findByLevelIdFuzzy(levelId).findAny().orElse(null) + fun findByLevelIdFuzzy(levelId: String): ArkLevel? { + return arkLevelRepo.findByLevelIdFuzzy(levelId).firstOrNull() } - fun queryLevelInfosByKeyword(keyword: String?): List { + fun queryLevelInfosByKeyword(keyword: String): List { val levels = arkLevelRepo.queryLevelByKeyword(keyword).toList() return arkLevelConverter.convert(levels) } diff --git a/src/main/java/plus/maa/backend/service/CommentsAreaService.kt b/src/main/java/plus/maa/backend/service/CommentsAreaService.kt index b0e4ed10..080ac991 100644 --- a/src/main/java/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/java/plus/maa/backend/service/CommentsAreaService.kt @@ -59,7 +59,7 @@ class CommentsAreaService( val message = commentsAddDTO.message val copilotOptional = copilotRepository.findByCopilotId(copilotId) Assert.isTrue(StringUtils.isNotBlank(message), "评论不可为空") - Assert.isTrue(copilotOptional.isPresent, "作业表不存在") + Assert.isTrue(copilotOptional!=null, "作业表不存在") var fromCommentsId: String? = null @@ -93,7 +93,7 @@ class CommentsAreaService( //判断是否需要通知 if (Objects.nonNull(isCopilotAuthor) && maaCopilotProperties.mail.notification) { - val copilot = copilotOptional.get() + val copilot = copilotOptional!! //通知作业作者或是评论作者 val replyUserId = if (isCopilotAuthor!!) copilot.uploaderId else commentsArea!!.uploaderId @@ -144,8 +144,7 @@ class CommentsAreaService( fun deleteComments(userId: String, commentsId: String) { val commentsArea = findCommentsById(commentsId) //允许作者删除评论 - copilotRepository.findByCopilotId(commentsArea.copilotId) - .ifPresent { copilot: Copilot -> + copilotRepository.findByCopilotId(commentsArea.copilotId)?.let { copilot: Copilot -> Assert.isTrue( userId == copilot.uploaderId || userId == commentsArea.uploaderId, "您无法删除不属于您的评论" @@ -244,8 +243,7 @@ class CommentsAreaService( val commentsArea = findCommentsById(commentsToppingDTO.commentId) Assert.isTrue(!commentsArea.isDelete, "评论不存在") // 只允许作者置顶评论 - copilotRepository.findByCopilotId(commentsArea.copilotId) - .ifPresent { copilot: Copilot -> + copilotRepository.findByCopilotId(commentsArea.copilotId)?.let { copilot: Copilot -> Assert.isTrue( userId == copilot.uploaderId, "只有作者才能置顶评论" diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/java/plus/maa/backend/service/CopilotService.kt index 11d22056..2d148d10 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotService.kt @@ -147,7 +147,7 @@ class CopilotService( * 根据作业id删除作业 */ fun delete(loginUserId: String, request: CopilotCUDRequest) { - copilotRepository.findByCopilotId(request.id).ifPresent { copilot: Copilot -> + copilotRepository.findByCopilotId(request.id)?.let { copilot: Copilot -> Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") copilot.isDelete = true copilotRepository.save(copilot) @@ -168,10 +168,10 @@ class CopilotService( /** * 指定查询 */ - fun getCopilotById(userIdOrIpAddress: String, id: Long): Optional { + fun getCopilotById(userIdOrIpAddress: String, id: Long): CopilotInfo? { // 根据ID获取作业, 如作业不存在则抛出异常返回 val copilotOptional = copilotRepository.findByCopilotIdAndDeleteIsFalse(id) - return copilotOptional.map { copilot: Copilot -> + return copilotOptional?.let { copilot: Copilot -> // 60分钟内限制同一个用户对访问量的增加 val cache = redisCache.getCache("views:$userIdOrIpAddress", RatingCache::class.java) if (Objects.isNull(cache) || Objects.isNull(cache!!.copilotIds) || @@ -392,7 +392,7 @@ class CopilotService( fun update(loginUserId: String, copilotCUDRequest: CopilotCUDRequest) { val content = copilotCUDRequest.content val id = copilotCUDRequest.id - copilotRepository.findByCopilotId(id).ifPresent { copilot: Copilot -> + copilotRepository.findByCopilotId(id)?.let { copilot: Copilot -> val copilotDTO = correctCopilot(parseToCopilotDto(content)) Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") copilot.uploadTime = LocalDateTime.now() @@ -523,10 +523,10 @@ class CopilotService( return info } - fun notificationStatus(userId: String, copilotId: Long?, status: Boolean) { + fun notificationStatus(userId: String?, copilotId: Long, status: Boolean) { val copilotOptional = copilotRepository.findByCopilotId(copilotId) - Assert.isTrue(copilotOptional.isPresent, "copilot不存在") - val copilot = copilotOptional.get() + Assert.isTrue(copilotOptional!=null, "copilot不存在") + val copilot = copilotOptional!! Assert.isTrue(userId == copilot.uploaderId, "您没有权限修改") copilot.notification = status copilotRepository.save(copilot) diff --git a/src/main/java/plus/maa/backend/service/session/UserSession.kt b/src/main/java/plus/maa/backend/service/session/UserSession.kt index 0dd09d90..93813643 100644 --- a/src/main/java/plus/maa/backend/service/session/UserSession.kt +++ b/src/main/java/plus/maa/backend/service/session/UserSession.kt @@ -1,4 +1,3 @@ -package plus.maa.backend.service.session; +package plus.maa.backend.service.session -public class UserSession { -} +class UserSession diff --git a/src/main/java/plus/maa/backend/service/session/UserSessionService.kt b/src/main/java/plus/maa/backend/service/session/UserSessionService.kt index f2d0b464..2ee74ab7 100644 --- a/src/main/java/plus/maa/backend/service/session/UserSessionService.kt +++ b/src/main/java/plus/maa/backend/service/session/UserSessionService.kt @@ -1,54 +1,44 @@ -package plus.maa.backend.service.session; +package plus.maa.backend.service.session -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.springframework.stereotype.Service; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.repository.RedisCache; - -import java.util.function.Consumer; +import org.springframework.stereotype.Service +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.repository.RedisCache +import java.util.function.Consumer @Service -public class UserSessionService { - - private static final String REDIS_USER_SESSION_PREFIX = "USER_SESSION_"; +class UserSessionService(private val cache: RedisCache, properties: MaaCopilotProperties) { + private val sessionExpiration = properties.jwt.refreshExpire - private static String buildUserCacheKey(String userId) { - return REDIS_USER_SESSION_PREFIX + userId; + fun getSession(id: String): UserSession? { + return cache.getCache(buildUserCacheKey(id), UserSession::class.java, null, sessionExpiration) } - private final RedisCache cache; - private final long sessionExpiration; - - public UserSessionService(RedisCache cache, MaaCopilotProperties properties) { - this.cache = cache; - sessionExpiration = properties.getJwt().getRefreshExpire(); + fun setSession(id: String, session: UserSession) { + cache.setCache(buildUserCacheKey(id), session, sessionExpiration) } - @Nullable - public UserSession getSession(String id) { - return cache.getCache(buildUserCacheKey(id), UserSession.class, null, sessionExpiration); + fun setSession(id: String, consumer: Consumer) { + val session = UserSession() + consumer.accept(session) + cache.setCache(buildUserCacheKey(id), session, sessionExpiration) } - public void setSession(@NotNull String id, @NotNull UserSession session) { - cache.setCache(buildUserCacheKey(id), session, sessionExpiration); + fun updateSessionIfPresent(id: String, consumer: Consumer) { + cache.updateCache(id, UserSession::class.java, null, { session: UserSession? -> + if (session != null) consumer.accept(session) + session + }, sessionExpiration) } - public void setSession(@NotNull String id,@NotNull Consumer consumer){ - var session = new UserSession(); - consumer.accept(session); - cache.setCache(buildUserCacheKey(id), session, sessionExpiration); + fun removeSession(id: String) { + cache.removeCache(buildUserCacheKey(id)) } - public void updateSessionIfPresent(@NotNull String id, @NotNull Consumer consumer) { - cache.updateCache(id, UserSession.class, null, (session) -> { - if (session != null) consumer.accept(session); - return session; - }, sessionExpiration); - } + companion object { + private const val REDIS_USER_SESSION_PREFIX = "USER_SESSION_" - public void removeSession(String id) { - cache.removeCache(buildUserCacheKey(id)); + private fun buildUserCacheKey(userId: String): String { + return REDIS_USER_SESSION_PREFIX + userId + } } - } From 83b48838491273a6aa06ca97d308de9bbf0dda0a Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 08:44:27 +0800 Subject: [PATCH 074/168] Rename .java to .kt --- .../{CopilotSetRepository.java => CopilotSetRepository.kt} | 0 .../repository/{GithubRepository.java => GithubRepository.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/repository/{CopilotSetRepository.java => CopilotSetRepository.kt} (100%) rename src/main/java/plus/maa/backend/repository/{GithubRepository.java => GithubRepository.kt} (100%) diff --git a/src/main/java/plus/maa/backend/repository/CopilotSetRepository.java b/src/main/java/plus/maa/backend/repository/CopilotSetRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/CopilotSetRepository.java rename to src/main/java/plus/maa/backend/repository/CopilotSetRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/GithubRepository.java b/src/main/java/plus/maa/backend/repository/GithubRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/GithubRepository.java rename to src/main/java/plus/maa/backend/repository/GithubRepository.kt From 3e01fdb3b75fc07f610a6d0f12793c4218791ecc Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 08:44:28 +0800 Subject: [PATCH 075/168] perf: remove several uses of java stream functions --- .../repository/CopilotSetRepository.kt | 31 ++++++++++--------- .../backend/repository/GithubRepository.kt | 31 +++++++++---------- .../maa/backend/service/ArkLevelService.kt | 27 ++++++---------- 3 files changed, 41 insertions(+), 48 deletions(-) diff --git a/src/main/java/plus/maa/backend/repository/CopilotSetRepository.kt b/src/main/java/plus/maa/backend/repository/CopilotSetRepository.kt index ab6814ad..6a70242c 100644 --- a/src/main/java/plus/maa/backend/repository/CopilotSetRepository.kt +++ b/src/main/java/plus/maa/backend/repository/CopilotSetRepository.kt @@ -1,25 +1,26 @@ -package plus.maa.backend.repository; +package plus.maa.backend.repository -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.data.mongodb.repository.Query; -import plus.maa.backend.repository.entity.CopilotSet; +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.mongodb.repository.MongoRepository +import org.springframework.data.mongodb.repository.Query +import plus.maa.backend.repository.entity.CopilotSet /** * @author dragove * create on 2024-01-01 */ -public interface CopilotSetRepository extends MongoRepository { - - @Query(""" +interface CopilotSetRepository : MongoRepository { + @Query( + """ { - "$or": [ - {"name": {'$regex': ?0 ,'$options':'i'}}, - {"description": {'$regex': ?0,'$options':'i' }} + "${'$'}or": [ + {"name": {'${'$'}regex': ?0 ,'${'$'}options':'i'}}, + {"description": {'${'$'}regex': ?0,'${'$'}options':'i' }} ] } - """) - Page findByKeyword(String keyword, Pageable pageable); - + + """ + ) + fun findByKeyword(keyword: String, pageable: Pageable): Page } diff --git a/src/main/java/plus/maa/backend/repository/GithubRepository.kt b/src/main/java/plus/maa/backend/repository/GithubRepository.kt index 7d495c20..d1924f21 100644 --- a/src/main/java/plus/maa/backend/repository/GithubRepository.kt +++ b/src/main/java/plus/maa/backend/repository/GithubRepository.kt @@ -1,30 +1,29 @@ -package plus.maa.backend.repository; +package plus.maa.backend.repository -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.service.annotation.GetExchange; -import plus.maa.backend.repository.entity.github.GithubCommit; -import plus.maa.backend.repository.entity.github.GithubContent; -import plus.maa.backend.repository.entity.github.GithubTrees; - -import java.util.List; +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.RequestHeader +import org.springframework.web.service.annotation.GetExchange +import plus.maa.backend.repository.entity.github.GithubCommit +import plus.maa.backend.repository.entity.github.GithubContent +import plus.maa.backend.repository.entity.github.GithubTrees /** * @author dragove * created on 2022/12/23 */ -public interface GithubRepository { - +interface GithubRepository { /** - * api doc: git trees api + * api doc: [git trees api](https://docs.github.com/en/rest/git/trees?apiVersion=2022-11-28#get-a-tree) */ @GetExchange(value = "/repos/MaaAssistantArknights/MaaAssistantArknights/git/trees/{sha}") - GithubTrees getTrees(@RequestHeader("Authorization") String token, @PathVariable("sha") String sha); + fun getTrees(@RequestHeader("Authorization") token: String, @PathVariable("sha") sha: String): GithubTrees @GetExchange(value = "/repos/MaaAssistantArknights/MaaAssistantArknights/commits") - List getCommits(@RequestHeader("Authorization") String token); + fun getCommits(@RequestHeader("Authorization") token: String): List @GetExchange(value = "/repos/MaaAssistantArknights/MaaAssistantArknights/contents/{path}") - List getContents(@RequestHeader("Authorization") String token, @PathVariable("path") String path); - + fun getContents( + @RequestHeader("Authorization") token: String, + @PathVariable("path") path: String + ): List } diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.kt b/src/main/java/plus/maa/backend/service/ArkLevelService.kt index 3387e23b..7957f2b9 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.kt +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.kt @@ -9,7 +9,6 @@ import org.springframework.cache.annotation.Cacheable import org.springframework.data.domain.Pageable import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Service -import org.springframework.util.CollectionUtils import plus.maa.backend.common.utils.ArkLevelUtil import plus.maa.backend.common.utils.converter.ArkLevelConverter import plus.maa.backend.controller.response.copilot.ArkLevelInfo @@ -92,39 +91,35 @@ class ArkLevelService( log.info { "[LEVEL]开始同步地图数据" } //获取地图文件夹最新的commit, 用于判断是否需要更新 val commits = githubRepo.getCommits(githubToken) - if (CollectionUtils.isEmpty(commits)) { + if (commits.isEmpty()) { log.info { "[LEVEL]获取地图数据最新commit失败" } return } //与缓存的commit比较,如果相同则不更新 val commit = commits[0] val lastCommit = redisCache.cacheLevelCommit - if (lastCommit != null && lastCommit == commit!!.sha) { + if (lastCommit != null && lastCommit == commit.sha) { log.info { "[LEVEL]地图数据已是最新" } return } //获取根目录文件列表 var trees: GithubTrees? - val files = Arrays.stream(tilePosPath.split("/".toRegex()).dropLastWhile { it.isEmpty() } - .toTypedArray()).toList() - trees = githubRepo.getTrees(githubToken, commit!!.sha) + val files = tilePosPath.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray().toList() + trees = githubRepo.getTrees(githubToken, commit.sha) //根据路径获取文件列表 for (file in files) { - if (trees == null || CollectionUtils.isEmpty(trees.tree)) { + if (trees == null || trees.tree.isEmpty()) { log.info { "[LEVEL]地图数据获取失败" } return } - val tree = trees.tree.stream() - .filter { t: GithubTree -> t.path == file && t.type == "tree" } - .findFirst() - .orElse(null) + val tree = trees.tree.firstOrNull { t: GithubTree -> t.path == file && t.type == "tree" } if (tree == null) { log.info { "[LEVEL]地图数据获取失败, 未找到文件夹$file" } return } trees = githubRepo.getTrees(githubToken, tree.sha) } - if (trees == null || CollectionUtils.isEmpty(trees.tree)) { + if (trees == null || trees.tree.isEmpty()) { log.info { "[LEVEL]地图数据获取失败, 未找到文件夹$tilePosPath" } return } @@ -135,7 +130,7 @@ class ArkLevelService( log.info { "[LEVEL]已发现${levelTrees.size}份地图数据" } //根据sha筛选无需更新的地图 - val shaList = arkLevelRepo.findAllShaBy().stream().map { obj: ArkLevelSha -> obj.sha }.toList() + val shaList = arkLevelRepo.findAllShaBy().map { obj: ArkLevelSha -> obj.sha }.toList() levelTrees.removeIf { t: GithubTree -> shaList.contains(t.sha) } // 排除overview文件、肉鸽、训练关卡和 Guide? 不知道是啥 levelTrees.removeIf { t: GithubTree -> @@ -169,10 +164,8 @@ class ArkLevelService( */ fun updateActivitiesOpenStatus() { log.info { "[ACTIVITIES-OPEN-STATUS]准备更新活动地图开放状态" } - val stages = githubRepo.getContents(githubToken, "resource").stream() - .filter { content: GithubContent -> content.isFile && "stages.json" == content.name } - .findFirst() - .orElse(null) + val stages = githubRepo.getContents(githubToken, "resource").firstOrNull { content: GithubContent -> content.isFile && "stages.json" == content.name } + if (stages == null) { log.info { "[ACTIVITIES-OPEN-STATUS]活动地图开放状态数据不存在" } return From e4eee6d435d88c74ac6a90b05f47f0868037d170 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 09:33:18 +0800 Subject: [PATCH 076/168] Rename .java to .kt --- ...ontentLengthRepairFilter.java => ContentLengthRepairFilter.kt} | 0 ...gistrationBean.java => MaaEtagHeaderFilterRegistrationBean.kt} | 0 ...terceptHandlerImpl.java => AccessLimitInterceptHandlerImpl.kt} | 0 .../{GlobalExceptionHandler.java => GlobalExceptionHandler.kt} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/filter/{ContentLengthRepairFilter.java => ContentLengthRepairFilter.kt} (100%) rename src/main/java/plus/maa/backend/filter/{MaaEtagHeaderFilterRegistrationBean.java => MaaEtagHeaderFilterRegistrationBean.kt} (100%) rename src/main/java/plus/maa/backend/handler/{AccessLimitInterceptHandlerImpl.java => AccessLimitInterceptHandlerImpl.kt} (100%) rename src/main/java/plus/maa/backend/handler/{GlobalExceptionHandler.java => GlobalExceptionHandler.kt} (100%) diff --git a/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java b/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.kt similarity index 100% rename from src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.java rename to src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.kt diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.java b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt similarity index 100% rename from src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.java rename to src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt diff --git a/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.java b/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt similarity index 100% rename from src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.java rename to src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt diff --git a/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.java b/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt similarity index 100% rename from src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.java rename to src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt From b6dd0b11281d3eb2be53527ac1bc5dabd32e8394 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 09:33:19 +0800 Subject: [PATCH 077/168] refactor: handlers in kotlin --- .../filter/ContentLengthRepairFilter.kt | 53 ++--- .../MaaEtagHeaderFilterRegistrationBean.kt | 73 ++++--- .../AccessLimitInterceptHandlerImpl.kt | 131 ++++++------ .../backend/handler/GlobalExceptionHandler.kt | 190 +++++++++--------- 4 files changed, 224 insertions(+), 223 deletions(-) diff --git a/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.kt b/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.kt index fc2d1fc5..dd9d9858 100644 --- a/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.kt +++ b/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.kt @@ -1,16 +1,15 @@ -package plus.maa.backend.filter; +package plus.maa.backend.filter -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.ShallowEtagHeaderFilter; -import org.springframework.web.util.ContentCachingResponseWrapper; - -import java.io.IOException; -import java.io.InputStream; +import jakarta.servlet.FilterChain +import jakarta.servlet.ServletException +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty +import org.springframework.stereotype.Component +import org.springframework.web.filter.ShallowEtagHeaderFilter +import org.springframework.web.util.ContentCachingResponseWrapper +import java.io.IOException +import java.io.InputStream /** * 解决了 GZIP 无法对 JSON 响应正常处理 min-response-size 的问题, @@ -19,23 +18,27 @@ import java.io.InputStream; * * @author lixuhuilll */ - @Component -@ConditionalOnProperty(name = "server.compression.enabled", havingValue = "true") -public class ContentLengthRepairFilter extends ShallowEtagHeaderFilter { - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { - if (response instanceof ContentCachingResponseWrapper) { +@ConditionalOnProperty(name = ["server.compression.enabled"], havingValue = "true") +class ContentLengthRepairFilter : ShallowEtagHeaderFilter() { + @Throws(ServletException::class, IOException::class) + override fun doFilterInternal( + request: HttpServletRequest, + response: HttpServletResponse, + filterChain: FilterChain + ) { + if (response is ContentCachingResponseWrapper) { // 不对已包装过的响应体做处理 - filterChain.doFilter(request, response); + filterChain.doFilter(request, response) } else { - super.doFilterInternal(request, response, filterChain); + super.doFilterInternal(request, response, filterChain) } } - @Override - protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, int responseStatusCode, InputStream inputStream) { - return false; - } + override fun isEligibleForEtag( + request: HttpServletRequest, + response: HttpServletResponse, + responseStatusCode: Int, + inputStream: InputStream + ) = false } diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt index 239bebfc..fb26e1d0 100644 --- a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt +++ b/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt @@ -1,65 +1,60 @@ -package plus.maa.backend.filter; - -import jakarta.annotation.PostConstruct; -import jakarta.servlet.Filter; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.boot.web.servlet.FilterRegistrationBean; -import org.springframework.http.HttpHeaders; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.ShallowEtagHeaderFilter; - -import java.io.InputStream; -import java.util.Set; - +package plus.maa.backend.filter + +import jakarta.annotation.PostConstruct +import jakarta.servlet.Filter +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.boot.web.servlet.FilterRegistrationBean +import org.springframework.http.HttpHeaders +import org.springframework.stereotype.Component +import org.springframework.web.filter.ShallowEtagHeaderFilter +import java.io.InputStream /** * 提供基于 Etag 机制的 HTTP 缓存,有助于降低网络传输的压力 * * @author lixuhuilll */ - @Component -public class MaaEtagHeaderFilterRegistrationBean extends FilterRegistrationBean { - +class MaaEtagHeaderFilterRegistrationBean : FilterRegistrationBean() { /** * 配置需要使用 Etag 机制的 URI,采用 Servlet 的 URI 匹配语法 */ - private final Set ETAG_URI = Set.of( - "/arknights/level", - "/copilot/query" - ); + private val ETAG_URI = setOf( + "/arknights/level", + "/copilot/query" + ) @PostConstruct - public void init() { - setFilter(new MaaEtagHeaderFilter()); - setUrlPatterns(ETAG_URI); + fun init() { + filter = MaaEtagHeaderFilter() + urlPatterns = ETAG_URI } - private static class MaaEtagHeaderFilter extends ShallowEtagHeaderFilter { - - private static final String CACHE_HEAD = "private, no-cache, max-age=0, must-revalidate"; - - @Override - protected void initFilterBean() { + private class MaaEtagHeaderFilter : ShallowEtagHeaderFilter() { + override fun initFilterBean() { // Etag 必须使用弱校验才能与自动压缩兼容 - setWriteWeakETag(true); + isWriteWeakETag = true } - @Override - protected boolean isEligibleForEtag(HttpServletRequest request, HttpServletResponse response, - int responseStatusCode, InputStream inputStream) { - + override fun isEligibleForEtag( + request: HttpServletRequest, response: HttpServletResponse, + responseStatusCode: Int, inputStream: InputStream + ): Boolean { if (super.isEligibleForEtag(request, response, responseStatusCode, inputStream)) { // 使用 ETag 机制的 URI,若其响应中不存在缓存控制头,则配置默认值 - final String cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL); + val cacheControl = response.getHeader(HttpHeaders.CACHE_CONTROL) if (cacheControl == null) { - response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD); + response.setHeader(HttpHeaders.CACHE_CONTROL, CACHE_HEAD) } - return true; + return true } - return false; + return false + } + + companion object { + private const val CACHE_HEAD = "private, no-cache, max-age=0, must-revalidate" } } } diff --git a/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt b/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt index 456bcc39..a29f4d03 100644 --- a/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt +++ b/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt @@ -1,36 +1,30 @@ -package plus.maa.backend.handler; - -import java.lang.reflect.Method; -import java.util.concurrent.TimeUnit; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerInterceptor; -import org.springframework.web.servlet.ModelAndView; - -import com.fasterxml.jackson.databind.ObjectMapper; - -import io.micrometer.common.util.StringUtils; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import plus.maa.backend.common.annotation.AccessLimit; -import plus.maa.backend.common.utils.IpUtil; -import plus.maa.backend.common.utils.SpringUtil; -import plus.maa.backend.common.utils.WebUtils; -import plus.maa.backend.controller.response.MaaResult; +package plus.maa.backend.handler + +import com.fasterxml.jackson.databind.ObjectMapper +import io.github.oshai.kotlinlogging.KotlinLogging +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.data.redis.core.StringRedisTemplate +import org.springframework.http.HttpStatus +import org.springframework.lang.Nullable +import org.springframework.stereotype.Component +import org.springframework.web.method.HandlerMethod +import org.springframework.web.servlet.HandlerInterceptor +import org.springframework.web.servlet.ModelAndView +import plus.maa.backend.common.annotation.AccessLimit +import plus.maa.backend.common.utils.IpUtil +import plus.maa.backend.common.utils.SpringUtil +import plus.maa.backend.common.utils.WebUtils +import plus.maa.backend.controller.response.MaaResult.Companion.fail +import java.util.concurrent.TimeUnit + +private val log = KotlinLogging.logger { } /** * @author Baip1995 */ @Component -public class AccessLimitInterceptHandlerImpl implements HandlerInterceptor { - - private static final Logger logger = LoggerFactory.getLogger(AccessLimitInterceptHandlerImpl.class); - +class AccessLimitInterceptHandlerImpl : HandlerInterceptor { // @Resource // private RedisCache redisCache; /** @@ -42,75 +36,76 @@ public class AccessLimitInterceptHandlerImpl implements HandlerInterceptor { * @return * @throws Exception */ - @Override - public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) - throws Exception { + @Throws(Exception::class) + override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { try { // handler是否为 HandleMethod 实例 - if (handler instanceof HandlerMethod) { + if (handler is HandlerMethod) { // 强转 - HandlerMethod handlerMethod = (HandlerMethod) handler; // 获取方法 - Method method = handlerMethod.getMethod(); + val method = handler.method // 判断方式是否有AccessLimit注解,有的才需要做限流 - if (!method.isAnnotationPresent(AccessLimit.class)) { - return true; + if (!method.isAnnotationPresent(AccessLimit::class.java)) { + return true } - StringRedisTemplate stringRedisTemplate = SpringUtil.getApplicationContext() - .getBean(StringRedisTemplate.class); + val stringRedisTemplate = SpringUtil.getApplicationContext() + .getBean(StringRedisTemplate::class.java) // 获取注解上的内容 - AccessLimit accessLimit = method.getAnnotation(AccessLimit.class); - if (accessLimit == null) { - return true; - } + val accessLimit = method.getAnnotation(AccessLimit::class.java) ?: return true // 获取方法注解上的请求次数 - int times = accessLimit.times(); + val times = accessLimit.times // 获取方法注解上的请求时间 - Integer second = accessLimit.second(); + val second = accessLimit.second // 拼接redis key = IP + Api限流 - String key = IpUtil.getIpAddr(request) + request.getRequestURI(); + val key = IpUtil.getIpAddr(request) + request.requestURI // 获取redis的value - Integer maxTimes = null; + var maxTimes: Int? = null - String value = stringRedisTemplate.opsForValue().get(key); - if (StringUtils.isNotEmpty(value)) { - maxTimes = Integer.valueOf(value); + val value = stringRedisTemplate.opsForValue()[key] + if (!value.isNullOrEmpty()) { + maxTimes = value.toInt() } if (maxTimes == null) { // 如果redis中没有该ip对应的时间则表示第一次调用,保存key到redis - stringRedisTemplate.opsForValue().set(key, "1", second, TimeUnit.SECONDS); + stringRedisTemplate.opsForValue()[key, "1", second.toLong()] = TimeUnit.SECONDS } else if (maxTimes < times) { // 如果redis中的时间比注解上的时间小则表示可以允许访问,这是修改redis的value时间 - stringRedisTemplate.opsForValue().set(key, maxTimes + 1 + "", second, TimeUnit.SECONDS); + stringRedisTemplate.opsForValue()[key, (maxTimes + 1).toString() + "", second.toLong()] = + TimeUnit.SECONDS } else { // 请求过于频繁 - logger.info(key + " 请求过于频繁"); - MaaResult result = MaaResult.fail(HttpStatus.TOO_MANY_REQUESTS.value(), "请求过于频繁"); - String json = new ObjectMapper().writeValueAsString(result); - WebUtils.renderString(response, json, HttpStatus.TOO_MANY_REQUESTS.value()); - return false; + log.info { "$key 请求过于频繁" } + val result = fail(HttpStatus.TOO_MANY_REQUESTS.value(), "请求过于频繁") + val json = ObjectMapper().writeValueAsString(result) + WebUtils.renderString(response, json, HttpStatus.TOO_MANY_REQUESTS.value()) + return false } } - } catch (Exception e) { - logger.error("API请求限流拦截异常,异常原因:", e); + } catch (e: Exception) { + log.error(e) { "API请求限流拦截异常,异常原因:" } // throw new Exception(""); } - return true; + return true } - @Override - public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, - ModelAndView modelAndView) throws Exception { - + @Throws(Exception::class) + override fun postHandle( + request: HttpServletRequest, + response: HttpServletResponse, + handler: Any, + @Nullable modelAndView: ModelAndView? + ) { } - @Override - public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) - throws Exception { - + @Throws(Exception::class) + override fun afterCompletion( + request: HttpServletRequest, + response: HttpServletResponse, + handler: Any, + @Nullable ex: java.lang.Exception? + ) { } - } diff --git a/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt b/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt index b4ea56bd..67a6760f 100644 --- a/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt +++ b/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt @@ -1,43 +1,45 @@ -package plus.maa.backend.handler; - -import org.springframework.http.HttpStatus; -import org.springframework.security.core.AuthenticationException; -import org.springframework.validation.FieldError; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.MissingServletRequestParameterException; -import org.springframework.web.bind.annotation.ExceptionHandler; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; -import org.springframework.web.multipart.MultipartException; -import org.springframework.web.server.ResponseStatusException; -import org.springframework.web.servlet.NoHandlerFoundException; - -import jakarta.servlet.http.HttpServletRequest; -import lombok.extern.slf4j.Slf4j; -import plus.maa.backend.controller.response.MaaResult; -import plus.maa.backend.controller.response.MaaResultException; +package plus.maa.backend.handler + +import io.github.oshai.kotlinlogging.KotlinLogging +import jakarta.servlet.http.HttpServletRequest +import lombok.extern.slf4j.Slf4j +import org.springframework.http.HttpStatus +import org.springframework.security.core.AuthenticationException +import org.springframework.web.HttpRequestMethodNotSupportedException +import org.springframework.web.bind.MethodArgumentNotValidException +import org.springframework.web.bind.MissingServletRequestParameterException +import org.springframework.web.bind.annotation.ExceptionHandler +import org.springframework.web.bind.annotation.ResponseBody +import org.springframework.web.bind.annotation.RestControllerAdvice +import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException +import org.springframework.web.multipart.MultipartException +import org.springframework.web.server.ResponseStatusException +import org.springframework.web.servlet.NoHandlerFoundException +import plus.maa.backend.controller.response.MaaResult +import plus.maa.backend.controller.response.MaaResult.Companion.fail +import plus.maa.backend.controller.response.MaaResultException + +private val log = KotlinLogging.logger { } /** * @author john180 */ -@Slf4j @RestControllerAdvice -public class GlobalExceptionHandler { - +class GlobalExceptionHandler { /** * @return plus.maa.backend.controller.response.MaaResult * @author FAll * @description 请求参数缺失 * @date 2022/12/23 12:00 - */ - @ExceptionHandler(MissingServletRequestParameterException.class) - public MaaResult missingServletRequestParameterException(MissingServletRequestParameterException e, - HttpServletRequest request) { - logWarn(request); - log.warn("请求参数缺失", e); - return MaaResult.fail(400, String.format("请求参数缺失:%s", e.getParameterName())); + */ + @ExceptionHandler(MissingServletRequestParameterException::class) + fun missingServletRequestParameterException( + e: MissingServletRequestParameterException, + request: HttpServletRequest + ): MaaResult { + logWarn(request) + log.warn(e) { "请求参数缺失" } + return fail(400, String.format("请求参数缺失:%s", e.parameterName)) } /** @@ -45,13 +47,15 @@ public class GlobalExceptionHandler { * @author FAll * @description 参数类型不匹配 * @date 2022/12/23 12:01 - */ - @ExceptionHandler(MethodArgumentTypeMismatchException.class) - public MaaResult methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, - HttpServletRequest request) { - logWarn(request); - log.warn("参数类型不匹配", e); - return MaaResult.fail(400, String.format("参数类型不匹配:%s", e.getMessage())); + */ + @ExceptionHandler(MethodArgumentTypeMismatchException::class) + fun methodArgumentTypeMismatchException( + e: MethodArgumentTypeMismatchException, + request: HttpServletRequest + ): MaaResult { + logWarn(request) + log.warn(e) { "参数类型不匹配" } + return fail(400, String.format("参数类型不匹配:%s", e.message)) } /** @@ -59,14 +63,14 @@ public class GlobalExceptionHandler { * @author FAll * @description 参数校验错误 * @date 2022/12/23 12:02 - */ - @ExceptionHandler(MethodArgumentNotValidException.class) - public MaaResult methodArgumentNotValidException(MethodArgumentNotValidException e) { - FieldError fieldError = e.getBindingResult().getFieldError(); + */ + @ExceptionHandler(MethodArgumentNotValidException::class) + fun methodArgumentNotValidException(e: MethodArgumentNotValidException): MaaResult { + val fieldError = e.bindingResult.fieldError if (fieldError != null) { - return MaaResult.fail(400, String.format("参数校验错误: %s", fieldError.getDefaultMessage())); + return fail(400, String.format("参数校验错误: %s", fieldError.defaultMessage)) } - return MaaResult.fail(400, String.format("参数校验错误: %s", e.getMessage())); + return fail(400, String.format("参数校验错误: %s", e.message)) } /** @@ -74,11 +78,11 @@ public class GlobalExceptionHandler { * @author FAll * @description 请求地址不存在 * @date 2022/12/23 12:03 - */ - @ExceptionHandler(NoHandlerFoundException.class) - public MaaResult noHandlerFoundExceptionHandler(NoHandlerFoundException e) { - log.warn("请求地址不存在", e); - return MaaResult.fail(404, String.format("请求地址 %s 不存在", e.getRequestURL())); + */ + @ExceptionHandler(NoHandlerFoundException::class) + fun noHandlerFoundExceptionHandler(e: NoHandlerFoundException): MaaResult { + log.warn(e) { "请求地址不存在" } + return fail(404, String.format("请求地址 %s 不存在", e.requestURL)) } /** @@ -86,21 +90,23 @@ public class GlobalExceptionHandler { * @author FAll * @description * @date 2022/12/23 12:04 - */ - @ExceptionHandler(HttpRequestMethodNotSupportedException.class) - public MaaResult httpRequestMethodNotSupportedExceptionHandler(HttpRequestMethodNotSupportedException e, - HttpServletRequest request) { - logWarn(request); - log.warn("请求方式错误", e); - return MaaResult.fail(405, String.format("请求方法不正确:%s", e.getMessage())); + */ + @ExceptionHandler(HttpRequestMethodNotSupportedException::class) + fun httpRequestMethodNotSupportedExceptionHandler( + e: HttpRequestMethodNotSupportedException, + request: HttpServletRequest + ): MaaResult { + logWarn(request) + log.warn(e) { "请求方式错误" } + return fail(405, String.format("请求方法不正确:%s", e.message)) } /** - * 处理由 {@link org.springframework.util.Assert} 工具产生的异常 + * 处理由 [org.springframework.util.Assert] 工具产生的异常 */ - @ExceptionHandler({IllegalArgumentException.class, IllegalStateException.class}) - public MaaResult illegalArgumentOrStateExceptionHandler(RuntimeException e) { - return MaaResult.fail(HttpStatus.BAD_REQUEST.value(), e.getMessage()); + @ExceptionHandler(IllegalArgumentException::class, IllegalStateException::class) + fun illegalArgumentOrStateExceptionHandler(e: RuntimeException): MaaResult { + return fail(HttpStatus.BAD_REQUEST.value(), e.message) } /** @@ -108,59 +114,61 @@ public class GlobalExceptionHandler { * @author cbc * @description * @date 2022/12/26 12:00 - */ - @ExceptionHandler(MaaResultException.class) - public MaaResult maaResultExceptionHandler(MaaResultException e) { - return MaaResult.fail(e.getCode(), e.getMsg()); + */ + @ExceptionHandler(MaaResultException::class) + fun maaResultExceptionHandler(e: MaaResultException): MaaResult { + return fail(e.code, e.msg) } /** * @author john180 * @description 用户鉴权相关,异常兜底处理 */ - @ExceptionHandler(AuthenticationException.class) - public MaaResult authExceptionHandler(AuthenticationException e) { - return MaaResult.fail(401, e.getMessage()); + @ExceptionHandler(AuthenticationException::class) + fun authExceptionHandler(e: AuthenticationException): MaaResult { + return fail(401, e.message) } - @ExceptionHandler(MultipartException.class) - public MaaResult fileSizeThresholdHandler(MultipartException e) { - return MaaResult.fail(413, e.getMessage()); + @ExceptionHandler(MultipartException::class) + fun fileSizeThresholdHandler(e: MultipartException): MaaResult { + return fail(413, e.message) } - @ExceptionHandler(ResponseStatusException.class) - public MaaResult handleResponseStatusException(ResponseStatusException ex) { - return MaaResult.fail(ex.getStatusCode().value(), ex.getMessage()); + @ExceptionHandler(ResponseStatusException::class) + fun handleResponseStatusException(ex: ResponseStatusException): MaaResult { + return fail(ex.statusCode.value(), ex.message) } /** - * @return plus.maa.backend.controller.response.MaaResult + * @return plus.maa.backend.controller.response.MaaResult * @author john180 * @description 服务器内部错误,异常兜底处理 * @date 2022/12/23 12:06 */ @ResponseBody - @ExceptionHandler(value = Exception.class) - public MaaResult defaultExceptionHandler(Exception e, - HttpServletRequest request) { - logError(request); - log.error("Exception: ", e); - return MaaResult.fail(500, "服务器内部错误", null); + @ExceptionHandler(value = [Exception::class]) + fun defaultExceptionHandler( + e: Exception, + request: HttpServletRequest + ): MaaResult<*> { + logError(request) + log.error(e) { "Exception: " } + return fail(500, "服务器内部错误", null) } - private void logWarn(HttpServletRequest request) { - log.warn("Request URL: {}", request.getRequestURL()); - log.warn("Request Method: {}", request.getMethod()); - log.warn("Request IP: {}", request.getRemoteAddr()); - log.warn("Request Headers: {}", request.getHeaderNames()); - log.warn("Request Parameters: {}", request.getParameterMap()); + private fun logWarn(request: HttpServletRequest) { + log.warn { "Request URL: ${request.requestURL}" } + log.warn { "Request Method: ${request.method}" } + log.warn { "Request IP: ${request.remoteAddr}" } + log.warn { "Request Headers: ${request.headerNames}" } + log.warn { "Request Parameters: ${request.parameterMap}" } } - private void logError(HttpServletRequest request) { - log.error("Request URL: {}", request.getRequestURL()); - log.error("Request Method: {}", request.getMethod()); - log.error("Request IP: {}", request.getRemoteAddr()); - log.error("Request Headers: {}", request.getHeaderNames()); - log.error("Request Parameters: {}", request.getParameterMap()); + private fun logError(request: HttpServletRequest) { + log.error { "Request URL: ${request.requestURL}" } + log.error { "Request Method: ${request.method}" } + log.error { "Request IP: ${request.remoteAddr}" } + log.error { "Request Headers: ${request.headerNames}" } + log.error { "Request Parameters: ${request.parameterMap}" } } } From 497a44ec7296b48e8e3d4456319887f4be695719 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 09:49:27 +0800 Subject: [PATCH 078/168] Rename .java to .kt --- .../maa/backend/common/utils/{IdComponent.java => IdComponent.kt} | 0 .../java/plus/maa/backend/common/utils/{IpUtil.java => IpUtil.kt} | 0 .../maa/backend/common/utils/{OkHttpUtils.java => OkHttpUtils.kt} | 0 .../maa/backend/common/utils/{SpringUtil.java => SpringUtil.kt} | 0 .../plus/maa/backend/common/utils/{WebUtils.java => WebUtils.kt} | 0 .../{AccessDeniedHandlerImpl.java => AccessDeniedHandlerImpl.kt} | 0 ...icationEntryPointImpl.java => AuthenticationEntryPointImpl.kt} | 0 .../{AuthenticationHelper.java => AuthenticationHelper.kt} | 0 .../repository/entity/{CollectionMeta.java => CollectionMeta.kt} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/common/utils/{IdComponent.java => IdComponent.kt} (100%) rename src/main/java/plus/maa/backend/common/utils/{IpUtil.java => IpUtil.kt} (100%) rename src/main/java/plus/maa/backend/common/utils/{OkHttpUtils.java => OkHttpUtils.kt} (100%) rename src/main/java/plus/maa/backend/common/utils/{SpringUtil.java => SpringUtil.kt} (100%) rename src/main/java/plus/maa/backend/common/utils/{WebUtils.java => WebUtils.kt} (100%) rename src/main/java/plus/maa/backend/config/security/{AccessDeniedHandlerImpl.java => AccessDeniedHandlerImpl.kt} (100%) rename src/main/java/plus/maa/backend/config/security/{AuthenticationEntryPointImpl.java => AuthenticationEntryPointImpl.kt} (100%) rename src/main/java/plus/maa/backend/config/security/{AuthenticationHelper.java => AuthenticationHelper.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/{CollectionMeta.java => CollectionMeta.kt} (100%) diff --git a/src/main/java/plus/maa/backend/common/utils/IdComponent.java b/src/main/java/plus/maa/backend/common/utils/IdComponent.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/IdComponent.java rename to src/main/java/plus/maa/backend/common/utils/IdComponent.kt diff --git a/src/main/java/plus/maa/backend/common/utils/IpUtil.java b/src/main/java/plus/maa/backend/common/utils/IpUtil.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/IpUtil.java rename to src/main/java/plus/maa/backend/common/utils/IpUtil.kt diff --git a/src/main/java/plus/maa/backend/common/utils/OkHttpUtils.java b/src/main/java/plus/maa/backend/common/utils/OkHttpUtils.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/OkHttpUtils.java rename to src/main/java/plus/maa/backend/common/utils/OkHttpUtils.kt diff --git a/src/main/java/plus/maa/backend/common/utils/SpringUtil.java b/src/main/java/plus/maa/backend/common/utils/SpringUtil.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/SpringUtil.java rename to src/main/java/plus/maa/backend/common/utils/SpringUtil.kt diff --git a/src/main/java/plus/maa/backend/common/utils/WebUtils.java b/src/main/java/plus/maa/backend/common/utils/WebUtils.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/WebUtils.java rename to src/main/java/plus/maa/backend/common/utils/WebUtils.kt diff --git a/src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.java b/src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.java rename to src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt diff --git a/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.java b/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.java rename to src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt diff --git a/src/main/java/plus/maa/backend/config/security/AuthenticationHelper.java b/src/main/java/plus/maa/backend/config/security/AuthenticationHelper.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/AuthenticationHelper.java rename to src/main/java/plus/maa/backend/config/security/AuthenticationHelper.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/CollectionMeta.java rename to src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt From 4ddefab5d14f82696c800eb47bf1f4cecfa3f418 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 09:49:28 +0800 Subject: [PATCH 079/168] refactor: utils in kotlin --- .../maa/backend/common/utils/IdComponent.kt | 67 ++++++------- .../plus/maa/backend/common/utils/IpUtil.kt | 46 +++++---- .../maa/backend/common/utils/OkHttpUtils.kt | 27 +++-- .../maa/backend/common/utils/SpringUtil.kt | 45 +++++---- .../plus/maa/backend/common/utils/WebUtils.kt | 23 +++-- .../security/AccessDeniedHandlerImpl.kt | 39 ++++---- .../security/AuthenticationEntryPointImpl.kt | 44 +++++---- .../config/security/AuthenticationHelper.kt | 99 +++++++++---------- .../AccessLimitInterceptHandlerImpl.kt | 3 +- .../repository/entity/CollectionMeta.kt | 14 ++- 10 files changed, 201 insertions(+), 206 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/utils/IdComponent.kt b/src/main/java/plus/maa/backend/common/utils/IdComponent.kt index 62a6ccec..c819bebc 100644 --- a/src/main/java/plus/maa/backend/common/utils/IdComponent.kt +++ b/src/main/java/plus/maa/backend/common/utils/IdComponent.kt @@ -1,53 +1,50 @@ -package plus.maa.backend.common.utils; +package plus.maa.backend.common.utils -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Sort; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Query; -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.CollectionMeta; +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.data.domain.Sort +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.core.query.Query +import org.springframework.stereotype.Component +import plus.maa.backend.repository.entity.CollectionMeta +import java.util.* +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.atomic.AtomicLong -import java.util.Map; -import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicLong; -import java.util.function.Function; +private val log = KotlinLogging.logger { } -@Slf4j @Component -@RequiredArgsConstructor -public class IdComponent { - private final MongoTemplate mongoTemplate; - private final Map CURRENT_ID_MAP = new ConcurrentHashMap<>(); +class IdComponent( + private val mongoTemplate: MongoTemplate +) { + private val currentIdMap: MutableMap = ConcurrentHashMap() /** * 获取id数据 * @param meta 集合元数据 * @return 新的id */ - public long getId(CollectionMeta meta) { - Class cls = meta.entityClass(); - String collectionName = mongoTemplate.getCollectionName(cls); - AtomicLong v = CURRENT_ID_MAP.get(collectionName); + fun getId(meta: CollectionMeta): Long { + val cls = meta.entityClass + val collectionName = mongoTemplate.getCollectionName(cls) + var v = currentIdMap[collectionName] if (v == null) { - synchronized (cls) { - v = CURRENT_ID_MAP.get(collectionName); + synchronized(cls) { + v = currentIdMap[collectionName] if (v == null) { - v = new AtomicLong(getMax(cls, meta.idGetter(), meta.incIdField())); - log.info("初始化获取 collection: {} 的最大 id,id: {}", collectionName, v.get()); - CURRENT_ID_MAP.put(collectionName, v); + v = AtomicLong(getMax(cls, meta.idGetter, meta.incIdField)) + log.info { "初始化获取 collection: $collectionName 的最大 id,id: ${v!!.get()}" } + currentIdMap[collectionName] = v!! } } } - return v.incrementAndGet(); + return v!!.incrementAndGet() } - private Long getMax(Class entityClass, Function idGetter, String fieldName) { - return Optional.ofNullable(mongoTemplate.findOne( - new Query().with(Sort.by(fieldName).descending()).limit(1), - entityClass)) - .map(idGetter) - .orElse(20000L); - } + private fun getMax(entityClass: Class, idGetter: (T)->Long, fieldName: String) = + mongoTemplate.findOne( + Query().with(Sort.by(fieldName).descending()).limit(1), + entityClass + ) + ?.let(idGetter) + ?: 20000L } diff --git a/src/main/java/plus/maa/backend/common/utils/IpUtil.kt b/src/main/java/plus/maa/backend/common/utils/IpUtil.kt index fd27df99..d9384dc8 100644 --- a/src/main/java/plus/maa/backend/common/utils/IpUtil.kt +++ b/src/main/java/plus/maa/backend/common/utils/IpUtil.kt @@ -1,48 +1,46 @@ -package plus.maa.backend.common.utils; +package plus.maa.backend.common.utils -import java.net.InetAddress; -import java.net.UnknownHostException; - -import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest +import java.net.InetAddress +import java.net.UnknownHostException /** * @Author leaves * @Date 2023/1/20 14:33 */ -public class IpUtil { +object IpUtil { /** * 获取登录用户IP地址 * * @param request * @return */ - public static String getIpAddr(HttpServletRequest request) { - String ip = request.getHeader("x-forwarded-for"); - if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("Proxy-Client-IP"); + fun getIpAddr(request: HttpServletRequest): String { + var ip = request.getHeader("x-forwarded-for") + if (ip.isNullOrEmpty() || "unknown".equals(ip, ignoreCase = true)) { + ip = request.getHeader("Proxy-Client-IP") } - if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getHeader("WL-Proxy-Client-IP"); + if (ip.isNullOrEmpty()|| "unknown".equals(ip, ignoreCase = true)) { + ip = request.getHeader("WL-Proxy-Client-IP") } - if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { - ip = request.getRemoteAddr(); - if (ip.equals("127.0.0.1")) { + if (ip.isNullOrEmpty()|| "unknown".equals(ip, ignoreCase = true)) { + ip = request.remoteAddr + if (ip == "127.0.0.1") { //根据网卡取本机配置的IP - InetAddress inet = null; + val inet: InetAddress? try { - inet = InetAddress.getLocalHost(); - ip = inet.getHostAddress(); - } catch (UnknownHostException ignored) { + inet = InetAddress.getLocalHost() + ip = inet.hostAddress + } catch (ignored: UnknownHostException) { } } } // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 - if(ip != null && ip.length() > 15){ - if(ip.indexOf(",") > 0){ - ip = ip.substring(0, ip.indexOf(",")); + if (ip != null && ip.length > 15) { + if (ip.indexOf(",") > 0) { + ip = ip.substring(0, ip.indexOf(",")) } } - return ip; + return ip } - } diff --git a/src/main/java/plus/maa/backend/common/utils/OkHttpUtils.kt b/src/main/java/plus/maa/backend/common/utils/OkHttpUtils.kt index 823c2339..225e2627 100644 --- a/src/main/java/plus/maa/backend/common/utils/OkHttpUtils.kt +++ b/src/main/java/plus/maa/backend/common/utils/OkHttpUtils.kt @@ -1,28 +1,27 @@ -package plus.maa.backend.common.utils; +package plus.maa.backend.common.utils -import okhttp3.ConnectionPool; -import okhttp3.OkHttpClient; -import org.springframework.context.annotation.Bean; -import org.springframework.stereotype.Component; - -import java.util.concurrent.TimeUnit; +import okhttp3.ConnectionPool +import okhttp3.OkHttpClient +import org.springframework.context.annotation.Bean +import org.springframework.stereotype.Component +import java.util.concurrent.TimeUnit /** * @author john180 */ @Component -public class OkHttpUtils { +class OkHttpUtils { /** * 缺省 OkHttpClient * * @return OkHttpClient */ @Bean - public OkHttpClient defaultOkHttpClient() { - return new OkHttpClient().newBuilder() - .connectTimeout(5, TimeUnit.SECONDS) - .readTimeout(5, TimeUnit.SECONDS) - .connectionPool(new ConnectionPool(10, 5, TimeUnit.MINUTES)) - .build(); + fun defaultOkHttpClient(): OkHttpClient { + return OkHttpClient().newBuilder() + .connectTimeout(5, TimeUnit.SECONDS) + .readTimeout(5, TimeUnit.SECONDS) + .connectionPool(ConnectionPool(10, 5, TimeUnit.MINUTES)) + .build() } } diff --git a/src/main/java/plus/maa/backend/common/utils/SpringUtil.kt b/src/main/java/plus/maa/backend/common/utils/SpringUtil.kt index a3d3d003..c44933cc 100644 --- a/src/main/java/plus/maa/backend/common/utils/SpringUtil.kt +++ b/src/main/java/plus/maa/backend/common/utils/SpringUtil.kt @@ -1,10 +1,10 @@ -package plus.maa.backend.common.utils; +package plus.maa.backend.common.utils -import org.springframework.beans.BeansException; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.context.annotation.Lazy; -import org.springframework.stereotype.Component; +import org.springframework.beans.BeansException +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware +import org.springframework.context.annotation.Lazy +import org.springframework.stereotype.Component /** * @Author leaves @@ -12,26 +12,29 @@ import org.springframework.stereotype.Component; */ @Component @Lazy(false) -public class SpringUtil implements ApplicationContextAware { - private static ApplicationContext applicationContext = null; - public static ApplicationContext getApplicationContext(){return applicationContext;} - @Override - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { +class SpringUtil : ApplicationContextAware { + @Throws(BeansException::class) + override fun setApplicationContext(applicationContext: ApplicationContext) { // TODO Auto-generated method stub - if(SpringUtil.applicationContext == null){ - SpringUtil.applicationContext = applicationContext; + if (Companion.applicationContext == null) { + Companion.applicationContext = applicationContext } } - public static Object getBean(String name) { - return getApplicationContext().getBean(name); - } + companion object { + var applicationContext: ApplicationContext? = null + private set - public static T getBean(Class clazz) { - return getApplicationContext().getBean(clazz); - } + fun getBean(name: String?): Any { + return applicationContext!!.getBean(name) + } - public static T getBean(String name, Class clazz) { - return getApplicationContext().getBean(name, clazz); + fun getBean(clazz: Class?): T { + return applicationContext!!.getBean(clazz) + } + + fun getBean(name: String?, clazz: Class?): T { + return applicationContext!!.getBean(name, clazz) + } } } diff --git a/src/main/java/plus/maa/backend/common/utils/WebUtils.kt b/src/main/java/plus/maa/backend/common/utils/WebUtils.kt index d66bc5a4..9b818b9c 100644 --- a/src/main/java/plus/maa/backend/common/utils/WebUtils.kt +++ b/src/main/java/plus/maa/backend/common/utils/WebUtils.kt @@ -1,21 +1,20 @@ -package plus.maa.backend.common.utils; +package plus.maa.backend.common.utils -import jakarta.servlet.http.HttpServletResponse; - -import java.io.IOException; +import jakarta.servlet.http.HttpServletResponse +import java.io.IOException /** * @author AnselYuki */ -public class WebUtils { - public static void renderString(HttpServletResponse response, String json, int code) { +object WebUtils { + fun renderString(response: HttpServletResponse, json: String?, code: Int) { try { - response.setStatus(code); - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - response.getWriter().println(json); - } catch (IOException e) { - e.printStackTrace(); + response.status = code + response.contentType = "application/json" + response.characterEncoding = "UTF-8" + response.writer.println(json) + } catch (e: IOException) { + e.printStackTrace() } } } diff --git a/src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt b/src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt index 17782695..2c7966cc 100644 --- a/src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt +++ b/src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt @@ -1,26 +1,29 @@ -package plus.maa.backend.config.security; +package plus.maa.backend.config.security -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.http.HttpStatus; -import org.springframework.security.access.AccessDeniedException; -import org.springframework.security.web.access.AccessDeniedHandler; -import org.springframework.stereotype.Component; -import plus.maa.backend.common.utils.WebUtils; -import plus.maa.backend.controller.response.MaaResult; - -import java.io.IOException; +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.http.HttpStatus +import org.springframework.security.access.AccessDeniedException +import org.springframework.security.web.access.AccessDeniedHandler +import org.springframework.stereotype.Component +import plus.maa.backend.common.utils.WebUtils.renderString +import plus.maa.backend.controller.response.MaaResult.Companion.fail +import java.io.IOException /** * @author AnselYuki */ @Component -public class AccessDeniedHandlerImpl implements AccessDeniedHandler { - @Override - public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException { - var result = MaaResult.fail(HttpStatus.FORBIDDEN.value(), "权限不足"); - String json = new ObjectMapper().writeValueAsString(result); - WebUtils.renderString(response, json, HttpStatus.FORBIDDEN.value()); +class AccessDeniedHandlerImpl : AccessDeniedHandler { + @Throws(IOException::class) + override fun handle( + request: HttpServletRequest, + response: HttpServletResponse, + accessDeniedException: AccessDeniedException + ) { + val result = fail(HttpStatus.FORBIDDEN.value(), "权限不足") + val json = ObjectMapper().writeValueAsString(result) + renderString(response, json, HttpStatus.FORBIDDEN.value()) } } diff --git a/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt b/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt index a973f4f6..0e0b5859 100644 --- a/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt +++ b/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt @@ -1,31 +1,33 @@ -package plus.maa.backend.config.security; +package plus.maa.backend.config.security -import com.fasterxml.jackson.databind.ObjectMapper; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpStatus; -import org.springframework.security.core.AuthenticationException; -import org.springframework.security.web.AuthenticationEntryPoint; -import org.springframework.stereotype.Component; -import plus.maa.backend.common.utils.WebUtils; -import plus.maa.backend.controller.response.MaaResult; - -import java.io.IOException; +import com.fasterxml.jackson.databind.ObjectMapper +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import lombok.RequiredArgsConstructor +import org.springframework.http.HttpStatus +import org.springframework.security.core.AuthenticationException +import org.springframework.security.web.AuthenticationEntryPoint +import org.springframework.stereotype.Component +import plus.maa.backend.common.utils.WebUtils.renderString +import plus.maa.backend.controller.response.MaaResult.Companion.fail +import java.io.IOException /** * @author AnselYuki */ @Component @RequiredArgsConstructor -public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { - - private final ObjectMapper objectMapper; +class AuthenticationEntryPointImpl : AuthenticationEntryPoint { + private val objectMapper: ObjectMapper? = null - @Override - public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { - MaaResult result = MaaResult.fail(HttpStatus.UNAUTHORIZED.value(), authException.getMessage()); - String json = objectMapper.writeValueAsString(result); - WebUtils.renderString(response, json, HttpStatus.UNAUTHORIZED.value()); + @Throws(IOException::class) + override fun commence( + request: HttpServletRequest, + response: HttpServletResponse, + authException: AuthenticationException + ) { + val result = fail(HttpStatus.UNAUTHORIZED.value(), authException.message) + val json = objectMapper!!.writeValueAsString(result) + renderString(response, json, HttpStatus.UNAUTHORIZED.value()) } } diff --git a/src/main/java/plus/maa/backend/config/security/AuthenticationHelper.kt b/src/main/java/plus/maa/backend/config/security/AuthenticationHelper.kt index 2bdb7ebf..2499b96f 100644 --- a/src/main/java/plus/maa/backend/config/security/AuthenticationHelper.kt +++ b/src/main/java/plus/maa/backend/config/security/AuthenticationHelper.kt @@ -1,33 +1,30 @@ -package plus.maa.backend.config.security; +package plus.maa.backend.config.security -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.springframework.http.HttpStatus; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; -import org.springframework.web.server.ResponseStatusException; -import plus.maa.backend.common.utils.IpUtil; -import plus.maa.backend.service.jwt.JwtAuthToken; -import plus.maa.backend.service.model.LoginUser; - -import java.util.Objects; +import org.springframework.http.HttpStatus +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken +import org.springframework.security.core.Authentication +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.stereotype.Component +import org.springframework.web.context.request.RequestContextHolder +import org.springframework.web.context.request.ServletRequestAttributes +import org.springframework.web.server.ResponseStatusException +import plus.maa.backend.common.utils.IpUtil.getIpAddr +import plus.maa.backend.service.jwt.JwtAuthToken +import plus.maa.backend.service.model.LoginUser +import java.util.* /** * Auth 助手,统一 auth 的设置和获取 */ @Component -public class AuthenticationHelper { +class AuthenticationHelper { /** * 设置当前 auth, 是 SecurityContextHolder.getContext().setAuthentication(authentication) 的集中调用 * * @param authentication 当前的 auth */ - public void setAuthentication(Authentication authentication) { - SecurityContextHolder.getContext().setAuthentication(authentication); + fun setAuthentication(authentication: Authentication?) { + SecurityContextHolder.getContext().authentication = authentication } /** @@ -36,41 +33,41 @@ public class AuthenticationHelper { * @return 已经验证的用户 id * @throws ResponseStatusException 用户未通过验证 */ - public @NotNull String requireUserId() throws ResponseStatusException { - var id = getUserId(); - if (id == null) - throw new ResponseStatusException(HttpStatus.UNAUTHORIZED); - return id; + @Throws(ResponseStatusException::class) + fun requireUserId(): String { + val id = userId ?: throw ResponseStatusException(HttpStatus.UNAUTHORIZED) + return id } - /** - * 获取用户 id - * - * @return 用户 id,如未验证则返回 null - */ - public @Nullable String getUserId() { - var auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth == null) return null; - if (auth instanceof UsernamePasswordAuthenticationToken) { - var principal = auth.getPrincipal(); - if (principal instanceof LoginUser) return ((LoginUser) principal).getUserId(); - } else if (auth instanceof JwtAuthToken) { - return ((JwtAuthToken) auth).getSubject(); + val userId: String? + /** + * 获取用户 id + * + * @return 用户 id,如未验证则返回 null + */ + get() { + val auth = SecurityContextHolder.getContext().authentication ?: return null + if (auth is UsernamePasswordAuthenticationToken) { + val principal = auth.getPrincipal() + if (principal is LoginUser) return principal.userId + } else if (auth is JwtAuthToken) { + return auth.subject + } + return null } - return null; - } - /** - * 获取已验证用户 id 或者未验证用户 ip 地址。在 HTTP request 之外调用该方法获取 ip 会抛出 NPE - * - * @return 用户 id 或者 ip 地址 - */ - public @NotNull String getUserIdOrIpAddress() { - var id = getUserId(); - if (id != null) return id; + val userIdOrIpAddress: String + /** + * 获取已验证用户 id 或者未验证用户 ip 地址。在 HTTP request 之外调用该方法获取 ip 会抛出 NPE + * + * @return 用户 id 或者 ip 地址 + */ + get() { + val id = userId + if (id != null) return id - var attributes = Objects.requireNonNull(RequestContextHolder.getRequestAttributes()); - var request = ((ServletRequestAttributes) attributes).getRequest(); - return IpUtil.getIpAddr(request); - } + val attributes = Objects.requireNonNull(RequestContextHolder.getRequestAttributes()) + val request = (attributes as ServletRequestAttributes).request + return getIpAddr(request) + } } diff --git a/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt b/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt index a29f4d03..a0a18e50 100644 --- a/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt +++ b/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt @@ -48,8 +48,7 @@ class AccessLimitInterceptHandlerImpl : HandlerInterceptor { if (!method.isAnnotationPresent(AccessLimit::class.java)) { return true } - val stringRedisTemplate = SpringUtil.getApplicationContext() - .getBean(StringRedisTemplate::class.java) + val stringRedisTemplate = SpringUtil.applicationContext!!.getBean(StringRedisTemplate::class.java) // 获取注解上的内容 val accessLimit = method.getAnnotation(AccessLimit::class.java) ?: return true diff --git a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt index 68736d6a..5f8a706e 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt +++ b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt @@ -1,7 +1,7 @@ -package plus.maa.backend.repository.entity; +package plus.maa.backend.repository.entity -import java.io.Serializable; -import java.util.function.Function; +import java.io.Serializable +import java.util.function.Function /** * mongodb 集合元数据 @@ -9,8 +9,6 @@ import java.util.function.Function; * @param 集合对应实体数据类型 * @author dragove * created on 2023-12-27 - */ -public record CollectionMeta(Function idGetter, String incIdField, Class entityClass) - implements Serializable { - -} + */ +data class CollectionMeta(val idGetter: (T)->Long, val incIdField: String, val entityClass: Class) : + Serializable From 4f3d3cb751db3792598a8efcb49617a279c58b4f Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 11:14:39 +0800 Subject: [PATCH 080/168] Rename .java to .kt --- .../common/annotation/{AccessLimit.java => AccessLimit.kt} | 0 .../common/annotation/{CurrentUser.java => CurrentUser.kt} | 0 .../backend/common/annotation/{JsonSchema.java => JsonSchema.kt} | 0 .../{SensitiveWordDetection.java => SensitiveWordDetection.kt} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/common/annotation/{AccessLimit.java => AccessLimit.kt} (100%) rename src/main/java/plus/maa/backend/common/annotation/{CurrentUser.java => CurrentUser.kt} (100%) rename src/main/java/plus/maa/backend/common/annotation/{JsonSchema.java => JsonSchema.kt} (100%) rename src/main/java/plus/maa/backend/common/annotation/{SensitiveWordDetection.java => SensitiveWordDetection.kt} (100%) diff --git a/src/main/java/plus/maa/backend/common/annotation/AccessLimit.java b/src/main/java/plus/maa/backend/common/annotation/AccessLimit.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/annotation/AccessLimit.java rename to src/main/java/plus/maa/backend/common/annotation/AccessLimit.kt diff --git a/src/main/java/plus/maa/backend/common/annotation/CurrentUser.java b/src/main/java/plus/maa/backend/common/annotation/CurrentUser.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/annotation/CurrentUser.java rename to src/main/java/plus/maa/backend/common/annotation/CurrentUser.kt diff --git a/src/main/java/plus/maa/backend/common/annotation/JsonSchema.java b/src/main/java/plus/maa/backend/common/annotation/JsonSchema.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/annotation/JsonSchema.java rename to src/main/java/plus/maa/backend/common/annotation/JsonSchema.kt diff --git a/src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.java b/src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.java rename to src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.kt From cf90f005c3604104de0b5ad855dc0414726bb573 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 11:14:40 +0800 Subject: [PATCH 081/168] refactor: annotations in kotlin --- .../backend/common/annotation/AccessLimit.kt | 27 ++++++++++++------- .../backend/common/annotation/CurrentUser.kt | 16 ++++------- .../backend/common/annotation/JsonSchema.kt | 17 +++++------- .../annotation/SensitiveWordDetection.kt | 24 ++++++++--------- 4 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/annotation/AccessLimit.kt b/src/main/java/plus/maa/backend/common/annotation/AccessLimit.kt index ba8f7421..b9bcd0b0 100644 --- a/src/main/java/plus/maa/backend/common/annotation/AccessLimit.kt +++ b/src/main/java/plus/maa/backend/common/annotation/AccessLimit.kt @@ -1,22 +1,29 @@ -package plus.maa.backend.common.annotation; +package plus.maa.backend.common.annotation -import java.lang.annotation.*; +import java.lang.annotation.Inherited /** * @author Baip1995 */ @Inherited -@Documented -@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface AccessLimit { +@MustBeDocumented +@Target( + AnnotationTarget.FIELD, + AnnotationTarget.CLASS, + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER +) +@Retention( + AnnotationRetention.RUNTIME +) +annotation class AccessLimit( /** * 指定second 时间内,API最多的请求次数 */ - int times() default 3; - + val times: Int = 3, /** * 指定时间second,redis数据过期时间 */ - int second() default 10; -} + val second: Int = 10 +) diff --git a/src/main/java/plus/maa/backend/common/annotation/CurrentUser.kt b/src/main/java/plus/maa/backend/common/annotation/CurrentUser.kt index 7adaa215..b4aa1a83 100644 --- a/src/main/java/plus/maa/backend/common/annotation/CurrentUser.kt +++ b/src/main/java/plus/maa/backend/common/annotation/CurrentUser.kt @@ -1,17 +1,11 @@ -package plus.maa.backend.common.annotation; +package plus.maa.backend.common.annotation -import org.springframework.security.core.annotation.AuthenticationPrincipal; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import org.springframework.security.core.annotation.AuthenticationPrincipal /** * @author john180 */ -@Target({ElementType.PARAMETER}) -@Retention(RetentionPolicy.RUNTIME) +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.RUNTIME) @AuthenticationPrincipal -public @interface CurrentUser { -} +annotation class CurrentUser diff --git a/src/main/java/plus/maa/backend/common/annotation/JsonSchema.kt b/src/main/java/plus/maa/backend/common/annotation/JsonSchema.kt index 891d2147..7bca737d 100644 --- a/src/main/java/plus/maa/backend/common/annotation/JsonSchema.kt +++ b/src/main/java/plus/maa/backend/common/annotation/JsonSchema.kt @@ -1,16 +1,11 @@ -package plus.maa.backend.common.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +package plus.maa.backend.common.annotation /** * @author LoMu * Date 2023-01-22 17:49 */ - -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) -public @interface JsonSchema { -} +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) +@Retention( + AnnotationRetention.RUNTIME +) +annotation class JsonSchema diff --git a/src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.kt b/src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.kt index 7999de92..78de8081 100644 --- a/src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.kt +++ b/src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.kt @@ -1,23 +1,21 @@ -package plus.maa.backend.common.annotation; - -import java.lang.annotation.*; +package plus.maa.backend.common.annotation /** - * 敏感词检测注解
- * 用于方法上,标注该方法需要进行敏感词检测
+ * 敏感词检测注解

+ * 用于方法上,标注该方法需要进行敏感词检测

* 通过 SpEL 表达式获取方法参数 * * @author lixuhuilll * Date: 2023-08-25 18:50 */ - -@Documented -@Target(ElementType.METHOD) -@Retention(RetentionPolicy.RUNTIME) -public @interface SensitiveWordDetection { - +@MustBeDocumented +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) +@Retention( + AnnotationRetention.RUNTIME +) +annotation class SensitiveWordDetection( /** * SpEL 表达式 */ - String[] value() default {}; -} + vararg val value: String = [] +) From 4fd657adb10d4cfc68efef6085bff9d3f0fb81db Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 11:34:55 +0800 Subject: [PATCH 082/168] Rename .java to .kt --- .../{CopilotQueriesRequest.java => CopilotQueriesRequest.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/request/copilot/{CopilotQueriesRequest.java => CopilotQueriesRequest.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.java b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.java rename to src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt From b6a1d5b50637689109ee8b6bddadd2d6425c56a5 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 11:34:56 +0800 Subject: [PATCH 083/168] perf: use kotlin functions instead of java counterparts --- .../request/copilot/CopilotQueriesRequest.kt | 68 +++++++++---------- .../maa/backend/service/CopilotService.kt | 52 ++++++-------- 2 files changed, 53 insertions(+), 67 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt index 1ec5133c..85267ac8 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt +++ b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt @@ -1,33 +1,28 @@ -package plus.maa.backend.controller.request.copilot; +package plus.maa.backend.controller.request.copilot -import com.fasterxml.jackson.annotation.JsonIgnore; -import jakarta.validation.constraints.Max; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore +import jakarta.validation.constraints.Max +import lombok.AllArgsConstructor +import lombok.Data +import lombok.NoArgsConstructor /** * @author LoMu * Date 2022-12-26 2:48 */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CopilotQueriesRequest { - private int page = 0; - @Max(value = 50, message = "单页大小不得超过50") - private int limit = 10; - private String levelKeyword; - private String operator; - private String content; - private String document; - private String uploaderId; - private boolean desc = true; - private String orderBy; - private String language; - private List copilotIds; +data class CopilotQueriesRequest( + val page: Int = 0, + val limit: @Max(value = 50, message = "单页大小不得超过50") Int = 10, + var levelKeyword: String? = null, + val operator: String? = null, + val content: String? = null, + val document: String? = null, + var uploaderId: String? = null, + val desc: Boolean = true, + var orderBy: String? = null, + val language: String? = null, + var copilotIds: List? = null +) { /* * 这里为了正确接收前端的下划线风格,手动写了三个 setter 用于起别名 @@ -36,27 +31,26 @@ public class CopilotQueriesRequest { * (吐槽一下,同样是Get请求,怎么CommentsQueries是驼峰命名,到了CopilotQueries就成了下划线命名) */ @JsonIgnore - @SuppressWarnings("unused") - public void setLevel_keyword(String levelKeyword) { - this.levelKeyword = levelKeyword; + @Suppress("unused") + fun setLevel_keyword(levelKeyword: String?) { + this.levelKeyword = levelKeyword } @JsonIgnore - @SuppressWarnings("unused") - public void setUploader_id(String uploaderId) { - this.uploaderId = uploaderId; + @Suppress("unused") + fun setUploader_id(uploaderId: String?) { + this.uploaderId = uploaderId } @JsonIgnore - @SuppressWarnings("unused") - public void setOrder_by(String orderBy) { - this.orderBy = orderBy; + @Suppress("unused") + fun setOrder_by(orderBy: String?) { + this.orderBy = orderBy } @JsonIgnore - @SuppressWarnings("unused") - public void setCopilot_ids(List copilotIds) { - this.copilotIds = copilotIds; + @Suppress("unused") + fun setCopilot_ids(copilotIds: List?) { + this.copilotIds = copilotIds } - } diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/java/plus/maa/backend/service/CopilotService.kt index 2d148d10..a742aca4 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotService.kt @@ -1,6 +1,5 @@ package plus.maa.backend.service -import cn.hutool.core.collection.CollectionUtil import com.fasterxml.jackson.core.JsonProcessingException import com.fasterxml.jackson.databind.ObjectMapper import com.google.common.collect.Sets @@ -224,35 +223,27 @@ class CopilotService( val setKey = AtomicReference() // 只缓存默认状态下热度和访问量排序的结果,并且最多只缓存前三页 if (request.page <= 3 && request.document == null && request.levelKeyword == null && request.uploaderId == null && request.operator == null && - CollectionUtil.isEmpty(request.copilotIds) + request.copilotIds.isNullOrEmpty() ) { - val cacheOptional = Optional.ofNullable(request.orderBy) - .filter { cs: String? -> StringUtils.isNotBlank(cs) } - .map { key: String? -> HOME_PAGE_CACHE_CONFIG[key] } - .map { t: Long? -> - cacheTimeout.set(t!!) + request.orderBy?.takeIf { orderBy -> orderBy.isNotBlank() } + ?.let { key -> HOME_PAGE_CACHE_CONFIG[key] } + ?.let { t -> + cacheTimeout.set(t) setKey.set(String.format("home:%s:copilotIds", request.orderBy)) cacheKey.set(String.format("home:%s:%s", request.orderBy, request.hashCode())) redisCache.getCache(cacheKey.get(), CopilotPageInfo::class.java) - } - - // 如果缓存存在则直接返回 - if (cacheOptional.isPresent) { - return cacheOptional.get() - } + }?.let { return it } } val sortOrder = Sort.Order( - if (request.isDesc) Sort.Direction.DESC else Sort.Direction.ASC, - Optional.ofNullable(request.orderBy) - .filter { cs: String? -> StringUtils.isNotBlank(cs) } - .map { ob: String? -> - when (ob) { - "hot" -> "hotScore" - "id" -> "copilotId" - else -> request.orderBy - } - }.orElse("copilotId") + if (request.desc) Sort.Direction.DESC else Sort.Direction.ASC, + request.orderBy?.takeIf { orderBy -> orderBy.isNotBlank() }?.let { ob -> + when (ob) { + "hot" -> "hotScore" + "id" -> "copilotId" + else -> request.orderBy + } + }?: "copilotId" ) // 判断是否有值 无值则为默认 val page = if (request.page > 0) request.page else 1 @@ -271,10 +262,11 @@ class CopilotService( //关卡名、关卡类型、关卡编号 - if (StringUtils.isNotBlank(request.levelKeyword)) { - val levelInfo = levelService.queryLevelInfosByKeyword(request.levelKeyword) + if (!request.levelKeyword.isNullOrBlank()) { + val keyword = request.levelKeyword!! + val levelInfo = levelService.queryLevelInfosByKeyword(keyword) if (levelInfo.isEmpty()) { - andQueries.add(Criteria.where("stageName").regex(caseInsensitive(request.levelKeyword))) + andQueries.add(Criteria.where("stageName").regex(caseInsensitive(keyword))) } else { andQueries.add( Criteria.where("stageName").`in`( @@ -285,12 +277,12 @@ class CopilotService( } // 作业id列表 - if (CollectionUtil.isNotEmpty(request.copilotIds)) { - andQueries.add(Criteria.where("copilotId").`in`(request.copilotIds)) + if (!request.copilotIds.isNullOrEmpty()) { + andQueries.add(Criteria.where("copilotId").`in`(request.copilotIds!!)) } //标题、描述、神秘代码 - if (StringUtils.isNotBlank(request.document)) { + if (!request.document.isNullOrBlank()) { orQueries.add(Criteria.where("doc.title").regex(caseInsensitive(request.document))) orQueries.add(Criteria.where("doc.details").regex(caseInsensitive(request.document))) } @@ -298,7 +290,7 @@ class CopilotService( //包含或排除干员 var oper = request.operator - if (StringUtils.isNotBlank(oper)) { + if (!oper.isNullOrBlank()) { oper = oper.replace("[“\"”]".toRegex(), "") val operators = oper.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() for (operator in operators) { From c89a74b65060d4f8d556d32c7a1497e58d2a39c7 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 11:42:35 +0800 Subject: [PATCH 084/168] perf: remove usage of Consumer --- .../controller/request/copilot/CopilotQueriesRequest.kt | 3 --- .../maa/backend/service/session/UserSessionService.kt | 9 ++++----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt index 85267ac8..1062d48e 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt +++ b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt @@ -2,9 +2,6 @@ package plus.maa.backend.controller.request.copilot import com.fasterxml.jackson.annotation.JsonIgnore import jakarta.validation.constraints.Max -import lombok.AllArgsConstructor -import lombok.Data -import lombok.NoArgsConstructor /** * @author LoMu diff --git a/src/main/java/plus/maa/backend/service/session/UserSessionService.kt b/src/main/java/plus/maa/backend/service/session/UserSessionService.kt index 2ee74ab7..93edb82d 100644 --- a/src/main/java/plus/maa/backend/service/session/UserSessionService.kt +++ b/src/main/java/plus/maa/backend/service/session/UserSessionService.kt @@ -3,7 +3,6 @@ package plus.maa.backend.service.session import org.springframework.stereotype.Service import plus.maa.backend.config.external.MaaCopilotProperties import plus.maa.backend.repository.RedisCache -import java.util.function.Consumer @Service class UserSessionService(private val cache: RedisCache, properties: MaaCopilotProperties) { @@ -17,15 +16,15 @@ class UserSessionService(private val cache: RedisCache, properties: MaaCopilotPr cache.setCache(buildUserCacheKey(id), session, sessionExpiration) } - fun setSession(id: String, consumer: Consumer) { + fun setSession(id: String, consumer: (UserSession) -> Unit) { val session = UserSession() - consumer.accept(session) + consumer(session) cache.setCache(buildUserCacheKey(id), session, sessionExpiration) } - fun updateSessionIfPresent(id: String, consumer: Consumer) { + fun updateSessionIfPresent(id: String, consumer: (UserSession) -> Unit){ cache.updateCache(id, UserSession::class.java, null, { session: UserSession? -> - if (session != null) consumer.accept(session) + if (session != null) consumer(session) session }, sessionExpiration) } From bbff88540260028c25b38e666d85a0f1a9b5b42d Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Wed, 7 Feb 2024 19:02:03 +0800 Subject: [PATCH 085/168] fix: remove lombok annotation --- .../backend/config/security/AuthenticationEntryPointImpl.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt b/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt index 0e0b5859..5f13379e 100644 --- a/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt +++ b/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt @@ -16,9 +16,9 @@ import java.io.IOException * @author AnselYuki */ @Component -@RequiredArgsConstructor -class AuthenticationEntryPointImpl : AuthenticationEntryPoint { - private val objectMapper: ObjectMapper? = null +class AuthenticationEntryPointImpl( + private val objectMapper: ObjectMapper +) : AuthenticationEntryPoint { @Throws(IOException::class) override fun commence( From 10e10ce8f93013b05d3f34afa7ce51e1bbb9f05e Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 07:47:09 +0800 Subject: [PATCH 086/168] Rename .java to .kt --- .../backend/common/aop/{JsonSchemaAop.java => JsonSchemaAop.kt} | 0 .../common/aop/{SensitiveWordAop.java => SensitiveWordAop.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/common/aop/{JsonSchemaAop.java => JsonSchemaAop.kt} (100%) rename src/main/java/plus/maa/backend/common/aop/{SensitiveWordAop.java => SensitiveWordAop.kt} (100%) diff --git a/src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.java b/src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.java rename to src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.kt diff --git a/src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.java b/src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.java rename to src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.kt From abd621da453072a6aa0ff0e658070778d8bb531f Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 07:47:09 +0800 Subject: [PATCH 087/168] refactor: aop in kotlin --- .../maa/backend/common/aop/JsonSchemaAop.kt | 114 +++++++++--------- .../backend/common/aop/SensitiveWordAop.kt | 97 +++++++-------- 2 files changed, 97 insertions(+), 114 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.kt b/src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.kt index 60cbfcbb..8782a51c 100644 --- a/src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.kt +++ b/src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.kt @@ -1,48 +1,39 @@ -package plus.maa.backend.common.aop; +package plus.maa.backend.common.aop +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.ObjectMapper +import io.github.oshai.kotlinlogging.KotlinLogging +import org.aspectj.lang.JoinPoint +import org.aspectj.lang.annotation.Aspect +import org.aspectj.lang.annotation.Before +import org.aspectj.lang.annotation.Pointcut +import org.everit.json.schema.ValidationException +import org.everit.json.schema.loader.SchemaLoader +import org.json.JSONObject +import org.json.JSONTokener +import org.springframework.core.io.ClassPathResource +import org.springframework.http.HttpStatus +import org.springframework.stereotype.Component +import plus.maa.backend.common.annotation.JsonSchema +import plus.maa.backend.controller.request.comments.CommentsRatingDTO +import plus.maa.backend.controller.request.copilot.CopilotCUDRequest +import plus.maa.backend.controller.request.copilot.CopilotRatingReq +import plus.maa.backend.controller.response.MaaResultException +import java.io.IOException -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.aspectj.lang.annotation.Pointcut; -import org.everit.json.schema.Schema; -import org.everit.json.schema.ValidationException; -import org.everit.json.schema.loader.SchemaLoader; -import org.json.JSONObject; -import org.json.JSONTokener; -import org.springframework.core.io.ClassPathResource; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; -import plus.maa.backend.common.annotation.JsonSchema; -import plus.maa.backend.controller.request.comments.CommentsRatingDTO; -import plus.maa.backend.controller.request.copilot.CopilotCUDRequest; -import plus.maa.backend.controller.request.copilot.CopilotRatingReq; -import plus.maa.backend.controller.response.MaaResultException; - -import java.io.IOException; -import java.io.InputStream; - +private val log = KotlinLogging.logger { } /** * @author LoMu * Date 2023-01-22 17:53 */ - @Component @Aspect -@Slf4j -@RequiredArgsConstructor -public class JsonSchemaAop { - private final ObjectMapper mapper; - private static final String COPILOT_SCHEMA_JSON = "static/templates/maa-copilot-schema.json"; - private static final String RATING_SCHEMA_JSON = "static/templates/maa-rating-schema.json"; - +class JsonSchemaAop( + private val mapper: ObjectMapper +) { @Pointcut("@annotation(plus.maa.backend.common.annotation.JsonSchema)") - public void pt() { + fun pt() { } /** @@ -52,38 +43,45 @@ public class JsonSchemaAop { * @param jsonSchema 注解 */ @Before("pt() && @annotation(jsonSchema)") - public void before(JoinPoint joinPoint, JsonSchema jsonSchema) { - String schema_json = null; - String content = null; + fun before(joinPoint: JoinPoint, jsonSchema: JsonSchema?) { + var schemaJson: String? = null + var content: String? = null //判断是验证的是Copilot还是Rating - for (Object arg : joinPoint.getArgs()) { - if (arg instanceof CopilotCUDRequest) { - content = ((CopilotCUDRequest) arg).getContent(); - schema_json = COPILOT_SCHEMA_JSON; + for (arg in joinPoint.args) { + if (arg is CopilotCUDRequest) { + content = arg.content + schemaJson = COPILOT_SCHEMA_JSON } - if (arg instanceof CopilotRatingReq || arg instanceof CommentsRatingDTO) { + if (arg is CopilotRatingReq || arg is CommentsRatingDTO) { try { - schema_json = RATING_SCHEMA_JSON; - content = mapper.writeValueAsString(arg); - } catch (JsonProcessingException e) { - log.error("json解析失败", e); + schemaJson = RATING_SCHEMA_JSON + content = mapper.writeValueAsString(arg) + } catch (e: JsonProcessingException) { + log.error(e) { "json解析失败" } } } } - if (content == null) return; + if (content == null) return //获取json schema json路径并验证 - try (InputStream inputStream = new ClassPathResource(schema_json).getInputStream()) { - JSONObject json = new JSONObject(content); - JSONObject jsonObject = new JSONObject(new JSONTokener(inputStream)); - Schema schema = SchemaLoader.load(jsonObject); - schema.validate(json); - } catch (IOException e) { - throw new RuntimeException(e); - } catch (ValidationException e) { - log.warn("schema Location: {}", e.getViolatedSchema().getSchemaLocation()); - throw new MaaResultException(HttpStatus.BAD_REQUEST.value(), "数据不符合规范,请前往前端作业编辑器进行操作"); + try { + ClassPathResource(schemaJson!!).inputStream.use { inputStream -> + val json = JSONObject(content) + val jsonObject = JSONObject(JSONTokener(inputStream)) + val schema = SchemaLoader.load(jsonObject) + schema.validate(json) + } + } catch (e: IOException) { + throw RuntimeException(e) + } catch (e: ValidationException) { + log.warn { "schema Location: ${e.violatedSchema.schemaLocation}" } + throw MaaResultException(HttpStatus.BAD_REQUEST.value(), "数据不符合规范,请前往前端作业编辑器进行操作") } } + + companion object { + private const val COPILOT_SCHEMA_JSON = "static/templates/maa-copilot-schema.json" + private const val RATING_SCHEMA_JSON = "static/templates/maa-rating-schema.json" + } } \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.kt b/src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.kt index ece2a309..e95eed9d 100644 --- a/src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.kt +++ b/src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.kt @@ -1,89 +1,74 @@ -package plus.maa.backend.common.aop; +package plus.maa.backend.common.aop -import cn.hutool.dfa.WordTree; -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.aspectj.lang.JoinPoint; -import org.aspectj.lang.Signature; -import org.aspectj.lang.annotation.Aspect; -import org.aspectj.lang.annotation.Before; -import org.aspectj.lang.reflect.MethodSignature; -import org.jetbrains.annotations.Nullable; -import org.springframework.core.DefaultParameterNameDiscoverer; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.Expression; -import org.springframework.expression.spel.standard.SpelExpressionParser; -import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; -import plus.maa.backend.common.annotation.SensitiveWordDetection; -import plus.maa.backend.controller.response.MaaResultException; - -import java.util.List; +import cn.hutool.dfa.WordTree +import com.fasterxml.jackson.databind.ObjectMapper +import org.aspectj.lang.JoinPoint +import org.aspectj.lang.annotation.Aspect +import org.aspectj.lang.annotation.Before +import org.aspectj.lang.reflect.MethodSignature +import org.springframework.core.DefaultParameterNameDiscoverer +import org.springframework.expression.EvaluationContext +import org.springframework.expression.spel.standard.SpelExpressionParser +import org.springframework.expression.spel.support.StandardEvaluationContext +import org.springframework.http.HttpStatus +import org.springframework.stereotype.Component +import plus.maa.backend.common.annotation.SensitiveWordDetection +import plus.maa.backend.controller.response.MaaResultException /** - * 敏感词处理程序
+ * 敏感词处理程序

* * @author lixuhuilll * Date: 2023-08-25 18:50 */ - -@Slf4j @Aspect @Component -@RequiredArgsConstructor -public class SensitiveWordAop { - +class SensitiveWordAop( // 敏感词库 - private final WordTree wordTree; - - private final ObjectMapper objectMapper; + private val wordTree: WordTree, + private val objectMapper: ObjectMapper +) { // SpEL 表达式解析器 - private final SpelExpressionParser parser = new SpelExpressionParser(); + private val parser = SpelExpressionParser() // 用于获取方法参数名 - private final DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer(); + private val nameDiscoverer = DefaultParameterNameDiscoverer() - @Nullable - public Object getObjectBySpEL(String spELString, JoinPoint joinPoint) { + fun getObjectBySpEL(spELString: String, joinPoint: JoinPoint): Any? { // 获取被注解方法 - Signature signature = joinPoint.getSignature(); - if (!(signature instanceof MethodSignature methodSignature)) { - return null; - } + val signature = joinPoint.signature as? MethodSignature ?: return null // 获取方法参数名数组 - String[] paramNames = nameDiscoverer.getParameterNames(methodSignature.getMethod()); + val paramNames = nameDiscoverer.getParameterNames(signature.method) // 解析 Spring 表达式对象 - Expression expression = parser.parseExpression(spELString); + val expression = parser.parseExpression(spELString) // Spring 表达式上下文对象 - EvaluationContext context = new StandardEvaluationContext(); + val context: EvaluationContext = StandardEvaluationContext() // 通过 joinPoint 获取被注解方法的参数 - Object[] args = joinPoint.getArgs(); + val args = joinPoint.args // 给上下文赋值 - for (int i = 0; i < args.length; i++) { + for (i in args.indices) { if (paramNames != null) { - context.setVariable(paramNames[i], args[i]); + context.setVariable(paramNames[i], args[i]) } } - context.setVariable("objectMapper", objectMapper); + context.setVariable("objectMapper", objectMapper) // 表达式从上下文中计算出实际参数值 - return expression.getValue(context); + return expression.getValue(context) } - @Before("@annotation(annotation)") // 处理 SensitiveWordDetection 注解 - public void before(JoinPoint joinPoint, SensitiveWordDetection annotation) { + @Before("@annotation(annotation)") // 处理 SensitiveWordDetection 注解 + fun before(joinPoint: JoinPoint, annotation: SensitiveWordDetection) { // 获取 SpEL 表达式 - String[] expressions = annotation.value(); - for (String expression : expressions) { + val expressions = annotation.value + for (expression in expressions) { // 解析 SpEL 表达式 - Object value = getObjectBySpEL(expression, joinPoint); + val value = getObjectBySpEL(expression, joinPoint) // 校验 - if (value instanceof String text) { - List matchAll = wordTree.matchAll(text); - if (matchAll != null && !matchAll.isEmpty()) { - throw new MaaResultException(HttpStatus.BAD_REQUEST.value(), "包含敏感词:" + matchAll); + if (value is String) { + val matchAll = wordTree.matchAll(value) + if (matchAll != null && matchAll.isNotEmpty()) { + throw MaaResultException(HttpStatus.BAD_REQUEST.value(), "包含敏感词:$matchAll") } } } From 4e74f275cf054411fce66682592bdc1ec87601d9 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 08:00:40 +0800 Subject: [PATCH 088/168] Rename .java to .kt --- .../bo/{EmailBusinessObject.java => EmailBusinessObject.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/common/bo/{EmailBusinessObject.java => EmailBusinessObject.kt} (100%) diff --git a/src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.java b/src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.java rename to src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.kt From 91a9345e99a5c8786cc587ca6cb113bef3d1e58e Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 08:00:40 +0800 Subject: [PATCH 089/168] refactor: EmailBusinessObject in kotlin --- .../backend/common/bo/EmailBusinessObject.kt | 189 ++++++++---------- .../plus/maa/backend/service/EmailService.kt | 25 +-- 2 files changed, 98 insertions(+), 116 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.kt b/src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.kt index 53094885..87c1c259 100644 --- a/src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.kt +++ b/src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.kt @@ -1,74 +1,39 @@ -package plus.maa.backend.common.bo; +package plus.maa.backend.common.bo +import cn.hutool.extra.mail.MailAccount +import cn.hutool.extra.mail.MailUtil +import io.github.oshai.kotlinlogging.KotlinLogging +import plus.maa.backend.common.utils.FreeMarkerUtils +import java.io.File +import kotlin.collections.ArrayList +import kotlin.collections.Collection +import kotlin.collections.MutableList +import kotlin.collections.MutableMap +import kotlin.collections.set -import cn.hutool.extra.mail.MailAccount; -import cn.hutool.extra.mail.MailUtil; -import lombok.NoArgsConstructor; -import lombok.Setter; -import lombok.experimental.Accessors; -import lombok.extern.slf4j.Slf4j; -import plus.maa.backend.common.utils.FreeMarkerUtils; - -import java.io.File; -import java.util.*; - +private val log = KotlinLogging.logger { } /** * @author LoMu * Date 2022-12-23 23:57 */ -@Slf4j -@Accessors(chain = true) -@Setter -@NoArgsConstructor -public class EmailBusinessObject { - - // 默认邮件模板 - private static final String DEFAULT_MAIL_TEMPLATE = "mail.ftlh"; - - - private static final String DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE = "mail-includeHtml.ftlh"; - - private static final String DEFAULT_TITLE_PREFIX = "Maa Backend Center"; - - //发件人信息 - private MailAccount mailAccount; - - private List emailList = new ArrayList<>(); - +class EmailBusinessObject( + // 发件人信息 + private val mailAccount: MailAccount, // 自定义标题 - private String title = DEFAULT_TITLE_PREFIX; - + private val title: String = DEFAULT_TITLE_PREFIX, // 邮件内容 - private String message; - + private val message: String? = null, // html标签是否被识别使用 - private Boolean isHtml = true; + private val isHtml: Boolean = true, +) { - /** - * 静态创建工厂 - * - * @return EmailBusinessObject - */ - public static EmailBusinessObject builder() { - return new EmailBusinessObject(); - } - - - public EmailBusinessObject setEmail(String email) { - emailList.add(email); - return this; - } + private val emailList: MutableList = ArrayList() - /** - * 设置邮件标题 默认为 Maa Backend Center - * - * @param title 标题 - */ - public EmailBusinessObject setTitle(String title) { - this.title = title; - return this; + fun setEmail(email: String): EmailBusinessObject { + emailList.add(email) + return this } /** @@ -77,15 +42,15 @@ public class EmailBusinessObject { * @param content 邮件动态内容 * @param templateName ftlh名称,例如 mail.ftlh */ - public void sendCustomStaticTemplates(String content, String templateName) { - sendCustomStaticTemplatesFiles(content, templateName, (File[]) null); + fun sendCustomStaticTemplates(content: String?, templateName: String?) { + sendCustomStaticTemplatesFiles(content, templateName) } /** * 通过默认模板发送自定义Message内容 */ - public void sendCustomMessage() { - sendCustomStaticTemplates(message, DEFAULT_MAIL_TEMPLATE); + fun sendCustomMessage() { + sendCustomStaticTemplates(message, DEFAULT_MAIL_TEMPLATE) } /** @@ -93,8 +58,8 @@ public class EmailBusinessObject { * * @param files 附件 */ - public void sendCustomMessageFiles(File... files) { - sendCustomStaticTemplatesFiles(message, DEFAULT_MAIL_TEMPLATE, files); + fun sendCustomMessageFiles(vararg files: File?) { + sendCustomStaticTemplatesFiles(message, DEFAULT_MAIL_TEMPLATE, *files) } @@ -105,12 +70,14 @@ public class EmailBusinessObject { * @param templateName ftl路径 * @param files 附件 */ - public void sendCustomStaticTemplatesFiles(String content, String templateName, File... files) { + fun sendCustomStaticTemplatesFiles(content: String?, templateName: String?, vararg files: File?) { try { - log.info("send email to: {}, templateName: {}, content: {}", emailList, templateName, content); - send(this.mailAccount, emailList, title, parseMessages(content, templateName), isHtml, files); - } catch (Exception ex) { - throw new RuntimeException(ex); + log.info { + "send email to: $emailList, templateName: $templateName, content: $content" + } + send(this.mailAccount, emailList, title, parseMessages(content, templateName), isHtml, *files) + } catch (ex: Exception) { + throw RuntimeException(ex) } } @@ -118,40 +85,41 @@ public class EmailBusinessObject { /** * 发送验证码 */ - public void sendVerificationCodeMessage(String code) { - + fun sendVerificationCodeMessage(code: String) { try { - send(this.mailAccount, this.emailList - , this.title + " 验证码" - , defaultMailIncludeHtmlTemplates( - "mail-vCode.ftlh", code - ) - , this.isHtml - ); - } catch (Exception ex) { - throw new RuntimeException("邮件发送失败", ex); + send( + this.mailAccount, this.emailList, + this.title + " 验证码", + defaultMailIncludeHtmlTemplates( + "mail-vCode.ftlh", code + ), + this.isHtml + ) + } catch (ex: Exception) { + throw RuntimeException("邮件发送失败", ex) } } - public void sendCommentNotification(Map map) { + fun sendCommentNotification(map: MutableMap) { try { - send(this.mailAccount, - this.emailList, - this.title, - defaultMailIncludeHtmlTemplates("mail-comment-notification.ftlh", map), - this.isHtml - ); - } catch (Exception ex) { - throw new RuntimeException("邮件发送失败", ex); + send( + this.mailAccount, + this.emailList, + this.title, + defaultMailIncludeHtmlTemplates("mail-comment-notification.ftlh", map), + this.isHtml + ) + } catch (ex: Exception) { + throw RuntimeException("邮件发送失败", ex) } } - private String defaultMailIncludeHtmlTemplates(String content, String obj) { - return parseMessages(content, obj, DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE); + private fun defaultMailIncludeHtmlTemplates(content: String, obj: String): String { + return parseMessages(content, obj, DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE) } - private String defaultMailIncludeHtmlTemplates(String content, Map map) { - return parseMessages(content, DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE, map); + private fun defaultMailIncludeHtmlTemplates(content: String, map: MutableMap): String { + return parseMessages(content, DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE, map) } @@ -160,8 +128,8 @@ public class EmailBusinessObject { * @param templateName ftlh路径 * @return String */ - private String parseMessages(String content, String templateName) { - return FreeMarkerUtils.parseData(Collections.singletonMap("content", content), templateName); + private fun parseMessages(content: String?, templateName: String?): String { + return FreeMarkerUtils.parseData(mapOf("content" to content), templateName) } /** @@ -170,13 +138,13 @@ public class EmailBusinessObject { * @param content 邮件内嵌ftlh路径 * @return String */ - private String parseMessages(String content, String templateName, Map map) { - map.put("content", content); - return FreeMarkerUtils.parseData(map, templateName); + private fun parseMessages(content: String, templateName: String, map: MutableMap): String { + map["content"] = content + return FreeMarkerUtils.parseData(map, templateName) } - private String parseMessages(String content, String obj, String templateName) { - return FreeMarkerUtils.parseData(Map.of("content", content, "obj", obj), templateName); + private fun parseMessages(content: String, obj: String, templateName: String): String { + return FreeMarkerUtils.parseData(mapOf("content" to content, "obj" to obj), templateName) } @@ -190,7 +158,24 @@ public class EmailBusinessObject { * @param isHtml 是否为HTML格式 * @param files 附件列表 */ - private void send(MailAccount mailAccount, Collection tos, String subject, String content, boolean isHtml, File... files) { - MailUtil.send(mailAccount, tos, null, null, subject, content, null, isHtml, files); + private fun send( + mailAccount: MailAccount?, + tos: Collection, + subject: String, + content: String, + isHtml: Boolean, + vararg files: File? + ) { + MailUtil.send(mailAccount, tos, null, null, subject, content, null, isHtml, *files) + } + + companion object { + // 默认邮件模板 + private const val DEFAULT_MAIL_TEMPLATE = "mail.ftlh" + + + private const val DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE = "mail-includeHtml.ftlh" + + private const val DEFAULT_TITLE_PREFIX = "Maa Backend Center" } } diff --git a/src/main/java/plus/maa/backend/service/EmailService.kt b/src/main/java/plus/maa/backend/service/EmailService.kt index 69e9f6dd..e7d179cb 100644 --- a/src/main/java/plus/maa/backend/service/EmailService.kt +++ b/src/main/java/plus/maa/backend/service/EmailService.kt @@ -17,7 +17,7 @@ import plus.maa.backend.repository.RedisCache import plus.maa.backend.service.model.CommentNotification import java.util.* -private val log = KotlinLogging.logger { } +private val log = KotlinLogging.logger { } /** * @author LoMu @@ -26,12 +26,12 @@ private val log = KotlinLogging.logger { } @Service class EmailService( @Value("\${maa-copilot.vcode.expire:600}") - private val expire:Int, + private val expire: Int, @Value("\${maa-copilot.info.domain}") private val domain: String, private val maaCopilotProperties: MaaCopilotProperties, @Value("\${debug.email.no-send:false}") - private val flagNoSend:Boolean = false, + private val flagNoSend: Boolean = false, private val redisCache: RedisCache, @Resource(name = "emailTaskExecutor") private val emailTaskExecutor: AsyncTaskExecutor @@ -40,7 +40,6 @@ class EmailService( private val mainAccount = MailAccount() - /** * 初始化邮件账户信息 */ @@ -85,10 +84,9 @@ class EmailService( log.debug { "vcode is $vcode" } log.warn { "Email not sent, no-send enabled" } } else { - EmailBusinessObject.builder() - .setMailAccount(mainAccount) - .setEmail(email) - .sendVerificationCodeMessage(vcode) + EmailBusinessObject( + mailAccount = mainAccount + ).setEmail(email).sendVerificationCodeMessage(vcode) } // 存redis redisCache.setCache("vCodeEmail:$email", vcode, expire.toLong()) @@ -108,7 +106,7 @@ class EmailService( } @Async("emailTaskExecutor") - fun sendCommentNotification(email: String?, commentNotification: CommentNotification) { + fun sendCommentNotification(email: String, commentNotification: CommentNotification) { val limit = 25 var title = commentNotification.title @@ -125,10 +123,9 @@ class EmailService( map["date"] = commentNotification.date map["title"] = title map["reMessage"] = commentNotification.reMessage - EmailBusinessObject.builder() - .setTitle("收到新回复 来自用户@" + commentNotification.reName + " Re: " + map["title"]) - .setMailAccount(mainAccount) - .setEmail(email) - .sendCommentNotification(map) + EmailBusinessObject( + mailAccount = mainAccount, + title = "收到新回复 来自用户@" + commentNotification.reName + " Re: " + map["title"] + ).setEmail(email).sendCommentNotification(map) } } From ddafd7c9d4c5d75af5db1652255e22284d6a864a Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 08:10:10 +0800 Subject: [PATCH 090/168] Rename .java to .kt --- .../converter/{ArkLevelConverter.java => ArkLevelConverter.kt} | 0 .../converter/{CommentConverter.java => CommentConverter.kt} | 0 .../converter/{CopilotConverter.java => CopilotConverter.kt} | 0 .../{CopilotSetConverter.java => CopilotSetConverter.kt} | 0 .../converter/{MaaUserConverter.java => MaaUserConverter.kt} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/common/utils/converter/{ArkLevelConverter.java => ArkLevelConverter.kt} (100%) rename src/main/java/plus/maa/backend/common/utils/converter/{CommentConverter.java => CommentConverter.kt} (100%) rename src/main/java/plus/maa/backend/common/utils/converter/{CopilotConverter.java => CopilotConverter.kt} (100%) rename src/main/java/plus/maa/backend/common/utils/converter/{CopilotSetConverter.java => CopilotSetConverter.kt} (100%) rename src/main/java/plus/maa/backend/common/utils/converter/{MaaUserConverter.java => MaaUserConverter.kt} (100%) diff --git a/src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.java rename to src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.java rename to src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.java rename to src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.java rename to src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.java b/src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.java rename to src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.kt From c80e3ed7d66d0e7e5cdc88a409f291123b508a44 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 08:10:10 +0800 Subject: [PATCH 091/168] refactor: converters in kotlin --- .../utils/converter/ArkLevelConverter.kt | 19 ++++------- .../utils/converter/CommentConverter.kt | 22 ++++++------ .../utils/converter/CopilotConverter.kt | 30 ++++++++-------- .../utils/converter/CopilotSetConverter.kt | 34 +++++++++---------- .../utils/converter/MaaUserConverter.kt | 27 +++++++-------- .../backend/repository/ArkLevelRepository.kt | 2 +- .../maa/backend/service/ArkLevelService.kt | 2 +- .../maa/backend/service/CopilotService.kt | 2 +- .../maa/backend/service/CopilotSetService.kt | 2 +- 9 files changed, 65 insertions(+), 75 deletions(-) diff --git a/src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt b/src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt index f96ec923..ace69dd6 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt +++ b/src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt @@ -1,21 +1,16 @@ -package plus.maa.backend.common.utils.converter; +package plus.maa.backend.common.utils.converter -import org.mapstruct.Mapper; - -import plus.maa.backend.controller.response.copilot.ArkLevelInfo; -import plus.maa.backend.repository.entity.ArkLevel; - -import java.util.List; +import org.mapstruct.Mapper +import plus.maa.backend.controller.response.copilot.ArkLevelInfo +import plus.maa.backend.repository.entity.ArkLevel /** * @author dragove * created on 2022/12/26 */ @Mapper(componentModel = "spring") -public interface ArkLevelConverter { - - ArkLevelInfo convert(ArkLevel arkLevel); - - List convert(List arkLevel); +interface ArkLevelConverter { + fun convert(arkLevel: ArkLevel): ArkLevelInfo + fun convert(arkLevel: List): List } diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.kt b/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.kt index 0f88940b..63980a8a 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.kt +++ b/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.kt @@ -1,26 +1,24 @@ -package plus.maa.backend.common.utils.converter; +package plus.maa.backend.common.utils.converter -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import plus.maa.backend.controller.response.comments.CommentsInfo; -import plus.maa.backend.controller.response.comments.SubCommentsInfo; -import plus.maa.backend.repository.entity.CommentsArea; -import plus.maa.backend.repository.entity.MaaUser; +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import plus.maa.backend.controller.response.comments.CommentsInfo +import plus.maa.backend.controller.response.comments.SubCommentsInfo +import plus.maa.backend.repository.entity.CommentsArea +import plus.maa.backend.repository.entity.MaaUser /** * @author LoMu * Date 2023-02-21 18:16 */ - @Mapper(componentModel = "spring") -public interface CommentConverter { - +interface CommentConverter { @Mapping(target = "like", source = "commentsArea.likeCount") @Mapping(target = "dislike", source = "commentsArea.dislikeCount") @Mapping(target = "uploader", source = "maaUser.userName") @Mapping(target = "commentId", source = "commentsArea.id") @Mapping(target = "subCommentsInfos", ignore = true) - CommentsInfo toCommentsInfo(CommentsArea commentsArea, MaaUser maaUser); + fun toCommentsInfo(commentsArea: CommentsArea, maaUser: MaaUser): CommentsInfo @Mapping(target = "like", source = "commentsArea.likeCount") @@ -28,5 +26,5 @@ public interface CommentConverter { @Mapping(target = "uploader", source = "maaUser.userName") @Mapping(target = "commentId", source = "commentsArea.id") @Mapping(target = "deleted", source = "commentsArea.delete") - SubCommentsInfo toSubCommentsInfo(CommentsArea commentsArea, MaaUser maaUser); + fun toSubCommentsInfo(commentsArea: CommentsArea, maaUser: MaaUser): SubCommentsInfo } diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.kt b/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.kt index 8dd9f9f9..2217af7f 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.kt +++ b/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.kt @@ -1,21 +1,17 @@ -package plus.maa.backend.common.utils.converter; - -import org.mapstruct.*; -import plus.maa.backend.controller.request.copilot.CopilotDTO; -import plus.maa.backend.controller.response.copilot.CopilotInfo; -import plus.maa.backend.repository.entity.Copilot; - -import java.time.LocalDateTime; +package plus.maa.backend.common.utils.converter +import org.mapstruct.* +import plus.maa.backend.controller.request.copilot.CopilotDTO +import plus.maa.backend.controller.response.copilot.CopilotInfo +import plus.maa.backend.repository.entity.Copilot +import java.time.LocalDateTime /** * @author LoMu * Date 2023-01-10 19:10 */ - @Mapper(componentModel = "spring") -public interface CopilotConverter { - +interface CopilotConverter { /** * 实现增量更新 * 将copilotDto 映射覆盖数据库中的 copilot @@ -38,7 +34,7 @@ public interface CopilotConverter { @Mapping(target = "ratingRatio", ignore = true) @Mapping(target = "ratingLevel", ignore = true) @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) - void updateCopilotFromDto(CopilotDTO copilotDTO, String content, @MappingTarget Copilot copilot); + fun updateCopilotFromDto(copilotDTO: CopilotDTO, content: String, @MappingTarget copilot: Copilot) @Mapping(target = "id", ignore = true) @Mapping(target = "deleteTime", ignore = true) @@ -52,7 +48,13 @@ public interface CopilotConverter { @Mapping(target = "uploadTime", source = "now") @Mapping(target = "firstUploadTime", source = "now") @Mapping(target = "uploaderId", source = "userId") - Copilot toCopilot(CopilotDTO copilotDto, Long copilotId, String userId, LocalDateTime now, String content); + fun toCopilot( + copilotDto: CopilotDTO, + copilotId: Long, + userId: String, + now: LocalDateTime, + content: String + ): Copilot @Mapping(target = "ratingType", ignore = true) @Mapping(target = "ratingRatio", ignore = true) @@ -64,5 +66,5 @@ public interface CopilotConverter { @Mapping(target = "like", source = "copilot.likeCount") @Mapping(target = "dislike", source = "copilot.dislikeCount") @Mapping(target = "commentsCount", conditionExpression = "java(commentsCount != null)") - CopilotInfo toCopilotInfo(Copilot copilot, String userName, Long copilotId, Long commentsCount); + fun toCopilotInfo(copilot: Copilot, userName: String, copilotId: Long, commentsCount: Long?): CopilotInfo } diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt index 3057af84..f0f5a86e 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt +++ b/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt @@ -1,33 +1,31 @@ -package plus.maa.backend.common.utils.converter; +package plus.maa.backend.common.utils.converter -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; -import plus.maa.backend.controller.response.CopilotSetRes; -import plus.maa.backend.controller.response.user.CopilotSetListRes; -import plus.maa.backend.repository.entity.CopilotSet; - -import java.time.LocalDateTime; +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq +import plus.maa.backend.controller.response.CopilotSetRes +import plus.maa.backend.controller.response.user.CopilotSetListRes +import plus.maa.backend.repository.entity.CopilotSet +import java.time.LocalDateTime /** * @author dragove * create on 2024-01-01 */ -@Mapper(componentModel = "spring", imports = { - LocalDateTime.class -}) -public interface CopilotSetConverter { - +@Mapper( + componentModel = "spring", imports = [LocalDateTime::class + ] +) +interface CopilotSetConverter { @Mapping(target = "delete", ignore = true) @Mapping(target = "deleteTime", ignore = true) @Mapping(target = "copilotIds", expression = "java(createReq.getDistinctIdsAndCheck())") @Mapping(target = "createTime", expression = "java(LocalDateTime.now())") @Mapping(target = "updateTime", expression = "java(LocalDateTime.now())") - CopilotSet convert(CopilotSetCreateReq createReq, long id, String creatorId); + fun convert(createReq: CopilotSetCreateReq, id: Long, creatorId: String?): CopilotSet @Mapping(target = "creator", ignore = true) - CopilotSetListRes convert(CopilotSet copilotSet, String creator); - - CopilotSetRes convertDetail(CopilotSet copilotSet, String creator); + fun convert(copilotSet: CopilotSet, creator: String): CopilotSetListRes? + fun convertDetail(copilotSet: CopilotSet, creator: String): CopilotSetRes } diff --git a/src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.kt b/src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.kt index 9c91d139..afcc6060 100644 --- a/src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.kt +++ b/src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.kt @@ -1,25 +1,22 @@ -package plus.maa.backend.common.utils.converter; +package plus.maa.backend.common.utils.converter -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import plus.maa.backend.controller.response.user.MaaUserInfo; -import plus.maa.backend.repository.entity.MaaUser; - -import java.util.Objects; +import org.mapstruct.Mapper +import org.mapstruct.Mapping +import plus.maa.backend.controller.response.user.MaaUserInfo +import plus.maa.backend.repository.entity.MaaUser +import java.util.* /** * @author dragove * created on 2022/12/26 */ -@Mapper(componentModel = "spring", - imports = { - Objects.class - }) -public interface MaaUserConverter { - +@Mapper( + componentModel = "spring", imports = [Objects::class + ] +) +interface MaaUserConverter { @Mapping(source = "userId", target = "id") @Mapping(target = "activated", expression = "java(Objects.equals(user.getStatus(), 1))") @Mapping(target = "uploadCount", ignore = true) - MaaUserInfo convert(MaaUser user); - + fun convert(user: MaaUser): MaaUserInfo } diff --git a/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt b/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt index 2b08150b..c4a786ee 100644 --- a/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt +++ b/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt @@ -10,7 +10,7 @@ import plus.maa.backend.repository.entity.ArkLevelSha /** * @author john180 */ -interface ArkLevelRepository : MongoRepository { +interface ArkLevelRepository : MongoRepository { fun findAllShaBy(): List fun findAllByCatOne(catOne: String, pageable: Pageable): Page diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.kt b/src/main/java/plus/maa/backend/service/ArkLevelService.kt index 7957f2b9..84466db0 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelService.kt +++ b/src/main/java/plus/maa/backend/service/ArkLevelService.kt @@ -70,7 +70,7 @@ class ArkLevelService( @get:Cacheable("arkLevelInfos") val arkLevelInfos: List get() = arkLevelRepo.findAll() - .map { arkLevel: ArkLevel? -> arkLevelConverter.convert(arkLevel) } + .map { arkLevel -> arkLevelConverter.convert(arkLevel) } .toList() @Cacheable("arkLevel") diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/java/plus/maa/backend/service/CopilotService.kt index a742aca4..eed325b9 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotService.kt @@ -131,7 +131,7 @@ class CopilotService( * @param content 前端编辑json作业内容 * @return 返回_id */ - fun upload(loginUserId: String?, content: String): Long { + fun upload(loginUserId: String, content: String): Long { val copilotDTO = correctCopilot(parseToCopilotDto(content)) // 将其转换为数据库存储对象 val copilot = copilotConverter.toCopilot( diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.kt b/src/main/java/plus/maa/backend/service/CopilotSetService.kt index 5433d1d8..0e564f6d 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.kt @@ -44,7 +44,7 @@ class CopilotSetService( * @param userId 创建者用户id * @return 作业集id */ - fun create(req: CopilotSetCreateReq?, userId: String?): Long { + fun create(req: CopilotSetCreateReq, userId: String?): Long { val id = idComponent.getId(CopilotSet.META) val newCopilotSet = converter.convert(req, id, userId) From 4dc0833128618671ca192de417c419bab0756706 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 08:17:56 +0800 Subject: [PATCH 092/168] perf: remove uses of Java stream --- .../plus/maa/backend/service/CommentsAreaService.kt | 10 +++++----- .../java/plus/maa/backend/service/CopilotService.kt | 5 ++--- .../java/plus/maa/backend/service/CopilotSetService.kt | 10 ++++------ 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/CommentsAreaService.kt b/src/main/java/plus/maa/backend/service/CommentsAreaService.kt index 080ac991..fc76f370 100644 --- a/src/main/java/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/java/plus/maa/backend/service/CommentsAreaService.kt @@ -310,7 +310,7 @@ class CommentsAreaService( //获取子评论 val subCommentsList = commentsAreaRepository.findByMainCommentIdIn( - mainCommentsList.stream() + mainCommentsList .map { obj: CommentsArea -> obj.id } .toList() ) @@ -324,16 +324,16 @@ class CommentsAreaService( //所有评论 - val allComments: MutableList = ArrayList(mainCommentsList.stream().toList()) + val allComments: MutableList = ArrayList(mainCommentsList.toList()) allComments.addAll(subCommentsList) //获取所有评论用户 - val userId = allComments.stream().map { obj: CommentsArea -> obj.uploaderId }.distinct().toList() + val userId = allComments.map { obj: CommentsArea -> obj.uploaderId }.distinct().toList() val maaUserMap = userRepository.findByUsersId(userId) //转换主评论数据并填充用户名 - val commentsInfos = mainCommentsList.stream().map { mainComment: CommentsArea -> + val commentsInfos = mainCommentsList.map { mainComment: CommentsArea -> val commentsInfo = commentConverter .toCommentsInfo( @@ -343,7 +343,7 @@ class CommentsAreaService( MaaUser.UNKNOWN ) ) - val subCommentsInfoList = subCommentsList.stream() + val subCommentsInfoList = subCommentsList .filter { comment: CommentsArea -> commentsInfo.commentId == comment.mainCommentId } //转换子评论数据并填充用户名 .map { subComment: CommentsArea -> commentConverter diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/java/plus/maa/backend/service/CopilotService.kt index eed325b9..0cb35d5d 100644 --- a/src/main/java/plus/maa/backend/service/CopilotService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotService.kt @@ -344,14 +344,13 @@ class CopilotService( // 新版评分系统 // 反正目前首页和搜索不会直接展示当前用户有没有点赞,干脆直接不查,要用户点进作业才显示自己是否点赞 - val infos = copilots.stream().map { copilot: Copilot -> + val infos = copilots.map { copilot -> formatCopilot( copilot, null, maaUsers[copilot.uploaderId]!!.userName, commentsCount[copilot.copilotId] ) - } - .toList() + }.toList() // 计算页面 val pageNumber = ceil(count.toDouble() / limit).toInt() diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.kt b/src/main/java/plus/maa/backend/service/CopilotSetService.kt index 0e564f6d..4e825c7a 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.kt @@ -2,7 +2,6 @@ package plus.maa.backend.service import cn.hutool.core.lang.Assert import io.github.oshai.kotlinlogging.KotlinLogging -import org.apache.commons.lang3.StringUtils import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Sort import org.springframework.stereotype.Service @@ -19,7 +18,6 @@ import plus.maa.backend.repository.UserRepository import plus.maa.backend.repository.entity.CopilotSet import plus.maa.backend.repository.entity.MaaUser import java.time.LocalDateTime -import java.util.* private val log = KotlinLogging.logger { } @@ -109,14 +107,14 @@ class CopilotSetService( val pageRequest = PageRequest.of(req.page - 1, req.limit, DEFAULT_SORT) val keyword = req.keyword - val copilotSets = if (StringUtils.isBlank(keyword)) { + val copilotSets = if (keyword.isNullOrBlank()) { repository.findAll(pageRequest) } else { repository.findByKeyword(keyword, pageRequest) } - val userIds = copilotSets.stream().map { obj: CopilotSet -> obj.creatorId } - .filter { obj: String? -> Objects.nonNull(obj) } + val userIds = copilotSets + .map { obj: CopilotSet -> obj.creatorId } .distinct() .toList() val userById = userRepository.findByUsersId(userIds) @@ -124,7 +122,7 @@ class CopilotSetService( .setPage(copilotSets.number + 1) .setTotal(copilotSets.totalElements) .setHasNext(copilotSets.totalPages > req.page) - .setData(copilotSets.stream().map { cs: CopilotSet -> + .setData(copilotSets.map { cs: CopilotSet -> val user = userById.getOrDefault(cs.creatorId, MaaUser.UNKNOWN) converter.convert(cs, user.userName) }.toList()) From 941bd91a6cf0e2984bd7e7bcd8d65ef0584d9117 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 10:28:22 +0800 Subject: [PATCH 093/168] Rename .java to .kt --- .../controller/{ArkLevelController.java => ArkLevelController.kt} | 0 .../{CommentsAreaController.java => CommentsAreaController.kt} | 0 .../{CopilotSetController.java => CopilotSetController.kt} | 0 .../backend/controller/{UserController.java => UserController.kt} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/{ArkLevelController.java => ArkLevelController.kt} (100%) rename src/main/java/plus/maa/backend/controller/{CommentsAreaController.java => CommentsAreaController.kt} (100%) rename src/main/java/plus/maa/backend/controller/{CopilotSetController.java => CopilotSetController.kt} (100%) rename src/main/java/plus/maa/backend/controller/{UserController.java => UserController.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/ArkLevelController.java b/src/main/java/plus/maa/backend/controller/ArkLevelController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/ArkLevelController.java rename to src/main/java/plus/maa/backend/controller/ArkLevelController.kt diff --git a/src/main/java/plus/maa/backend/controller/CommentsAreaController.java b/src/main/java/plus/maa/backend/controller/CommentsAreaController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/CommentsAreaController.java rename to src/main/java/plus/maa/backend/controller/CommentsAreaController.kt diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.java b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/CopilotSetController.java rename to src/main/java/plus/maa/backend/controller/CopilotSetController.kt diff --git a/src/main/java/plus/maa/backend/controller/UserController.java b/src/main/java/plus/maa/backend/controller/UserController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/UserController.java rename to src/main/java/plus/maa/backend/controller/UserController.kt From d70816f16785c95c5e925f7535fa254f19ab2424 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 10:28:22 +0800 Subject: [PATCH 094/168] refactor: controllers in kotlin --- .../backend/controller/ArkLevelController.kt | 38 +++--- .../controller/CommentsAreaController.kt | 98 +++++++------- .../controller/CopilotSetController.kt | 104 +++++++-------- .../backend/controller/SystemController.kt | 9 +- .../maa/backend/controller/UserController.kt | 120 +++++++++--------- 5 files changed, 181 insertions(+), 188 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/ArkLevelController.kt b/src/main/java/plus/maa/backend/controller/ArkLevelController.kt index 3d5d45c9..9854c9d3 100644 --- a/src/main/java/plus/maa/backend/controller/ArkLevelController.kt +++ b/src/main/java/plus/maa/backend/controller/ArkLevelController.kt @@ -1,32 +1,28 @@ -package plus.maa.backend.controller; +package plus.maa.backend.controller -import java.util.List; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import plus.maa.backend.controller.response.copilot.ArkLevelInfo; -import plus.maa.backend.controller.response.MaaResult; -import plus.maa.backend.service.ArkLevelService; +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.RestController +import plus.maa.backend.controller.response.MaaResult +import plus.maa.backend.controller.response.MaaResult.Companion.success +import plus.maa.backend.controller.response.copilot.ArkLevelInfo +import plus.maa.backend.service.ArkLevelService /** * @author john180 */ @RestController -@RequiredArgsConstructor @Tag(name = "ArkLevelController", description = "关卡数据管理接口") -public class ArkLevelController { - private final ArkLevelService arkLevelService; +class ArkLevelController( + private val arkLevelService: ArkLevelService +) { - @Operation(summary = "获取关卡数据") - @ApiResponse(description = "关卡数据") @GetMapping("/arknights/level") - public MaaResult> getLevels() { - return MaaResult.success(arkLevelService.getArkLevelInfos()); + @ApiResponse(description = "关卡数据") + @Operation(summary = "获取关卡数据") + fun getLevels(): MaaResult> { + return success(arkLevelService.arkLevelInfos) } - } diff --git a/src/main/java/plus/maa/backend/controller/CommentsAreaController.kt b/src/main/java/plus/maa/backend/controller/CommentsAreaController.kt index affbbd2c..ea392ac3 100644 --- a/src/main/java/plus/maa/backend/controller/CommentsAreaController.kt +++ b/src/main/java/plus/maa/backend/controller/CommentsAreaController.kt @@ -1,65 +1,63 @@ -package plus.maa.backend.controller; +package plus.maa.backend.controller -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; -import plus.maa.backend.common.annotation.JsonSchema; -import plus.maa.backend.common.annotation.SensitiveWordDetection; -import plus.maa.backend.config.doc.RequireJwt; -import plus.maa.backend.config.security.AuthenticationHelper; -import plus.maa.backend.controller.request.comments.*; -import plus.maa.backend.controller.response.MaaResult; -import plus.maa.backend.controller.response.comments.CommentsAreaInfo; -import plus.maa.backend.service.CommentsAreaService; +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.validation.Valid +import jakarta.validation.constraints.NotBlank +import org.springframework.web.bind.annotation.* +import plus.maa.backend.common.annotation.JsonSchema +import plus.maa.backend.common.annotation.SensitiveWordDetection +import plus.maa.backend.config.doc.RequireJwt +import plus.maa.backend.config.security.AuthenticationHelper +import plus.maa.backend.controller.request.comments.* +import plus.maa.backend.controller.response.MaaResult +import plus.maa.backend.controller.response.MaaResult.Companion.success +import plus.maa.backend.controller.response.comments.CommentsAreaInfo +import plus.maa.backend.service.CommentsAreaService /** * @author LoMu * Date 2023-02-17 14:56 */ - @RestController -@RequiredArgsConstructor @Tag(name = "CommentArea", description = "评论区管理接口") @RequestMapping("/comments") -public class CommentsAreaController { - private final CommentsAreaService commentsAreaService; - private final AuthenticationHelper authHelper; - +class CommentsAreaController( + private val commentsAreaService: CommentsAreaService, + private val authHelper: AuthenticationHelper +) { @SensitiveWordDetection("#comments.message") @PostMapping("/add") @Operation(summary = "发送评论") @ApiResponse(description = "发送评论结果") @RequireJwt - public MaaResult sendComments( - @Parameter(description = "评论") @Valid @RequestBody CommentsAddDTO comments - ) { - commentsAreaService.addComments(authHelper.requireUserId(), comments); - return MaaResult.success("评论成功"); + fun sendComments( + @Parameter(description = "评论") @RequestBody comments: @Valid CommentsAddDTO + ): MaaResult { + commentsAreaService.addComments(authHelper.requireUserId(), comments) + return success("评论成功") } @GetMapping("/query") @Operation(summary = "分页查询评论") @ApiResponse(description = "评论区信息") - public MaaResult queriesCommentsArea( - @Parameter(description = "评论查询对象") @Valid CommentsQueriesDTO parsed - ) { - return MaaResult.success(commentsAreaService.queriesCommentsArea(parsed)); + fun queriesCommentsArea( + @Parameter(description = "评论查询对象") parsed: @Valid CommentsQueriesDTO + ): MaaResult { + return success(commentsAreaService.queriesCommentsArea(parsed)) } @PostMapping("/delete") @Operation(summary = "删除评论") @ApiResponse(description = "评论删除结果") @RequireJwt - public MaaResult deleteComments( - @Parameter(description = "评论删除对象") @Valid @RequestBody CommentsDeleteDTO comments - ) { - commentsAreaService.deleteComments(authHelper.requireUserId(), comments.getCommentId()); - return MaaResult.success("评论已删除"); + fun deleteComments( + @Parameter(description = "评论删除对象") @RequestBody comments: @Valid CommentsDeleteDTO + ): MaaResult { + commentsAreaService.deleteComments(authHelper.requireUserId(), comments.commentId) + return success("评论已删除") } @JsonSchema @@ -67,29 +65,29 @@ public class CommentsAreaController { @ApiResponse(description = "点赞结果") @RequireJwt @PostMapping("/rating") - public MaaResult ratesComments( - @Parameter(description = "评论点赞对象") @Valid @RequestBody CommentsRatingDTO commentsRatingDTO - ) { - commentsAreaService.rates(authHelper.requireUserId(), commentsRatingDTO); - return MaaResult.success("成功"); + fun ratesComments( + @Parameter(description = "评论点赞对象") @RequestBody commentsRatingDTO: @Valid CommentsRatingDTO + ): MaaResult { + commentsAreaService.rates(authHelper.requireUserId(), commentsRatingDTO) + return success("成功") } @Operation(summary = "为评论置顶/取消置顶") @ApiResponse(description = "置顶/取消置顶结果") @RequireJwt @PostMapping("/topping") - public MaaResult toppingComments( - @Parameter(description = "评论置顶对象") @Valid @RequestBody CommentsToppingDTO commentsToppingDTO - ) { - commentsAreaService.topping(authHelper.requireUserId(), commentsToppingDTO); - return MaaResult.success("成功"); + fun toppingComments( + @Parameter(description = "评论置顶对象") @RequestBody commentsToppingDTO: @Valid CommentsToppingDTO + ): MaaResult { + commentsAreaService.topping(authHelper.requireUserId(), commentsToppingDTO) + return success("成功") } @Operation(summary = "设置通知接收状态") @RequireJwt @GetMapping("/status") - public MaaResult modifyStatus(@RequestParam @NotBlank String id, @RequestParam boolean status) { - commentsAreaService.notificationStatus(authHelper.getUserId(), id, status); - return MaaResult.success("success"); + fun modifyStatus(@RequestParam id: @NotBlank String, @RequestParam status: Boolean): MaaResult { + commentsAreaService.notificationStatus(authHelper.userId!!, id, status) + return success("success") } } diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt index 152862a1..6843bb40 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt @@ -1,23 +1,24 @@ -package plus.maa.backend.controller; +package plus.maa.backend.controller -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.*; -import plus.maa.backend.config.doc.RequireJwt; -import plus.maa.backend.config.security.AuthenticationHelper; -import plus.maa.backend.controller.request.CommonIdReq; -import plus.maa.backend.controller.request.CopilotSetQuery; -import plus.maa.backend.controller.request.CopilotSetUpdateReq; -import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq; -import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq; -import plus.maa.backend.controller.response.CopilotSetPageRes; -import plus.maa.backend.controller.response.CopilotSetRes; -import plus.maa.backend.controller.response.MaaResult; -import plus.maa.backend.service.CopilotSetService; +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.validation.Valid +import lombok.RequiredArgsConstructor +import org.springframework.web.bind.annotation.* +import plus.maa.backend.config.doc.RequireJwt +import plus.maa.backend.config.security.AuthenticationHelper +import plus.maa.backend.controller.request.CommonIdReq +import plus.maa.backend.controller.request.CopilotSetQuery +import plus.maa.backend.controller.request.CopilotSetUpdateReq +import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq +import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq +import plus.maa.backend.controller.response.CopilotSetPageRes +import plus.maa.backend.controller.response.CopilotSetRes +import plus.maa.backend.controller.response.MaaResult +import plus.maa.backend.controller.response.MaaResult.Companion.success +import plus.maa.backend.service.CopilotSetService /** * @author dragove @@ -27,71 +28,74 @@ import plus.maa.backend.service.CopilotSetService; @RequestMapping("/set") @RestController @RequiredArgsConstructor -public class CopilotSetController { - - private final CopilotSetService service; - private final AuthenticationHelper helper; +class CopilotSetController( + private val service: CopilotSetService, + private val helper: AuthenticationHelper +) { @Operation(summary = "查询作业集列表") @ApiResponse(description = "作业集id") @PostMapping("/query") - public MaaResult querySets( - @Parameter(description = "作业集列表查询请求") @Valid @RequestBody CopilotSetQuery req) { - return MaaResult.success(service.query(req)); + fun querySets( + @Parameter(description = "作业集列表查询请求") @RequestBody req: @Valid CopilotSetQuery + ): MaaResult { + return success(service.query(req)) } @Operation(summary = "查询作业集列表") @ApiResponse(description = "作业集id") @GetMapping("/get") - public MaaResult getSet(@RequestParam @Parameter(description = "作业id") long id) { - return MaaResult.success(service.get(id)); + fun getSet(@RequestParam @Parameter(description = "作业id") id: Long): MaaResult { + return success(service.get(id)) } - @Operation(summary = "创建作业集") @ApiResponse(description = "作业集id") @RequireJwt @PostMapping("/create") - public MaaResult createSet( - @Parameter(description = "作业集新增请求") @Valid @RequestBody CopilotSetCreateReq req) { - return MaaResult.success(service.create(req, helper.getUserId())); + fun createSet( + @Parameter(description = "作业集新增请求") @RequestBody req: @Valid CopilotSetCreateReq + ): MaaResult { + return success(service.create(req, helper.userId)) } @Operation(summary = "添加作业集作业列表") @RequireJwt @PostMapping("/add") - public MaaResult addCopilotIds( - @Parameter(description = "作业集中加入新作业请求") @Valid @RequestBody CopilotSetModCopilotsReq req) { - service.addCopilotIds(req, helper.getUserId()); - return MaaResult.success(); + fun addCopilotIds( + @Parameter(description = "作业集中加入新作业请求") @RequestBody req: @Valid CopilotSetModCopilotsReq + ): MaaResult { + service.addCopilotIds(req, helper.userId!!) + return success() } @Operation(summary = "添加作业集作业列表") @RequireJwt @PostMapping("/remove") - public MaaResult removeCopilotIds( - @Parameter(description = "作业集中删除作业请求") @Valid @RequestBody CopilotSetModCopilotsReq req) { - service.removeCopilotIds(req, helper.getUserId()); - return MaaResult.success(); + fun removeCopilotIds( + @Parameter(description = "作业集中删除作业请求") @RequestBody req: @Valid CopilotSetModCopilotsReq + ): MaaResult { + service.removeCopilotIds(req, helper.userId!!) + return success() } @Operation(summary = "更新作业集信息") @RequireJwt @PostMapping("/update") - public MaaResult updateCopilotSet( - @Parameter(description = "更新作业集信息请求") @Valid @RequestBody CopilotSetUpdateReq req) { - service.update(req, helper.getUserId()); - return MaaResult.success(); + fun updateCopilotSet( + @Parameter(description = "更新作业集信息请求") @RequestBody req: @Valid CopilotSetUpdateReq + ): MaaResult { + service.update(req, helper.userId!!) + return success() } @Operation(summary = "删除作业集") @RequireJwt @PostMapping("/delete") - public MaaResult deleteCopilotSet( - @Parameter(description = "删除作业集信息请求") @Valid @RequestBody CommonIdReq req) { - service.delete(req.getId(), helper.getUserId()); - return MaaResult.success(); + fun deleteCopilotSet( + @Parameter(description = "删除作业集信息请求") @RequestBody req: @Valid CommonIdReq + ): MaaResult { + service.delete(req.id!!, helper.userId!!) + return success() } - - } diff --git a/src/main/java/plus/maa/backend/controller/SystemController.kt b/src/main/java/plus/maa/backend/controller/SystemController.kt index dfd7c14c..742d31ea 100644 --- a/src/main/java/plus/maa/backend/controller/SystemController.kt +++ b/src/main/java/plus/maa/backend/controller/SystemController.kt @@ -16,7 +16,7 @@ import plus.maa.backend.controller.response.MaaResult @RestController class SystemController( private val properties: MaaCopilotProperties, - private val gitProperties: GitProperties? + private val gitProperties: GitProperties ) { /** @@ -24,9 +24,8 @@ class SystemController( * @return 系统启动信息 */ @GetMapping("/") - fun test(): MaaResult { - return MaaResult.success("Maa Copilot Server is Running", null) - } + fun test() = MaaResult.success("Maa Copilot Server is Running", null) + /** * Gets the current version of the server. @@ -35,7 +34,7 @@ class SystemController( @GetMapping("version") fun getSystemVersion(): MaaResult { val info = properties.info - val systemInfo = MaaSystemInfo(info.title, info.description, info.version, gitProperties!!) + val systemInfo = MaaSystemInfo(info.title, info.description, info.version, gitProperties) return MaaResult.success(systemInfo) } diff --git a/src/main/java/plus/maa/backend/controller/UserController.kt b/src/main/java/plus/maa/backend/controller/UserController.kt index c9c0abd3..ec0495a2 100644 --- a/src/main/java/plus/maa/backend/controller/UserController.kt +++ b/src/main/java/plus/maa/backend/controller/UserController.kt @@ -1,48 +1,44 @@ -package plus.maa.backend.controller; +package plus.maa.backend.controller -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import io.swagger.v3.oas.annotations.tags.Tag; -import jakarta.validation.Valid; -import lombok.Data; -import lombok.RequiredArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import plus.maa.backend.config.doc.RequireJwt; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.config.security.AuthenticationHelper; -import plus.maa.backend.controller.request.user.*; -import plus.maa.backend.controller.response.MaaResult; -import plus.maa.backend.controller.response.user.MaaLoginRsp; -import plus.maa.backend.controller.response.user.MaaUserInfo; -import plus.maa.backend.service.EmailService; -import plus.maa.backend.service.UserService; +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.responses.ApiResponse +import io.swagger.v3.oas.annotations.tags.Tag +import jakarta.validation.Valid +import org.springframework.beans.factory.annotation.Value +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController +import plus.maa.backend.config.doc.RequireJwt +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.config.security.AuthenticationHelper +import plus.maa.backend.controller.request.user.* +import plus.maa.backend.controller.response.MaaResult +import plus.maa.backend.controller.response.MaaResult.Companion.success +import plus.maa.backend.controller.response.user.MaaLoginRsp +import plus.maa.backend.controller.response.user.MaaUserInfo +import plus.maa.backend.service.EmailService +import plus.maa.backend.service.UserService /** * 用户相关接口 - * 前端api约定文件 + * [前端api约定文件](https://github.com/MaaAssistantArknights/maa-copilot-frontend/blob/dev/src/apis/auth.ts) * * @author AnselYuki */ -@Data @Tag(name = "CopilotUser", description = "用户管理") @RequestMapping("/user") @Validated @RestController -@RequiredArgsConstructor -public class UserController { - private final UserService userService; - private final EmailService emailService; - private final MaaCopilotProperties properties; - private final AuthenticationHelper helper; - @Value("${maa-copilot.jwt.header}") - private String header; +class UserController( + private val userService: UserService, + private val emailService: EmailService, + private val properties: MaaCopilotProperties, + private val helper: AuthenticationHelper, + @Value("\${maa-copilot.jwt.header}") private val header: String +) { /** * 更新当前用户的密码(根据原密码) @@ -53,11 +49,11 @@ public class UserController { @ApiResponse(description = "修改密码结果") @RequireJwt @PostMapping("/update/password") - public MaaResult updatePassword( - @Parameter(description = "修改密码请求") @RequestBody @Valid PasswordUpdateDTO updateDTO - ) { - userService.modifyPassword(helper.requireUserId(), updateDTO.getNewPassword()); - return MaaResult.success(); + fun updatePassword( + @Parameter(description = "修改密码请求") @RequestBody updateDTO: @Valid PasswordUpdateDTO + ): MaaResult { + userService.modifyPassword(helper.requireUserId(), updateDTO.newPassword) + return success() } /** @@ -70,11 +66,11 @@ public class UserController { @ApiResponse(description = "更新结果") @RequireJwt @PostMapping("/update/info") - public MaaResult updateInfo( - @Parameter(description = "更新用户详细信息请求") @Valid @RequestBody UserInfoUpdateDTO updateDTO - ) { - userService.updateUserInfo(helper.requireUserId(), updateDTO); - return MaaResult.success(); + fun updateInfo( + @Parameter(description = "更新用户详细信息请求") @RequestBody updateDTO: @Valid UserInfoUpdateDTO + ): MaaResult { + userService.updateUserInfo(helper.requireUserId(), updateDTO) + return success() } /** @@ -86,11 +82,11 @@ public class UserController { @PostMapping("/password/reset") @Operation(summary = "重置密码") @ApiResponse(description = "重置密码结果") - public MaaResult passwordReset(@Parameter(description = "重置密码请求") @RequestBody @Valid PasswordResetDTO passwordResetDTO) { + fun passwordReset(@Parameter(description = "重置密码请求") @RequestBody passwordResetDTO: @Valid PasswordResetDTO?): MaaResult { // 校验用户邮箱是否存在 - userService.checkUserExistByEmail(passwordResetDTO.getEmail()); - userService.modifyPasswordByActiveCode(passwordResetDTO); - return MaaResult.success(); + userService!!.checkUserExistByEmail(passwordResetDTO!!.email) + userService.modifyPasswordByActiveCode(passwordResetDTO) + return success() } /** @@ -102,11 +98,11 @@ public class UserController { @PostMapping("/password/reset_request") @Operation(summary = "发送用于重置密码的验证码") @ApiResponse(description = "验证码发送结果") - public MaaResult passwordResetRequest(@Parameter(description = "发送重置密码的验证码请求") @RequestBody @Valid PasswordResetVCodeDTO passwordResetVCodeDTO) { + fun passwordResetRequest(@Parameter(description = "发送重置密码的验证码请求") @RequestBody passwordResetVCodeDTO: @Valid PasswordResetVCodeDTO): MaaResult { // 校验用户邮箱是否存在 - userService.checkUserExistByEmail(passwordResetVCodeDTO.getEmail()); - emailService.sendVCode(passwordResetVCodeDTO.getEmail()); - return MaaResult.success(); + userService.checkUserExistByEmail(passwordResetVCodeDTO.email) + emailService.sendVCode(passwordResetVCodeDTO.email) + return success() } /** @@ -118,9 +114,9 @@ public class UserController { @PostMapping("/refresh") @Operation(summary = "刷新token") @ApiResponse(description = "刷新token结果") - public MaaResult refresh(@Parameter(description = "刷新token请求") @RequestBody RefreshReq request) { - var res = userService.refreshToken(request.getRefreshToken()); - return MaaResult.success(res); + fun refresh(@Parameter(description = "刷新token请求") @RequestBody request: RefreshReq): MaaResult { + val res = userService.refreshToken(request.refreshToken) + return success(res) } /** @@ -132,8 +128,8 @@ public class UserController { @PostMapping("/register") @Operation(summary = "用户注册") @ApiResponse(description = "注册结果") - public MaaResult register(@Parameter(description = "用户注册请求") @Valid @RequestBody RegisterDTO user) { - return MaaResult.success(userService.register(user)); + fun register(@Parameter(description = "用户注册请求") @RequestBody user: @Valid RegisterDTO): MaaResult { + return success(userService.register(user)) } /** @@ -142,9 +138,9 @@ public class UserController { @PostMapping("/sendRegistrationToken") @Operation(summary = "注册时发送验证码") @ApiResponse(description = "发送验证码结果", responseCode = "204") - public MaaResult sendRegistrationToken(@Parameter(description = "发送注册验证码请求") @RequestBody @Valid SendRegistrationTokenDTO regDTO) { - userService.sendRegistrationToken(regDTO); - return new MaaResult<>(204, null, null); + fun sendRegistrationToken(@Parameter(description = "发送注册验证码请求") @RequestBody regDTO: @Valid SendRegistrationTokenDTO): MaaResult { + userService.sendRegistrationToken(regDTO) + return MaaResult(204, null, null) } /** @@ -156,7 +152,7 @@ public class UserController { @PostMapping("/login") @Operation(summary = "用户登录") @ApiResponse(description = "登录结果") - public MaaResult login(@Parameter(description = "登录请求") @RequestBody @Valid LoginDTO user) { - return MaaResult.success("登陆成功", userService.login(user)); + fun login(@Parameter(description = "登录请求") @RequestBody user: @Valid LoginDTO): MaaResult { + return success("登陆成功", userService.login(user)) } } From 9c62c43359962c03d3fe89f5886d04bb88205225 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 18:30:18 +0800 Subject: [PATCH 095/168] Rename .java to .kt --- .../plus/maa/backend/config/{CorsConfig.java => CorsConfig.kt} | 0 .../config/{HttpInterfaceConfig.java => HttpInterfaceConfig.kt} | 0 .../{NativeReflectionConfig.java => NativeReflectionConfig.kt} | 0 .../config/{SensitiveWordConfig.java => SensitiveWordConfig.kt} | 0 .../backend/config/{ThreadPoolConfig.java => ThreadPoolConfig.kt} | 0 .../maa/backend/config/doc/{RequireJwt.java => RequireJwt.kt} | 0 .../config/doc/{SpringDocConfig.java => SpringDocConfig.kt} | 0 ...enticationTokenFilter.java => JwtAuthenticationTokenFilter.kt} | 0 .../config/security/{SecurityConfig.java => SecurityConfig.kt} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/config/{CorsConfig.java => CorsConfig.kt} (100%) rename src/main/java/plus/maa/backend/config/{HttpInterfaceConfig.java => HttpInterfaceConfig.kt} (100%) rename src/main/java/plus/maa/backend/config/{NativeReflectionConfig.java => NativeReflectionConfig.kt} (100%) rename src/main/java/plus/maa/backend/config/{SensitiveWordConfig.java => SensitiveWordConfig.kt} (100%) rename src/main/java/plus/maa/backend/config/{ThreadPoolConfig.java => ThreadPoolConfig.kt} (100%) rename src/main/java/plus/maa/backend/config/doc/{RequireJwt.java => RequireJwt.kt} (100%) rename src/main/java/plus/maa/backend/config/doc/{SpringDocConfig.java => SpringDocConfig.kt} (100%) rename src/main/java/plus/maa/backend/config/security/{JwtAuthenticationTokenFilter.java => JwtAuthenticationTokenFilter.kt} (100%) rename src/main/java/plus/maa/backend/config/security/{SecurityConfig.java => SecurityConfig.kt} (100%) diff --git a/src/main/java/plus/maa/backend/config/CorsConfig.java b/src/main/java/plus/maa/backend/config/CorsConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/CorsConfig.java rename to src/main/java/plus/maa/backend/config/CorsConfig.kt diff --git a/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.java b/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/HttpInterfaceConfig.java rename to src/main/java/plus/maa/backend/config/HttpInterfaceConfig.kt diff --git a/src/main/java/plus/maa/backend/config/NativeReflectionConfig.java b/src/main/java/plus/maa/backend/config/NativeReflectionConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/NativeReflectionConfig.java rename to src/main/java/plus/maa/backend/config/NativeReflectionConfig.kt diff --git a/src/main/java/plus/maa/backend/config/SensitiveWordConfig.java b/src/main/java/plus/maa/backend/config/SensitiveWordConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/SensitiveWordConfig.java rename to src/main/java/plus/maa/backend/config/SensitiveWordConfig.kt diff --git a/src/main/java/plus/maa/backend/config/ThreadPoolConfig.java b/src/main/java/plus/maa/backend/config/ThreadPoolConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/ThreadPoolConfig.java rename to src/main/java/plus/maa/backend/config/ThreadPoolConfig.kt diff --git a/src/main/java/plus/maa/backend/config/doc/RequireJwt.java b/src/main/java/plus/maa/backend/config/doc/RequireJwt.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/doc/RequireJwt.java rename to src/main/java/plus/maa/backend/config/doc/RequireJwt.kt diff --git a/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.java b/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/doc/SpringDocConfig.java rename to src/main/java/plus/maa/backend/config/doc/SpringDocConfig.kt diff --git a/src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.java b/src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.java rename to src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt diff --git a/src/main/java/plus/maa/backend/config/security/SecurityConfig.java b/src/main/java/plus/maa/backend/config/security/SecurityConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/SecurityConfig.java rename to src/main/java/plus/maa/backend/config/security/SecurityConfig.kt From 3f507635a61e7bc31e62bfae247edb73262009bf Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 18:30:19 +0800 Subject: [PATCH 096/168] refactor: configs in kotlin --- .../backend/common/model/CopilotSetType.java | 29 ---- .../backend/common/model/CopilotSetType.kt | 22 +++ .../plus/maa/backend/config/CorsConfig.kt | 41 ++--- .../maa/backend/config/HttpInterfaceConfig.kt | 81 +++++----- .../backend/config/NativeReflectionConfig.kt | 44 +++--- .../maa/backend/config/SensitiveWordConfig.kt | 72 ++++----- .../maa/backend/config/ThreadPoolConfig.kt | 43 +++-- .../plus/maa/backend/config/doc/RequireJwt.kt | 22 ++- .../maa/backend/config/doc/SpringDocConfig.kt | 147 +++++++++--------- .../security/JwtAuthenticationTokenFilter.kt | 72 ++++----- .../backend/config/security/SecurityConfig.kt | 145 +++++++++-------- .../plus/maa/backend/filter/package-info.java | 4 - .../backend/service/ArkLevelParserService.kt | 7 +- 13 files changed, 358 insertions(+), 371 deletions(-) delete mode 100644 src/main/java/plus/maa/backend/common/model/CopilotSetType.java create mode 100644 src/main/java/plus/maa/backend/common/model/CopilotSetType.kt delete mode 100644 src/main/java/plus/maa/backend/filter/package-info.java diff --git a/src/main/java/plus/maa/backend/common/model/CopilotSetType.java b/src/main/java/plus/maa/backend/common/model/CopilotSetType.java deleted file mode 100644 index 70300cb6..00000000 --- a/src/main/java/plus/maa/backend/common/model/CopilotSetType.java +++ /dev/null @@ -1,29 +0,0 @@ -package plus.maa.backend.common.model; - -import org.springframework.util.Assert; - -import java.util.Collections; -import java.util.List; - -/** - * @author dragove - * create on 2024-01-01 - */ -public interface CopilotSetType { - - List getCopilotIds(); - - default List getDistinctIdsAndCheck() { - List copilotIds = getCopilotIds(); - if (copilotIds == null) { - return Collections.emptyList(); - } - if (copilotIds.isEmpty() || copilotIds.size() == 1) { - return getCopilotIds(); - } - copilotIds = copilotIds.stream().distinct().toList(); - Assert.state(copilotIds.size() <= 1000, "作业集总作业数量不能超过1000条"); - return copilotIds; - } - -} diff --git a/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt b/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt new file mode 100644 index 00000000..327bdcb2 --- /dev/null +++ b/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt @@ -0,0 +1,22 @@ +package plus.maa.backend.common.model + +import org.springframework.util.Assert + +/** + * @author dragove + * create on 2024-01-01 + */ +interface CopilotSetType { + val copilotIds: List? + + val distinctIdsAndCheck: List? + get() { + var copilotIds = copilotIds ?: return emptyList() + if (copilotIds.isEmpty() || copilotIds.size == 1) { + return this.copilotIds + } + copilotIds = copilotIds.distinct().toList() + Assert.state(copilotIds.size <= 1000, "作业集总作业数量不能超过1000条") + return copilotIds + } +} diff --git a/src/main/java/plus/maa/backend/config/CorsConfig.kt b/src/main/java/plus/maa/backend/config/CorsConfig.kt index 60df9368..28bee1ee 100644 --- a/src/main/java/plus/maa/backend/config/CorsConfig.kt +++ b/src/main/java/plus/maa/backend/config/CorsConfig.kt @@ -1,38 +1,29 @@ -package plus.maa.backend.config; +package plus.maa.backend.config -import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.CorsRegistry; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import plus.maa.backend.handler.AccessLimitInterceptHandlerImpl; +import org.springframework.context.annotation.Configuration +import org.springframework.web.servlet.config.annotation.CorsRegistry +import org.springframework.web.servlet.config.annotation.InterceptorRegistry +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import plus.maa.backend.handler.AccessLimitInterceptHandlerImpl /** * @author AnselYuki */ @Configuration -public class CorsConfig implements WebMvcConfigurer { - - - @Override - public void addCorsMappings(CorsRegistry registry) { +class CorsConfig : WebMvcConfigurer { + override fun addCorsMappings(registry: CorsRegistry) { // 设置允许跨域的路径 registry - .addMapping("/**") - // 设置允许跨域请求的域名 - .allowedOriginPatterns("*") - // 是否允许cookie - .allowCredentials(true) - // 设置允许的请求方式 - .allowedMethods("GET", "POST", "DELETE", "PUT") - // 设置允许的header属性 - .allowedHeaders("*") - // 跨域允许时间 - .maxAge(3600); + .addMapping("/**") // 设置允许跨域请求的域名 + .allowedOriginPatterns("*") // 是否允许cookie + .allowCredentials(true) // 设置允许的请求方式 + .allowedMethods("GET", "POST", "DELETE", "PUT") // 设置允许的header属性 + .allowedHeaders("*") // 跨域允许时间 + .maxAge(3600) } - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(new AccessLimitInterceptHandlerImpl()); + override fun addInterceptors(registry: InterceptorRegistry) { + registry.addInterceptor(AccessLimitInterceptHandlerImpl()) } } diff --git a/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.kt b/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.kt index 1fde03b7..223811bb 100644 --- a/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.kt +++ b/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.kt @@ -1,49 +1,48 @@ -package plus.maa.backend.config; +package plus.maa.backend.config -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.codec.json.Jackson2JsonDecoder; -import org.springframework.http.codec.json.Jackson2JsonEncoder; -import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; -import org.springframework.web.reactive.function.client.ExchangeStrategies; -import org.springframework.web.reactive.function.client.WebClient; -import org.springframework.web.reactive.function.client.support.WebClientAdapter; -import org.springframework.web.service.invoker.HttpServiceProxyFactory; -import plus.maa.backend.repository.GithubRepository; +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpHeaders +import org.springframework.http.codec.ClientCodecConfigurer +import org.springframework.http.codec.json.Jackson2JsonDecoder +import org.springframework.http.codec.json.Jackson2JsonEncoder +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder +import org.springframework.web.reactive.function.client.ExchangeStrategies +import org.springframework.web.reactive.function.client.WebClient +import org.springframework.web.reactive.function.client.support.WebClientAdapter +import org.springframework.web.service.invoker.HttpServiceProxyFactory +import plus.maa.backend.repository.GithubRepository @Configuration -public class HttpInterfaceConfig { - +class HttpInterfaceConfig { @Bean - GithubRepository githubRepository() { - - ObjectMapper mapper = Jackson2ObjectMapperBuilder.json() - .propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE) - .build(); + fun githubRepository(): GithubRepository { + val mapper = Jackson2ObjectMapperBuilder.json() + .propertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE) + .build() - WebClient client = WebClient.builder() - .baseUrl("https://api.github.com") - .exchangeStrategies(ExchangeStrategies - .builder() - .codecs(codecs -> { - codecs.defaultCodecs() - .jackson2JsonEncoder(new Jackson2JsonEncoder(mapper)); - codecs.defaultCodecs() - .jackson2JsonDecoder(new Jackson2JsonDecoder(mapper)); - // 最大 20MB - codecs.defaultCodecs().maxInMemorySize(20 * 1024 * 1024); - }) - .build()) - .defaultHeaders(headers -> { - headers.add("Accept", "application/vnd.github+json"); - headers.add("X-GitHub-Api-Version", "2022-11-28"); - }) - .build(); + val client = WebClient.builder() + .baseUrl("https://api.github.com") + .exchangeStrategies(ExchangeStrategies + .builder() + .codecs { codecs: ClientCodecConfigurer -> + codecs.defaultCodecs() + .jackson2JsonEncoder(Jackson2JsonEncoder(mapper)) + codecs.defaultCodecs() + .jackson2JsonDecoder(Jackson2JsonDecoder(mapper)) + // 最大 20MB + codecs.defaultCodecs().maxInMemorySize(20 * 1024 * 1024) + } + .build()) + .defaultHeaders { headers: HttpHeaders -> + headers.add("Accept", "application/vnd.github+json") + headers.add("X-GitHub-Api-Version", "2022-11-28") + } + .build() return HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)) - .build() - .createClient(GithubRepository.class); + .build() + .createClient(GithubRepository::class.java) } - } diff --git a/src/main/java/plus/maa/backend/config/NativeReflectionConfig.kt b/src/main/java/plus/maa/backend/config/NativeReflectionConfig.kt index 3e1de075..a5ea3eb8 100644 --- a/src/main/java/plus/maa/backend/config/NativeReflectionConfig.kt +++ b/src/main/java/plus/maa/backend/config/NativeReflectionConfig.kt @@ -1,12 +1,14 @@ -package plus.maa.backend.config; +package plus.maa.backend.config -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import org.springframework.aot.hint.annotation.RegisterReflectionForBinding; -import org.springframework.context.annotation.Configuration; -import plus.maa.backend.controller.request.copilot.CopilotDTO; -import plus.maa.backend.repository.entity.gamedata.*; -import plus.maa.backend.service.model.RatingCache; -import plus.maa.backend.service.session.UserSession; +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.PropertyNamingStrategies.LowerCamelCaseStrategy +import org.springframework.aot.hint.annotation.RegisterReflectionForBinding +import org.springframework.context.annotation.Configuration +import plus.maa.backend.controller.request.copilot.CopilotDTO +import plus.maa.backend.repository.entity.gamedata.* +import plus.maa.backend.repository.entity.gamedata.ArkTilePos.Tile +import plus.maa.backend.service.model.RatingCache +import plus.maa.backend.service.session.UserSession /** * 添加所有需要用到反射的类到此处,用于 native image @@ -16,14 +18,18 @@ import plus.maa.backend.service.session.UserSession; * created on 2023/08/18 */ @Configuration -@RegisterReflectionForBinding({ - ArkActivity.class, ArkCharacter.class, ArkStage.class, - ArkTilePos.class, ArkTilePos.Tile.class, ArkTower.class, - ArkZone.class, CopilotDTO.class, RatingCache.class, - UserSession.class, - PropertyNamingStrategies.SnakeCaseStrategy.class, - PropertyNamingStrategies.LowerCamelCaseStrategy.class -}) -public class NativeReflectionConfig { - -} +@RegisterReflectionForBinding( + ArkActivity::class, + ArkCharacter::class, + ArkStage::class, + ArkTilePos::class, + Tile::class, + ArkTower::class, + ArkZone::class, + CopilotDTO::class, + RatingCache::class, + UserSession::class, + PropertyNamingStrategies.SnakeCaseStrategy::class, + LowerCamelCaseStrategy::class +) +class NativeReflectionConfig diff --git a/src/main/java/plus/maa/backend/config/SensitiveWordConfig.kt b/src/main/java/plus/maa/backend/config/SensitiveWordConfig.kt index d603a72e..36b4d247 100644 --- a/src/main/java/plus/maa/backend/config/SensitiveWordConfig.kt +++ b/src/main/java/plus/maa/backend/config/SensitiveWordConfig.kt @@ -1,63 +1,63 @@ -package plus.maa.backend.config; +package plus.maa.backend.config -import cn.hutool.dfa.WordTree; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.io.Resource; +import cn.hutool.dfa.WordTree +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.ApplicationContext +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import java.io.BufferedReader +import java.io.IOException +import java.io.InputStreamReader -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; +private val log = KotlinLogging.logger { } /** - * 敏感词配置类
+ * 敏感词配置类

* * @author lixuhuilll * Date: 2023-08-25 18:50 */ - -@Slf4j @Configuration -public class SensitiveWordConfig { - +class SensitiveWordConfig( // 标准的 Spring 路径匹配语法,默认为 classpath:sensitive-word.txt - @Value("${maa-copilot.sensitive-word.path:classpath:sensitive-word.txt}") - String sensitiveWordPath; + @Value("\${maa-copilot.sensitive-word.path:classpath:sensitive-word.txt}") + private val sensitiveWordPath: String +) { /** - * 敏感词库初始化
- * 使用 Hutool 的 DFA 算法库,如果后续需要可转其他开源库或者使用付费的敏感词库
+ * 敏感词库初始化

+ * 使用 Hutool 的 DFA 算法库,如果后续需要可转其他开源库或者使用付费的敏感词库

* * @return 敏感词库 */ - @Bean - public WordTree sensitiveWordInit(ApplicationContext applicationContext) throws IOException { + @Throws(IOException::class) + fun sensitiveWordInit(applicationContext: ApplicationContext): WordTree { // Spring 上下文获取敏感词文件 - Resource sensitiveWordResource = applicationContext.getResource(sensitiveWordPath); - WordTree wordTree = new WordTree(); + val sensitiveWordResource = applicationContext.getResource(sensitiveWordPath) + val wordTree = WordTree() // 获取载入用时 - long start = System.currentTimeMillis(); + val start = System.currentTimeMillis() // 以行为单位载入敏感词 - try (BufferedReader bufferedReader = new BufferedReader( - new InputStreamReader(sensitiveWordResource.getInputStream())) - ) { - String line; - while ((line = bufferedReader.readLine()) != null) { - wordTree.addWord(line); + try { + BufferedReader( + InputStreamReader(sensitiveWordResource.inputStream) + ).use { bufferedReader -> + var line: String? + while ((bufferedReader.readLine().also { line = it }) != null) { + wordTree.addWord(line) + } } - } catch (Exception e) { - log.error("敏感词库初始化失败:{}", e.getMessage()); - throw e; + } catch (e: Exception) { + log.error { "敏感词库初始化失败:${e.message}" } + throw e } - log.info("敏感词库初始化完成,耗时 {} ms", System.currentTimeMillis() - start); + log.info { "敏感词库初始化完成,耗时 ${System.currentTimeMillis() - start} ms" } - return wordTree; + return wordTree } } diff --git a/src/main/java/plus/maa/backend/config/ThreadPoolConfig.kt b/src/main/java/plus/maa/backend/config/ThreadPoolConfig.kt index 30d82135..4c9dbb7a 100644 --- a/src/main/java/plus/maa/backend/config/ThreadPoolConfig.kt +++ b/src/main/java/plus/maa/backend/config/ThreadPoolConfig.kt @@ -1,35 +1,32 @@ -package plus.maa.backend.config; +package plus.maa.backend.config -import org.springframework.boot.task.TaskExecutorBuilder; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Lazy; -import org.springframework.context.annotation.Primary; -import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor; -import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; - -import static org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME; +import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration +import org.springframework.boot.task.TaskExecutorBuilder +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Lazy +import org.springframework.context.annotation.Primary +import org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor @Configuration(proxyBeanMethods = false) -public class ThreadPoolConfig { - +class ThreadPoolConfig { @Lazy @Primary - @Bean(name = {APPLICATION_TASK_EXECUTOR_BEAN_NAME, - AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME}) - public ThreadPoolTaskExecutor defaultTaskExecutor(TaskExecutorBuilder builder) { - return builder.build(); - } + @Bean( + name = [TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME, AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME] + ) + fun defaultTaskExecutor(builder: TaskExecutorBuilder): ThreadPoolTaskExecutor = builder.build() @Bean - public ThreadPoolTaskExecutor emailTaskExecutor() { + fun emailTaskExecutor(): ThreadPoolTaskExecutor { // 在默认线程池配置的基础上修改了核心线程数和线程名称 - var taskExecutor = new ThreadPoolTaskExecutor(); + val taskExecutor = ThreadPoolTaskExecutor() // I/O 密集型配置 - taskExecutor.setCorePoolSize(Runtime.getRuntime().availableProcessors() * 2); - taskExecutor.setThreadNamePrefix("email-task-"); + taskExecutor.corePoolSize = Runtime.getRuntime().availableProcessors() * 2 + taskExecutor.threadNamePrefix = "email-task-" // 动态的核心线程数量 - taskExecutor.setAllowCoreThreadTimeOut(true); - return taskExecutor; + taskExecutor.setAllowCoreThreadTimeOut(true) + return taskExecutor } } diff --git a/src/main/java/plus/maa/backend/config/doc/RequireJwt.kt b/src/main/java/plus/maa/backend/config/doc/RequireJwt.kt index ea8626bb..1384f4c1 100644 --- a/src/main/java/plus/maa/backend/config/doc/RequireJwt.kt +++ b/src/main/java/plus/maa/backend/config/doc/RequireJwt.kt @@ -1,15 +1,21 @@ -package plus.maa.backend.config.doc; +package plus.maa.backend.config.doc -import io.swagger.v3.oas.annotations.security.SecurityRequirement; - -import java.lang.annotation.*; +import io.swagger.v3.oas.annotations.security.SecurityRequirement +import java.lang.annotation.Inherited /** * 指示需要 Jwt 认证 */ -@Target({ElementType.METHOD, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) -@Retention(RetentionPolicy.RUNTIME) +@Target( + AnnotationTarget.FUNCTION, + AnnotationTarget.PROPERTY_GETTER, + AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.CLASS, + AnnotationTarget.ANNOTATION_CLASS +) +@Retention( + AnnotationRetention.RUNTIME +) @Inherited @SecurityRequirement(name = SpringDocConfig.SECURITY_SCHEME_JWT) -public @interface RequireJwt { -} +annotation class RequireJwt diff --git a/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.kt b/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.kt index bb3d9ccc..186d47d8 100644 --- a/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.kt +++ b/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.kt @@ -1,99 +1,98 @@ -package plus.maa.backend.config.doc; +package plus.maa.backend.config.doc -import com.fasterxml.jackson.databind.ObjectMapper; -import io.swagger.v3.core.jackson.ModelResolver; -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.ExternalDocumentation; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.info.License; -import io.swagger.v3.oas.models.security.SecurityRequirement; -import io.swagger.v3.oas.models.security.SecurityScheme; -import org.springdoc.core.customizers.OperationCustomizer; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.core.MethodParameter; -import plus.maa.backend.common.annotation.CurrentUser; - -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import com.fasterxml.jackson.databind.ObjectMapper +import io.swagger.v3.core.jackson.ModelResolver +import io.swagger.v3.oas.models.Components +import io.swagger.v3.oas.models.ExternalDocumentation +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.Operation +import io.swagger.v3.oas.models.info.Info +import io.swagger.v3.oas.models.info.License +import io.swagger.v3.oas.models.security.SecurityRequirement +import io.swagger.v3.oas.models.security.SecurityScheme +import org.springdoc.core.customizers.OperationCustomizer +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.web.method.HandlerMethod +import plus.maa.backend.common.annotation.CurrentUser /** * @author AnselYuki */ @Configuration -public class SpringDocConfig { - - @Value("${maa-copilot.info.version}") - private String version; - - @Value("${maa-copilot.info.title}") - private String title; - - @Value("${maa-copilot.info.description}") - private String description; - - @Value("${maa-copilot.jwt.header}") - private String securitySchemeHeader; - - public static final String SECURITY_SCHEME_JWT = "Jwt"; +class SpringDocConfig( + @Value("\${maa-copilot.info.version}") + private val version: String, + @Value("\${maa-copilot.info.title}") + private val title: String, + @Value("\${maa-copilot.info.description}") + private val description: String, + @Value("\${maa-copilot.jwt.header}") + private val securitySchemeHeader: String +) { @Bean - public OpenAPI emergencyLogistics() { - return new OpenAPI() - .info(docInfos()) - .externalDocs(new ExternalDocumentation() - .description("GitHub repo") - .url("https://github.com/MaaAssistantArknights/MaaBackendCenter")) - .components(new Components() - .addSecuritySchemes(SECURITY_SCHEME_JWT, - new SecurityScheme() - .type(SecurityScheme.Type.HTTP) - .scheme("bearer") - .in(SecurityScheme.In.HEADER) - .name(securitySchemeHeader) - .description("JWT Authorization header using the Bearer scheme. Raw head example: \"%s: Bearer {token}\"".formatted(securitySchemeHeader)) - )); + fun emergencyLogistics(): OpenAPI { + return OpenAPI() + .info(docInfos()) + .externalDocs( + ExternalDocumentation() + .description("GitHub repo") + .url("https://github.com/MaaAssistantArknights/MaaBackendCenter") + ) + .components( + Components() + .addSecuritySchemes( + SECURITY_SCHEME_JWT, + SecurityScheme() + .type(SecurityScheme.Type.HTTP) + .scheme("bearer") + .`in`(SecurityScheme.In.HEADER) + .name(securitySchemeHeader) + .description( + "JWT Authorization header using the Bearer scheme. Raw head example: \"$securitySchemeHeader: Bearer {token}\"" + ) + ) + ) } /** - * 为使用了 {@link CurrentUser} 注解的接口在 OpenAPI 上添加 security scheme + * 为使用了 [CurrentUser] 注解的接口在 OpenAPI 上添加 security scheme */ @Bean - public OperationCustomizer currentUserOperationCustomizer() { - return (operation, handlerMethod) -> { - for (MethodParameter parameter : handlerMethod.getMethodParameters()) { - if (parameter.hasParameterAnnotation(CurrentUser.class)) { - var security = Optional.ofNullable(operation.getSecurity()); + fun currentUserOperationCustomizer(): OperationCustomizer { + return OperationCustomizer { operation: Operation, handlerMethod: HandlerMethod -> + for (parameter in handlerMethod.methodParameters) { + if (parameter.hasParameterAnnotation(CurrentUser::class.java)) { // 已有 security scheme - if (security.stream().flatMap(List::stream).anyMatch(s -> s.containsKey(SECURITY_SCHEME_JWT))) { - break; + if (operation.security.any { it.containsKey(SECURITY_SCHEME_JWT) }) { + break } // 添加 security scheme - operation.setSecurity(security.orElseGet(ArrayList::new)); - operation.getSecurity().add(new SecurityRequirement().addList(SECURITY_SCHEME_JWT)); - break; + operation.security.add(SecurityRequirement().addList(SECURITY_SCHEME_JWT)) + break } } - return operation; - }; + operation + } } - private Info docInfos() { - return new Info() - .title(title) - .description(description) - .version(version) - .license(new License() - .name("GNU Affero General Public License v3.0") - .url("https://www.gnu.org/licenses/agpl-3.0.html")); - } + private fun docInfos() = Info() + .title(title) + .description(description) + .version(version) + .license( + License() + .name("GNU Affero General Public License v3.0") + .url("https://www.gnu.org/licenses/agpl-3.0.html") + ) @Bean - public ModelResolver modelResolver(ObjectMapper objectMapper) { - return new ModelResolver(objectMapper); + fun modelResolver(objectMapper: ObjectMapper?) = ModelResolver(objectMapper) + + companion object { + const val SECURITY_SCHEME_JWT: String = "Jwt" } } diff --git a/src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt b/src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt index 0d30ceab..b5ef49ef 100644 --- a/src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt +++ b/src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt @@ -1,51 +1,47 @@ -package plus.maa.backend.config.security; +package plus.maa.backend.config.security -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.jetbrains.annotations.NotNull; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.service.jwt.JwtService; - -import java.io.IOException; +import jakarta.servlet.FilterChain +import jakarta.servlet.ServletException +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.security.core.context.SecurityContextHolder +import org.springframework.stereotype.Component +import org.springframework.web.filter.OncePerRequestFilter +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.service.jwt.JwtService +import java.io.IOException /** * @author AnselYuki */ @Component -public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { - public JwtAuthenticationTokenFilter(AuthenticationHelper helper, MaaCopilotProperties properties, JwtService jwtService) { - this.helper = helper; - this.properties = properties; - this.jwtService = jwtService; - } - - private final AuthenticationHelper helper; - private final MaaCopilotProperties properties; - private final JwtService jwtService; - - @Override - protected void doFilterInternal(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws IOException, ServletException { +class JwtAuthenticationTokenFilter( + private val helper: AuthenticationHelper, + private val properties: MaaCopilotProperties, + private val jwtService: JwtService +) : OncePerRequestFilter() { + @Throws(IOException::class, ServletException::class) + override fun doFilterInternal( + request: HttpServletRequest, + response: HttpServletResponse, + filterChain: FilterChain + ) { try { - var token = extractToken(request); - var authToken = jwtService.verifyAndParseAuthToken(token); - helper.setAuthentication(authToken); - } catch (Exception ex) { - logger.trace(ex.getMessage()); + val token = extractToken(request) + val authToken = jwtService.verifyAndParseAuthToken(token) + helper.setAuthentication(authToken) + } catch (ex: Exception) { + logger.trace(ex.message) } finally { - filterChain.doFilter(request, response); + filterChain.doFilter(request, response) } } - @NotNull - private String extractToken(HttpServletRequest request) throws Exception { - if (SecurityContextHolder.getContext().getAuthentication() != null) throw new Exception("no need to auth"); - var head = request.getHeader(properties.getJwt().getHeader()); - if (head == null || !head.startsWith("Bearer ")) throw new Exception("token not found"); - return head.substring(7); + @Throws(Exception::class) + private fun extractToken(request: HttpServletRequest): String { + if (SecurityContextHolder.getContext().authentication != null) throw Exception("no need to auth") + val head = request.getHeader(properties.jwt.header) + if (head == null || !head.startsWith("Bearer ")) throw Exception("token not found") + return head.substring(7) } } diff --git a/src/main/java/plus/maa/backend/config/security/SecurityConfig.kt b/src/main/java/plus/maa/backend/config/security/SecurityConfig.kt index 43466348..84ec20b8 100644 --- a/src/main/java/plus/maa/backend/config/security/SecurityConfig.kt +++ b/src/main/java/plus/maa/backend/config/security/SecurityConfig.kt @@ -1,35 +1,83 @@ -package plus.maa.backend.config.security; +package plus.maa.backend.config.security -import lombok.RequiredArgsConstructor; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; -import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; - -import static org.springframework.security.config.Customizer.withDefaults; +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.authentication.AuthenticationManager +import org.springframework.security.config.Customizer +import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration +import org.springframework.security.config.annotation.web.builders.HttpSecurity +import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer +import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer +import org.springframework.security.config.annotation.web.configurers.SessionManagementConfigurer +import org.springframework.security.config.http.SessionCreationPolicy +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder +import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter /** * @author AnselYuki */ @Configuration -@RequiredArgsConstructor -public class SecurityConfig { - /** - * 添加放行接口在此处 - */ - private static final String[] URL_WHITELIST = { +class SecurityConfig( + private val authenticationConfiguration: AuthenticationConfiguration, + private val jwtAuthenticationTokenFilter: JwtAuthenticationTokenFilter, + private val authenticationEntryPoint: AuthenticationEntryPointImpl, + private val accessDeniedHandler: AccessDeniedHandlerImpl +) { + + @Bean + fun passwordEncoder() = BCryptPasswordEncoder() + + @Bean + @Throws(Exception::class) + fun authenticationManager(): AuthenticationManager = authenticationConfiguration.authenticationManager + + @Bean + @Throws(Exception::class) + fun filterChain(http: HttpSecurity): SecurityFilterChain { + //关闭CSRF,设置无状态连接 + http.csrf { obj: CsrfConfigurer -> obj.disable() } //不通过Session获取SecurityContext + .sessionManagement { sessionManagement: SessionManagementConfigurer -> + sessionManagement.sessionCreationPolicy( + SessionCreationPolicy.STATELESS + ) + } + + //允许匿名访问的接口,如果是测试想要方便点就把这段全注释掉 + http.authorizeHttpRequests { authorize -> + authorize.requestMatchers(*URL_WHITELIST).anonymous() + .requestMatchers(*URL_PERMIT_ALL).permitAll() //权限 0 未激活 1 激活 等等.. (拥有权限1必然拥有权限0 拥有权限2必然拥有权限1、0) + //指定接口需要指定权限才能访问 如果不开启RBAC注释掉这一段即可 + .requestMatchers(*URL_AUTHENTICATION_1).hasAuthority("1") //此处用于管理员操作接口 + .requestMatchers(*URL_AUTHENTICATION_2).hasAuthority("2") + .anyRequest().authenticated() + } + //添加过滤器 + http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter::class.java) + + //配置异常处理器,处理认证失败的JSON响应 + http.exceptionHandling { exceptionHandling: ExceptionHandlingConfigurer -> + exceptionHandling.authenticationEntryPoint( + authenticationEntryPoint + ).accessDeniedHandler(accessDeniedHandler) + } + + //开启跨域请求 + http.cors(Customizer.withDefaults()) + return http.build() + } + + companion object { + /** + * 添加放行接口在此处 + */ + private val URL_WHITELIST = arrayOf( "/user/login", "/user/register", "/user/sendRegistrationToken" - }; + ) - private static final String[] URL_PERMIT_ALL = { + private val URL_PERMIT_ALL = arrayOf( "/", "/error", "/version", @@ -50,64 +98,23 @@ public class SecurityConfig { "/file/upload", "/comments/status", "/copilot/status" - }; + ) - //添加需要权限1才能访问的接口 - private static final String[] URL_AUTHENTICATION_1 = { + //添加需要权限1才能访问的接口 + private val URL_AUTHENTICATION_1 = arrayOf( "/copilot/delete", "/copilot/update", "/copilot/upload", "/comments/add", "/comments/delete" - }; + ) - private static final String[] URL_AUTHENTICATION_2 = { + private val URL_AUTHENTICATION_2 = arrayOf( "/file/download/**", "/file/download/", "/file/disable", "/file/enable", "/file/upload_ability" - }; - private final AuthenticationConfiguration authenticationConfiguration; - private final JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; - private final AuthenticationEntryPointImpl authenticationEntryPoint; - private final AccessDeniedHandlerImpl accessDeniedHandler; - - @Bean - public BCryptPasswordEncoder passwordEncoder() { - return new BCryptPasswordEncoder(); - } - - @Bean - public AuthenticationManager authenticationManager() throws Exception { - return authenticationConfiguration.getAuthenticationManager(); - } - - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - //关闭CSRF,设置无状态连接 - http.csrf(AbstractHttpConfigurer::disable) - //不通过Session获取SecurityContext - .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); - - //允许匿名访问的接口,如果是测试想要方便点就把这段全注释掉 - http.authorizeHttpRequests(authorize -> - authorize.requestMatchers(URL_WHITELIST).anonymous() - .requestMatchers(URL_PERMIT_ALL).permitAll() - //权限 0 未激活 1 激活 等等.. (拥有权限1必然拥有权限0 拥有权限2必然拥有权限1、0) - //指定接口需要指定权限才能访问 如果不开启RBAC注释掉这一段即可 - .requestMatchers(URL_AUTHENTICATION_1).hasAuthority("1") - //此处用于管理员操作接口 - .requestMatchers(URL_AUTHENTICATION_2).hasAuthority("2") - .anyRequest().authenticated()); - //添加过滤器 - http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); - - //配置异常处理器,处理认证失败的JSON响应 - http.exceptionHandling(exceptionHandling -> exceptionHandling.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler)); - - //开启跨域请求 - http.cors(withDefaults()); - return http.build(); + ) } } diff --git a/src/main/java/plus/maa/backend/filter/package-info.java b/src/main/java/plus/maa/backend/filter/package-info.java deleted file mode 100644 index 19141fe0..00000000 --- a/src/main/java/plus/maa/backend/filter/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -@NonNullApi -package plus.maa.backend.filter; - -import org.springframework.lang.NonNullApi; \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt b/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt index 199954ab..dedb5a66 100644 --- a/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt +++ b/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt @@ -32,7 +32,7 @@ class ArkLevelParserService(private val parsers: List) { .name(tilePos.name) .width(tilePos.width) .height(tilePos.height) - .build(); + .build() return parseLevel(level, tilePos) } @@ -42,10 +42,7 @@ class ArkLevelParserService(private val parsers: List) { log.warn { "[PARSER]未知关卡类型:${level.levelId}" } return null } - val parser = parsers.stream() - .filter { p: ArkLevelParser? -> p!!.supportType(type) } - .findFirst() - .orElse(null) + val parser = parsers.firstOrNull { it.supportType(type) } if (parser == null) { //类型存在但无对应Parser直接跳过 return ArkLevel.EMPTY From 47d99c99d0899b80c3e8d62643475d17a9875dca Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 19:05:48 +0800 Subject: [PATCH 097/168] Rename .java to .kt --- .../controller/file/{FileController.java => FileController.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/file/{FileController.java => FileController.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/file/FileController.java b/src/main/java/plus/maa/backend/controller/file/FileController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/file/FileController.java rename to src/main/java/plus/maa/backend/controller/file/FileController.kt From 9228152a45eb20758b27534000303060a74b5165 Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 19:05:49 +0800 Subject: [PATCH 098/168] refactor: FileController in kotlin --- .../backend/controller/file/FileController.kt | 122 +++++++++--------- .../plus/maa/backend/service/FileService.kt | 2 +- 2 files changed, 61 insertions(+), 63 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/file/FileController.kt b/src/main/java/plus/maa/backend/controller/file/FileController.kt index 6b20d577..125cffa0 100644 --- a/src/main/java/plus/maa/backend/controller/file/FileController.kt +++ b/src/main/java/plus/maa/backend/controller/file/FileController.kt @@ -1,35 +1,34 @@ -package plus.maa.backend.controller.file; +package plus.maa.backend.controller.file +import io.swagger.v3.oas.annotations.Operation +import io.swagger.v3.oas.annotations.Parameter +import io.swagger.v3.oas.annotations.media.Content +import io.swagger.v3.oas.annotations.media.Schema +import io.swagger.v3.oas.annotations.responses.ApiResponse +import jakarta.servlet.http.HttpServletResponse +import jakarta.validation.Valid +import org.springframework.http.MediaType +import org.springframework.web.bind.annotation.* +import org.springframework.web.multipart.MultipartFile +import plus.maa.backend.common.annotation.AccessLimit +import plus.maa.backend.config.doc.RequireJwt +import plus.maa.backend.config.security.AuthenticationHelper +import plus.maa.backend.controller.response.MaaResult +import plus.maa.backend.controller.response.MaaResult.Companion.fail +import plus.maa.backend.controller.response.MaaResult.Companion.success +import plus.maa.backend.service.FileService -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Content; -import io.swagger.v3.oas.annotations.media.Schema; -import io.swagger.v3.oas.annotations.responses.ApiResponse; -import jakarta.servlet.http.HttpServletResponse; -import jakarta.validation.Valid; -import lombok.RequiredArgsConstructor; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; -import plus.maa.backend.common.annotation.AccessLimit; -import plus.maa.backend.config.doc.RequireJwt; -import plus.maa.backend.config.security.AuthenticationHelper; -import plus.maa.backend.controller.response.MaaResult; -import plus.maa.backend.service.FileService; /** * @author LoMu * Date 2023-03-31 16:41 */ - @RestController @RequestMapping("file") -@RequiredArgsConstructor -public class FileController { - private final FileService fileService; - private final AuthenticationHelper helper; - +class FileController( + private val fileService: FileService, + private val helper: AuthenticationHelper +) { /** * 支持匿名 * @@ -37,81 +36,80 @@ public class FileController { * @return 上传成功, 数据已被接收 */ @AccessLimit - @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public MaaResult uploadFile( - @RequestPart MultipartFile file, - @RequestPart String type, - @RequestPart String version, - @RequestPart(required = false) String classification, - @RequestPart(required = false) String label - ) { - fileService.uploadFile(file, type, version, classification, label, helper.getUserIdOrIpAddress()); - return MaaResult.success("上传成功,数据已被接收"); + @PostMapping(value = ["/upload"], consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) + fun uploadFile( + @RequestPart file: MultipartFile, + @RequestPart type: String?, + @RequestPart version: String, + @RequestPart(required = false) classification: String?, + @RequestPart(required = false) label: String + ): MaaResult { + fileService.uploadFile(file, type, version, classification, label, helper.userIdOrIpAddress) + return success("上传成功,数据已被接收") } @Operation(summary = "下载文件") @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/zip", schema = @Schema(type = "string", format = "binary")) + responseCode = "200", + content = [Content(mediaType = "application/zip", schema = Schema(type = "string", format = "binary"))] ) @RequireJwt @AccessLimit @GetMapping("/download") - public void downloadSpecifiedDateFile( - @Parameter(description = "日期 yyyy-MM-dd") String date, - @Parameter(description = "在日期之前或之后[before,after]") String beLocated, - @Parameter(description = "对查询到的数据进行删除") boolean delete, - HttpServletResponse response + fun downloadSpecifiedDateFile( + @Parameter(description = "日期 yyyy-MM-dd") date: String?, + @Parameter(description = "在日期之前或之后[before,after]") beLocated: String, + @Parameter(description = "对查询到的数据进行删除") delete: Boolean, + response: HttpServletResponse ) { - fileService.downloadDateFile(date, beLocated, delete, response); + fileService.downloadDateFile(date, beLocated, delete, response) } @Operation(summary = "下载文件") @ApiResponse( - responseCode = "200", - content = @Content(mediaType = "application/zip", schema = @Schema(type = "string", format = "binary")) + responseCode = "200", + content = [Content(mediaType = "application/zip", schema = Schema(type = "string", format = "binary"))] ) @RequireJwt @PostMapping("/download") - public void downloadFile(@RequestBody @Valid - ImageDownloadDTO imageDownloadDTO, - HttpServletResponse response) { - fileService.downloadFile(imageDownloadDTO, response); + fun downloadFile( + @RequestBody imageDownloadDTO: @Valid ImageDownloadDTO, + response: HttpServletResponse + ) { + fileService.downloadFile(imageDownloadDTO, response) } @Operation(summary = "设置上传文件功能状态") @RequireJwt @PostMapping("/upload_ability") - public MaaResult setUploadAbility(@RequestBody UploadAbility request) { - fileService.setUploadEnabled(request.enabled); - return MaaResult.success(); + fun setUploadAbility(@RequestBody request: UploadAbility): MaaResult { + fileService.isUploadEnabled = request.enabled + return success() } - @Operation(summary = "获取上传文件功能状态") - @RequireJwt @GetMapping("/upload_ability") - public MaaResult getUploadAbility() { - return MaaResult.success(new UploadAbility(fileService.isUploadEnabled())); + @RequireJwt + @Operation(summary = "获取上传文件功能状态") + fun getUploadAbility(): MaaResult { + return success(UploadAbility(fileService.isUploadEnabled)) } - @Operation(summary = "关闭uploadfile接口") @RequireJwt @PostMapping("/disable") - public MaaResult disable(@RequestBody boolean status) { + fun disable(@RequestBody status: Boolean): MaaResult { if (!status) { - return MaaResult.fail(403, "Forbidden"); + return fail(403, "Forbidden") } - return MaaResult.success(fileService.disable()); + return success(fileService.disable()) } @Operation(summary = "开启uploadfile接口") @RequireJwt @PostMapping("/enable") - public MaaResult enable(@RequestBody boolean status) { + fun enable(@RequestBody status: Boolean): MaaResult { if (!status) { - return MaaResult.fail(403, "Forbidden"); + return fail(403, "Forbidden") } - return MaaResult.success(fileService.enable()); + return success(fileService.enable()) } - } diff --git a/src/main/java/plus/maa/backend/service/FileService.kt b/src/main/java/plus/maa/backend/service/FileService.kt index 201e4204..d7190444 100644 --- a/src/main/java/plus/maa/backend/service/FileService.kt +++ b/src/main/java/plus/maa/backend/service/FileService.kt @@ -91,7 +91,7 @@ class FileService( val formatter = SimpleDateFormat("yyyy-MM-dd") val query: Query - val d = if (StringUtils.isBlank(date)) { + val d = if (date.isNullOrBlank()) { Date(System.currentTimeMillis()) } else { try { From 3c6ffa4cdba0980d3c91c2ce788ed19739e7750c Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 19:16:32 +0800 Subject: [PATCH 099/168] fix: rollback CopilotSetType --- .../backend/common/model/CopilotSetType.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 src/main/java/plus/maa/backend/common/model/CopilotSetType.java diff --git a/src/main/java/plus/maa/backend/common/model/CopilotSetType.java b/src/main/java/plus/maa/backend/common/model/CopilotSetType.java new file mode 100644 index 00000000..70300cb6 --- /dev/null +++ b/src/main/java/plus/maa/backend/common/model/CopilotSetType.java @@ -0,0 +1,29 @@ +package plus.maa.backend.common.model; + +import org.springframework.util.Assert; + +import java.util.Collections; +import java.util.List; + +/** + * @author dragove + * create on 2024-01-01 + */ +public interface CopilotSetType { + + List getCopilotIds(); + + default List getDistinctIdsAndCheck() { + List copilotIds = getCopilotIds(); + if (copilotIds == null) { + return Collections.emptyList(); + } + if (copilotIds.isEmpty() || copilotIds.size() == 1) { + return getCopilotIds(); + } + copilotIds = copilotIds.stream().distinct().toList(); + Assert.state(copilotIds.size() <= 1000, "作业集总作业数量不能超过1000条"); + return copilotIds; + } + +} From 9adfbe000c2b1db550751b93bfe715013bf3e3cb Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Thu, 8 Feb 2024 19:16:38 +0800 Subject: [PATCH 100/168] fix: rollback CopilotSetType --- .../backend/common/model/CopilotSetType.kt | 22 ------------------- .../maa/backend/service/CopilotSetService.kt | 2 +- 2 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 src/main/java/plus/maa/backend/common/model/CopilotSetType.kt diff --git a/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt b/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt deleted file mode 100644 index 327bdcb2..00000000 --- a/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt +++ /dev/null @@ -1,22 +0,0 @@ -package plus.maa.backend.common.model - -import org.springframework.util.Assert - -/** - * @author dragove - * create on 2024-01-01 - */ -interface CopilotSetType { - val copilotIds: List? - - val distinctIdsAndCheck: List? - get() { - var copilotIds = copilotIds ?: return emptyList() - if (copilotIds.isEmpty() || copilotIds.size == 1) { - return this.copilotIds - } - copilotIds = copilotIds.distinct().toList() - Assert.state(copilotIds.size <= 1000, "作业集总作业数量不能超过1000条") - return copilotIds - } -} diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.kt b/src/main/java/plus/maa/backend/service/CopilotSetService.kt index 4e825c7a..82607172 100644 --- a/src/main/java/plus/maa/backend/service/CopilotSetService.kt +++ b/src/main/java/plus/maa/backend/service/CopilotSetService.kt @@ -58,7 +58,7 @@ class CopilotSetService( .orElseThrow { IllegalArgumentException("作业集不存在") } Assert.state(copilotSet.creatorId == userId, "您不是该作业集的创建者,无权修改该作业集") copilotSet.copilotIds.addAll(req.copilotIds) - copilotSet.setCopilotIds(copilotSet.distinctIdsAndCheck) + copilotSet.setCopilotIds(copilotSet.getDistinctIdsAndCheck()) repository.save(copilotSet) } From e647515cc18266da573c8ad0785571809e0a1a88 Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 00:40:28 +0800 Subject: [PATCH 101/168] Rename .java to .kt --- .../common/utils/{ArkLevelUtilTest.java => ArkLevelUtilTest.kt} | 0 ...onTokenFilterTest.java => JwtAuthenticationTokenFilterTest.kt} | 0 .../{GithubRepositoryTest.java => GithubRepositoryTest.kt} | 0 .../service/{CopilotServiceTest.java => CopilotServiceTest.kt} | 0 .../service/jwt/{JwtServiceTest.java => JwtServiceTest.kt} | 0 ...otScoreRefreshTaskTest.java => CopilotScoreRefreshTaskTest.kt} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/test/java/plus/maa/backend/common/utils/{ArkLevelUtilTest.java => ArkLevelUtilTest.kt} (100%) rename src/test/java/plus/maa/backend/config/security/{JwtAuthenticationTokenFilterTest.java => JwtAuthenticationTokenFilterTest.kt} (100%) rename src/test/java/plus/maa/backend/repository/{GithubRepositoryTest.java => GithubRepositoryTest.kt} (100%) rename src/test/java/plus/maa/backend/service/{CopilotServiceTest.java => CopilotServiceTest.kt} (100%) rename src/test/java/plus/maa/backend/service/jwt/{JwtServiceTest.java => JwtServiceTest.kt} (100%) rename src/test/java/plus/maa/backend/task/{CopilotScoreRefreshTaskTest.java => CopilotScoreRefreshTaskTest.kt} (100%) diff --git a/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java b/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.java rename to src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.kt diff --git a/src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.java b/src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.java rename to src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt diff --git a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java b/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/repository/GithubRepositoryTest.java rename to src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt diff --git a/src/test/java/plus/maa/backend/service/CopilotServiceTest.java b/src/test/java/plus/maa/backend/service/CopilotServiceTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/service/CopilotServiceTest.java rename to src/test/java/plus/maa/backend/service/CopilotServiceTest.kt diff --git a/src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.java b/src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.java rename to src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.kt diff --git a/src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.java b/src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.java rename to src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt From fd0648a05dc3df658749568ffd5732d59c0603aa Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 00:40:28 +0800 Subject: [PATCH 102/168] =?UTF-8?q?refactor:=20=E5=B0=86=E6=89=80=E6=9C=89?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95=E8=BF=81=E7=A7=BB=E5=88=B0?= =?UTF-8?q?kt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 3 +- .../java/plus/maa/backend/BaseMockTest.java | 23 -- .../backend/common/utils/ArkLevelUtilTest.kt | 78 +++---- .../JwtAuthenticationTokenFilterTest.kt | 62 +++--- .../repository/GithubRepositoryTest.kt | 43 ++-- .../maa/backend/service/CopilotServiceTest.kt | 101 +++++---- .../maa/backend/service/jwt/JwtServiceTest.kt | 91 ++++---- .../task/CopilotScoreRefreshTaskTest.kt | 204 ++++++++++-------- 8 files changed, 289 insertions(+), 316 deletions(-) delete mode 100644 src/test/java/plus/maa/backend/BaseMockTest.java diff --git a/build.gradle b/build.gradle index e7c34fdc..bbc690e3 100644 --- a/build.gradle +++ b/build.gradle @@ -36,7 +36,8 @@ dependencies { kapt 'org.springframework.boot:spring-boot-configuration-processor' - implementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'io.mockk:mockk:1.13.9' + testImplementation 'org.springframework.boot:spring-boot-starter-test' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'org.springframework.boot:spring-boot-starter-security' diff --git a/src/test/java/plus/maa/backend/BaseMockTest.java b/src/test/java/plus/maa/backend/BaseMockTest.java deleted file mode 100644 index a9588fd1..00000000 --- a/src/test/java/plus/maa/backend/BaseMockTest.java +++ /dev/null @@ -1,23 +0,0 @@ -package plus.maa.backend; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.TestInstance; -import org.mockito.MockitoAnnotations; - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -public class BaseMockTest { - - AutoCloseable closeable; - - @BeforeAll - void initTest() { - this.closeable = MockitoAnnotations.openMocks(this); - } - - @AfterAll - void endTest() throws Exception { - this.closeable.close(); - } - -} diff --git a/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.kt b/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.kt index 381746f5..298ca850 100644 --- a/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.kt +++ b/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.kt @@ -1,52 +1,40 @@ -package plus.maa.backend.common.utils; +package plus.maa.backend.common.utils -import org.junit.jupiter.api.Test; - -import java.util.Map; - -import static java.util.Map.entry; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static plus.maa.backend.common.utils.ArkLevelUtil.getKeyInfoById; +import org.junit.jupiter.api.Test class ArkLevelUtilTest { - @Test - void testGetKeyInfoById() { - - var ids = Map.ofEntries( - entry("level_rune_09-01", "level_rune_09-02"), - entry("level_crisis_v2_01-07", "crisis_v2_season_1_1"), - entry("a001_01_perm", "a001_ex05"), - entry("act11d0_ex08#f#", "act11d0_s02"), - entry("act11mini_03#f#", "act11mini_04"), - entry("act17side_01", "act17side_s01_a"), - entry("act17side_01_rep", "act17side_02_perm") - ); - - var idsWithInfo = Map.ofEntries( - entry("level_rune_09-01", "rune_9"), - entry("level_crisis_v2_01-07", "crisis_v2_1"), - entry("a001_01_perm", "a1"), - entry("act11d0_ex08#f#", "act11d0"), - entry("act11mini_03#f#", "act11mini"), - entry("act17side_01", "act17side"), - entry("act17side_01_rep", "act17side") - ); - - for (var entity : ids.entrySet()) { - var key = entity.getKey(); - var value = entity.getValue(); - var infoOfKey = getKeyInfoById(key); - assertEquals( - infoOfKey, getKeyInfoById(value), - () -> key + " 与 " + value + " 的地图标识不相同" - ); - - var infoOfMap = idsWithInfo.get(key); - assertEquals( - infoOfKey, infoOfMap, - () -> key + " 的地图标识不为 " + infoOfMap - ); + fun testGetKeyInfoById() { + val ids = mapOf( + "level_rune_09-01" to "level_rune_09-02", + "level_crisis_v2_01-07" to "crisis_v2_season_1_1", + "a001_01_perm" to "a001_ex05", + "act11d0_ex08#f#" to "act11d0_s02", + "act11mini_03#f#" to "act11mini_04", + "act17side_01" to "act17side_s01_a", + "act17side_01_rep" to "act17side_02_perm" + ) + + val idsWithInfo = mapOf( + "level_rune_09-01" to "rune_9", + "level_crisis_v2_01-07" to "crisis_v2_1", + "a001_01_perm" to "a1", + "act11d0_ex08#f#" to "act11d0", + "act11mini_03#f#" to "act11mini", + "act17side_01" to "act17side", + "act17side_01_rep" to "act17side" + ) + + for ((key, value) in ids) { + val infoOfKey = ArkLevelUtil.getKeyInfoById(key) + check(infoOfKey == ArkLevelUtil.getKeyInfoById(value)) { + "$key 与 $value 的地图标识不相同" + } + + val infoOfMap = idsWithInfo[key] + check(infoOfKey == infoOfMap) { + "$key 的地图标识不为 $infoOfMap" + } } } } \ No newline at end of file diff --git a/src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt b/src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt index 493320c8..0afce177 100644 --- a/src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt +++ b/src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt @@ -1,44 +1,38 @@ -package plus.maa.backend.config.security; +package plus.maa.backend.config.security -import jakarta.servlet.FilterChain; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.security.core.context.SecurityContextHolder; -import plus.maa.backend.config.external.Jwt; -import plus.maa.backend.config.external.MaaCopilotProperties; -import plus.maa.backend.service.jwt.JwtService; +import io.mockk.every +import io.mockk.spyk +import jakarta.servlet.FilterChain +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.junit.jupiter.api.Test +import org.springframework.security.core.context.SecurityContextHolder +import plus.maa.backend.config.external.Jwt +import plus.maa.backend.config.external.MaaCopilotProperties +import plus.maa.backend.service.jwt.JwtService -import java.util.ArrayList; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -@SpringBootTest class JwtAuthenticationTokenFilterTest { - @Test - void testValidToken() { - var properties = new MaaCopilotProperties(); - var jwtSettings = new Jwt(); - jwtSettings.setSecret("whatever you want"); - jwtSettings.setExpire(86400); - properties.setJwt(jwtSettings); + fun testValidToken() { + val properties = MaaCopilotProperties() + val jwtSettings = Jwt() + jwtSettings.secret = "whatever you want" + jwtSettings.expire = 86400 + properties.jwt = jwtSettings - var jwtService = new JwtService(properties); - var userId = "some user id"; - var authToken = jwtService.issueAuthToken(userId, null, new ArrayList<>()); - var jwt = authToken.getValue(); + val jwtService = JwtService(properties) + val userId = "some user id" + val authToken = jwtService.issueAuthToken(userId, null, ArrayList()) + val jwt = authToken.value - var filter = new JwtAuthenticationTokenFilter(new AuthenticationHelper(), properties, jwtService); - var request = mock(HttpServletRequest.class); - when(request.getHeader(properties.getJwt().getHeader())).thenReturn("Bearer " + jwt); - var filterChain = mock(FilterChain.class); + val filter = JwtAuthenticationTokenFilter(AuthenticationHelper(), properties, jwtService) + val request = spyk() + every { request.getHeader(properties.jwt.header) } returns "Bearer $jwt" + val filterChain = spyk() try { - filter.doFilter(request, mock(HttpServletResponse.class), filterChain); - } catch (Exception ignored) { + filter.doFilter(request, spyk(), filterChain) + } catch (ignored: Exception) { } - assert SecurityContextHolder.getContext().getAuthentication() != null; + requireNotNull(SecurityContextHolder.getContext().authentication) } } \ No newline at end of file diff --git a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt b/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt index 30f8012e..b4df27c6 100644 --- a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt +++ b/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt @@ -1,38 +1,29 @@ -package plus.maa.backend.repository; +package plus.maa.backend.repository -import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import plus.maa.backend.config.external.MaaCopilotProperties; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import plus.maa.backend.config.external.MaaCopilotProperties @SpringBootTest -class GithubRepositoryTest { - - @Autowired - private GithubRepository repository; - @Autowired - private MaaCopilotProperties properties; - +class GithubRepositoryTest( + @Autowired val repository: GithubRepository, + @Autowired val properties: MaaCopilotProperties +) { @Test - public void testGetTrees() { - var maaTree = repository.getTrees(properties.getGithub().getToken(), "d989739981db071e80df1c66e473c729b50e8073"); - assertNotNull(maaTree); + fun testGetTrees() { + repository.getTrees(properties.github.token, "d989739981db071e80df1c66e473c729b50e8073") } @Test - public void testGetCommits() { - var commits = repository.getCommits(properties.getGithub().getToken()); - assertNotNull(commits); - assertFalse(commits.isEmpty()); + fun testGetCommits() { + val commits = repository.getCommits(properties.github.token) + check(commits.isNotEmpty()) } @Test - void testGetContents() { - var contents = repository.getContents(properties.getGithub().getToken(),""); - assertNotNull(contents); - assertFalse(contents.isEmpty()); + fun testGetContents() { + val contents = repository.getContents(properties.github.token, "") + check(contents.isNotEmpty()) } } \ No newline at end of file diff --git a/src/test/java/plus/maa/backend/service/CopilotServiceTest.kt b/src/test/java/plus/maa/backend/service/CopilotServiceTest.kt index e64e5517..88423bcd 100644 --- a/src/test/java/plus/maa/backend/service/CopilotServiceTest.kt +++ b/src/test/java/plus/maa/backend/service/CopilotServiceTest.kt @@ -1,73 +1,70 @@ -package plus.maa.backend.service; +package plus.maa.backend.service -import org.junit.jupiter.api.Test; -import plus.maa.backend.repository.entity.Copilot; - -import java.time.LocalDateTime; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class CopilotServiceTest { +import org.junit.jupiter.api.Test +import plus.maa.backend.repository.entity.Copilot +import plus.maa.backend.service.CopilotService.Companion.getHotScore +import java.time.LocalDateTime +class CopilotServiceTest { @Test - void testHotScores() { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime beforeWeek = now.minusDays(8L); - Copilot[] copilots = new Copilot[5]; - long[] lastWeekLikeCounts = new long[5]; - long[] lastWeekDislikeCounts = new long[5]; + fun testHotScores() { + val now = LocalDateTime.now() + val beforeWeek = now.minusDays(8L) + val copilots = arrayOfNulls(5) + val lastWeekLikeCounts = LongArray(5) + val lastWeekDislikeCounts = LongArray(5) // 一月前的作业,评分高,但是只有一条近期好评,浏览量高 - Copilot oldGreat = new Copilot(); - oldGreat.setUploadTime(beforeWeek.minusDays(14)); - oldGreat.setViews(20000L); - copilots[0] = oldGreat; - lastWeekLikeCounts[0] = 1L; - lastWeekDislikeCounts[0] = 0L; + val oldGreat = Copilot() + oldGreat.uploadTime = beforeWeek.minusDays(14) + oldGreat.views = 20000L + copilots[0] = oldGreat + lastWeekLikeCounts[0] = 1L + lastWeekDislikeCounts[0] = 0L // 近期作业,含有差评,但是均为近期评分 - Copilot newGreat = new Copilot(); - newGreat.setUploadTime(now); - newGreat.setViews(1000L); - copilots[1] = newGreat; - lastWeekLikeCounts[1] = 6L; - lastWeekDislikeCounts[1] = 1L; + val newGreat = Copilot() + newGreat.uploadTime = now + newGreat.views = 1000L + copilots[1] = newGreat + lastWeekLikeCounts[1] = 6L + lastWeekDislikeCounts[1] = 1L // 近期作业,差评较多,均为近期评分 - Copilot newBad = new Copilot(); - newBad.setUploadTime(now); - newBad.setViews(500L); - copilots[2] = newBad; - lastWeekLikeCounts[2] = 2L; - lastWeekDislikeCounts[2] = 4L; + val newBad = Copilot() + newBad.uploadTime = now + newBad.views = 500L + copilots[2] = newBad + lastWeekLikeCounts[2] = 2L + lastWeekDislikeCounts[2] = 4L // 一月前的作业,评分高,但是只有一条近期好评,浏览量尚可 - Copilot oldNormal = new Copilot(); - oldNormal.setUploadTime(beforeWeek.minusDays(21L)); - oldNormal.setViews(4000L); - copilots[3] = oldNormal; - lastWeekLikeCounts[3] = 1L; - lastWeekDislikeCounts[3] = 0L; + val oldNormal = Copilot() + oldNormal.uploadTime = beforeWeek.minusDays(21L) + oldNormal.views = 4000L + copilots[3] = oldNormal + lastWeekLikeCounts[3] = 1L + lastWeekDislikeCounts[3] = 0L // 新增作业,暂无评分 - Copilot newEmpty = new Copilot(); - newEmpty.setUploadTime(now); - newEmpty.setViews(100L); - copilots[4] = newEmpty; - lastWeekLikeCounts[4] = 0L; - lastWeekDislikeCounts[4] = 0L; + val newEmpty = Copilot() + newEmpty.uploadTime = now + newEmpty.views = 100L + copilots[4] = newEmpty + lastWeekLikeCounts[4] = 0L + lastWeekDislikeCounts[4] = 0L - for (int i = 0; i < 5; i++) { - copilots[i].setHotScore(CopilotService.getHotScore(copilots[i], lastWeekLikeCounts[i], lastWeekDislikeCounts[i])); + for (i in 0..4) { + copilots[i]!!.hotScore = + getHotScore(copilots[i]!!, lastWeekLikeCounts[i], lastWeekDislikeCounts[i]) } // 近期好评 > 远古好评 > 近期新增 > 近期差评 > 远古一般 - assertTrue(newGreat.getHotScore() > oldGreat.getHotScore()); - assertTrue(newEmpty.getHotScore() > oldGreat.getHotScore()); - assertTrue(oldGreat.getHotScore() > newBad.getHotScore()); - assertTrue(oldNormal.getHotScore() > newBad.getHotScore()); + check(newGreat.hotScore > oldGreat.hotScore) + check(newEmpty.hotScore > oldGreat.hotScore) + check(oldGreat.hotScore > newBad.hotScore) + check(oldNormal.hotScore > newBad.hotScore) } - } diff --git a/src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.kt b/src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.kt index 490c67bc..6f65ed05 100644 --- a/src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.kt +++ b/src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.kt @@ -1,60 +1,61 @@ -package plus.maa.backend.service.jwt; +package plus.maa.backend.service.jwt -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import plus.maa.backend.config.external.Jwt; -import plus.maa.backend.config.external.MaaCopilotProperties; - -import java.util.ArrayList; +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import plus.maa.backend.config.external.Jwt +import plus.maa.backend.config.external.MaaCopilotProperties class JwtServiceTest { + private fun createService(): JwtService { + val properties = MaaCopilotProperties() + val jwtSettings = Jwt() + jwtSettings.secret = "whatever you want" + properties.jwt = jwtSettings - JwtService createService() { - var properties = new MaaCopilotProperties(); - var jwtSettings = new Jwt(); - jwtSettings.setSecret("whatever you want"); - properties.setJwt(jwtSettings); - - return new JwtService(properties); + return JwtService(properties) } @Test - void authTokenCodec() throws JwtExpiredException, JwtInvalidException { - var service = createService(); - var subject = "some user id"; - var jwtId = "some jwt Id"; - - var token = service.issueAuthToken(subject, jwtId, new ArrayList<>()); - var parsedToken = service.verifyAndParseAuthToken(token.getValue()); - - assert subject.equals(parsedToken.getSubject()); - assert jwtId.equals(parsedToken.getJwtId()); - assert parsedToken.isAuthenticated(); + @Throws(JwtExpiredException::class, JwtInvalidException::class) + fun authTokenCodec() { + val service = createService() + val subject = "some user id" + val jwtId = "some jwt Id" + + val token = service.issueAuthToken(subject, jwtId, ArrayList()) + val parsedToken = service.verifyAndParseAuthToken(token.value) + + check(subject == parsedToken.subject) + check(jwtId == parsedToken.jwtId) + check(parsedToken.isAuthenticated) } @Test - void refreshTokenCodec() throws JwtExpiredException, JwtInvalidException { - var service = createService(); - - var subject = "some user id"; - var origin = service.issueRefreshToken(subject, null); - - var parsedToken = service.verifyAndParseRefreshToken(origin.getValue()); - assert subject.equals(parsedToken.getSubject()); - - var newToken = service.newRefreshToken(parsedToken, null); - assert !newToken.getIssuedAt().isBefore(parsedToken.getIssuedAt()); - assert !newToken.getNotBefore().isBefore(parsedToken.getNotBefore()); - assert newToken.getExpiresAt().equals(parsedToken.getExpiresAt()); + @Throws(JwtExpiredException::class, JwtInvalidException::class) + fun refreshTokenCodec() { + val service = createService() + + val subject = "some user id" + val origin = service.issueRefreshToken(subject, null) + + val parsedToken = service.verifyAndParseRefreshToken(origin.value) + check(subject == parsedToken.subject) + val newToken = service.newRefreshToken(parsedToken, null) + check(!newToken.issuedAt.isBefore(parsedToken.issuedAt)) + check(!newToken.notBefore.isBefore(parsedToken.notBefore)) + check(newToken.expiresAt == parsedToken.expiresAt) } @Test - void wrongTypeParseShouldFail() { - var service = createService(); - var authToken = service.issueAuthToken("some user id", null, new ArrayList<>()); - Assertions.assertThrows(JwtInvalidException.class, () -> service.verifyAndParseRefreshToken(authToken.getValue())); - var refreshToken = service.issueRefreshToken("some user id", null); - Assertions.assertThrows(JwtInvalidException.class, () -> service.verifyAndParseAuthToken(refreshToken.getValue())); + fun wrongTypeParseShouldFail() { + val service = createService() + val authToken = service.issueAuthToken("some user id", null, ArrayList()) + assertThrows { + service.verifyAndParseRefreshToken(authToken.value) + } + val refreshToken = service.issueRefreshToken("some user id", null) + assertThrows { + service.verifyAndParseAuthToken(refreshToken.value) + } } - } \ No newline at end of file diff --git a/src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt b/src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt index 3280dafa..e857fe65 100644 --- a/src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt +++ b/src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt @@ -1,108 +1,132 @@ -package plus.maa.backend.task; +package plus.maa.backend.task + +import io.mockk.every +import io.mockk.mockk +import org.bson.Document +import org.junit.jupiter.api.Test +import org.springframework.data.domain.PageImpl +import org.springframework.data.domain.Pageable +import org.springframework.data.mongodb.core.MongoTemplate +import org.springframework.data.mongodb.core.aggregation.AggregationResults +import plus.maa.backend.repository.CopilotRepository +import plus.maa.backend.repository.RedisCache +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.Copilot +import plus.maa.backend.repository.entity.Rating +import plus.maa.backend.service.ArkLevelService +import plus.maa.backend.service.model.RatingCount +import java.time.LocalDateTime +import java.time.temporal.ChronoUnit + +class CopilotScoreRefreshTaskTest { + private val copilotRepository = mockk() + private val mongoTemplate = mockk() + private val redisCache = mockk() + private val arkLevelService = mockk() + private val refreshTask: CopilotScoreRefreshTask = CopilotScoreRefreshTask( + arkLevelService, + redisCache, + copilotRepository, + mongoTemplate + ) -import org.bson.Document; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.aggregation.AggregationResults; -import plus.maa.backend.BaseMockTest; -import plus.maa.backend.repository.CopilotRepository; -import plus.maa.backend.repository.RedisCache; -import plus.maa.backend.repository.entity.Copilot; -import plus.maa.backend.repository.entity.Rating; -import plus.maa.backend.service.model.RatingCount; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Set; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.when; - -public class CopilotScoreRefreshTaskTest extends BaseMockTest { - - @InjectMocks - CopilotScoreRefreshTask refreshTask; - - @Mock - CopilotRepository copilotRepository; - @Mock - MongoTemplate mongoTemplate; - @Mock - RedisCache redisCache; @Test - void testRefreshScores() { - LocalDateTime now = LocalDateTime.now(); - Copilot copilot1 = new Copilot(); - copilot1.setCopilotId(1L); - copilot1.setViews(100L); - copilot1.setUploadTime(now); - Copilot copilot2 = new Copilot(); - copilot2.setCopilotId(2L); - copilot2.setViews(200L); - copilot2.setUploadTime(now); - Copilot copilot3 = new Copilot(); - copilot3.setCopilotId(3L); - copilot3.setViews(200L); - copilot3.setUploadTime(now); + fun testRefreshScores() { + val now = LocalDateTime.now() + val copilot1 = Copilot() + copilot1.copilotId = 1L + copilot1.views = 100L + copilot1.uploadTime = now + copilot1.stageName = "stage1" + val copilot2 = Copilot() + copilot2.copilotId = 2L + copilot2.views = 200L + copilot2.uploadTime = now + copilot2.stageName = "stage2" + val copilot3 = Copilot() + copilot3.copilotId = 3L + copilot3.views = 200L + copilot3.uploadTime = now + copilot3.stageName = "stage3" + val allCopilots = listOf(copilot1, copilot2, copilot3) // 配置copilotRepository - when(copilotRepository.findAllByDeleteIsFalse(any(Pageable.class))) - .thenReturn(new PageImpl<>(List.of(copilot1, copilot2, copilot3))); + every { + copilotRepository.findAllByDeleteIsFalse(any()) + } returns PageImpl(allCopilots) // 配置mongoTemplate - when(mongoTemplate.aggregate(any(), eq(Rating.class), eq(RatingCount.class))) - .thenReturn(new AggregationResults<>(List.of( - new RatingCount("1", 1L), - new RatingCount("2", 0L), - new RatingCount("3", 0L)), new Document())); - - refreshTask.refreshHotScores(); - - assertTrue(copilot1.getHotScore() > 0); - assertTrue(copilot2.getHotScore() > 0); + every { + mongoTemplate.aggregate(any(), Rating::class.java, RatingCount::class.java) + } returns AggregationResults( + listOf( + RatingCount("1", 1L), + RatingCount("2", 0L), + RatingCount("3", 0L) + ), Document() + ) + + val arkLevel = ArkLevel() + arkLevel.isOpen = true + arkLevel.closeTime = LocalDateTime.now().plus(1, ChronoUnit.DAYS) + every { arkLevelService.findByLevelIdFuzzy(any()) } returns arkLevel + every { copilotRepository.saveAll(any>()) } returns allCopilots + every { redisCache.syncRemoveCacheByPattern(any()) } returns Unit + refreshTask.refreshHotScores() + + check(copilot1.hotScore > 0) + check(copilot2.hotScore > 0) } @Test - void testRefreshTop100HotScores() { - LocalDateTime now = LocalDateTime.now(); - Copilot copilot1 = new Copilot(); - copilot1.setCopilotId(1L); - copilot1.setViews(100L); - copilot1.setUploadTime(now); - Copilot copilot2 = new Copilot(); - copilot2.setCopilotId(2L); - copilot2.setViews(200L); - copilot2.setUploadTime(now); - Copilot copilot3 = new Copilot(); - copilot3.setCopilotId(3L); - copilot3.setViews(200L); - copilot3.setUploadTime(now); + fun testRefreshTop100HotScores() { + val now = LocalDateTime.now() + val copilot1 = Copilot() + copilot1.copilotId = 1L + copilot1.views = 100L + copilot1.uploadTime = now + copilot1.stageName = "stage1" + val copilot2 = Copilot() + copilot2.copilotId = 2L + copilot2.views = 200L + copilot2.uploadTime = now + copilot2.stageName = "stage2" + val copilot3 = Copilot() + copilot3.copilotId = 3L + copilot3.views = 200L + copilot3.uploadTime = now + copilot3.stageName = "stage3" + val allCopilots = listOf(copilot1, copilot2, copilot3) // 配置 RedisCache - when(redisCache.getZSetReverse("rate:hot:copilotIds", 0, 99)) - .thenReturn(Set.of("1", "2", "3")); + every { redisCache.getZSetReverse("rate:hot:copilotIds", 0, 99) } returns setOf("1", "2", "3") // 配置copilotRepository - when(copilotRepository.findByCopilotIdInAndDeleteIsFalse(anyCollection())) - .thenReturn(List.of(copilot1, copilot2, copilot3)); + every { + copilotRepository.findByCopilotIdInAndDeleteIsFalse(any()) + } returns allCopilots // 配置mongoTemplate - when(mongoTemplate.aggregate(any(), eq(Rating.class), eq(RatingCount.class))) - .thenReturn(new AggregationResults<>(List.of( - new RatingCount("1", 1L), - new RatingCount("2", 0L), - new RatingCount("3", 0L)), new Document())); - - refreshTask.refreshTop100HotScores(); - - assertTrue(copilot1.getHotScore() > 0); - assertTrue(copilot2.getHotScore() > 0); + every { + mongoTemplate.aggregate(any(), Rating::class.java, RatingCount::class.java) + } returns AggregationResults( + listOf( + RatingCount("1", 1L), + RatingCount("2", 0L), + RatingCount("3", 0L) + ), Document() + ) + val arkLevel = ArkLevel() + arkLevel.isOpen = true + arkLevel.closeTime = LocalDateTime.now().plus(1, ChronoUnit.DAYS) + every { arkLevelService.findByLevelIdFuzzy(any()) } returns arkLevel + every { copilotRepository.saveAll(any>()) } returns allCopilots + every { redisCache.removeCache(any()) } returns Unit + every { redisCache.syncRemoveCacheByPattern(any()) } returns Unit + refreshTask.refreshTop100HotScores() + + check(copilot1.hotScore > 0) + check(copilot2.hotScore > 0) } - } From fb612428dd7df51992e32b7dc972eef84f770410 Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 17:45:12 +0800 Subject: [PATCH 103/168] Rename .java to .kt --- .../plus/maa/backend/common/utils/ArkLevelUtil.kt} | 0 .../plus/maa/backend/common/utils/FreeMarkerUtils.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/{java/plus/maa/backend/common/utils/ArkLevelUtil.java => kotlin/plus/maa/backend/common/utils/ArkLevelUtil.kt} (100%) rename src/main/{java/plus/maa/backend/common/utils/FreeMarkerUtils.java => kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt} (100%) diff --git a/src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java b/src/main/kotlin/plus/maa/backend/common/utils/ArkLevelUtil.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/ArkLevelUtil.java rename to src/main/kotlin/plus/maa/backend/common/utils/ArkLevelUtil.kt diff --git a/src/main/java/plus/maa/backend/common/utils/FreeMarkerUtils.java b/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/FreeMarkerUtils.java rename to src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt From a7b2ddec926da4605ae00e2b3187496f1fde5961 Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 17:45:12 +0800 Subject: [PATCH 104/168] =?UTF-8?q?refactor:=20=E5=B0=86=E8=BF=81=E7=A7=BB?= =?UTF-8?q?=E8=87=B3kotlin=E7=9A=84=E9=83=A8=E5=88=86=E5=8D=95=E7=8B=AC?= =?UTF-8?q?=E6=94=BE=E5=88=B0kotlin=E6=BA=90=E4=BB=A3=E7=A0=81=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E4=B8=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/MainApplication.kt | 0 .../plus/maa/backend/common/MaaStatusCode.kt | 0 .../backend/common/annotation/AccessLimit.kt | 0 .../backend/common/annotation/CurrentUser.kt | 0 .../backend/common/annotation/JsonSchema.kt | 0 .../annotation/SensitiveWordDetection.kt | 0 .../maa/backend/common/aop/JsonSchemaAop.kt | 0 .../backend/common/aop/SensitiveWordAop.kt | 0 .../backend/common/bo/EmailBusinessObject.kt | 0 .../maa/backend/common/utils/ArkLevelUtil.kt | 27 ++++----- .../backend/common/utils/FreeMarkerUtils.kt | 47 ++++++++-------- .../maa/backend/common/utils/IdComponent.kt | 1 - .../plus/maa/backend/common/utils/IpUtil.kt | 0 .../maa/backend/common/utils/OkHttpUtils.kt | 0 .../maa/backend/common/utils/SpringUtil.kt | 6 +- .../plus/maa/backend/common/utils/WebUtils.kt | 0 .../utils/converter/ArkLevelConverter.kt | 0 .../utils/converter/CommentConverter.kt | 0 .../utils/converter/CopilotConverter.kt | 0 .../utils/converter/CopilotSetConverter.kt | 0 .../utils/converter/MaaUserConverter.kt | 0 .../plus/maa/backend/config/CorsConfig.kt | 0 .../maa/backend/config/HttpInterfaceConfig.kt | 0 .../backend/config/NativeReflectionConfig.kt | 0 .../maa/backend/config/SensitiveWordConfig.kt | 0 .../maa/backend/config/ThreadPoolConfig.kt | 0 .../plus/maa/backend/config/doc/RequireJwt.kt | 0 .../maa/backend/config/doc/SpringDocConfig.kt | 0 .../backend/config/external/ArkLevelGit.kt | 0 .../plus/maa/backend/config/external/Cache.kt | 0 .../maa/backend/config/external/Copilot.kt | 0 .../backend/config/external/CopilotBackup.kt | 0 .../maa/backend/config/external/Github.kt | 0 .../plus/maa/backend/config/external/Info.kt | 0 .../plus/maa/backend/config/external/Jwt.kt | 0 .../config/external/MaaCopilotProperties.kt | 0 .../plus/maa/backend/config/external/Mail.kt | 0 .../backend/config/external/SensitiveWord.kt | 0 .../maa/backend/config/external/TaskCron.kt | 0 .../plus/maa/backend/config/external/Vcode.kt | 0 .../security/AccessDeniedHandlerImpl.kt | 0 .../security/AuthenticationEntryPointImpl.kt | 3 +- .../config/security/AuthenticationHelper.kt | 0 .../security/JwtAuthenticationTokenFilter.kt | 0 .../backend/config/security/SecurityConfig.kt | 0 .../filter/ContentLengthRepairFilter.kt | 0 .../MaaEtagHeaderFilterRegistrationBean.kt | 0 .../AccessLimitInterceptHandlerImpl.kt | 0 .../backend/handler/GlobalExceptionHandler.kt | 1 - .../maa/backend/service/ArkGameDataService.kt | 0 .../backend/service/ArkLevelParserService.kt | 0 .../maa/backend/service/ArkLevelService.kt | 0 .../backend/service/CommentsAreaService.kt | 0 .../maa/backend/service/CopilotService.kt | 0 .../maa/backend/service/CopilotSetService.kt | 0 .../plus/maa/backend/service/EmailService.kt | 0 .../plus/maa/backend/service/FileService.kt | 10 ++-- .../backend/service/UserDetailServiceImpl.kt | 0 .../plus/maa/backend/service/UserService.kt | 0 .../backend/service/session/UserSession.kt | 0 .../service/session/UserSessionService.kt | 0 .../plus/maa/backend/task/ArkLevelSyncTask.kt | 1 - .../maa/backend/task/CopilotBackupTask.kt | 0 .../backend/task/CopilotScoreRefreshTask.kt | 5 +- .../backend/common/utils/ArkLevelUtilTest.kt | 0 .../JwtAuthenticationTokenFilterTest.kt | 0 .../repository/GithubRepositoryTest.kt | 56 +++++++++---------- .../maa/backend/service/CopilotServiceTest.kt | 0 .../maa/backend/service/jwt/JwtServiceTest.kt | 0 .../task/CopilotScoreRefreshTaskTest.kt | 0 70 files changed, 71 insertions(+), 86 deletions(-) rename src/main/{java => kotlin}/plus/maa/backend/MainApplication.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/MaaStatusCode.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/annotation/AccessLimit.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/annotation/CurrentUser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/annotation/JsonSchema.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/annotation/SensitiveWordDetection.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/aop/JsonSchemaAop.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/aop/SensitiveWordAop.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/bo/EmailBusinessObject.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/IdComponent.kt (98%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/IpUtil.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/OkHttpUtils.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/SpringUtil.kt (87%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/WebUtils.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/converter/CommentConverter.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/converter/CopilotConverter.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/common/utils/converter/MaaUserConverter.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/CorsConfig.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/HttpInterfaceConfig.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/NativeReflectionConfig.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/SensitiveWordConfig.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/ThreadPoolConfig.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/doc/RequireJwt.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/doc/SpringDocConfig.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/ArkLevelGit.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/Cache.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/Copilot.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/CopilotBackup.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/Github.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/Info.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/Jwt.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/MaaCopilotProperties.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/Mail.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/SensitiveWord.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/TaskCron.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/external/Vcode.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt (91%) rename src/main/{java => kotlin}/plus/maa/backend/config/security/AuthenticationHelper.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/config/security/SecurityConfig.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/filter/ContentLengthRepairFilter.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/handler/GlobalExceptionHandler.kt (99%) rename src/main/{java => kotlin}/plus/maa/backend/service/ArkGameDataService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/ArkLevelParserService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/ArkLevelService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/CommentsAreaService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/CopilotService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/CopilotSetService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/EmailService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/FileService.kt (96%) rename src/main/{java => kotlin}/plus/maa/backend/service/UserDetailServiceImpl.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/UserService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/session/UserSession.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/session/UserSessionService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/task/ArkLevelSyncTask.kt (96%) rename src/main/{java => kotlin}/plus/maa/backend/task/CopilotBackupTask.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/task/CopilotScoreRefreshTask.kt (97%) rename src/test/{java => kotlin}/plus/maa/backend/common/utils/ArkLevelUtilTest.kt (100%) rename src/test/{java => kotlin}/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt (100%) rename src/test/{java => kotlin}/plus/maa/backend/repository/GithubRepositoryTest.kt (96%) rename src/test/{java => kotlin}/plus/maa/backend/service/CopilotServiceTest.kt (100%) rename src/test/{java => kotlin}/plus/maa/backend/service/jwt/JwtServiceTest.kt (100%) rename src/test/{java => kotlin}/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt (100%) diff --git a/src/main/java/plus/maa/backend/MainApplication.kt b/src/main/kotlin/plus/maa/backend/MainApplication.kt similarity index 100% rename from src/main/java/plus/maa/backend/MainApplication.kt rename to src/main/kotlin/plus/maa/backend/MainApplication.kt diff --git a/src/main/java/plus/maa/backend/common/MaaStatusCode.kt b/src/main/kotlin/plus/maa/backend/common/MaaStatusCode.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/MaaStatusCode.kt rename to src/main/kotlin/plus/maa/backend/common/MaaStatusCode.kt diff --git a/src/main/java/plus/maa/backend/common/annotation/AccessLimit.kt b/src/main/kotlin/plus/maa/backend/common/annotation/AccessLimit.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/annotation/AccessLimit.kt rename to src/main/kotlin/plus/maa/backend/common/annotation/AccessLimit.kt diff --git a/src/main/java/plus/maa/backend/common/annotation/CurrentUser.kt b/src/main/kotlin/plus/maa/backend/common/annotation/CurrentUser.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/annotation/CurrentUser.kt rename to src/main/kotlin/plus/maa/backend/common/annotation/CurrentUser.kt diff --git a/src/main/java/plus/maa/backend/common/annotation/JsonSchema.kt b/src/main/kotlin/plus/maa/backend/common/annotation/JsonSchema.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/annotation/JsonSchema.kt rename to src/main/kotlin/plus/maa/backend/common/annotation/JsonSchema.kt diff --git a/src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.kt b/src/main/kotlin/plus/maa/backend/common/annotation/SensitiveWordDetection.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/annotation/SensitiveWordDetection.kt rename to src/main/kotlin/plus/maa/backend/common/annotation/SensitiveWordDetection.kt diff --git a/src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.kt b/src/main/kotlin/plus/maa/backend/common/aop/JsonSchemaAop.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/aop/JsonSchemaAop.kt rename to src/main/kotlin/plus/maa/backend/common/aop/JsonSchemaAop.kt diff --git a/src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.kt b/src/main/kotlin/plus/maa/backend/common/aop/SensitiveWordAop.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/aop/SensitiveWordAop.kt rename to src/main/kotlin/plus/maa/backend/common/aop/SensitiveWordAop.kt diff --git a/src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.kt b/src/main/kotlin/plus/maa/backend/common/bo/EmailBusinessObject.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/bo/EmailBusinessObject.kt rename to src/main/kotlin/plus/maa/backend/common/bo/EmailBusinessObject.kt diff --git a/src/main/kotlin/plus/maa/backend/common/utils/ArkLevelUtil.kt b/src/main/kotlin/plus/maa/backend/common/utils/ArkLevelUtil.kt index 81468105..6c52bfb5 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/ArkLevelUtil.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/ArkLevelUtil.kt @@ -1,31 +1,24 @@ -package plus.maa.backend.common.utils; +package plus.maa.backend.common.utils -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; +import java.util.regex.Pattern -import java.util.regex.Pattern; - -public class ArkLevelUtil { - - private static final Pattern NOT_KEY_INFO = Pattern.compile( - // level_、各种难度前缀、season_、前导零、以-或者_划分的后缀 - "^level_|^easy_|^hard_|^tough_|^main_|season_|(? + * @return 地图系列的唯一标识

* 例如:a1(骑兵与猎人)、act11d0(沃伦姆德的薄暮)、act11mini(未尽篇章)、crisis_v2_1(浊燃作战) */ - @NotNull - public static String getKeyInfoById(@Nullable String id) { + fun getKeyInfoById(id: String?): String { if (id == null) { - return ""; + return "" } // 去除所有非关键信息 - return NOT_KEY_INFO.matcher(id).replaceAll(""); + return NOT_KEY_INFO.matcher(id).replaceAll("") } - } diff --git a/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt b/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt index eaf7fa56..80f83b97 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt @@ -1,38 +1,35 @@ -package plus.maa.backend.common.utils; +package plus.maa.backend.common.utils -import freemarker.template.Configuration; -import freemarker.template.Template; -import freemarker.template.TemplateException; -import plus.maa.backend.controller.response.MaaResultException; - -import java.io.IOException; -import java.io.StringWriter; -import java.nio.charset.StandardCharsets; -import java.util.Locale; +import freemarker.template.Configuration +import freemarker.template.TemplateException +import plus.maa.backend.controller.response.MaaResultException +import java.io.IOException +import java.io.StringWriter +import java.nio.charset.StandardCharsets +import java.util.* /** * @author dragove * created on 2023/1/17 */ -public class FreeMarkerUtils { +object FreeMarkerUtils { + private val cfg = Configuration(Configuration.VERSION_2_3_32) - private static final Configuration cfg = new Configuration(Configuration.VERSION_2_3_32); - static { - cfg.setClassForTemplateLoading(FreeMarkerUtils.class, "/static/templates/ftlh"); - cfg.setEncoding(Locale.CHINA, StandardCharsets.UTF_8.name()); + init { + cfg.setClassForTemplateLoading(FreeMarkerUtils::class.java, "/static/templates/ftlh") + cfg.setEncoding(Locale.CHINA, StandardCharsets.UTF_8.name()) } - public static String parseData(Object dataModel, String templateName) { + fun parseData(dataModel: Any?, templateName: String?): String { try { - Template template = cfg.getTemplate(templateName); - StringWriter sw = new StringWriter(); - template.process(dataModel, sw); - return sw.toString(); - } catch (IOException e) { - throw new MaaResultException("获取freemarker模板失败"); - } catch (TemplateException e) { - throw new MaaResultException("freemarker模板处理失败"); + val template = cfg.getTemplate(templateName) + val sw = StringWriter() + template.process(dataModel, sw) + return sw.toString() + } catch (e: IOException) { + throw MaaResultException("获取freemarker模板失败") + } catch (e: TemplateException) { + throw MaaResultException("freemarker模板处理失败") } } - } diff --git a/src/main/java/plus/maa/backend/common/utils/IdComponent.kt b/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt similarity index 98% rename from src/main/java/plus/maa/backend/common/utils/IdComponent.kt rename to src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt index c819bebc..3dc77425 100644 --- a/src/main/java/plus/maa/backend/common/utils/IdComponent.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt @@ -6,7 +6,6 @@ import org.springframework.data.mongodb.core.MongoTemplate import org.springframework.data.mongodb.core.query.Query import org.springframework.stereotype.Component import plus.maa.backend.repository.entity.CollectionMeta -import java.util.* import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicLong diff --git a/src/main/java/plus/maa/backend/common/utils/IpUtil.kt b/src/main/kotlin/plus/maa/backend/common/utils/IpUtil.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/IpUtil.kt rename to src/main/kotlin/plus/maa/backend/common/utils/IpUtil.kt diff --git a/src/main/java/plus/maa/backend/common/utils/OkHttpUtils.kt b/src/main/kotlin/plus/maa/backend/common/utils/OkHttpUtils.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/OkHttpUtils.kt rename to src/main/kotlin/plus/maa/backend/common/utils/OkHttpUtils.kt diff --git a/src/main/java/plus/maa/backend/common/utils/SpringUtil.kt b/src/main/kotlin/plus/maa/backend/common/utils/SpringUtil.kt similarity index 87% rename from src/main/java/plus/maa/backend/common/utils/SpringUtil.kt rename to src/main/kotlin/plus/maa/backend/common/utils/SpringUtil.kt index c44933cc..74654b11 100644 --- a/src/main/java/plus/maa/backend/common/utils/SpringUtil.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/SpringUtil.kt @@ -25,15 +25,15 @@ class SpringUtil : ApplicationContextAware { var applicationContext: ApplicationContext? = null private set - fun getBean(name: String?): Any { + fun getBean(name: String): Any { return applicationContext!!.getBean(name) } - fun getBean(clazz: Class?): T { + fun getBean(clazz: Class): T { return applicationContext!!.getBean(clazz) } - fun getBean(name: String?, clazz: Class?): T { + fun getBean(name: String, clazz: Class): T { return applicationContext!!.getBean(name, clazz) } } diff --git a/src/main/java/plus/maa/backend/common/utils/WebUtils.kt b/src/main/kotlin/plus/maa/backend/common/utils/WebUtils.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/WebUtils.kt rename to src/main/kotlin/plus/maa/backend/common/utils/WebUtils.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt rename to src/main/kotlin/plus/maa/backend/common/utils/converter/ArkLevelConverter.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/CommentConverter.kt rename to src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/CopilotConverter.kt rename to src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt rename to src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt diff --git a/src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/MaaUserConverter.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/utils/converter/MaaUserConverter.kt rename to src/main/kotlin/plus/maa/backend/common/utils/converter/MaaUserConverter.kt diff --git a/src/main/java/plus/maa/backend/config/CorsConfig.kt b/src/main/kotlin/plus/maa/backend/config/CorsConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/CorsConfig.kt rename to src/main/kotlin/plus/maa/backend/config/CorsConfig.kt diff --git a/src/main/java/plus/maa/backend/config/HttpInterfaceConfig.kt b/src/main/kotlin/plus/maa/backend/config/HttpInterfaceConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/HttpInterfaceConfig.kt rename to src/main/kotlin/plus/maa/backend/config/HttpInterfaceConfig.kt diff --git a/src/main/java/plus/maa/backend/config/NativeReflectionConfig.kt b/src/main/kotlin/plus/maa/backend/config/NativeReflectionConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/NativeReflectionConfig.kt rename to src/main/kotlin/plus/maa/backend/config/NativeReflectionConfig.kt diff --git a/src/main/java/plus/maa/backend/config/SensitiveWordConfig.kt b/src/main/kotlin/plus/maa/backend/config/SensitiveWordConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/SensitiveWordConfig.kt rename to src/main/kotlin/plus/maa/backend/config/SensitiveWordConfig.kt diff --git a/src/main/java/plus/maa/backend/config/ThreadPoolConfig.kt b/src/main/kotlin/plus/maa/backend/config/ThreadPoolConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/ThreadPoolConfig.kt rename to src/main/kotlin/plus/maa/backend/config/ThreadPoolConfig.kt diff --git a/src/main/java/plus/maa/backend/config/doc/RequireJwt.kt b/src/main/kotlin/plus/maa/backend/config/doc/RequireJwt.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/doc/RequireJwt.kt rename to src/main/kotlin/plus/maa/backend/config/doc/RequireJwt.kt diff --git a/src/main/java/plus/maa/backend/config/doc/SpringDocConfig.kt b/src/main/kotlin/plus/maa/backend/config/doc/SpringDocConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/doc/SpringDocConfig.kt rename to src/main/kotlin/plus/maa/backend/config/doc/SpringDocConfig.kt diff --git a/src/main/java/plus/maa/backend/config/external/ArkLevelGit.kt b/src/main/kotlin/plus/maa/backend/config/external/ArkLevelGit.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/ArkLevelGit.kt rename to src/main/kotlin/plus/maa/backend/config/external/ArkLevelGit.kt diff --git a/src/main/java/plus/maa/backend/config/external/Cache.kt b/src/main/kotlin/plus/maa/backend/config/external/Cache.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Cache.kt rename to src/main/kotlin/plus/maa/backend/config/external/Cache.kt diff --git a/src/main/java/plus/maa/backend/config/external/Copilot.kt b/src/main/kotlin/plus/maa/backend/config/external/Copilot.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Copilot.kt rename to src/main/kotlin/plus/maa/backend/config/external/Copilot.kt diff --git a/src/main/java/plus/maa/backend/config/external/CopilotBackup.kt b/src/main/kotlin/plus/maa/backend/config/external/CopilotBackup.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/CopilotBackup.kt rename to src/main/kotlin/plus/maa/backend/config/external/CopilotBackup.kt diff --git a/src/main/java/plus/maa/backend/config/external/Github.kt b/src/main/kotlin/plus/maa/backend/config/external/Github.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Github.kt rename to src/main/kotlin/plus/maa/backend/config/external/Github.kt diff --git a/src/main/java/plus/maa/backend/config/external/Info.kt b/src/main/kotlin/plus/maa/backend/config/external/Info.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Info.kt rename to src/main/kotlin/plus/maa/backend/config/external/Info.kt diff --git a/src/main/java/plus/maa/backend/config/external/Jwt.kt b/src/main/kotlin/plus/maa/backend/config/external/Jwt.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Jwt.kt rename to src/main/kotlin/plus/maa/backend/config/external/Jwt.kt diff --git a/src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.kt b/src/main/kotlin/plus/maa/backend/config/external/MaaCopilotProperties.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/MaaCopilotProperties.kt rename to src/main/kotlin/plus/maa/backend/config/external/MaaCopilotProperties.kt diff --git a/src/main/java/plus/maa/backend/config/external/Mail.kt b/src/main/kotlin/plus/maa/backend/config/external/Mail.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Mail.kt rename to src/main/kotlin/plus/maa/backend/config/external/Mail.kt diff --git a/src/main/java/plus/maa/backend/config/external/SensitiveWord.kt b/src/main/kotlin/plus/maa/backend/config/external/SensitiveWord.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/SensitiveWord.kt rename to src/main/kotlin/plus/maa/backend/config/external/SensitiveWord.kt diff --git a/src/main/java/plus/maa/backend/config/external/TaskCron.kt b/src/main/kotlin/plus/maa/backend/config/external/TaskCron.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/TaskCron.kt rename to src/main/kotlin/plus/maa/backend/config/external/TaskCron.kt diff --git a/src/main/java/plus/maa/backend/config/external/Vcode.kt b/src/main/kotlin/plus/maa/backend/config/external/Vcode.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/external/Vcode.kt rename to src/main/kotlin/plus/maa/backend/config/external/Vcode.kt diff --git a/src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt b/src/main/kotlin/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt rename to src/main/kotlin/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt diff --git a/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt b/src/main/kotlin/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt similarity index 91% rename from src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt rename to src/main/kotlin/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt index 5f13379e..16ad92a2 100644 --- a/src/main/java/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt +++ b/src/main/kotlin/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt @@ -3,7 +3,6 @@ package plus.maa.backend.config.security import com.fasterxml.jackson.databind.ObjectMapper import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse -import lombok.RequiredArgsConstructor import org.springframework.http.HttpStatus import org.springframework.security.core.AuthenticationException import org.springframework.security.web.AuthenticationEntryPoint @@ -27,7 +26,7 @@ class AuthenticationEntryPointImpl( authException: AuthenticationException ) { val result = fail(HttpStatus.UNAUTHORIZED.value(), authException.message) - val json = objectMapper!!.writeValueAsString(result) + val json = objectMapper.writeValueAsString(result) renderString(response, json, HttpStatus.UNAUTHORIZED.value()) } } diff --git a/src/main/java/plus/maa/backend/config/security/AuthenticationHelper.kt b/src/main/kotlin/plus/maa/backend/config/security/AuthenticationHelper.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/AuthenticationHelper.kt rename to src/main/kotlin/plus/maa/backend/config/security/AuthenticationHelper.kt diff --git a/src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt b/src/main/kotlin/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt rename to src/main/kotlin/plus/maa/backend/config/security/JwtAuthenticationTokenFilter.kt diff --git a/src/main/java/plus/maa/backend/config/security/SecurityConfig.kt b/src/main/kotlin/plus/maa/backend/config/security/SecurityConfig.kt similarity index 100% rename from src/main/java/plus/maa/backend/config/security/SecurityConfig.kt rename to src/main/kotlin/plus/maa/backend/config/security/SecurityConfig.kt diff --git a/src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.kt b/src/main/kotlin/plus/maa/backend/filter/ContentLengthRepairFilter.kt similarity index 100% rename from src/main/java/plus/maa/backend/filter/ContentLengthRepairFilter.kt rename to src/main/kotlin/plus/maa/backend/filter/ContentLengthRepairFilter.kt diff --git a/src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt b/src/main/kotlin/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt similarity index 100% rename from src/main/java/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt rename to src/main/kotlin/plus/maa/backend/filter/MaaEtagHeaderFilterRegistrationBean.kt diff --git a/src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt b/src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt similarity index 100% rename from src/main/java/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt rename to src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt diff --git a/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt b/src/main/kotlin/plus/maa/backend/handler/GlobalExceptionHandler.kt similarity index 99% rename from src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt rename to src/main/kotlin/plus/maa/backend/handler/GlobalExceptionHandler.kt index 67a6760f..984f370d 100644 --- a/src/main/java/plus/maa/backend/handler/GlobalExceptionHandler.kt +++ b/src/main/kotlin/plus/maa/backend/handler/GlobalExceptionHandler.kt @@ -2,7 +2,6 @@ package plus.maa.backend.handler import io.github.oshai.kotlinlogging.KotlinLogging import jakarta.servlet.http.HttpServletRequest -import lombok.extern.slf4j.Slf4j import org.springframework.http.HttpStatus import org.springframework.security.core.AuthenticationException import org.springframework.web.HttpRequestMethodNotSupportedException diff --git a/src/main/java/plus/maa/backend/service/ArkGameDataService.kt b/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/ArkGameDataService.kt rename to src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt diff --git a/src/main/java/plus/maa/backend/service/ArkLevelParserService.kt b/src/main/kotlin/plus/maa/backend/service/ArkLevelParserService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/ArkLevelParserService.kt rename to src/main/kotlin/plus/maa/backend/service/ArkLevelParserService.kt diff --git a/src/main/java/plus/maa/backend/service/ArkLevelService.kt b/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/ArkLevelService.kt rename to src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt diff --git a/src/main/java/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/CommentsAreaService.kt rename to src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt diff --git a/src/main/java/plus/maa/backend/service/CopilotService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/CopilotService.kt rename to src/main/kotlin/plus/maa/backend/service/CopilotService.kt diff --git a/src/main/java/plus/maa/backend/service/CopilotSetService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/CopilotSetService.kt rename to src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt diff --git a/src/main/java/plus/maa/backend/service/EmailService.kt b/src/main/kotlin/plus/maa/backend/service/EmailService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/EmailService.kt rename to src/main/kotlin/plus/maa/backend/service/EmailService.kt diff --git a/src/main/java/plus/maa/backend/service/FileService.kt b/src/main/kotlin/plus/maa/backend/service/FileService.kt similarity index 96% rename from src/main/java/plus/maa/backend/service/FileService.kt rename to src/main/kotlin/plus/maa/backend/service/FileService.kt index d7190444..39332acb 100644 --- a/src/main/java/plus/maa/backend/service/FileService.kt +++ b/src/main/kotlin/plus/maa/backend/service/FileService.kt @@ -45,7 +45,7 @@ class FileService( ) { //redis持久化 - var version = version + var realVersion = version if (redisCache.getCache("NotEnable:UploadFile", String::class.java) != null) { throw MaaResultException(403, "closed uploadfile") } @@ -57,14 +57,14 @@ class FileService( Assert.notNull(file.originalFilename, "文件名不可为空") var antecedentVersion: String? = null - if (version.contains("-")) { - val split = version.split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() - version = split[0] + if (realVersion.contains("-")) { + val split = realVersion.split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + realVersion = split[0] antecedentVersion = split[1] } val document = Document() - document["version"] = version + document["version"] = realVersion document["antecedentVersion"] = antecedentVersion document["label"] = label document["classification"] = classification diff --git a/src/main/java/plus/maa/backend/service/UserDetailServiceImpl.kt b/src/main/kotlin/plus/maa/backend/service/UserDetailServiceImpl.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/UserDetailServiceImpl.kt rename to src/main/kotlin/plus/maa/backend/service/UserDetailServiceImpl.kt diff --git a/src/main/java/plus/maa/backend/service/UserService.kt b/src/main/kotlin/plus/maa/backend/service/UserService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/UserService.kt rename to src/main/kotlin/plus/maa/backend/service/UserService.kt diff --git a/src/main/java/plus/maa/backend/service/session/UserSession.kt b/src/main/kotlin/plus/maa/backend/service/session/UserSession.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/session/UserSession.kt rename to src/main/kotlin/plus/maa/backend/service/session/UserSession.kt diff --git a/src/main/java/plus/maa/backend/service/session/UserSessionService.kt b/src/main/kotlin/plus/maa/backend/service/session/UserSessionService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/session/UserSessionService.kt rename to src/main/kotlin/plus/maa/backend/service/session/UserSessionService.kt diff --git a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt similarity index 96% rename from src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt rename to src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt index 1157507c..fc0b1284 100644 --- a/src/main/java/plus/maa/backend/task/ArkLevelSyncTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt @@ -1,6 +1,5 @@ package plus.maa.backend.task -import lombok.RequiredArgsConstructor import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Component import plus.maa.backend.service.ArkLevelService diff --git a/src/main/java/plus/maa/backend/task/CopilotBackupTask.kt b/src/main/kotlin/plus/maa/backend/task/CopilotBackupTask.kt similarity index 100% rename from src/main/java/plus/maa/backend/task/CopilotBackupTask.kt rename to src/main/kotlin/plus/maa/backend/task/CopilotBackupTask.kt diff --git a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt b/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt similarity index 97% rename from src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt rename to src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt index efa4012d..ea70b5cc 100644 --- a/src/main/java/plus/maa/backend/task/CopilotScoreRefreshTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt @@ -15,7 +15,6 @@ import plus.maa.backend.service.CopilotService.Companion.getHotScore import plus.maa.backend.service.model.RatingCount import plus.maa.backend.service.model.RatingType import java.time.LocalDateTime -import kotlin.String /** * 作业热度值刷入任务,每日执行,用于计算基于时间的热度值 @@ -71,7 +70,7 @@ class CopilotScoreRefreshTask( val copilots = copilotRepository.findByCopilotIdInAndDeleteIsFalse( copilotIdSTRs.map { s: String? -> s!!.toLong() } ) - if (copilots == null || copilots.isEmpty()) { + if (copilots.isEmpty()) { return } @@ -106,7 +105,7 @@ class CopilotScoreRefreshTask( hotScore /= 3.0 } - copilot.setHotScore(hotScore) + copilot.hotScore = hotScore } // 批量更新热度值 copilotRepository.saveAll(copilots) diff --git a/src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.kt b/src/test/kotlin/plus/maa/backend/common/utils/ArkLevelUtilTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/common/utils/ArkLevelUtilTest.kt rename to src/test/kotlin/plus/maa/backend/common/utils/ArkLevelUtilTest.kt diff --git a/src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt b/src/test/kotlin/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt rename to src/test/kotlin/plus/maa/backend/config/security/JwtAuthenticationTokenFilterTest.kt diff --git a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt b/src/test/kotlin/plus/maa/backend/repository/GithubRepositoryTest.kt similarity index 96% rename from src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt rename to src/test/kotlin/plus/maa/backend/repository/GithubRepositoryTest.kt index b4df27c6..6bbc3e17 100644 --- a/src/test/java/plus/maa/backend/repository/GithubRepositoryTest.kt +++ b/src/test/kotlin/plus/maa/backend/repository/GithubRepositoryTest.kt @@ -1,29 +1,29 @@ -package plus.maa.backend.repository - -import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import plus.maa.backend.config.external.MaaCopilotProperties - -@SpringBootTest -class GithubRepositoryTest( - @Autowired val repository: GithubRepository, - @Autowired val properties: MaaCopilotProperties -) { - @Test - fun testGetTrees() { - repository.getTrees(properties.github.token, "d989739981db071e80df1c66e473c729b50e8073") - } - - @Test - fun testGetCommits() { - val commits = repository.getCommits(properties.github.token) - check(commits.isNotEmpty()) - } - - @Test - fun testGetContents() { - val contents = repository.getContents(properties.github.token, "") - check(contents.isNotEmpty()) - } +package plus.maa.backend.repository + +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import plus.maa.backend.config.external.MaaCopilotProperties + +@SpringBootTest +class GithubRepositoryTest( + @Autowired val repository: GithubRepository, + @Autowired val properties: MaaCopilotProperties +) { + @Test + fun testGetTrees() { + repository.getTrees(properties.github.token, "d989739981db071e80df1c66e473c729b50e8073") + } + + @Test + fun testGetCommits() { + val commits = repository.getCommits(properties.github.token) + check(commits.isNotEmpty()) + } + + @Test + fun testGetContents() { + val contents = repository.getContents(properties.github.token, "") + check(contents.isNotEmpty()) + } } \ No newline at end of file diff --git a/src/test/java/plus/maa/backend/service/CopilotServiceTest.kt b/src/test/kotlin/plus/maa/backend/service/CopilotServiceTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/service/CopilotServiceTest.kt rename to src/test/kotlin/plus/maa/backend/service/CopilotServiceTest.kt diff --git a/src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.kt b/src/test/kotlin/plus/maa/backend/service/jwt/JwtServiceTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/service/jwt/JwtServiceTest.kt rename to src/test/kotlin/plus/maa/backend/service/jwt/JwtServiceTest.kt diff --git a/src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt b/src/test/kotlin/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt similarity index 100% rename from src/test/java/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt rename to src/test/kotlin/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt From edc01c403b2612e26e1ec07f7a4dfc806046cf9d Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 22:27:56 +0800 Subject: [PATCH 105/168] Rename .java to .kt --- .../file/{ImageDownloadDTO.java => ImageDownloadDTO.kt} | 0 .../controller/file/{UploadAbility.java => UploadAbility.kt} | 0 .../request/comments/{CommentsAddDTO.java => CommentsAddDTO.kt} | 0 .../comments/{CommentsDeleteDTO.java => CommentsDeleteDTO.kt} | 0 .../comments/{CommentsQueriesDTO.java => CommentsQueriesDTO.kt} | 0 .../comments/{CommentsRatingDTO.java => CommentsRatingDTO.kt} | 0 .../comments/{CommentsToppingDTO.java => CommentsToppingDTO.kt} | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/file/{ImageDownloadDTO.java => ImageDownloadDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/file/{UploadAbility.java => UploadAbility.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/comments/{CommentsAddDTO.java => CommentsAddDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/comments/{CommentsDeleteDTO.java => CommentsDeleteDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/comments/{CommentsQueriesDTO.java => CommentsQueriesDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/comments/{CommentsRatingDTO.java => CommentsRatingDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/comments/{CommentsToppingDTO.java => CommentsToppingDTO.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.java b/src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.java rename to src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/file/UploadAbility.java b/src/main/java/plus/maa/backend/controller/file/UploadAbility.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/file/UploadAbility.java rename to src/main/java/plus/maa/backend/controller/file/UploadAbility.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.java b/src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.java rename to src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.java b/src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.java rename to src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.java b/src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.java rename to src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.java b/src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.java rename to src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.java b/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.java rename to src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt From c300e624984b3524c55b0703bb3213bba8d8e202 Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 22:27:56 +0800 Subject: [PATCH 106/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD=20pojo=20?= =?UTF-8?q?=E7=B1=BB=E5=88=B0=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/file/ImageDownloadDTO.kt | 28 ++++----- .../backend/controller/file/UploadAbility.kt | 16 ++--- .../request/comments/CommentsAddDTO.kt | 38 +++++------- .../request/comments/CommentsDeleteDTO.kt | 19 ++---- .../request/comments/CommentsQueriesDTO.kt | 34 ++++------- .../request/comments/CommentsRatingDTO.kt | 22 +++---- .../request/comments/CommentsToppingDTO.kt | 20 +++---- .../backend/service/CommentsAreaService.kt | 60 +++++++++---------- .../plus/maa/backend/service/FileService.kt | 8 +-- 9 files changed, 100 insertions(+), 145 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.kt b/src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.kt index 930204b9..9a7dc258 100644 --- a/src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.kt +++ b/src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.kt @@ -1,24 +1,16 @@ -package plus.maa.backend.controller.file; - -import jakarta.validation.constraints.NotNull; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.hibernate.validator.constraints.Length; - -import java.util.List; +package plus.maa.backend.controller.file +import jakarta.validation.constraints.NotNull /** * @author LoMu * Date 2023-04-16 17:41 */ - -@Data -public class ImageDownloadDTO { - @NotNull - private String type; - private String classification; - private List version; - private String label; - private boolean delete; -} +data class ImageDownloadDTO( + @field:NotNull + val type: String, + val classification: String? = null, + val version: List? = null, + val label: String? = null, + val delete: Boolean = false +) diff --git a/src/main/java/plus/maa/backend/controller/file/UploadAbility.kt b/src/main/java/plus/maa/backend/controller/file/UploadAbility.kt index 4dd47b73..80281dd9 100644 --- a/src/main/java/plus/maa/backend/controller/file/UploadAbility.kt +++ b/src/main/java/plus/maa/backend/controller/file/UploadAbility.kt @@ -1,15 +1,11 @@ -package plus.maa.backend.controller.file; +package plus.maa.backend.controller.file -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; +import jakarta.validation.constraints.NotNull -@AllArgsConstructor -@Data -public class UploadAbility { +class UploadAbility( /** * 是否开启上传功能 */ - @NotNull - Boolean enabled; -} + @field:NotNull + var enabled: Boolean +) diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt b/src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt index 6b2dde89..3404df3a 100644 --- a/src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt @@ -1,29 +1,21 @@ -package plus.maa.backend.controller.request.comments; +package plus.maa.backend.controller.request.comments -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.hibernate.validator.constraints.Length; +import jakarta.validation.constraints.NotBlank +import org.hibernate.validator.constraints.Length /** * @author LoMu * Date 2023-02-17 14:58 */ - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CommentsAddDTO { - @Length(min = 1, max = 150, message = "评论内容不可超过150字,请删减") - private String message; - - @NotBlank(message = "作业id不可为空") - private String copilotId; - - //子评论(回复评论) - private String fromCommentId; - - private boolean notification = true; - -} +data class CommentsAddDTO( + // 评论内容 + @field:Length(min = 1, max = 150, message = "评论内容不可超过150字,请删减") + @field:NotBlank(message = "请填写评论内容") + val message: String, + // 评论的作业id + @field:NotBlank(message = "作业id不可为空") + val copilotId: String, + // 子评论来源评论id(回复评论) + val fromCommentId: String? = null, + val notification: Boolean = true +) diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt b/src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt index 5eae397c..2c7d8667 100644 --- a/src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt @@ -1,19 +1,12 @@ -package plus.maa.backend.controller.request.comments; +package plus.maa.backend.controller.request.comments -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.validation.constraints.NotBlank /** * @author LoMu * Date 2023-02-19 10:50 */ - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CommentsDeleteDTO { - @NotBlank(message = "评论id不可为空") - private String commentId; -} +data class CommentsDeleteDTO( + @field:NotBlank(message = "评论id不可为空") + val commentId: String +) \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt b/src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt index 9fe4afdb..85b76510 100644 --- a/src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt @@ -1,27 +1,19 @@ -package plus.maa.backend.controller.request.comments; +package plus.maa.backend.controller.request.comments -import jakarta.validation.constraints.Max; -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.validation.constraints.Max +import jakarta.validation.constraints.NotNull /** * @author LoMu * Date 2023-02-20 17:13 */ - - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CommentsQueriesDTO { - @NotNull(message = "作业id不可为空") - private Long copilotId; - private int page = 0; - @Max(value = 50, message = "单页大小不得超过50") - private int limit = 10; - private boolean desc = true; - private String orderBy; - private String justSeeId; -} +data class CommentsQueriesDTO( + @field:NotNull(message = "作业id不可为空") + val copilotId: Long, + val page: Int = 0, + @field:Max(value = 50, message = "单页大小不得超过50") + val limit: Int = 10, + val desc: Boolean = true, + val orderBy: String? = null, + val justSeeId: String? = null +) diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt b/src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt index 23b8c995..54dbda36 100644 --- a/src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt @@ -1,20 +1,14 @@ -package plus.maa.backend.controller.request.comments; +package plus.maa.backend.controller.request.comments -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.validation.constraints.NotBlank /** * @author LoMu * Date 2023-02-19 13:39 */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CommentsRatingDTO { - @NotBlank(message = "评分id不可为空") - private String commentId; - @NotBlank(message = "评分不能为空") - private String rating; -} +data class CommentsRatingDTO( + @field:NotBlank(message = "评分id不可为空") + val commentId: String, + @field:NotBlank(message = "评分不能为空") + val rating: String +) diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt b/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt index 5f2d05b9..2c0ef894 100644 --- a/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt @@ -1,9 +1,9 @@ -package plus.maa.backend.controller.request.comments; +package plus.maa.backend.controller.request.comments -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import jakarta.validation.constraints.NotBlank +import lombok.AllArgsConstructor +import lombok.Data +import lombok.NoArgsConstructor /** * @author Lixuhuilll @@ -12,9 +12,9 @@ import lombok.NoArgsConstructor; @Data @NoArgsConstructor @AllArgsConstructor -public class CommentsToppingDTO { - @NotBlank(message = "评论id不可为空") - private String commentId; +class CommentsToppingDTO ( + @field:NotBlank(message = "评论id不可为空") + val commentId: String, // 是否将指定评论置顶 - private boolean topping = true; -} + val topping: Boolean = true +) diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index fc76f370..da899e2c 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -59,7 +59,7 @@ class CommentsAreaService( val message = commentsAddDTO.message val copilotOptional = copilotRepository.findByCopilotId(copilotId) Assert.isTrue(StringUtils.isNotBlank(message), "评论不可为空") - Assert.isTrue(copilotOptional!=null, "作业表不存在") + Assert.isTrue(copilotOptional != null, "作业表不存在") var fromCommentsId: String? = null @@ -70,7 +70,7 @@ class CommentsAreaService( //代表这是一条回复评论 - if (StringUtils.isNoneBlank(commentsAddDTO.fromCommentId)) { + if (!commentsAddDTO.fromCommentId.isNullOrBlank()) { val commentsAreaOptional = commentsAreaRepository.findById(commentsAddDTO.fromCommentId) Assert.isTrue(commentsAreaOptional.isPresent, "回复的评论不存在") commentsArea = commentsAreaOptional.get() @@ -136,7 +136,7 @@ class CommentsAreaService( .setFromCommentId(fromCommentsId) .setMainCommentId(mainCommentsId) .setMessage(message) - .setNotification(commentsAddDTO.isNotification) + .setNotification(commentsAddDTO.notification) ) } @@ -145,11 +145,11 @@ class CommentsAreaService( val commentsArea = findCommentsById(commentsId) //允许作者删除评论 copilotRepository.findByCopilotId(commentsArea.copilotId)?.let { copilot: Copilot -> - Assert.isTrue( - userId == copilot.uploaderId || userId == commentsArea.uploaderId, - "您无法删除不属于您的评论" - ) - } + Assert.isTrue( + userId == copilot.uploaderId || userId == commentsArea.uploaderId, + "您无法删除不属于您的评论" + ) + } val now = LocalDateTime.now() commentsArea.setDelete(true) commentsArea.setDeleteTime(now) @@ -244,13 +244,13 @@ class CommentsAreaService( Assert.isTrue(!commentsArea.isDelete, "评论不存在") // 只允许作者置顶评论 copilotRepository.findByCopilotId(commentsArea.copilotId)?.let { copilot: Copilot -> - Assert.isTrue( - userId == copilot.uploaderId, - "只有作者才能置顶评论" - ) - commentsArea.setTopping(commentsToppingDTO.isTopping) - commentsAreaRepository.save(commentsArea) - } + Assert.isTrue( + userId == copilot.uploaderId, + "只有作者才能置顶评论" + ) + commentsArea.setTopping(commentsToppingDTO.topping) + commentsAreaRepository.save(commentsArea) + } } /** @@ -263,16 +263,12 @@ class CommentsAreaService( val toppingOrder = Sort.Order.desc("topping") val sortOrder = Sort.Order( - if (request.isDesc) Sort.Direction.DESC else Sort.Direction.ASC, - Optional.ofNullable(request.orderBy) - .filter { cs: String? -> StringUtils.isNotBlank(cs) } - .map { ob: String? -> - when (ob) { - "hot" -> "likeCount" - "id" -> "uploadTime" - else -> request.orderBy - } - }.orElse("likeCount") + if (request.desc) Sort.Direction.DESC else Sort.Direction.ASC, + when (request.orderBy) { + "hot" -> "likeCount" + "id" -> "uploadTime" + else -> request.orderBy ?: "likeCount" + } ) val page = if (request.page > 0) request.page else 1 @@ -283,20 +279,20 @@ class CommentsAreaService( //主评论 - val mainCommentsList = if (StringUtils.isNotBlank(request.justSeeId)) { + val mainCommentsList = if (!request.justSeeId.isNullOrBlank()) { commentsAreaRepository.findByCopilotIdAndUploaderIdAndDeleteAndMainCommentIdExists( request.copilotId, request.justSeeId, - false, - false, - pageable + delete = false, + exists = false, + pageable = pageable ) } else { commentsAreaRepository.findByCopilotIdAndDeleteAndMainCommentIdExists( request.copilotId, - false, - false, - pageable + delete = false, + exists = false, + pageable = pageable ) } diff --git a/src/main/kotlin/plus/maa/backend/service/FileService.kt b/src/main/kotlin/plus/maa/backend/service/FileService.kt index 39332acb..e473fe13 100644 --- a/src/main/kotlin/plus/maa/backend/service/FileService.kt +++ b/src/main/kotlin/plus/maa/backend/service/FileService.kt @@ -129,7 +129,7 @@ class FileService( ) //指定下载某个类型的图片 - if (StringUtils.isNotBlank(imageDownloadDTO.classification)) { + if (!imageDownloadDTO.classification.isNullOrBlank()) { criteriaSet.add( GridFsCriteria.whereMetaData("classification") .regex(Pattern.compile(imageDownloadDTO.classification, Pattern.CASE_INSENSITIVE)) @@ -137,7 +137,7 @@ class FileService( } //指定版本或指定范围版本 - if (!Objects.isNull(imageDownloadDTO.version)) { + if (!imageDownloadDTO.version.isNullOrEmpty()) { val version = imageDownloadDTO.version if (version.size == 1) { @@ -155,7 +155,7 @@ class FileService( } } - if (StringUtils.isNotBlank(imageDownloadDTO.label)) { + if (!imageDownloadDTO.label.isNullOrBlank()) { criteriaSet.add( GridFsCriteria.whereMetaData("label") .regex(Pattern.compile(imageDownloadDTO.label, Pattern.CASE_INSENSITIVE)) @@ -172,7 +172,7 @@ class FileService( gzip(response, gridFSFiles) - if (imageDownloadDTO.isDelete) { + if (imageDownloadDTO.delete) { gridFsOperations.delete(query) } } From 83e3eeaef99c98dad6582794b38b1bd0d01067d5 Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 22:47:22 +0800 Subject: [PATCH 107/168] Rename .java to .kt --- .../comments/{CommentsAreaInfo.java => CommentsAreaInfo.kt} | 0 .../response/comments/{CommentsInfo.java => CommentsInfo.kt} | 0 .../comments/{SubCommentsInfo.java => SubCommentsInfo.kt} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/response/comments/{CommentsAreaInfo.java => CommentsAreaInfo.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/comments/{CommentsInfo.java => CommentsInfo.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/comments/{SubCommentsInfo.java => SubCommentsInfo.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.java b/src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.java rename to src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.java b/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.java rename to src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.java b/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.java rename to src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt From c8e86368185500c3582e9bd6286f093ba9e33165 Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 22:47:22 +0800 Subject: [PATCH 108/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=E8=AF=84?= =?UTF-8?q?=E8=AE=BA=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD=20pojo=20?= =?UTF-8?q?=E7=B1=BB=E5=88=B0=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/comments/CommentsToppingDTO.kt | 8 +--- .../response/comments/CommentsAreaInfo.kt | 27 ++++-------- .../response/comments/CommentsInfo.kt | 40 +++++++----------- .../response/comments/SubCommentsInfo.kt | 41 +++++++------------ .../utils/converter/CommentConverter.kt | 3 +- .../backend/service/CommentsAreaService.kt | 38 +++++++---------- 6 files changed, 53 insertions(+), 104 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt b/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt index 2c0ef894..ccd33698 100644 --- a/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt @@ -1,18 +1,12 @@ package plus.maa.backend.controller.request.comments import jakarta.validation.constraints.NotBlank -import lombok.AllArgsConstructor -import lombok.Data -import lombok.NoArgsConstructor /** * @author Lixuhuilll * Date 2023-08-17 11:20 */ -@Data -@NoArgsConstructor -@AllArgsConstructor -class CommentsToppingDTO ( +data class CommentsToppingDTO ( @field:NotBlank(message = "评论id不可为空") val commentId: String, // 是否将指定评论置顶 diff --git a/src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt b/src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt index 3f526927..7532a8e1 100644 --- a/src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt @@ -1,25 +1,12 @@ -package plus.maa.backend.controller.response.comments; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; - -import java.util.List; - +package plus.maa.backend.controller.response.comments /** * @author LoMu * Date 2023-02-19 11:47 */ - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Accessors(chain = true) -public class CommentsAreaInfo { - private Boolean hasNext; - private Integer page; - private Long total; - private List data; -} +data class CommentsAreaInfo ( + val hasNext: Boolean, + val page: Int, + val total: Long, + val data: List +) diff --git a/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.kt b/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.kt index e41a3193..b7e3fb66 100644 --- a/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.kt @@ -1,33 +1,21 @@ -package plus.maa.backend.controller.response.comments; +package plus.maa.backend.controller.response.comments -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; +import java.time.LocalDateTime /** * @author LoMu * Date 2023-02-20 17:04 */ +data class CommentsInfo( + val commentId: String, + val uploader: String, + val uploaderId: String, -@Data -@NoArgsConstructor -@Accessors(chain = true) -@AllArgsConstructor -public class CommentsInfo { - private String commentId; - private String uploader; - private String uploaderId; - - //评论内容 - private String message; - private LocalDateTime uploadTime; - private long like; - private long dislike; - private boolean topping; - private List subCommentsInfos = new ArrayList<>(); -} + //评论内容, + val message: String, + val uploadTime: LocalDateTime, + val like: Long = 0, + val dislike: Long = 0, + val topping: Boolean = false, + val subCommentsInfos: List, +) diff --git a/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt b/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt index ebe24c51..79b89c7b 100644 --- a/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt @@ -1,32 +1,21 @@ -package plus.maa.backend.controller.response.comments; +package plus.maa.backend.controller.response.comments -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; - -import java.time.LocalDateTime; +import java.time.LocalDateTime /** * @author LoMu * Date 2023-02-20 17:05 */ - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Accessors(chain = true) -public class SubCommentsInfo { - private String commentId; - private String uploader; - private String uploaderId; - - //评论内容 - private String message; - private LocalDateTime uploadTime; - private long like; - private long dislike; - private String fromCommentId; - private String mainCommentId; - private boolean deleted; -} +data class SubCommentsInfo( + private val commentId: String, + private val uploader: String, + private val uploaderId: String, + //评论内容, + private val message: String, + private val uploadTime: LocalDateTime, + private val like: Long = 0, + private val dislike: Long = 0, + private val fromCommentId: String, + private val mainCommentId: String, + private val deleted: Boolean = false +) diff --git a/src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt index 63980a8a..7cd7710c 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/converter/CommentConverter.kt @@ -17,8 +17,7 @@ interface CommentConverter { @Mapping(target = "dislike", source = "commentsArea.dislikeCount") @Mapping(target = "uploader", source = "maaUser.userName") @Mapping(target = "commentId", source = "commentsArea.id") - @Mapping(target = "subCommentsInfos", ignore = true) - fun toCommentsInfo(commentsArea: CommentsArea, maaUser: MaaUser): CommentsInfo + fun toCommentsInfo(commentsArea: CommentsArea, maaUser: MaaUser, subCommentsInfos: List): CommentsInfo @Mapping(target = "like", source = "commentsArea.likeCount") diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index da899e2c..55b9dfe1 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -330,37 +330,29 @@ class CommentsAreaService( //转换主评论数据并填充用户名 val commentsInfos = mainCommentsList.map { mainComment: CommentsArea -> - val commentsInfo = - commentConverter - .toCommentsInfo( - mainComment, + val subCommentsInfoList = subCommentsList + .filter { comment: CommentsArea -> mainComment.id == comment.mainCommentId } //转换子评论数据并填充用户名 + .map { subComment: CommentsArea -> + commentConverter.toSubCommentsInfo( + subComment, //填充评论用户名 maaUserMap.getOrDefault( - mainComment.uploaderId, + subComment.uploaderId, MaaUser.UNKNOWN ) ) - val subCommentsInfoList = subCommentsList - .filter { comment: CommentsArea -> commentsInfo.commentId == comment.mainCommentId } //转换子评论数据并填充用户名 - .map { subComment: CommentsArea -> - commentConverter - .toSubCommentsInfo( - subComment, //填充评论用户名 - maaUserMap.getOrDefault( - subComment.uploaderId, - MaaUser.UNKNOWN - ) - ) }.toList() - - - commentsInfo.setSubCommentsInfos(subCommentsInfoList) + val commentsInfo = commentConverter.toCommentsInfo( + mainComment, + maaUserMap.getOrDefault( + mainComment.uploaderId, + MaaUser.UNKNOWN + ), + subCommentsInfoList + ) commentsInfo }.toList() - return CommentsAreaInfo().setHasNext(hasNext) - .setPage(pageNumber) - .setTotal(count) - .setData(commentsInfos) + return CommentsAreaInfo(hasNext, pageNumber, count, commentsInfos) } From 564f486ef80dc50b8bb8c94e0cbd814446430650 Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 23:13:56 +0800 Subject: [PATCH 109/168] Rename .java to .kt --- .../copilot/{CopilotCUDRequest.java => CopilotCUDRequest.kt} | 0 .../controller/request/copilot/{CopilotDTO.java => CopilotDTO.kt} | 0 .../copilot/{CopilotRatingReq.java => CopilotRatingReq.kt} | 0 .../response/copilot/{ArkLevelInfo.java => ArkLevelInfo.kt} | 0 .../response/copilot/{CopilotInfo.java => CopilotInfo.kt} | 0 .../response/copilot/{CopilotPageInfo.java => CopilotPageInfo.kt} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/request/copilot/{CopilotCUDRequest.java => CopilotCUDRequest.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/copilot/{CopilotDTO.java => CopilotDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/copilot/{CopilotRatingReq.java => CopilotRatingReq.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/copilot/{ArkLevelInfo.java => ArkLevelInfo.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/copilot/{CopilotInfo.java => CopilotInfo.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/copilot/{CopilotPageInfo.java => CopilotPageInfo.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.java b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.java rename to src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.java b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.java rename to src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.java b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.java rename to src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.java rename to src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.java b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.java rename to src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.java b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.java rename to src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt From 410870690d18f4b710350b515dee23051991964c Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 11 Feb 2024 23:13:56 +0800 Subject: [PATCH 110/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD=20pojo=20?= =?UTF-8?q?=E7=B1=BB=E5=88=B0=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/copilot/CopilotCUDRequest.kt | 17 +++---- .../controller/request/copilot/CopilotDTO.kt | 42 +++++++----------- .../request/copilot/CopilotRatingReq.kt | 14 +++--- .../response/copilot/ArkLevelInfo.kt | 35 +++++---------- .../response/copilot/CopilotInfo.kt | 44 ++++++++----------- .../response/copilot/CopilotPageInfo.kt | 29 +++++------- .../utils/converter/CopilotConverter.kt | 4 +- .../maa/backend/service/CopilotService.kt | 44 +++++++++---------- 8 files changed, 94 insertions(+), 135 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt index 6cfbccad..a4d73a3f 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt +++ b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt @@ -1,13 +1,6 @@ -package plus.maa.backend.controller.request.copilot; +package plus.maa.backend.controller.request.copilot -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CopilotCUDRequest { - private String content; - private Long id; -} +data class CopilotCUDRequest ( + val content: String? = null, + val id: Long? = null +) diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.kt b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.kt index 5fcbb54a..0cf4d665 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.kt @@ -1,44 +1,36 @@ -package plus.maa.backend.controller.request.copilot; +package plus.maa.backend.controller.request.copilot +import jakarta.validation.constraints.NotBlank +import plus.maa.backend.repository.entity.Copilot -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import plus.maa.backend.repository.entity.Copilot; - -import java.util.List; /** * @author LoMu * Date 2023-01-10 19:50 */ - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CopilotDTO { - +data class CopilotDTO ( //关卡名 - @NotBlank(message = "关卡名不能为空") - private String stageName; + @field:NotBlank(message = "关卡名不能为空") + var stageName: String, //难度 - private int difficulty; + val difficulty: Int = 0, //版本号(文档中说明:最低要求 maa 版本号,必选。保留字段) - @NotBlank(message = "最低要求 maa 版本不可为空") - private String minimumRequired; + @field:NotBlank(message = "最低要求 maa 版本不可为空") + val minimumRequired: String, //指定干员 - private List opers; + val opers: List? = null, + //群组 - private List groups; + val groups: List? = null, + // 战斗中的操作 - private List actions; + val actions: List? = null, //描述 - private Copilot.Doc doc; + val doc: Copilot.Doc? = null, - private boolean notification; -} + val notification: Boolean = false +) diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt index d9acc43e..a241bcec 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt +++ b/src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt @@ -1,16 +1,14 @@ -package plus.maa.backend.controller.request.copilot; +package plus.maa.backend.controller.request.copilot -import jakarta.validation.constraints.NotBlank; -import lombok.Data; +import jakarta.validation.constraints.NotBlank /** * @author LoMu * Date 2023-01-20 16:25 */ -@Data -public class CopilotRatingReq { +data class CopilotRatingReq( @NotBlank(message = "评分作业id不能为空") - private Long id; + val id: Long, @NotBlank(message = "评分不能为空") - private String rating; -} + val rating: String +) diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt index 7df5976d..bcbb2412 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt @@ -1,28 +1,17 @@ -package plus.maa.backend.controller.response.copilot; +package plus.maa.backend.controller.response.copilot -import com.fasterxml.jackson.annotation.JsonInclude; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; - -import java.io.Serializable; +import java.io.Serializable /** * @author john180 */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_NULL) -public class ArkLevelInfo implements Serializable { - private String levelId; - private String stageId; - private String catOne; - private String catTwo; - private String catThree; - private String name; - private int width; - private int height; -} +data class ArkLevelInfo( + val levelId: String, + val stageId: String, + val catOne: String, + val catTwo: String, + val catThree: String, + val name: String, + val width: Int = 0, + val height: Int = 0 +) : Serializable \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt index 8bb00bc7..e68bff37 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt @@ -1,30 +1,24 @@ -package plus.maa.backend.controller.response.copilot; +package plus.maa.backend.controller.response.copilot -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +import java.io.Serializable +import java.time.LocalDateTime -import java.io.Serializable; -import java.time.LocalDateTime; +data class CopilotInfo ( + val id: Long, -@Data -@NoArgsConstructor -@AllArgsConstructor -public class CopilotInfo implements Serializable { - private Long id; + val uploadTime: LocalDateTime, + val uploader: String, - private LocalDateTime uploadTime; - private String uploader; //用于前端显示的格式化后的干员信息 [干员名]::[技能] - private int views; - private int hotScore; - private boolean available; - private int ratingLevel; - private boolean isNotEnoughRating; - private double ratingRatio; - private int ratingType; - private long commentsCount; - private String content; - private long like; - private long dislike; -} + val views: Long = 0, + val hotScore: Double = 0.0, + var available: Boolean = false, + var ratingLevel: Int = 0, + var isNotEnoughRating: Boolean = false, + var ratingRatio: Double = 0.0, + var ratingType: Int = 0, + val commentsCount: Long = 0, + val content: String, + val like: Long = 0, + val dislike: Long = 0 +): Serializable diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt index 4d457b80..0dc7d68c 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt @@ -1,23 +1,18 @@ -package plus.maa.backend.controller.response.copilot; +package plus.maa.backend.controller.response.copilot -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Data; -import lombok.experimental.Accessors; - -import java.io.Serializable; -import java.util.List; +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import java.io.Serializable /** * @author LoMu * Date 2022-12-27 12:39 */ -@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) -@Accessors(chain = true) -@Data -public class CopilotPageInfo implements Serializable { - private Boolean hasNext; - private Integer page; - private Long total; - private List data; -} +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) +data class CopilotPageInfo( + private val hasNext: Boolean, + private val page: Int, + private val total: Long, + private val data: List +) : Serializable + diff --git a/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt index 2217af7f..35ca99cc 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt @@ -53,13 +53,13 @@ interface CopilotConverter { copilotId: Long, userId: String, now: LocalDateTime, - content: String + content: String? ): Copilot @Mapping(target = "ratingType", ignore = true) @Mapping(target = "ratingRatio", ignore = true) @Mapping(target = "ratingLevel", ignore = true) - @Mapping(target = "notEnoughRating", ignore = true) + @Mapping(target = "isNotEnoughRating", ignore = true) @Mapping(target = "available", ignore = true) @Mapping(target = "id", source = "copilotId") @Mapping(target = "uploader", source = "userName") diff --git a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt index 0cb35d5d..3a92a1a8 100644 --- a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt @@ -46,7 +46,7 @@ import kotlin.math.ceil import kotlin.math.ln import kotlin.math.max -private val log = KotlinLogging.logger { } +private val log = KotlinLogging.logger { } /** * @author LoMu @@ -75,23 +75,23 @@ class CopilotService( private fun correctCopilot(copilotDTO: CopilotDTO): CopilotDTO { // 去除name的冗余部分 if (copilotDTO.groups != null) { - copilotDTO.groups.forEach{ group: Copilot.Groups -> - if (group.opers != null) { - group.opers.forEach{ oper: OperationGroup -> - oper.name = oper.name?.replace("[\"“”]".toRegex(), "") - } + copilotDTO.groups.forEach { group: Copilot.Groups -> + if (group.opers != null) { + group.opers.forEach { oper: OperationGroup -> + oper.name = oper.name?.replace("[\"“”]".toRegex(), "") } } + } } if (copilotDTO.opers != null) { - copilotDTO.opers.forEach{ operator: Copilot.Operators -> + copilotDTO.opers.forEach { operator: Copilot.Operators -> operator.name = operator.name?.replace("[\"“”]".toRegex(), "") } } // actions name 不是必须 if (copilotDTO.actions != null) { - copilotDTO.actions.forEach{ action: Copilot.Action -> + copilotDTO.actions.forEach { action: Copilot.Action -> action.name = if (action.name == null) null else action.name.replace("[\"“”]".toRegex(), "") } } @@ -109,8 +109,10 @@ class CopilotService( * @param content content * @return CopilotDTO */ - private fun parseToCopilotDto(content: String): CopilotDTO { - Assert.notNull(content, "作业内容不可为空") + private fun parseToCopilotDto(content: String?): CopilotDTO { + requireNotNull(content) { + "作业内容不可为空" + } try { return mapper.readValue(content, CopilotDTO::class.java) } catch (e: JsonProcessingException) { @@ -131,7 +133,7 @@ class CopilotService( * @param content 前端编辑json作业内容 * @return 返回_id */ - fun upload(loginUserId: String, content: String): Long { + fun upload(loginUserId: String, content: String?): Long { val copilotDTO = correctCopilot(parseToCopilotDto(content)) // 将其转换为数据库存储对象 val copilot = copilotConverter.toCopilot( @@ -146,7 +148,7 @@ class CopilotService( * 根据作业id删除作业 */ fun delete(loginUserId: String, request: CopilotCUDRequest) { - copilotRepository.findByCopilotId(request.id)?.let { copilot: Copilot -> + copilotRepository.findByCopilotId(request.id!!)?.let { copilot: Copilot -> Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") copilot.isDelete = true copilotRepository.save(copilot) @@ -243,7 +245,7 @@ class CopilotService( "id" -> "copilotId" else -> request.orderBy } - }?: "copilotId" + } ?: "copilotId" ) // 判断是否有值 无值则为默认 val page = if (request.page > 0) request.page else 1 @@ -338,7 +340,7 @@ class CopilotService( it.copilotId }.toSet() val maaUsers = userRepository.findByUsersId(copilots.map { it.uploaderId }.toList()) - val commentsCount = commentsAreaRepository.findByCopilotIdInAndDelete(copilotIds,false) + val commentsCount = commentsAreaRepository.findByCopilotIdInAndDelete(copilotIds, false) .groupBy { it.copilotId } .mapValues { it.value.size.toLong() } @@ -359,11 +361,7 @@ class CopilotService( val hasNext = count - page.toLong() * limit > 0 // 封装数据 - val data = CopilotPageInfo() - .setTotal(count) - .setHasNext(hasNext) - .setData(infos) - .setPage(pageNumber) + val data = CopilotPageInfo(hasNext, pageNumber, count, infos) // 决定是否缓存 if (cacheKey.get() != null) { @@ -383,11 +381,11 @@ class CopilotService( fun update(loginUserId: String, copilotCUDRequest: CopilotCUDRequest) { val content = copilotCUDRequest.content val id = copilotCUDRequest.id - copilotRepository.findByCopilotId(id)?.let { copilot: Copilot -> + copilotRepository.findByCopilotId(id!!)?.let { copilot: Copilot -> val copilotDTO = correctCopilot(parseToCopilotDto(content)) Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") copilot.uploadTime = LocalDateTime.now() - copilotConverter.updateCopilotFromDto(copilotDTO, content, copilot) + copilotConverter.updateCopilotFromDto(copilotDTO, content!!, copilot) copilotRepository.save(copilot) } } @@ -507,7 +505,7 @@ class CopilotService( info.isNotEnoughRating = copilot.likeCount + copilot.dislikeCount <= properties.copilot.minValueShowNotEnoughRating - info.isAvailable = true + info.available = true // 兼容客户端, 将作业ID替换为数字ID copilot.id = copilot.copilotId.toString() @@ -516,7 +514,7 @@ class CopilotService( fun notificationStatus(userId: String?, copilotId: Long, status: Boolean) { val copilotOptional = copilotRepository.findByCopilotId(copilotId) - Assert.isTrue(copilotOptional!=null, "copilot不存在") + Assert.isTrue(copilotOptional != null, "copilot不存在") val copilot = copilotOptional!! Assert.isTrue(userId == copilot.uploaderId, "您没有权限修改") copilot.notification = status From 4129cc2cb565e307bbc22c93479c68492525145f Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 00:46:55 +0800 Subject: [PATCH 111/168] Rename .java to .kt --- .../common/model/{CopilotSetType.java => CopilotSetType.kt} | 0 .../{CopilotSetCreateReq.java => CopilotSetCreateReq.kt} | 0 ...{CopilotSetModCopilotsReq.java => CopilotSetModCopilotsReq.kt} | 0 .../backend/repository/entity/{CopilotSet.java => CopilotSet.kt} | 0 .../service/model/{CopilotSetStatus.java => CopilotSetStatus.kt} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/common/model/{CopilotSetType.java => CopilotSetType.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/copilotset/{CopilotSetCreateReq.java => CopilotSetCreateReq.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/copilotset/{CopilotSetModCopilotsReq.java => CopilotSetModCopilotsReq.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/{CopilotSet.java => CopilotSet.kt} (100%) rename src/main/java/plus/maa/backend/service/model/{CopilotSetStatus.java => CopilotSetStatus.kt} (100%) diff --git a/src/main/java/plus/maa/backend/common/model/CopilotSetType.java b/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/model/CopilotSetType.java rename to src/main/java/plus/maa/backend/common/model/CopilotSetType.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.java b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.java rename to src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.java b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.java rename to src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.java b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/CopilotSet.java rename to src/main/java/plus/maa/backend/repository/entity/CopilotSet.kt diff --git a/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java b/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/CopilotSetStatus.java rename to src/main/java/plus/maa/backend/service/model/CopilotSetStatus.kt From e92d35ca350527909d54538646cc71c08bdf2873 Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 00:46:55 +0800 Subject: [PATCH 112/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E9=9B=86=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD=20pojo?= =?UTF-8?q?=20=E7=B1=BB=E5=88=B0=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/common/model/CopilotSetType.kt | 29 +++----- .../controller/CopilotSetController.kt | 8 +- .../controller/request/CopilotSetQuery.java | 31 -------- .../request/CopilotSetUpdateReq.java | 31 -------- .../request/copilotset/CopilotSetCreateReq.kt | 44 +++++------ .../copilotset/CopilotSetModCopilotsReq.kt | 28 +++---- .../request/copilotset/CopilotSetQuery.kt | 25 +++++++ .../request/copilotset/CopilotSetUpdateReq.kt | 27 +++++++ .../response/CopilotSetPageRes.java | 30 -------- .../controller/response/CopilotSetRes.java | 48 ------------ .../response/copilotset/CopilotSetPageRes.kt | 23 ++++++ .../response/copilotset/CopilotSetRes.kt | 39 ++++++++++ .../backend/repository/entity/CopilotSet.kt | 73 ++++++++++--------- .../backend/service/model/CopilotSetStatus.kt | 12 +-- .../utils/converter/CopilotSetConverter.kt | 11 ++- .../maa/backend/service/CopilotSetService.kt | 42 +++++------ 16 files changed, 223 insertions(+), 278 deletions(-) delete mode 100644 src/main/java/plus/maa/backend/controller/request/CopilotSetQuery.java delete mode 100644 src/main/java/plus/maa/backend/controller/request/CopilotSetUpdateReq.java create mode 100644 src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt create mode 100644 src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt delete mode 100644 src/main/java/plus/maa/backend/controller/response/CopilotSetPageRes.java delete mode 100644 src/main/java/plus/maa/backend/controller/response/CopilotSetRes.java create mode 100644 src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt create mode 100644 src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt diff --git a/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt b/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt index 70300cb6..d9606283 100644 --- a/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt +++ b/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt @@ -1,29 +1,20 @@ -package plus.maa.backend.common.model; +package plus.maa.backend.common.model -import org.springframework.util.Assert; - -import java.util.Collections; -import java.util.List; +import org.springframework.util.Assert /** * @author dragove * create on 2024-01-01 */ -public interface CopilotSetType { - - List getCopilotIds(); +interface CopilotSetType { + val copilotIds: MutableList - default List getDistinctIdsAndCheck() { - List copilotIds = getCopilotIds(); - if (copilotIds == null) { - return Collections.emptyList(); + fun distinctIdsAndCheck(): MutableList { + if (copilotIds.isEmpty() || copilotIds.size == 1) { + return this.copilotIds } - if (copilotIds.isEmpty() || copilotIds.size() == 1) { - return getCopilotIds(); - } - copilotIds = copilotIds.stream().distinct().toList(); - Assert.state(copilotIds.size() <= 1000, "作业集总作业数量不能超过1000条"); - return copilotIds; + val copilotIds = copilotIds.stream().distinct().toList() + Assert.state(copilotIds.size <= 1000, "作业集总作业数量不能超过1000条") + return copilotIds } - } diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt index 6843bb40..61a0f4c1 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt @@ -10,14 +10,14 @@ import org.springframework.web.bind.annotation.* import plus.maa.backend.config.doc.RequireJwt import plus.maa.backend.config.security.AuthenticationHelper import plus.maa.backend.controller.request.CommonIdReq -import plus.maa.backend.controller.request.CopilotSetQuery -import plus.maa.backend.controller.request.CopilotSetUpdateReq import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq -import plus.maa.backend.controller.response.CopilotSetPageRes -import plus.maa.backend.controller.response.CopilotSetRes +import plus.maa.backend.controller.request.copilotset.CopilotSetQuery +import plus.maa.backend.controller.request.copilotset.CopilotSetUpdateReq import plus.maa.backend.controller.response.MaaResult import plus.maa.backend.controller.response.MaaResult.Companion.success +import plus.maa.backend.controller.response.copilotset.CopilotSetPageRes +import plus.maa.backend.controller.response.copilotset.CopilotSetRes import plus.maa.backend.service.CopilotSetService /** diff --git a/src/main/java/plus/maa/backend/controller/request/CopilotSetQuery.java b/src/main/java/plus/maa/backend/controller/request/CopilotSetQuery.java deleted file mode 100644 index bd13920e..00000000 --- a/src/main/java/plus/maa/backend/controller/request/CopilotSetQuery.java +++ /dev/null @@ -1,31 +0,0 @@ -package plus.maa.backend.controller.request; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.Max; -import jakarta.validation.constraints.Positive; -import jakarta.validation.constraints.PositiveOrZero; -import lombok.Getter; -import lombok.Setter; - -/** - * @author dragove - * create on 2024-01-06 - */ -@Getter -@Setter -@Schema(title = "作业集列表查询接口参数") -public class CopilotSetQuery { - - @Positive(message = "页码必须为大于0的数字") - @Schema(title = "页码") - private int page = 1; - - @Schema(title = "单页数据量") - @PositiveOrZero(message = "单页数据量必须为大于等于0的数字") - @Max(value = 50, message = "单页大小不得超过50") - private int limit = 10; - - @Schema(title = "查询关键词") - private String keyword; - -} diff --git a/src/main/java/plus/maa/backend/controller/request/CopilotSetUpdateReq.java b/src/main/java/plus/maa/backend/controller/request/CopilotSetUpdateReq.java deleted file mode 100644 index a503403e..00000000 --- a/src/main/java/plus/maa/backend/controller/request/CopilotSetUpdateReq.java +++ /dev/null @@ -1,31 +0,0 @@ -package plus.maa.backend.controller.request; - -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; -import plus.maa.backend.service.model.CopilotSetStatus; - -/** - * @author dragove - * create on 2024-01-02 - */ -@Getter -@Setter -@Schema(title = "作业集更新请求") -public class CopilotSetUpdateReq { - @NotNull(message = "作业集id不能为空") - private long id; - - @Schema(title = "作业集名称") - @NotBlank(message = "作业集名称不能为空") - private String name; - - @Schema(title = "作业集额外描述") - private String description; - - @NotNull(message = "作业集公开状态不能为null") - @Schema(title = "作业集公开状态", enumAsRef = true) - private CopilotSetStatus status; -} diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt index 696d1dc1..d5348866 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt +++ b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt @@ -1,39 +1,33 @@ -package plus.maa.backend.controller.request.copilotset; +package plus.maa.backend.controller.request.copilotset -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import lombok.Getter; -import lombok.Setter; -import plus.maa.backend.common.model.CopilotSetType; -import plus.maa.backend.service.model.CopilotSetStatus; - -import java.util.List; +import io.swagger.v3.oas.annotations.media.Schema +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.Size +import plus.maa.backend.common.model.CopilotSetType +import plus.maa.backend.service.model.CopilotSetStatus /** * @author dragove * create on 2024-01-01 */ -@Getter -@Setter @Schema(title = "作业集创建请求") -public class CopilotSetCreateReq implements CopilotSetType { - +data class CopilotSetCreateReq( @Schema(title = "作业集名称") - @NotBlank(message = "作业集名称不能为空") - private String name; + @field:NotBlank(message = "作业集名称不能为空") + val name: String, @Schema(title = "作业集额外描述") - private String description; + val description: String = "", - @NotNull(message = "作业id列表字段不能为null") - @Size(max = 1000, message = "作业集作业列表最大只能为1000") @Schema(title = "初始关联作业列表") - private List copilotIds; + @field:NotNull(message = "作业id列表字段不能为null") @Size( + max = 1000, + message = "作业集作业列表最大只能为1000" + ) + override val copilotIds: MutableList, - @NotNull(message = "作业集公开状态不能为null") @Schema(title = "作业集公开状态", enumAsRef = true) - private CopilotSetStatus status; - -} + @field:NotNull(message = "作业集公开状态不能为null") + val status: CopilotSetStatus +) : CopilotSetType diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt index ce550f9c..1d3b3199 100644 --- a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt +++ b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt @@ -1,28 +1,20 @@ -package plus.maa.backend.controller.request.copilotset; +package plus.maa.backend.controller.request.copilotset -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; - -import java.util.List; +import io.swagger.v3.oas.annotations.media.Schema +import jakarta.validation.constraints.NotEmpty +import jakarta.validation.constraints.NotNull /** * @author dragove * create on 2024-01-02 */ -@Getter -@Setter @Schema(title = "作业集新增作业列表请求") -public class CopilotSetModCopilotsReq { - - @NotNull(message = "作业集id必填") +data class CopilotSetModCopilotsReq( @Schema(title = "作业集id") - private long id; + @field:NotNull(message = "作业集id必填") + val id: Long, - @NotEmpty(message = "添加/删除作业id列表不可为空") @Schema(title = "添加/删除收藏的作业id列表") - private List copilotIds; - -} + @field:NotEmpty(message = "添加/删除作业id列表不可为空") + val copilotIds: MutableList +) diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt new file mode 100644 index 00000000..bdd3642d --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt @@ -0,0 +1,25 @@ +package plus.maa.backend.controller.request.copilotset + +import io.swagger.v3.oas.annotations.media.Schema +import jakarta.validation.constraints.Max +import jakarta.validation.constraints.Positive +import jakarta.validation.constraints.PositiveOrZero + +/** + * @author dragove + * create on 2024-01-06 + */ +@Schema(title = "作业集列表查询接口参数") +data class CopilotSetQuery ( + @Schema(title = "页码") + val page: @Positive(message = "页码必须为大于0的数字") Int = 1, + + @Schema(title = "单页数据量") + val limit: @PositiveOrZero(message = "单页数据量必须为大于等于0的数字") @Max( + value = 50, + message = "单页大小不得超过50" + ) Int = 10, + + @Schema(title = "查询关键词") + val keyword: String? = null +) diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt new file mode 100644 index 00000000..c38ba2fa --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt @@ -0,0 +1,27 @@ +package plus.maa.backend.controller.request.copilotset + +import io.swagger.v3.oas.annotations.media.Schema +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotNull +import plus.maa.backend.service.model.CopilotSetStatus + +/** + * @author dragove + * create on 2024-01-02 + */ +@Schema(title = "作业集更新请求") +data class CopilotSetUpdateReq( + @field:NotNull(message = "作业集id不能为空") + val id: Long, + + @Schema(title = "作业集名称") + @field:NotBlank(message = "作业集名称不能为空") + val name: String, + + @Schema(title = "作业集额外描述") + val description: String = "", + + @Schema(title = "作业集公开状态", enumAsRef = true) + @field:NotNull(message = "作业集公开状态不能为null") + val status: CopilotSetStatus +) diff --git a/src/main/java/plus/maa/backend/controller/response/CopilotSetPageRes.java b/src/main/java/plus/maa/backend/controller/response/CopilotSetPageRes.java deleted file mode 100644 index 10e11603..00000000 --- a/src/main/java/plus/maa/backend/controller/response/CopilotSetPageRes.java +++ /dev/null @@ -1,30 +0,0 @@ -package plus.maa.backend.controller.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.Setter; -import lombok.experimental.Accessors; -import plus.maa.backend.controller.response.user.CopilotSetListRes; - -import java.util.List; - -/** - * @author dragove - * create on 2024-01-06 - */ -@Getter -@Setter -@Schema(title = "作业集分页返回数据") -@Accessors(chain = true) -public class CopilotSetPageRes { - - @Schema(title = "是否有下一页") - private boolean hasNext; - @Schema(title = "当前页码") - private int page; - @Schema(title = "总数据量") - private long total; - @Schema(title = "作业集列表") - private List data; - -} diff --git a/src/main/java/plus/maa/backend/controller/response/CopilotSetRes.java b/src/main/java/plus/maa/backend/controller/response/CopilotSetRes.java deleted file mode 100644 index 0349049b..00000000 --- a/src/main/java/plus/maa/backend/controller/response/CopilotSetRes.java +++ /dev/null @@ -1,48 +0,0 @@ -package plus.maa.backend.controller.response; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.Setter; -import plus.maa.backend.service.model.CopilotSetStatus; - -import java.time.LocalDateTime; -import java.util.List; - -/** - * @author dragove - * create on 2024-01-06 - */ -@Getter -@Setter -@Schema(title = "作业集响应") -public class CopilotSetRes { - - @Schema(title = "作业集id") - private long id; - - @Schema(title = "作业集名称") - private String name; - - @Schema(title = "额外描述") - private String description; - - @Schema(title = "作业id列表") - private List copilotIds; - - @Schema(title = "上传者id") - private String creatorId; - - @Schema(title = "上传者昵称") - private String creator; - - @Schema(title = "创建时间") - private LocalDateTime createTime; - - @Schema(title = "更新时间") - private LocalDateTime updateTime; - - @Schema(title = "作业状态", enumAsRef = true) - private CopilotSetStatus status; - - -} diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt new file mode 100644 index 00000000..aec50e80 --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt @@ -0,0 +1,23 @@ +package plus.maa.backend.controller.response.copilotset + +import io.swagger.v3.oas.annotations.media.Schema +import plus.maa.backend.controller.response.user.CopilotSetListRes + +/** + * @author dragove + * create on 2024-01-06 + */ +@Schema(title = "作业集分页返回数据") +data class CopilotSetPageRes ( + @Schema(title = "是否有下一页") + val hasNext: Boolean = false, + + @Schema(title = "当前页码") + val page: Int = 0, + + @Schema(title = "总数据量") + val total: Long = 0, + + @Schema(title = "作业集列表") + val data: MutableList +) diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt new file mode 100644 index 00000000..a7227530 --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt @@ -0,0 +1,39 @@ +package plus.maa.backend.controller.response.copilotset + +import io.swagger.v3.oas.annotations.media.Schema +import plus.maa.backend.service.model.CopilotSetStatus +import java.time.LocalDateTime + +/** + * @author dragove + * create on 2024-01-06 + */ +@Schema(title = "作业集响应") +data class CopilotSetRes( + @Schema(title = "作业集id") + private val id: Long, + + @Schema(title = "作业集名称") + private val name: String, + + @Schema(title = "额外描述") + private val description: String, + + @Schema(title = "作业id列表") + private val copilotIds: List, + + @Schema(title = "上传者id") + private val creatorId: String, + + @Schema(title = "上传者昵称") + private val creator: String, + + @Schema(title = "创建时间") + private val createTime: LocalDateTime, + + @Schema(title = "更新时间") + private val updateTime: LocalDateTime, + + @Schema(title = "作业状态", enumAsRef = true) + private val status: CopilotSetStatus +) diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.kt b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.kt index c43db05d..6a80fae6 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.kt +++ b/src/main/java/plus/maa/backend/repository/entity/CopilotSet.kt @@ -1,81 +1,82 @@ -package plus.maa.backend.repository.entity; +package plus.maa.backend.repository.entity -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.Data; -import lombok.experimental.Accessors; -import org.springframework.data.annotation.Id; -import org.springframework.data.annotation.Transient; -import org.springframework.data.mongodb.core.mapping.Document; -import plus.maa.backend.common.model.CopilotSetType; -import plus.maa.backend.service.model.CopilotSetStatus; - -import java.io.Serializable; -import java.time.LocalDateTime; -import java.util.List; +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import lombok.Data +import lombok.experimental.Accessors +import org.springframework.data.annotation.Id +import org.springframework.data.annotation.Transient +import org.springframework.data.mongodb.core.mapping.Document +import plus.maa.backend.common.model.CopilotSetType +import plus.maa.backend.service.model.CopilotSetStatus +import java.io.Serializable +import java.time.LocalDateTime /** * 作业集数据 */ @Data -@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) @Accessors(chain = true) @Document("maa_copilot_set") -public class CopilotSet implements Serializable, CopilotSetType { - - @Transient - public static final CollectionMeta META = new CollectionMeta<>(CopilotSet::getId, - "id", CopilotSet.class); - +data class CopilotSet( /** * 作业集id */ - @Id - private long id; + @field:Id + val id: Long = 0, /** * 作业集名称 */ - private String name; + var name: String, /** * 额外描述 */ - private String description; + var description: String, /** * 作业id列表 * 使用 list 保证有序 * 作业添加时应当保证唯一 */ - private List copilotIds; + override var copilotIds: MutableList, /** * 上传者id */ - private String creatorId; + val creatorId: String, /** * 创建时间 */ - private LocalDateTime createTime; + val createTime: LocalDateTime, /** * 更新时间 */ - private LocalDateTime updateTime; + var updateTime: LocalDateTime, /** * 作业状态 - * {@link plus.maa.backend.service.model.CopilotSetStatus} + * [plus.maa.backend.service.model.CopilotSetStatus] */ - private CopilotSetStatus status; + var status: CopilotSetStatus, - @JsonIgnore - private boolean delete; + @field:JsonIgnore + var delete: Boolean = false, - @JsonIgnore - private LocalDateTime deleteTime; + @field:JsonIgnore + var deleteTime: LocalDateTime? = null +) : Serializable, CopilotSetType { + companion object { + @field:Transient + val meta = CollectionMeta( + { obj: CopilotSet -> obj.id }, + "id", CopilotSet::class.java + ) + } } diff --git a/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.kt b/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.kt index cc1c7fd0..27933b58 100644 --- a/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.kt +++ b/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.kt @@ -1,23 +1,17 @@ -package plus.maa.backend.service.model; - -import lombok.AllArgsConstructor; -import lombok.Getter; +package plus.maa.backend.service.model /** * @author dragove * create on 2024-01-01 */ -@Getter -@AllArgsConstructor -public enum CopilotSetStatus { - +enum class CopilotSetStatus { /** * 私有,仅查看自己的作业集的时候展示,其他列表页面不展示,但是通过详情接口可查询(无权限控制) */ PRIVATE, + /** * 公开,可以被搜索 */ PUBLIC, - } diff --git a/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt index f0f5a86e..ac9a47d5 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt @@ -3,7 +3,7 @@ package plus.maa.backend.common.utils.converter import org.mapstruct.Mapper import org.mapstruct.Mapping import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq -import plus.maa.backend.controller.response.CopilotSetRes +import plus.maa.backend.controller.response.copilotset.CopilotSetRes import plus.maa.backend.controller.response.user.CopilotSetListRes import plus.maa.backend.repository.entity.CopilotSet import java.time.LocalDateTime @@ -13,19 +13,18 @@ import java.time.LocalDateTime * create on 2024-01-01 */ @Mapper( - componentModel = "spring", imports = [LocalDateTime::class - ] + componentModel = "spring", imports = [LocalDateTime::class] ) interface CopilotSetConverter { @Mapping(target = "delete", ignore = true) @Mapping(target = "deleteTime", ignore = true) - @Mapping(target = "copilotIds", expression = "java(createReq.getDistinctIdsAndCheck())") + @Mapping(target = "copilotIds", expression = "java(createReq.distinctIdsAndCheck())") @Mapping(target = "createTime", expression = "java(LocalDateTime.now())") @Mapping(target = "updateTime", expression = "java(LocalDateTime.now())") - fun convert(createReq: CopilotSetCreateReq, id: Long, creatorId: String?): CopilotSet + fun convert(createReq: CopilotSetCreateReq, id: Long, creatorId: String): CopilotSet @Mapping(target = "creator", ignore = true) - fun convert(copilotSet: CopilotSet, creator: String): CopilotSetListRes? + fun convert(copilotSet: CopilotSet, creator: String): CopilotSetListRes fun convertDetail(copilotSet: CopilotSet, creator: String): CopilotSetRes } diff --git a/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt index 82607172..ec6c4c9e 100644 --- a/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt @@ -7,12 +7,12 @@ import org.springframework.data.domain.Sort import org.springframework.stereotype.Service import plus.maa.backend.common.utils.IdComponent import plus.maa.backend.common.utils.converter.CopilotSetConverter -import plus.maa.backend.controller.request.CopilotSetQuery -import plus.maa.backend.controller.request.CopilotSetUpdateReq import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq import plus.maa.backend.controller.request.copilotset.CopilotSetModCopilotsReq -import plus.maa.backend.controller.response.CopilotSetPageRes -import plus.maa.backend.controller.response.CopilotSetRes +import plus.maa.backend.controller.request.copilotset.CopilotSetQuery +import plus.maa.backend.controller.request.copilotset.CopilotSetUpdateReq +import plus.maa.backend.controller.response.copilotset.CopilotSetPageRes +import plus.maa.backend.controller.response.copilotset.CopilotSetRes import plus.maa.backend.repository.CopilotSetRepository import plus.maa.backend.repository.UserRepository import plus.maa.backend.repository.entity.CopilotSet @@ -33,7 +33,7 @@ class CopilotSetService( private val userRepository: UserRepository, ) { - private val DEFAULT_SORT: Sort = Sort.by("id").descending() + private val defaultSort: Sort = Sort.by("id").descending() /** * 创建作业集 @@ -43,9 +43,8 @@ class CopilotSetService( * @return 作业集id */ fun create(req: CopilotSetCreateReq, userId: String?): Long { - val id = idComponent.getId(CopilotSet.META) - val newCopilotSet = - converter.convert(req, id, userId) + val id = idComponent.getId(CopilotSet.meta) + val newCopilotSet = converter.convert(req, id, userId!!) repository.insert(newCopilotSet) return id } @@ -58,7 +57,7 @@ class CopilotSetService( .orElseThrow { IllegalArgumentException("作业集不存在") } Assert.state(copilotSet.creatorId == userId, "您不是该作业集的创建者,无权修改该作业集") copilotSet.copilotIds.addAll(req.copilotIds) - copilotSet.setCopilotIds(copilotSet.getDistinctIdsAndCheck()) + copilotSet.copilotIds = copilotSet.distinctIdsAndCheck() repository.save(copilotSet) } @@ -81,9 +80,9 @@ class CopilotSetService( val copilotSet = repository.findById(req.id) .orElseThrow { IllegalArgumentException("作业集不存在") } Assert.state(copilotSet.creatorId == userId, "您不是该作业集的创建者,无权修改该作业集") - copilotSet.setName(req.name) - copilotSet.setDescription(req.description) - copilotSet.setStatus(req.status) + copilotSet.name = req.name + copilotSet.description = req.description + copilotSet.status = req.status repository.save(copilotSet) } @@ -98,13 +97,13 @@ class CopilotSetService( val copilotSet = repository.findById(id) .orElseThrow { IllegalArgumentException("作业集不存在") } Assert.state(copilotSet.creatorId == userId, "您不是该作业集的创建者,无权删除该作业集") - copilotSet.setDelete(true) - copilotSet.setDeleteTime(LocalDateTime.now()) + copilotSet.delete = true + copilotSet.deleteTime = LocalDateTime.now() repository.save(copilotSet) } fun query(req: CopilotSetQuery): CopilotSetPageRes { - val pageRequest = PageRequest.of(req.page - 1, req.limit, DEFAULT_SORT) + val pageRequest = PageRequest.of(req.page - 1, req.limit, defaultSort) val keyword = req.keyword val copilotSets = if (keyword.isNullOrBlank()) { @@ -118,14 +117,15 @@ class CopilotSetService( .distinct() .toList() val userById = userRepository.findByUsersId(userIds) - return CopilotSetPageRes() - .setPage(copilotSets.number + 1) - .setTotal(copilotSets.totalElements) - .setHasNext(copilotSets.totalPages > req.page) - .setData(copilotSets.map { cs: CopilotSet -> + return CopilotSetPageRes( + copilotSets.totalPages > req.page, + copilotSets.number + 1, + copilotSets.totalElements, + copilotSets.map { cs: CopilotSet -> val user = userById.getOrDefault(cs.creatorId, MaaUser.UNKNOWN) converter.convert(cs, user.userName) - }.toList()) + }.toList() + ) } fun get(id: Long): CopilotSetRes { From 45a60eb6412f42a5aca37d99a57d3d9bc4b09d85 Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 00:48:26 +0800 Subject: [PATCH 113/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E9=9B=86=E7=9B=B8=E5=85=B3=E5=8A=9F=E8=83=BD=20pojo?= =?UTF-8?q?=20=E7=B1=BB=E5=88=B0=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/common/model/CopilotSetType.kt | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/{java => kotlin}/plus/maa/backend/common/model/CopilotSetType.kt (100%) diff --git a/src/main/java/plus/maa/backend/common/model/CopilotSetType.kt b/src/main/kotlin/plus/maa/backend/common/model/CopilotSetType.kt similarity index 100% rename from src/main/java/plus/maa/backend/common/model/CopilotSetType.kt rename to src/main/kotlin/plus/maa/backend/common/model/CopilotSetType.kt From 6d8f6131ec94fb71a66ef56d312feec891214caa Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 01:01:45 +0800 Subject: [PATCH 114/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A=E4=BF=A1=E6=81=AF=E8=BF=94=E5=9B=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E7=9A=84=E5=90=8D=E7=A7=B0=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/controller/response/copilot/CopilotInfo.kt | 2 +- .../plus/maa/backend/common/utils/converter/CopilotConverter.kt | 2 +- src/main/kotlin/plus/maa/backend/service/CopilotService.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt index e68bff37..7bebf995 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt @@ -14,7 +14,7 @@ data class CopilotInfo ( val hotScore: Double = 0.0, var available: Boolean = false, var ratingLevel: Int = 0, - var isNotEnoughRating: Boolean = false, + var notEnoughRating: Boolean = false, var ratingRatio: Double = 0.0, var ratingType: Int = 0, val commentsCount: Long = 0, diff --git a/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt index 35ca99cc..2cdcf4fe 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotConverter.kt @@ -59,7 +59,7 @@ interface CopilotConverter { @Mapping(target = "ratingType", ignore = true) @Mapping(target = "ratingRatio", ignore = true) @Mapping(target = "ratingLevel", ignore = true) - @Mapping(target = "isNotEnoughRating", ignore = true) + @Mapping(target = "notEnoughRating", ignore = true) @Mapping(target = "available", ignore = true) @Mapping(target = "id", source = "copilotId") @Mapping(target = "uploader", source = "userName") diff --git a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt index 3a92a1a8..9dcbddd6 100644 --- a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt @@ -502,7 +502,7 @@ class CopilotService( info.ratingType = ratingType.display } // 评分数少于一定数量 - info.isNotEnoughRating = + info.notEnoughRating = copilot.likeCount + copilot.dislikeCount <= properties.copilot.minValueShowNotEnoughRating info.available = true From 99187a72ef9d0b94c4b91679111e2e11bdb41756 Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 01:03:23 +0800 Subject: [PATCH 115/168] Rename .java to .kt --- .../controller/request/{CommonIdReq.java => CommonIdReq.kt} | 0 .../response/{MaaResultException.java => MaaResultException.kt} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/request/{CommonIdReq.java => CommonIdReq.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/{MaaResultException.java => MaaResultException.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/request/CommonIdReq.java b/src/main/java/plus/maa/backend/controller/request/CommonIdReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/CommonIdReq.java rename to src/main/java/plus/maa/backend/controller/request/CommonIdReq.kt diff --git a/src/main/java/plus/maa/backend/controller/response/MaaResultException.java b/src/main/java/plus/maa/backend/controller/response/MaaResultException.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/MaaResultException.java rename to src/main/java/plus/maa/backend/controller/response/MaaResultException.kt From 6519097148ff64933b0d096ea8f5e454bad95c72 Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 01:03:23 +0800 Subject: [PATCH 116/168] =?UTF-8?q?refactor:=20CommonIdReq=20=E5=92=8C=20M?= =?UTF-8?q?aaResultException=20=E8=BF=81=E7=A7=BB=E8=87=B3=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/CopilotSetController.kt | 2 +- .../backend/controller/request/CommonIdReq.kt | 18 ++++-------- .../controller/response/MaaResultException.kt | 28 ++++++------------- 3 files changed, 16 insertions(+), 32 deletions(-) diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt index 61a0f4c1..ae1b9b49 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt @@ -95,7 +95,7 @@ class CopilotSetController( fun deleteCopilotSet( @Parameter(description = "删除作业集信息请求") @RequestBody req: @Valid CommonIdReq ): MaaResult { - service.delete(req.id!!, helper.userId!!) + service.delete(req.id, helper.userId!!) return success() } } diff --git a/src/main/java/plus/maa/backend/controller/request/CommonIdReq.kt b/src/main/java/plus/maa/backend/controller/request/CommonIdReq.kt index c8a6abd5..084b2359 100644 --- a/src/main/java/plus/maa/backend/controller/request/CommonIdReq.kt +++ b/src/main/java/plus/maa/backend/controller/request/CommonIdReq.kt @@ -1,18 +1,12 @@ -package plus.maa.backend.controller.request; +package plus.maa.backend.controller.request -import jakarta.validation.constraints.NotNull; -import lombok.Getter; -import lombok.Setter; +import jakarta.validation.constraints.NotNull /** * @author dragove * create on 2024-01-05 */ -@Getter -@Setter -public class CommonIdReq { - - @NotNull(message = "id必填") - private T id; - -} +data class CommonIdReq( + @field:NotNull(message = "id必填") + val id: T +) diff --git a/src/main/java/plus/maa/backend/controller/response/MaaResultException.kt b/src/main/java/plus/maa/backend/controller/response/MaaResultException.kt index 9c385452..2e69ed93 100644 --- a/src/main/java/plus/maa/backend/controller/response/MaaResultException.kt +++ b/src/main/java/plus/maa/backend/controller/response/MaaResultException.kt @@ -1,27 +1,17 @@ -package plus.maa.backend.controller.response; +package plus.maa.backend.controller.response -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import org.springframework.http.HttpStatus; -import plus.maa.backend.common.MaaStatusCode; +import org.springframework.http.HttpStatus +import plus.maa.backend.common.MaaStatusCode /** * @author john180 */ -@Data -@AllArgsConstructor -@EqualsAndHashCode(callSuper = true) -public class MaaResultException extends RuntimeException { - private final int code; - private final String msg; +class MaaResultException( + val code: Int, + val msg: String? +) : RuntimeException() { - public MaaResultException(String msg) { - this(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg); - } + constructor(statusCode: MaaStatusCode) : this(statusCode.code, statusCode.message) + constructor(msg: String) : this(HttpStatus.INTERNAL_SERVER_ERROR.value(), msg) - public MaaResultException(MaaStatusCode statusCode) { - this.code = statusCode.getCode(); - this.msg = statusCode.getMessage(); - } } From 8c6fa547c1976276292c8c987aebd7f143fb6d4a Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 13:03:04 +0800 Subject: [PATCH 117/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=E6=BC=8F?= =?UTF-8?q?=E6=8E=89=E7=9A=84=E4=BD=9C=E4=B8=9A=E9=9B=86=E7=B1=BB=E5=88=B0?= =?UTF-8?q?=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../response/copilotset/CopilotSetListRes.kt | 32 +++++++++++++++ .../response/copilotset/CopilotSetPageRes.kt | 1 - .../response/user/CopilotSetListRes.java | 39 ------------------- .../utils/converter/CopilotSetConverter.kt | 2 +- 4 files changed, 33 insertions(+), 41 deletions(-) create mode 100644 src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt delete mode 100644 src/main/java/plus/maa/backend/controller/response/user/CopilotSetListRes.java diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt new file mode 100644 index 00000000..04646440 --- /dev/null +++ b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt @@ -0,0 +1,32 @@ +package plus.maa.backend.controller.response.copilotset + +import io.swagger.v3.oas.annotations.media.Schema +import java.time.LocalDateTime + +/** + * @author dragove + * create on 2024-01-06 + */ +@Schema(title = "作业集响应(列表)") +data class CopilotSetListRes ( + @Schema(title = "作业集id") + private val id: Long, + + @Schema(title = "作业集名称") + private val name: String, + + @Schema(title = "额外描述") + private val description: String, + + @Schema(title = "上传者id") + private val creatorId: String, + + @Schema(title = "上传者昵称") + private val creator: String, + + @Schema(title = "创建时间") + private val createTime: LocalDateTime, + + @Schema(title = "更新时间") + private val updateTime: LocalDateTime +) diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt index aec50e80..063a0ddc 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt +++ b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt @@ -1,7 +1,6 @@ package plus.maa.backend.controller.response.copilotset import io.swagger.v3.oas.annotations.media.Schema -import plus.maa.backend.controller.response.user.CopilotSetListRes /** * @author dragove diff --git a/src/main/java/plus/maa/backend/controller/response/user/CopilotSetListRes.java b/src/main/java/plus/maa/backend/controller/response/user/CopilotSetListRes.java deleted file mode 100644 index 5b630bee..00000000 --- a/src/main/java/plus/maa/backend/controller/response/user/CopilotSetListRes.java +++ /dev/null @@ -1,39 +0,0 @@ -package plus.maa.backend.controller.response.user; - -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Getter; -import lombok.Setter; - -import java.time.LocalDateTime; - -/** - * @author dragove - * create on 2024-01-06 - */ -@Getter -@Setter -@Schema(title = "作业集响应(列表)") -public class CopilotSetListRes { - - @Schema(title = "作业集id") - private long id; - - @Schema(title = "作业集名称") - private String name; - - @Schema(title = "额外描述") - private String description; - - @Schema(title = "上传者id") - private String creatorId; - - @Schema(title = "上传者昵称") - private String creator; - - @Schema(title = "创建时间") - private LocalDateTime createTime; - - @Schema(title = "更新时间") - private LocalDateTime updateTime; - -} diff --git a/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt index ac9a47d5..6261ae97 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/converter/CopilotSetConverter.kt @@ -4,7 +4,7 @@ import org.mapstruct.Mapper import org.mapstruct.Mapping import plus.maa.backend.controller.request.copilotset.CopilotSetCreateReq import plus.maa.backend.controller.response.copilotset.CopilotSetRes -import plus.maa.backend.controller.response.user.CopilotSetListRes +import plus.maa.backend.controller.response.copilotset.CopilotSetListRes import plus.maa.backend.repository.entity.CopilotSet import java.time.LocalDateTime From ef3c0af119c4dd3dd436f76d89e1d42a020586b1 Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 13:09:12 +0800 Subject: [PATCH 118/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=83=A8?= =?UTF-8?q?=E5=88=86=E7=B1=BB=E5=9E=8B=E8=AE=BF=E9=97=AE=E9=99=90=E5=AE=9A?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/user/EmailActivateReq.java | 14 ------------- .../response/comments/SubCommentsInfo.kt | 20 +++++++++---------- .../response/copilot/CopilotPageInfo.kt | 8 ++++---- .../response/copilotset/CopilotSetListRes.kt | 14 ++++++------- .../response/copilotset/CopilotSetRes.kt | 18 ++++++++--------- .../repository/entity/gamedata/ArkTilePos.kt | 14 ++++++------- .../maa/backend/common/utils/IdComponent.kt | 16 +++++++-------- 7 files changed, 45 insertions(+), 59 deletions(-) delete mode 100644 src/main/java/plus/maa/backend/controller/request/user/EmailActivateReq.java diff --git a/src/main/java/plus/maa/backend/controller/request/user/EmailActivateReq.java b/src/main/java/plus/maa/backend/controller/request/user/EmailActivateReq.java deleted file mode 100644 index cc138ebf..00000000 --- a/src/main/java/plus/maa/backend/controller/request/user/EmailActivateReq.java +++ /dev/null @@ -1,14 +0,0 @@ -package plus.maa.backend.controller.request.user; - -import jakarta.validation.constraints.NotBlank; -import lombok.Data; - -/** - * @author dragove - * created on 2023/1/19 - */ -@Data -public class EmailActivateReq { - @NotBlank(message = "激活标识符不能为空") - private String nonce; -} diff --git a/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt b/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt index 79b89c7b..3ac2838f 100644 --- a/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt @@ -7,15 +7,15 @@ import java.time.LocalDateTime * Date 2023-02-20 17:05 */ data class SubCommentsInfo( - private val commentId: String, - private val uploader: String, - private val uploaderId: String, + val commentId: String, + val uploader: String, + val uploaderId: String, //评论内容, - private val message: String, - private val uploadTime: LocalDateTime, - private val like: Long = 0, - private val dislike: Long = 0, - private val fromCommentId: String, - private val mainCommentId: String, - private val deleted: Boolean = false + val message: String, + val uploadTime: LocalDateTime, + val like: Long = 0, + val dislike: Long = 0, + val fromCommentId: String, + val mainCommentId: String, + val deleted: Boolean = false ) diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt index 0dc7d68c..713212ec 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt @@ -10,9 +10,9 @@ import java.io.Serializable */ @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) data class CopilotPageInfo( - private val hasNext: Boolean, - private val page: Int, - private val total: Long, - private val data: List + val hasNext: Boolean, + val page: Int, + val total: Long, + val data: List ) : Serializable diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt index 04646440..6b3782c9 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt +++ b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt @@ -10,23 +10,23 @@ import java.time.LocalDateTime @Schema(title = "作业集响应(列表)") data class CopilotSetListRes ( @Schema(title = "作业集id") - private val id: Long, + val id: Long, @Schema(title = "作业集名称") - private val name: String, + val name: String, @Schema(title = "额外描述") - private val description: String, + val description: String, @Schema(title = "上传者id") - private val creatorId: String, + val creatorId: String, @Schema(title = "上传者昵称") - private val creator: String, + val creator: String, @Schema(title = "创建时间") - private val createTime: LocalDateTime, + val createTime: LocalDateTime, @Schema(title = "更新时间") - private val updateTime: LocalDateTime + val updateTime: LocalDateTime ) diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt index a7227530..95cb0713 100644 --- a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt +++ b/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt @@ -11,29 +11,29 @@ import java.time.LocalDateTime @Schema(title = "作业集响应") data class CopilotSetRes( @Schema(title = "作业集id") - private val id: Long, + val id: Long, @Schema(title = "作业集名称") - private val name: String, + val name: String, @Schema(title = "额外描述") - private val description: String, + val description: String, @Schema(title = "作业id列表") - private val copilotIds: List, + val copilotIds: List, @Schema(title = "上传者id") - private val creatorId: String, + val creatorId: String, @Schema(title = "上传者昵称") - private val creator: String, + val creator: String, @Schema(title = "创建时间") - private val createTime: LocalDateTime, + val createTime: LocalDateTime, @Schema(title = "更新时间") - private val updateTime: LocalDateTime, + val updateTime: LocalDateTime, @Schema(title = "作业状态", enumAsRef = true) - private val status: CopilotSetStatus + val status: CopilotSetStatus ) diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt index 9c3bab81..434755ce 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt @@ -17,15 +17,15 @@ data class ArkTilePos( val levelId: String? = null, val name: String? = null, val stageId: String? = null, - private val tiles: List>? = null, - private val view: List>? = null, + val tiles: List>? = null, + val view: List>? = null, ) { @JsonNaming(LowerCamelCaseStrategy::class) data class Tile( - private val tileKey: String? = null, - private val heightType: Int? = null, - private val buildableType: Int? = null, - private val isStart: Boolean? = null, - private val isEnd: Boolean? = null, + val tileKey: String? = null, + val heightType: Int? = null, + val buildableType: Int? = null, + val isStart: Boolean? = null, + val isEnd: Boolean? = null, ) } diff --git a/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt b/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt index 3dc77425..99cc0f0d 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt @@ -9,7 +9,7 @@ import plus.maa.backend.repository.entity.CollectionMeta import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.atomic.AtomicLong -private val log = KotlinLogging.logger { } +private val log = KotlinLogging.logger { } @Component class IdComponent( @@ -25,21 +25,21 @@ class IdComponent( fun getId(meta: CollectionMeta): Long { val cls = meta.entityClass val collectionName = mongoTemplate.getCollectionName(cls) - var v = currentIdMap[collectionName] + val v = currentIdMap[collectionName] if (v == null) { synchronized(cls) { - v = currentIdMap[collectionName] - if (v == null) { - v = AtomicLong(getMax(cls, meta.idGetter, meta.incIdField)) - log.info { "初始化获取 collection: $collectionName 的最大 id,id: ${v!!.get()}" } - currentIdMap[collectionName] = v!! + val rv = currentIdMap[collectionName] + if (rv == null) { + val nv = AtomicLong(getMax(cls, meta.idGetter, meta.incIdField)) + log.info { "初始化获取 collection: $collectionName 的最大 id,id: ${nv.get()}" } + currentIdMap[collectionName] = nv } } } return v!!.incrementAndGet() } - private fun getMax(entityClass: Class, idGetter: (T)->Long, fieldName: String) = + private fun getMax(entityClass: Class, idGetter: (T) -> Long, fieldName: String) = mongoTemplate.findOne( Query().with(Sort.by(fieldName).descending()).limit(1), entityClass From 998d37a5e6a731dcc65b26a3b5c3c9d92f050ba4 Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 14:50:35 +0800 Subject: [PATCH 119/168] Rename .java to .kt --- .../controller/request/user/{LoginDTO.java => LoginDTO.kt} | 0 .../request/user/{PasswordResetDTO.java => PasswordResetDTO.kt} | 0 .../user/{PasswordResetVCodeDTO.java => PasswordResetVCodeDTO.kt} | 0 .../request/user/{PasswordUpdateDTO.java => PasswordUpdateDTO.kt} | 0 .../controller/request/user/{RefreshReq.java => RefreshReq.kt} | 0 .../controller/request/user/{RegisterDTO.java => RegisterDTO.kt} | 0 ...{SendRegistrationTokenDTO.java => SendRegistrationTokenDTO.kt} | 0 .../request/user/{UserInfoUpdateDTO.java => UserInfoUpdateDTO.kt} | 0 .../controller/response/user/{MaaLoginRsp.java => MaaLoginRsp.kt} | 0 .../controller/response/user/{MaaUserInfo.java => MaaUserInfo.kt} | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/controller/request/user/{LoginDTO.java => LoginDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/user/{PasswordResetDTO.java => PasswordResetDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/user/{PasswordResetVCodeDTO.java => PasswordResetVCodeDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/user/{PasswordUpdateDTO.java => PasswordUpdateDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/user/{RefreshReq.java => RefreshReq.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/user/{RegisterDTO.java => RegisterDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/user/{SendRegistrationTokenDTO.java => SendRegistrationTokenDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/request/user/{UserInfoUpdateDTO.java => UserInfoUpdateDTO.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/user/{MaaLoginRsp.java => MaaLoginRsp.kt} (100%) rename src/main/java/plus/maa/backend/controller/response/user/{MaaUserInfo.java => MaaUserInfo.kt} (100%) diff --git a/src/main/java/plus/maa/backend/controller/request/user/LoginDTO.java b/src/main/java/plus/maa/backend/controller/request/user/LoginDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/LoginDTO.java rename to src/main/java/plus/maa/backend/controller/request/user/LoginDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.java b/src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.java rename to src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.java b/src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.java rename to src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.java b/src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.java rename to src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/RefreshReq.java b/src/main/java/plus/maa/backend/controller/request/user/RefreshReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/RefreshReq.java rename to src/main/java/plus/maa/backend/controller/request/user/RefreshReq.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.java b/src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.java rename to src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.java b/src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.java rename to src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.java b/src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.java rename to src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.java b/src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.java rename to src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.kt diff --git a/src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.java b/src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.java rename to src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.kt From ddf16f4c5371547bbf8577d9d55285fd310690ad Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 14:50:35 +0800 Subject: [PATCH 120/168] =?UTF-8?q?refactor:=20=E8=BF=94=E5=9B=9E=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E4=BD=BF=E7=94=A8=E5=92=8C=E7=B1=BB=E5=9E=8B=E5=8C=BA?= =?UTF-8?q?=E5=88=86=E6=88=90=E5=8A=9F=E5=92=8C=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/controller/CopilotController.kt | 4 +- .../controller/CopilotSetController.kt | 8 ++-- .../maa/backend/controller/UserController.kt | 18 ++++---- .../backend/controller/file/FileController.kt | 2 +- .../controller/request/user/LoginDTO.kt | 28 +++++-------- .../request/user/PasswordResetDTO.kt | 34 +++++++-------- .../request/user/PasswordResetVCodeDTO.kt | 24 ++++------- .../request/user/PasswordUpdateDTO.kt | 28 +++++-------- .../controller/request/user/RefreshReq.kt | 11 ++--- .../controller/request/user/RegisterDTO.kt | 42 ++++++++----------- .../request/user/SendRegistrationTokenDTO.kt | 18 ++++---- .../request/user/UserInfoUpdateDTO.kt | 24 ++++------- .../backend/controller/response/MaaResult.kt | 26 +++++------- .../controller/response/user/MaaLoginRsp.kt | 27 +++++------- .../controller/response/user/MaaUserInfo.kt | 32 ++++---------- .../utils/converter/MaaUserConverter.kt | 22 ---------- .../security/AccessDeniedHandlerImpl.kt | 2 +- .../security/AuthenticationEntryPointImpl.kt | 2 +- .../AccessLimitInterceptHandlerImpl.kt | 4 +- .../backend/handler/GlobalExceptionHandler.kt | 22 +++++----- .../plus/maa/backend/service/UserService.kt | 10 ++--- 21 files changed, 140 insertions(+), 248 deletions(-) delete mode 100644 src/main/kotlin/plus/maa/backend/common/utils/converter/MaaUserConverter.kt diff --git a/src/main/java/plus/maa/backend/controller/CopilotController.kt b/src/main/java/plus/maa/backend/controller/CopilotController.kt index adb80c95..f454b95d 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotController.kt +++ b/src/main/java/plus/maa/backend/controller/CopilotController.kt @@ -54,7 +54,7 @@ class CopilotController( @PostMapping("/delete") fun deleteCopilot( @Parameter(description = "作业操作请求") @RequestBody request: CopilotCUDRequest? - ): MaaResult { + ): MaaResult { copilotService.delete(helper.requireUserId(), request!!) return success() } @@ -90,7 +90,7 @@ class CopilotController( @PostMapping("/update") fun updateCopilot( @Parameter(description = "作业操作请求") @RequestBody copilotCUDRequest: CopilotCUDRequest - ): MaaResult { + ): MaaResult { copilotService.update(helper.requireUserId(), copilotCUDRequest) return success() } diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt index ae1b9b49..6c27da0f 100644 --- a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt +++ b/src/main/java/plus/maa/backend/controller/CopilotSetController.kt @@ -64,7 +64,7 @@ class CopilotSetController( @PostMapping("/add") fun addCopilotIds( @Parameter(description = "作业集中加入新作业请求") @RequestBody req: @Valid CopilotSetModCopilotsReq - ): MaaResult { + ): MaaResult { service.addCopilotIds(req, helper.userId!!) return success() } @@ -74,7 +74,7 @@ class CopilotSetController( @PostMapping("/remove") fun removeCopilotIds( @Parameter(description = "作业集中删除作业请求") @RequestBody req: @Valid CopilotSetModCopilotsReq - ): MaaResult { + ): MaaResult { service.removeCopilotIds(req, helper.userId!!) return success() } @@ -84,7 +84,7 @@ class CopilotSetController( @PostMapping("/update") fun updateCopilotSet( @Parameter(description = "更新作业集信息请求") @RequestBody req: @Valid CopilotSetUpdateReq - ): MaaResult { + ): MaaResult { service.update(req, helper.userId!!) return success() } @@ -94,7 +94,7 @@ class CopilotSetController( @PostMapping("/delete") fun deleteCopilotSet( @Parameter(description = "删除作业集信息请求") @RequestBody req: @Valid CommonIdReq - ): MaaResult { + ): MaaResult { service.delete(req.id, helper.userId!!) return success() } diff --git a/src/main/java/plus/maa/backend/controller/UserController.kt b/src/main/java/plus/maa/backend/controller/UserController.kt index ec0495a2..a8871f36 100644 --- a/src/main/java/plus/maa/backend/controller/UserController.kt +++ b/src/main/java/plus/maa/backend/controller/UserController.kt @@ -5,14 +5,12 @@ import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.tags.Tag import jakarta.validation.Valid -import org.springframework.beans.factory.annotation.Value import org.springframework.validation.annotation.Validated import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController import plus.maa.backend.config.doc.RequireJwt -import plus.maa.backend.config.external.MaaCopilotProperties import plus.maa.backend.config.security.AuthenticationHelper import plus.maa.backend.controller.request.user.* import plus.maa.backend.controller.response.MaaResult @@ -35,9 +33,7 @@ import plus.maa.backend.service.UserService class UserController( private val userService: UserService, private val emailService: EmailService, - private val properties: MaaCopilotProperties, private val helper: AuthenticationHelper, - @Value("\${maa-copilot.jwt.header}") private val header: String ) { /** @@ -51,7 +47,7 @@ class UserController( @PostMapping("/update/password") fun updatePassword( @Parameter(description = "修改密码请求") @RequestBody updateDTO: @Valid PasswordUpdateDTO - ): MaaResult { + ): MaaResult { userService.modifyPassword(helper.requireUserId(), updateDTO.newPassword) return success() } @@ -68,7 +64,7 @@ class UserController( @PostMapping("/update/info") fun updateInfo( @Parameter(description = "更新用户详细信息请求") @RequestBody updateDTO: @Valid UserInfoUpdateDTO - ): MaaResult { + ): MaaResult { userService.updateUserInfo(helper.requireUserId(), updateDTO) return success() } @@ -82,9 +78,9 @@ class UserController( @PostMapping("/password/reset") @Operation(summary = "重置密码") @ApiResponse(description = "重置密码结果") - fun passwordReset(@Parameter(description = "重置密码请求") @RequestBody passwordResetDTO: @Valid PasswordResetDTO?): MaaResult { + fun passwordReset(@Parameter(description = "重置密码请求") @RequestBody passwordResetDTO: @Valid PasswordResetDTO): MaaResult { // 校验用户邮箱是否存在 - userService!!.checkUserExistByEmail(passwordResetDTO!!.email) + userService.checkUserExistByEmail(passwordResetDTO.email) userService.modifyPasswordByActiveCode(passwordResetDTO) return success() } @@ -98,7 +94,7 @@ class UserController( @PostMapping("/password/reset_request") @Operation(summary = "发送用于重置密码的验证码") @ApiResponse(description = "验证码发送结果") - fun passwordResetRequest(@Parameter(description = "发送重置密码的验证码请求") @RequestBody passwordResetVCodeDTO: @Valid PasswordResetVCodeDTO): MaaResult { + fun passwordResetRequest(@Parameter(description = "发送重置密码的验证码请求") @RequestBody passwordResetVCodeDTO: @Valid PasswordResetVCodeDTO): MaaResult { // 校验用户邮箱是否存在 userService.checkUserExistByEmail(passwordResetVCodeDTO.email) emailService.sendVCode(passwordResetVCodeDTO.email) @@ -138,9 +134,9 @@ class UserController( @PostMapping("/sendRegistrationToken") @Operation(summary = "注册时发送验证码") @ApiResponse(description = "发送验证码结果", responseCode = "204") - fun sendRegistrationToken(@Parameter(description = "发送注册验证码请求") @RequestBody regDTO: @Valid SendRegistrationTokenDTO): MaaResult { + fun sendRegistrationToken(@Parameter(description = "发送注册验证码请求") @RequestBody regDTO: @Valid SendRegistrationTokenDTO): MaaResult { userService.sendRegistrationToken(regDTO) - return MaaResult(204, null, null) + return success() } /** diff --git a/src/main/java/plus/maa/backend/controller/file/FileController.kt b/src/main/java/plus/maa/backend/controller/file/FileController.kt index 125cffa0..87528075 100644 --- a/src/main/java/plus/maa/backend/controller/file/FileController.kt +++ b/src/main/java/plus/maa/backend/controller/file/FileController.kt @@ -82,7 +82,7 @@ class FileController( @Operation(summary = "设置上传文件功能状态") @RequireJwt @PostMapping("/upload_ability") - fun setUploadAbility(@RequestBody request: UploadAbility): MaaResult { + fun setUploadAbility(@RequestBody request: UploadAbility): MaaResult { fileService.isUploadEnabled = request.enabled return success() } diff --git a/src/main/java/plus/maa/backend/controller/request/user/LoginDTO.kt b/src/main/java/plus/maa/backend/controller/request/user/LoginDTO.kt index 2c2f8270..f81f7fe6 100644 --- a/src/main/java/plus/maa/backend/controller/request/user/LoginDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/user/LoginDTO.kt @@ -1,23 +1,15 @@ -package plus.maa.backend.controller.request.user; +package plus.maa.backend.controller.request.user -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; +import jakarta.validation.constraints.Email +import jakarta.validation.constraints.NotBlank /** * @author AnselYuki */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -public class LoginDTO { - @NotBlank(message = "邮箱格式错误") - @Email(message = "邮箱格式错误") - private String email; - @NotBlank(message = "请输入用户密码") - private String password; -} +data class LoginDTO( + @field:NotBlank(message = "邮箱格式错误") + @field:Email(message = "邮箱格式错误") + val email: String, + @field:NotBlank(message = "请输入用户密码") + val password: String +) diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.kt b/src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.kt index e0fdf9ad..6b113ba0 100644 --- a/src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.kt @@ -1,34 +1,28 @@ -package plus.maa.backend.controller.request.user; +package plus.maa.backend.controller.request.user -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; +import jakarta.validation.constraints.Email +import jakarta.validation.constraints.NotBlank /** * 通过邮件修改密码请求 */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -public class PasswordResetDTO { +data class PasswordResetDTO( /** * 邮箱 */ - @NotBlank(message = "邮箱格式错误") - @Email(message = "邮箱格式错误") - private String email; + @field:NotBlank(message = "邮箱格式错误") + @field:Email(message = "邮箱格式错误") + val email: String, + /** * 验证码 */ - @NotBlank(message = "请输入验证码") - private String activeCode; + @field:NotBlank(message = "请输入验证码") + val activeCode: String, + /** * 修改后的密码 */ - @NotBlank(message = "请输入用户密码") - private String password; -} + @field:NotBlank(message = "请输入用户密码") + val password: String +) diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt b/src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt index 4b843cd0..c573f315 100644 --- a/src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt @@ -1,24 +1,16 @@ -package plus.maa.backend.controller.request.user; +package plus.maa.backend.controller.request.user -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; +import jakarta.validation.constraints.Email +import jakarta.validation.constraints.NotBlank /** * 通过邮件修改密码发送验证码请求 */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -public class PasswordResetVCodeDTO { +data class PasswordResetVCodeDTO( /** * 邮箱 */ - @NotBlank(message = "邮箱格式错误") - @Email(message = "邮箱格式错误") - private String email; -} + @field:NotBlank(message = "邮箱格式错误") + @field:Email(message = "邮箱格式错误") + val email: String +) diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt b/src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt index 8775b4c6..824ba8b0 100644 --- a/src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt @@ -1,23 +1,15 @@ -package plus.maa.backend.controller.request.user; +package plus.maa.backend.controller.request.user -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; -import org.hibernate.validator.constraints.Length; +import jakarta.validation.constraints.NotBlank +import org.hibernate.validator.constraints.Length /** * @author AnselYuki */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -public class PasswordUpdateDTO { - @NotBlank(message = "请输入原密码") - private String originalPassword; - @NotBlank(message = "密码长度必须在8-32位之间") - @Length(min = 8, max = 32, message = "密码长度必须在8-32位之间") - private String newPassword; -} +data class PasswordUpdateDTO( + @field:NotBlank(message = "请输入原密码") + val originalPassword: String, + @field:NotBlank(message = "密码长度必须在8-32位之间") + @field:Length(min = 8, max = 32, message = "密码长度必须在8-32位之间") + val newPassword: String +) diff --git a/src/main/java/plus/maa/backend/controller/request/user/RefreshReq.kt b/src/main/java/plus/maa/backend/controller/request/user/RefreshReq.kt index 2f381c43..9a48f7b4 100644 --- a/src/main/java/plus/maa/backend/controller/request/user/RefreshReq.kt +++ b/src/main/java/plus/maa/backend/controller/request/user/RefreshReq.kt @@ -1,8 +1,5 @@ -package plus.maa.backend.controller.request.user; +package plus.maa.backend.controller.request.user -import lombok.Data; - -@Data -public class RefreshReq { - private String refreshToken; -} +data class RefreshReq( + val refreshToken: String +) diff --git a/src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.kt b/src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.kt index 4272cb9a..69e1ceaa 100644 --- a/src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.kt @@ -1,30 +1,22 @@ -package plus.maa.backend.controller.request.user; +package plus.maa.backend.controller.request.user -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; -import org.hibernate.validator.constraints.Length; +import jakarta.validation.constraints.Email +import jakarta.validation.constraints.NotBlank +import org.hibernate.validator.constraints.Length /** * @author AnselYuki */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -public class RegisterDTO { - @NotBlank(message = "邮箱格式错误") - @Email(message = "邮箱格式错误") - private String email; - @NotBlank(message = "用户名长度应在4-24位之间") - @Length(min = 4, max = 24, message = "用户名长度应在4-24位之间") - private String userName; - @NotBlank(message = "密码长度必须在8-32位之间") - @Length(min = 8, max = 32, message = "密码长度必须在8-32位之间") - private String password; - @NotBlank(message = "请输入验证码") - private String registrationToken; -} +data class RegisterDTO( + @field:NotBlank(message = "邮箱格式错误") + @field:Email(message = "邮箱格式错误") + val email: String, + @field:NotBlank(message = "用户名长度应在4-24位之间") + @field:Length(min = 4, max = 24, message = "用户名长度应在4-24位之间") + val userName: String, + @field:NotBlank(message = "密码长度必须在8-32位之间") + @field:Length(min = 8, max = 32, message = "密码长度必须在8-32位之间") + val password: String, + @field:NotBlank(message = "请输入验证码") + val registrationToken: String +) diff --git a/src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt b/src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt index 582271a4..2e5d5e85 100644 --- a/src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt @@ -1,12 +1,10 @@ -package plus.maa.backend.controller.request.user; +package plus.maa.backend.controller.request.user -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import lombok.Data; +import jakarta.validation.constraints.Email +import jakarta.validation.constraints.NotBlank -@Data -public class SendRegistrationTokenDTO { - @NotBlank(message = "邮箱格式错误") - @Email(message = "邮箱格式错误") - private String email; -} +data class SendRegistrationTokenDTO( + @field:NotBlank(message = "邮箱格式错误") + @field:Email(message = "邮箱格式错误") + val email: String +) diff --git a/src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt b/src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt index 2f03476a..8fcf21a6 100644 --- a/src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt +++ b/src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt @@ -1,21 +1,13 @@ -package plus.maa.backend.controller.request.user; +package plus.maa.backend.controller.request.user -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; -import org.hibernate.validator.constraints.Length; +import jakarta.validation.constraints.NotBlank +import org.hibernate.validator.constraints.Length /** * @author AnselYuki */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -public class UserInfoUpdateDTO { - @NotBlank(message = "用户名长度应在4-24位之间") - @Length(min = 4, max = 24, message = "用户名长度应在4-24位之间") - private String userName; -} +data class UserInfoUpdateDTO( + @field:NotBlank(message = "用户名长度应在4-24位之间") + @field:Length(min = 4, max = 24, message = "用户名长度应在4-24位之间") + val userName: String +) diff --git a/src/main/java/plus/maa/backend/controller/response/MaaResult.kt b/src/main/java/plus/maa/backend/controller/response/MaaResult.kt index bf74c443..9c5c93d2 100644 --- a/src/main/java/plus/maa/backend/controller/response/MaaResult.kt +++ b/src/main/java/plus/maa/backend/controller/response/MaaResult.kt @@ -6,31 +6,25 @@ import com.fasterxml.jackson.annotation.JsonInclude * @author AnselYuki */ @JsonInclude(JsonInclude.Include.NON_NULL) -data class MaaResult(val statusCode: Int, val message: String?, val data: T) { +sealed interface MaaResult { + data class Success(val statusCode: Int, val message: String?, val data: T) : MaaResult + data class Fail(val statusCode: Int, val message: String?) : MaaResult companion object { - @JvmStatic - fun success(data: T): MaaResult { + fun success(data: T): Success { return success(null, data) } - @JvmStatic - fun success(): MaaResult { - return success(null, null) + fun success(): Success { + return success(null, Unit) } - @JvmStatic - fun success(msg: String?, data: T): MaaResult { - return MaaResult(200, msg, data) + fun success(msg: String?, data: T): Success { + return Success(200, msg, data) } - @JvmStatic - fun fail(code: Int, msg: String?): MaaResult { - return fail(code, msg, null) + fun fail(code: Int, msg: String?): Fail { + return Fail(code, msg) } - @JvmStatic - fun fail(code: Int, msg: String?, data: T): MaaResult { - return MaaResult(code, msg, data) - } } } \ No newline at end of file diff --git a/src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.kt b/src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.kt index 6c651064..aab4ac31 100644 --- a/src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.kt +++ b/src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.kt @@ -1,18 +1,13 @@ -package plus.maa.backend.controller.response.user; +package plus.maa.backend.controller.response.user -import lombok.AllArgsConstructor; -import lombok.Data; +import java.time.LocalDateTime -import java.time.LocalDateTime; - -@Data -@AllArgsConstructor -public class MaaLoginRsp { - private String token; - private LocalDateTime validBefore; - private LocalDateTime validAfter; - private String refreshToken; - private LocalDateTime refreshTokenValidBefore; - private LocalDateTime refreshTokenValidAfter; - private MaaUserInfo userInfo; -} +data class MaaLoginRsp( + val token: String, + val validBefore: LocalDateTime, + val validAfter: LocalDateTime, + val refreshToken: String, + val refreshTokenValidBefore: LocalDateTime, + val refreshTokenValidAfter: LocalDateTime, + val userInfo: MaaUserInfo +) diff --git a/src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.kt b/src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.kt index 5741768f..6ba0a7dc 100644 --- a/src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.kt +++ b/src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.kt @@ -1,30 +1,14 @@ -package plus.maa.backend.controller.response.user; +package plus.maa.backend.controller.response.user -import org.springframework.beans.BeanUtils; - -import com.fasterxml.jackson.annotation.JsonInclude; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; -import plus.maa.backend.repository.entity.MaaUser; +import plus.maa.backend.repository.entity.MaaUser /** * @author AnselYuki */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -@JsonInclude(JsonInclude.Include.NON_NULL) -public class MaaUserInfo { - private String id; - private String userName; - private boolean activated; - private long uploadCount; - - public MaaUserInfo(MaaUser save) { - BeanUtils.copyProperties(save, this); - } +data class MaaUserInfo( + val id: String, + val userName: String, + val activated: Boolean = false +) { + constructor(user: MaaUser) : this(user.userId, user.userName, user.status == 1) } diff --git a/src/main/kotlin/plus/maa/backend/common/utils/converter/MaaUserConverter.kt b/src/main/kotlin/plus/maa/backend/common/utils/converter/MaaUserConverter.kt deleted file mode 100644 index afcc6060..00000000 --- a/src/main/kotlin/plus/maa/backend/common/utils/converter/MaaUserConverter.kt +++ /dev/null @@ -1,22 +0,0 @@ -package plus.maa.backend.common.utils.converter - -import org.mapstruct.Mapper -import org.mapstruct.Mapping -import plus.maa.backend.controller.response.user.MaaUserInfo -import plus.maa.backend.repository.entity.MaaUser -import java.util.* - -/** - * @author dragove - * created on 2022/12/26 - */ -@Mapper( - componentModel = "spring", imports = [Objects::class - ] -) -interface MaaUserConverter { - @Mapping(source = "userId", target = "id") - @Mapping(target = "activated", expression = "java(Objects.equals(user.getStatus(), 1))") - @Mapping(target = "uploadCount", ignore = true) - fun convert(user: MaaUser): MaaUserInfo -} diff --git a/src/main/kotlin/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt b/src/main/kotlin/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt index 2c7966cc..3ce13d83 100644 --- a/src/main/kotlin/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt +++ b/src/main/kotlin/plus/maa/backend/config/security/AccessDeniedHandlerImpl.kt @@ -22,7 +22,7 @@ class AccessDeniedHandlerImpl : AccessDeniedHandler { response: HttpServletResponse, accessDeniedException: AccessDeniedException ) { - val result = fail(HttpStatus.FORBIDDEN.value(), "权限不足") + val result = fail(HttpStatus.FORBIDDEN.value(), "权限不足") val json = ObjectMapper().writeValueAsString(result) renderString(response, json, HttpStatus.FORBIDDEN.value()) } diff --git a/src/main/kotlin/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt b/src/main/kotlin/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt index 16ad92a2..36b3ca8b 100644 --- a/src/main/kotlin/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt +++ b/src/main/kotlin/plus/maa/backend/config/security/AuthenticationEntryPointImpl.kt @@ -25,7 +25,7 @@ class AuthenticationEntryPointImpl( response: HttpServletResponse, authException: AuthenticationException ) { - val result = fail(HttpStatus.UNAUTHORIZED.value(), authException.message) + val result = fail(HttpStatus.UNAUTHORIZED.value(), authException.message) val json = objectMapper.writeValueAsString(result) renderString(response, json, HttpStatus.UNAUTHORIZED.value()) } diff --git a/src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt b/src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt index a0a18e50..2af15f8a 100644 --- a/src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt +++ b/src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt @@ -25,8 +25,6 @@ private val log = KotlinLogging.logger { } */ @Component class AccessLimitInterceptHandlerImpl : HandlerInterceptor { - // @Resource - // private RedisCache redisCache; /** * 接口调用前检查对方ip是否频繁调用接口 * @@ -77,7 +75,7 @@ class AccessLimitInterceptHandlerImpl : HandlerInterceptor { } else { // 请求过于频繁 log.info { "$key 请求过于频繁" } - val result = fail(HttpStatus.TOO_MANY_REQUESTS.value(), "请求过于频繁") + val result = fail(HttpStatus.TOO_MANY_REQUESTS.value(), "请求过于频繁") val json = ObjectMapper().writeValueAsString(result) WebUtils.renderString(response, json, HttpStatus.TOO_MANY_REQUESTS.value()) return false diff --git a/src/main/kotlin/plus/maa/backend/handler/GlobalExceptionHandler.kt b/src/main/kotlin/plus/maa/backend/handler/GlobalExceptionHandler.kt index 984f370d..664958b9 100644 --- a/src/main/kotlin/plus/maa/backend/handler/GlobalExceptionHandler.kt +++ b/src/main/kotlin/plus/maa/backend/handler/GlobalExceptionHandler.kt @@ -35,7 +35,7 @@ class GlobalExceptionHandler { fun missingServletRequestParameterException( e: MissingServletRequestParameterException, request: HttpServletRequest - ): MaaResult { + ): MaaResult { logWarn(request) log.warn(e) { "请求参数缺失" } return fail(400, String.format("请求参数缺失:%s", e.parameterName)) @@ -51,7 +51,7 @@ class GlobalExceptionHandler { fun methodArgumentTypeMismatchException( e: MethodArgumentTypeMismatchException, request: HttpServletRequest - ): MaaResult { + ): MaaResult { logWarn(request) log.warn(e) { "参数类型不匹配" } return fail(400, String.format("参数类型不匹配:%s", e.message)) @@ -64,7 +64,7 @@ class GlobalExceptionHandler { * @date 2022/12/23 12:02 */ @ExceptionHandler(MethodArgumentNotValidException::class) - fun methodArgumentNotValidException(e: MethodArgumentNotValidException): MaaResult { + fun methodArgumentNotValidException(e: MethodArgumentNotValidException): MaaResult { val fieldError = e.bindingResult.fieldError if (fieldError != null) { return fail(400, String.format("参数校验错误: %s", fieldError.defaultMessage)) @@ -79,7 +79,7 @@ class GlobalExceptionHandler { * @date 2022/12/23 12:03 */ @ExceptionHandler(NoHandlerFoundException::class) - fun noHandlerFoundExceptionHandler(e: NoHandlerFoundException): MaaResult { + fun noHandlerFoundExceptionHandler(e: NoHandlerFoundException): MaaResult { log.warn(e) { "请求地址不存在" } return fail(404, String.format("请求地址 %s 不存在", e.requestURL)) } @@ -94,7 +94,7 @@ class GlobalExceptionHandler { fun httpRequestMethodNotSupportedExceptionHandler( e: HttpRequestMethodNotSupportedException, request: HttpServletRequest - ): MaaResult { + ): MaaResult { logWarn(request) log.warn(e) { "请求方式错误" } return fail(405, String.format("请求方法不正确:%s", e.message)) @@ -104,7 +104,7 @@ class GlobalExceptionHandler { * 处理由 [org.springframework.util.Assert] 工具产生的异常 */ @ExceptionHandler(IllegalArgumentException::class, IllegalStateException::class) - fun illegalArgumentOrStateExceptionHandler(e: RuntimeException): MaaResult { + fun illegalArgumentOrStateExceptionHandler(e: RuntimeException): MaaResult { return fail(HttpStatus.BAD_REQUEST.value(), e.message) } @@ -115,7 +115,7 @@ class GlobalExceptionHandler { * @date 2022/12/26 12:00 */ @ExceptionHandler(MaaResultException::class) - fun maaResultExceptionHandler(e: MaaResultException): MaaResult { + fun maaResultExceptionHandler(e: MaaResultException): MaaResult { return fail(e.code, e.msg) } @@ -124,17 +124,17 @@ class GlobalExceptionHandler { * @description 用户鉴权相关,异常兜底处理 */ @ExceptionHandler(AuthenticationException::class) - fun authExceptionHandler(e: AuthenticationException): MaaResult { + fun authExceptionHandler(e: AuthenticationException): MaaResult { return fail(401, e.message) } @ExceptionHandler(MultipartException::class) - fun fileSizeThresholdHandler(e: MultipartException): MaaResult { + fun fileSizeThresholdHandler(e: MultipartException): MaaResult { return fail(413, e.message) } @ExceptionHandler(ResponseStatusException::class) - fun handleResponseStatusException(ex: ResponseStatusException): MaaResult { + fun handleResponseStatusException(ex: ResponseStatusException): MaaResult { return fail(ex.statusCode.value(), ex.message) } @@ -152,7 +152,7 @@ class GlobalExceptionHandler { ): MaaResult<*> { logError(request) log.error(e) { "Exception: " } - return fail(500, "服务器内部错误", null) + return fail(500, "服务器内部错误") } private fun logWarn(request: HttpServletRequest) { diff --git a/src/main/kotlin/plus/maa/backend/service/UserService.kt b/src/main/kotlin/plus/maa/backend/service/UserService.kt index a3623155..0d10f4ce 100644 --- a/src/main/kotlin/plus/maa/backend/service/UserService.kt +++ b/src/main/kotlin/plus/maa/backend/service/UserService.kt @@ -8,7 +8,6 @@ import org.springframework.dao.DuplicateKeyException import org.springframework.security.crypto.password.PasswordEncoder import org.springframework.stereotype.Service import plus.maa.backend.common.MaaStatusCode -import plus.maa.backend.common.utils.converter.MaaUserConverter import plus.maa.backend.config.external.MaaCopilotProperties import plus.maa.backend.controller.request.user.* import plus.maa.backend.controller.response.MaaResultException @@ -34,7 +33,6 @@ class UserService( private val passwordEncoder: PasswordEncoder, private val userDetailService: UserDetailServiceImpl, private val jwtService: JwtService, - private val maaUserConverter: MaaUserConverter, private val properties: MaaCopilotProperties ) { @@ -71,7 +69,7 @@ class UserService( refreshToken.value, refreshToken.expiresAt, refreshToken.notBefore, - maaUserConverter.convert(user) + MaaUserInfo(user) ) } @@ -135,7 +133,7 @@ class UserService( * * @param token token */ - fun refreshToken(token: String?): MaaLoginRsp { + fun refreshToken(token: String): MaaLoginRsp { try { val old = jwtService.verifyAndParseRefreshToken(token) @@ -163,7 +161,7 @@ class UserService( refreshToken.value, refreshToken.expiresAt, refreshToken.notBefore, - maaUserConverter.convert(user) + MaaUserInfo(user) ) } catch (e: JwtInvalidException) { throw MaaResultException(401, e.message) @@ -190,7 +188,7 @@ class UserService( * * @param email 用户邮箱 */ - fun checkUserExistByEmail(email: String?) { + fun checkUserExistByEmail(email: String) { if (null == userRepository.findByEmail(email)) { throw MaaResultException(MaaStatusCode.MAA_USER_NOT_FOUND) } From 93e2a0c8eebefe09c9b46c6a57b1ad7126793aac Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 20:05:39 +0800 Subject: [PATCH 121/168] =?UTF-8?q?refactor:=20=E7=A7=BB=E5=8A=A8=20contro?= =?UTF-8?q?ller=20=E5=88=B0=20kotlin=20=E7=9B=AE=E5=BD=95=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/controller/ArkLevelController.kt | 0 .../plus/maa/backend/controller/CommentsAreaController.kt | 0 .../plus/maa/backend/controller/CopilotController.kt | 0 .../plus/maa/backend/controller/CopilotSetController.kt | 0 .../plus/maa/backend/controller/SystemController.kt | 0 .../plus/maa/backend/controller/UserController.kt | 0 .../plus/maa/backend/controller/file/FileController.kt | 0 .../plus/maa/backend/controller/file/ImageDownloadDTO.kt | 0 .../plus/maa/backend/controller/file/UploadAbility.kt | 0 .../plus/maa/backend/controller/request/CommonIdReq.kt | 0 .../maa/backend/controller/request/comments/CommentsAddDTO.kt | 0 .../maa/backend/controller/request/comments/CommentsDeleteDTO.kt | 0 .../maa/backend/controller/request/comments/CommentsQueriesDTO.kt | 0 .../maa/backend/controller/request/comments/CommentsRatingDTO.kt | 0 .../maa/backend/controller/request/comments/CommentsToppingDTO.kt | 0 .../maa/backend/controller/request/copilot/CopilotCUDRequest.kt | 0 .../plus/maa/backend/controller/request/copilot/CopilotDTO.kt | 0 .../backend/controller/request/copilot/CopilotQueriesRequest.kt | 0 .../maa/backend/controller/request/copilot/CopilotRatingReq.kt | 0 .../backend/controller/request/copilotset/CopilotSetCreateReq.kt | 0 .../controller/request/copilotset/CopilotSetModCopilotsReq.kt | 0 .../maa/backend/controller/request/copilotset/CopilotSetQuery.kt | 0 .../backend/controller/request/copilotset/CopilotSetUpdateReq.kt | 0 .../plus/maa/backend/controller/request/user/LoginDTO.kt | 0 .../plus/maa/backend/controller/request/user/PasswordResetDTO.kt | 0 .../maa/backend/controller/request/user/PasswordResetVCodeDTO.kt | 0 .../plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt | 0 .../plus/maa/backend/controller/request/user/RefreshReq.kt | 0 .../plus/maa/backend/controller/request/user/RegisterDTO.kt | 0 .../backend/controller/request/user/SendRegistrationTokenDTO.kt | 0 .../plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt | 0 .../plus/maa/backend/controller/response/MaaResult.kt | 0 .../plus/maa/backend/controller/response/MaaResultException.kt | 0 .../maa/backend/controller/response/comments/CommentsAreaInfo.kt | 0 .../plus/maa/backend/controller/response/comments/CommentsInfo.kt | 0 .../maa/backend/controller/response/comments/SubCommentsInfo.kt | 0 .../plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt | 0 .../plus/maa/backend/controller/response/copilot/CopilotInfo.kt | 0 .../maa/backend/controller/response/copilot/CopilotPageInfo.kt | 0 .../backend/controller/response/copilotset/CopilotSetListRes.kt | 0 .../backend/controller/response/copilotset/CopilotSetPageRes.kt | 0 .../maa/backend/controller/response/copilotset/CopilotSetRes.kt | 0 .../plus/maa/backend/controller/response/user/MaaLoginRsp.kt | 0 .../plus/maa/backend/controller/response/user/MaaUserInfo.kt | 0 44 files changed, 0 insertions(+), 0 deletions(-) rename src/main/{java => kotlin}/plus/maa/backend/controller/ArkLevelController.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/CommentsAreaController.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/CopilotController.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/CopilotSetController.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/SystemController.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/UserController.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/file/FileController.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/file/ImageDownloadDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/file/UploadAbility.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/CommonIdReq.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/copilot/CopilotDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/user/LoginDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/user/PasswordResetDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/user/RefreshReq.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/user/RegisterDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/MaaResult.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/MaaResultException.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/comments/CommentsInfo.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/copilot/CopilotInfo.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/user/MaaLoginRsp.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/controller/response/user/MaaUserInfo.kt (100%) diff --git a/src/main/java/plus/maa/backend/controller/ArkLevelController.kt b/src/main/kotlin/plus/maa/backend/controller/ArkLevelController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/ArkLevelController.kt rename to src/main/kotlin/plus/maa/backend/controller/ArkLevelController.kt diff --git a/src/main/java/plus/maa/backend/controller/CommentsAreaController.kt b/src/main/kotlin/plus/maa/backend/controller/CommentsAreaController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/CommentsAreaController.kt rename to src/main/kotlin/plus/maa/backend/controller/CommentsAreaController.kt diff --git a/src/main/java/plus/maa/backend/controller/CopilotController.kt b/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/CopilotController.kt rename to src/main/kotlin/plus/maa/backend/controller/CopilotController.kt diff --git a/src/main/java/plus/maa/backend/controller/CopilotSetController.kt b/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/CopilotSetController.kt rename to src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt diff --git a/src/main/java/plus/maa/backend/controller/SystemController.kt b/src/main/kotlin/plus/maa/backend/controller/SystemController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/SystemController.kt rename to src/main/kotlin/plus/maa/backend/controller/SystemController.kt diff --git a/src/main/java/plus/maa/backend/controller/UserController.kt b/src/main/kotlin/plus/maa/backend/controller/UserController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/UserController.kt rename to src/main/kotlin/plus/maa/backend/controller/UserController.kt diff --git a/src/main/java/plus/maa/backend/controller/file/FileController.kt b/src/main/kotlin/plus/maa/backend/controller/file/FileController.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/file/FileController.kt rename to src/main/kotlin/plus/maa/backend/controller/file/FileController.kt diff --git a/src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.kt b/src/main/kotlin/plus/maa/backend/controller/file/ImageDownloadDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/file/ImageDownloadDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/file/ImageDownloadDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/file/UploadAbility.kt b/src/main/kotlin/plus/maa/backend/controller/file/UploadAbility.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/file/UploadAbility.kt rename to src/main/kotlin/plus/maa/backend/controller/file/UploadAbility.kt diff --git a/src/main/java/plus/maa/backend/controller/request/CommonIdReq.kt b/src/main/kotlin/plus/maa/backend/controller/request/CommonIdReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/CommonIdReq.kt rename to src/main/kotlin/plus/maa/backend/controller/request/CommonIdReq.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsDeleteDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsQueriesDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsRatingDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsToppingDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt rename to src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotCUDRequest.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilot/CopilotDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt rename to src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotQueriesRequest.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt rename to src/main/kotlin/plus/maa/backend/controller/request/copilot/CopilotRatingReq.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt rename to src/main/kotlin/plus/maa/backend/controller/request/copilotset/CopilotSetCreateReq.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt rename to src/main/kotlin/plus/maa/backend/controller/request/copilotset/CopilotSetModCopilotsReq.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt rename to src/main/kotlin/plus/maa/backend/controller/request/copilotset/CopilotSetQuery.kt diff --git a/src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt b/src/main/kotlin/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt rename to src/main/kotlin/plus/maa/backend/controller/request/copilotset/CopilotSetUpdateReq.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/LoginDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/user/LoginDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/LoginDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/user/LoginDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/user/PasswordResetDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/PasswordResetDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/user/PasswordResetDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/user/PasswordResetVCodeDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/user/PasswordUpdateDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/RefreshReq.kt b/src/main/kotlin/plus/maa/backend/controller/request/user/RefreshReq.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/RefreshReq.kt rename to src/main/kotlin/plus/maa/backend/controller/request/user/RefreshReq.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/user/RegisterDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/RegisterDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/user/RegisterDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/user/SendRegistrationTokenDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt rename to src/main/kotlin/plus/maa/backend/controller/request/user/UserInfoUpdateDTO.kt diff --git a/src/main/java/plus/maa/backend/controller/response/MaaResult.kt b/src/main/kotlin/plus/maa/backend/controller/response/MaaResult.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/MaaResult.kt rename to src/main/kotlin/plus/maa/backend/controller/response/MaaResult.kt diff --git a/src/main/java/plus/maa/backend/controller/response/MaaResultException.kt b/src/main/kotlin/plus/maa/backend/controller/response/MaaResultException.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/MaaResultException.kt rename to src/main/kotlin/plus/maa/backend/controller/response/MaaResultException.kt diff --git a/src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt rename to src/main/kotlin/plus/maa/backend/controller/response/comments/CommentsAreaInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/comments/CommentsInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/comments/CommentsInfo.kt rename to src/main/kotlin/plus/maa/backend/controller/response/comments/CommentsInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt rename to src/main/kotlin/plus/maa/backend/controller/response/comments/SubCommentsInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt rename to src/main/kotlin/plus/maa/backend/controller/response/copilot/ArkLevelInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/copilot/CopilotInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilot/CopilotInfo.kt rename to src/main/kotlin/plus/maa/backend/controller/response/copilot/CopilotInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt rename to src/main/kotlin/plus/maa/backend/controller/response/copilot/CopilotPageInfo.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt b/src/main/kotlin/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt rename to src/main/kotlin/plus/maa/backend/controller/response/copilotset/CopilotSetListRes.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt b/src/main/kotlin/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt rename to src/main/kotlin/plus/maa/backend/controller/response/copilotset/CopilotSetPageRes.kt diff --git a/src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt b/src/main/kotlin/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt rename to src/main/kotlin/plus/maa/backend/controller/response/copilotset/CopilotSetRes.kt diff --git a/src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.kt b/src/main/kotlin/plus/maa/backend/controller/response/user/MaaLoginRsp.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/user/MaaLoginRsp.kt rename to src/main/kotlin/plus/maa/backend/controller/response/user/MaaLoginRsp.kt diff --git a/src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/user/MaaUserInfo.kt similarity index 100% rename from src/main/java/plus/maa/backend/controller/response/user/MaaUserInfo.kt rename to src/main/kotlin/plus/maa/backend/controller/response/user/MaaUserInfo.kt From 939dc4251aa63090723f0a27724a71264296c9ca Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 22:20:30 +0800 Subject: [PATCH 122/168] Rename .java to .kt --- .../maa/backend/repository/{RedisCache.java => RedisCache.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/repository/{RedisCache.java => RedisCache.kt} (100%) diff --git a/src/main/java/plus/maa/backend/repository/RedisCache.java b/src/main/java/plus/maa/backend/repository/RedisCache.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/RedisCache.java rename to src/main/java/plus/maa/backend/repository/RedisCache.kt From d587bb108d64236f089ac7cd20454a32f72af34e Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 22:20:30 +0800 Subject: [PATCH 123/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20RedisCache?= =?UTF-8?q?=20=E5=9C=A8=E5=AD=98=E5=82=A8kt=E5=AF=B9=E8=B1=A1=E6=97=B6?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/repository/RedisCache.kt | 403 +++++++++--------- .../backend/config/NativeReflectionConfig.kt | 2 - .../maa/backend/service/CopilotService.kt | 6 +- .../backend/service/session/UserSession.kt | 3 - .../service/session/UserSessionService.kt | 43 -- 5 files changed, 198 insertions(+), 259 deletions(-) delete mode 100644 src/main/kotlin/plus/maa/backend/service/session/UserSession.kt delete mode 100644 src/main/kotlin/plus/maa/backend/service/session/UserSessionService.kt diff --git a/src/main/java/plus/maa/backend/repository/RedisCache.kt b/src/main/java/plus/maa/backend/repository/RedisCache.kt index 88ea5afa..efc4a3ce 100644 --- a/src/main/java/plus/maa/backend/repository/RedisCache.kt +++ b/src/main/java/plus/maa/backend/repository/RedisCache.kt @@ -1,34 +1,30 @@ -package plus.maa.backend.repository; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.json.JsonMapper; -import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; -import lombok.RequiredArgsConstructor; -import lombok.Setter; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.jetbrains.annotations.Nullable; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.io.ClassPathResource; -import org.springframework.dao.InvalidDataAccessApiUsageException; -import org.springframework.data.redis.RedisSystemException; -import org.springframework.data.redis.core.Cursor; -import org.springframework.data.redis.core.ScanOptions; -import org.springframework.data.redis.core.StringRedisTemplate; -import org.springframework.data.redis.core.script.RedisScript; -import org.springframework.scheduling.annotation.Async; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Function; -import java.util.function.Supplier; +package plus.maa.backend.repository + +import com.fasterxml.jackson.core.JsonProcessingException +import com.fasterxml.jackson.databind.DeserializationFeature +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import io.github.oshai.kotlinlogging.KotlinLogging +import lombok.RequiredArgsConstructor +import lombok.Setter +import lombok.extern.slf4j.Slf4j +import org.apache.commons.lang3.StringUtils +import org.springframework.beans.factory.annotation.Value +import org.springframework.core.io.ClassPathResource +import org.springframework.dao.InvalidDataAccessApiUsageException +import org.springframework.data.redis.RedisSystemException +import org.springframework.data.redis.core.ScanOptions +import org.springframework.data.redis.core.StringRedisTemplate +import org.springframework.data.redis.core.script.RedisScript +import org.springframework.scheduling.annotation.Async +import org.springframework.stereotype.Component +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicBoolean +import java.util.function.Function +import java.util.function.Supplier + +private val log = KotlinLogging.logger { } /** * Redis工具类 @@ -39,51 +35,49 @@ import java.util.function.Supplier; @Setter @Component @RequiredArgsConstructor -public class RedisCache { - @Value("${maa-copilot.cache.default-expire}") - private int expire; - - private final StringRedisTemplate redisTemplate; +class RedisCache( + @Value("\${maa-copilot.cache.default-expire}") + private val expire: Int = 0, + private val redisTemplate: StringRedisTemplate? = null +) { // 添加 JSR310 模块,以便顺利序列化 LocalDateTime 等类型 - private final ObjectMapper writeMapper = JsonMapper.builder() - .addModule(new JavaTimeModule()) - .build(); - private final ObjectMapper readMapper = JsonMapper.builder() - .addModule(new JavaTimeModule()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .build(); - + private val writeMapper: ObjectMapper = jacksonObjectMapper() + .registerModules(JavaTimeModule()) + private val readMapper: ObjectMapper = jacksonObjectMapper() + .registerModules(JavaTimeModule()) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - private final AtomicBoolean supportUnlink = new AtomicBoolean(true); + private val supportUnlink = AtomicBoolean(true) /* 使用 lua 脚本插入数据,维持 ZSet 的相对大小(size <= 实际大小 <= size + 50)以及过期时间 实际大小这么设计是为了避免频繁的 ZREMRANGEBYRANK 操作 */ - private final RedisScript incZSetRedisScript = RedisScript.of(new ClassPathResource("redis-lua/incZSet.lua")); + private val incZSetRedisScript: RedisScript = RedisScript.of(ClassPathResource("redis-lua/incZSet.lua")) + // 比较与输入的键值对是否相同,相同则删除 - private final RedisScript removeKVIfEqualsScript = RedisScript.of(new ClassPathResource("redis-lua/removeKVIfEquals.lua"), Boolean.class); + private val removeKVIfEqualsScript: RedisScript = + RedisScript.of(ClassPathResource("redis-lua/removeKVIfEquals.lua"), Boolean::class.java) - public void setData(final String key, T value) { - setCache(key, value, 0, TimeUnit.SECONDS); + fun setData(key: String, value: T) { + setCache(key, value, 0, TimeUnit.SECONDS) } - public void setCache(final String key, T value) { - setCache(key, value, expire, TimeUnit.SECONDS); + fun setCache(key: String, value: T) { + setCache(key, value, expire.toLong(), TimeUnit.SECONDS) } - public void setCache(final String key, T value, long timeout) { - setCache(key, value, timeout, TimeUnit.SECONDS); + fun setCache(key: String, value: T, timeout: Long) { + setCache(key, value, timeout, TimeUnit.SECONDS) } - public void setCache(final String key, T value, long timeout, TimeUnit timeUnit) { - String json = getJson(value); - if (json == null) return; + fun setCache(key: String, value: T, timeout: Long, timeUnit: TimeUnit) { + val json = getJson(value) ?: return if (timeout <= 0) { - redisTemplate.opsForValue().set(key, json); + redisTemplate!!.opsForValue()[key] = json } else { - redisTemplate.opsForValue().set(key, json, timeout, timeUnit); + redisTemplate!!.opsForValue()[key, json, timeout] = timeUnit } } @@ -94,9 +88,8 @@ public class RedisCache { * @param value 被缓存的值 * @return 是否 set */ - - public boolean setCacheIfAbsent(final String key, T value) { - return setCacheIfAbsent(key, value, expire); + fun setCacheIfAbsent(key: String, value: T): Boolean { + return setCacheIfAbsent(key, value, expire.toLong()) } /** @@ -107,9 +100,8 @@ public class RedisCache { * @param timeout 过期时间 * @return 是否 set */ - - public boolean setCacheIfAbsent(final String key, T value, long timeout) { - return setCacheIfAbsent(key, value, timeout, TimeUnit.SECONDS); + fun setCacheIfAbsent(key: String, value: T, timeout: Long): Boolean { + return setCacheIfAbsent(key, value, timeout, TimeUnit.SECONDS) } /** @@ -121,46 +113,43 @@ public class RedisCache { * @param timeUnit 过期时间的单位 * @return 是否 set */ - public boolean setCacheIfAbsent(final String key, T value, long timeout, TimeUnit timeUnit) { - String json = getJson(value); - if (json == null) return false; - boolean result; - if (timeout <= 0) { - result = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, json)); + fun setCacheIfAbsent(key: String, value: T, timeout: Long, timeUnit: TimeUnit): Boolean { + val json = getJson(value) ?: return false + val result = if (timeout <= 0) { + java.lang.Boolean.TRUE == redisTemplate!!.opsForValue().setIfAbsent(key, json) } else { - result = Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, json, timeout, timeUnit)); + java.lang.Boolean.TRUE == redisTemplate!!.opsForValue().setIfAbsent(key, json, timeout, timeUnit) } - return result; + return result } - public void addSet(final String key, Collection set, long timeout) { - addSet(key, set, timeout, TimeUnit.SECONDS); + fun addSet(key: String, set: Collection, timeout: Long) { + addSet(key, set, timeout, TimeUnit.SECONDS) } - public void addSet(final String key, Collection set, long timeout, TimeUnit timeUnit) { - if (key == null || set == null || set.isEmpty()) { // Redis 会拒绝空集合 - return; + fun addSet(key: String, set: Collection, timeout: Long, timeUnit: TimeUnit) { + if (set.isEmpty()) { + return } - String[] jsonList = new String[set.size()]; - int i = 0; - for (T t : set) { - String json = getJson(t); - if (json == null) return; - jsonList[i++] = json; + val jsonList = arrayOfNulls(set.size) + var i = 0 + for (t in set) { + val json = getJson(t) ?: return + jsonList[i++] = json } if (timeout <= 0) { - redisTemplate.opsForSet().add(key, jsonList); + redisTemplate!!.opsForSet().add(key, *jsonList) } else { - redisTemplate.opsForSet().add(key, jsonList); - redisTemplate.expire(key, timeout, timeUnit); + redisTemplate!!.opsForSet().add(key, *jsonList) + redisTemplate.expire(key, timeout, timeUnit) } } /** - * ZSet 中元素的 score += incScore,如果元素不存在则插入
- * 会维持 ZSet 的相对大小(size <= 实际大小 <= size + 50)以及过期时间
+ * ZSet 中元素的 score += incScore,如果元素不存在则插入

+ * 会维持 ZSet 的相对大小(size <= 实际大小 <= size + 50)以及过期时间

* 当大小超出 size + 50 时,会优先删除 score 最小的元素,直到大小等于 size * * @param key ZSet 的 key @@ -169,151 +158,155 @@ public class RedisCache { * @param size ZSet 的相对大小 * @param timeout ZSet 的过期时间 */ - - public void incZSet(final String key, String member, double incScore, long size, long timeout) { - redisTemplate.execute(incZSetRedisScript, List.of(key), member, Double.toString(incScore), Long.toString(size), Long.toString(timeout)); + fun incZSet(key: String, member: String?, incScore: Double, size: Long, timeout: Long) { + redisTemplate!!.execute( + incZSetRedisScript, + listOf(key), + member, + incScore.toString(), + size.toString(), + timeout.toString() + ) } // 获取的元素是按照 score 从小到大排列的 - @Nullable - public Set getZSet(final String key, long start, long end) { - return redisTemplate.opsForZSet().range(key, start, end); + fun getZSet(key: String, start: Long, end: Long): Set? { + return redisTemplate!!.opsForZSet().range(key, start, end) } // 获取的元素是按照 score 从大到小排列的 - @Nullable - public Set getZSetReverse(final String key, long start, long end) { - return redisTemplate.opsForZSet().reverseRange(key, start, end); + fun getZSetReverse(key: String, start: Long, end: Long): Set? { + return redisTemplate!!.opsForZSet().reverseRange(key, start, end) } - public boolean valueMemberInSet(final String key, T value) { + fun valueMemberInSet(key: String, value: T): Boolean { try { - String json = getJson(value); - if (json == null) return false; - return Boolean.TRUE.equals(redisTemplate.opsForSet().isMember(key, json)); - } catch (Exception e) { - log.error(e.getMessage(), e); + val json = getJson(value) ?: return false + return java.lang.Boolean.TRUE == redisTemplate!!.opsForSet().isMember(key, json) + } catch (e: Exception) { + log.error(e) { e.message } } - return false; + return false } - @Nullable - public T getCache(final String key, Class valueType) { - return getCache(key, valueType, null, expire, TimeUnit.SECONDS); + fun getCache(key: String, valueType: Class): T? { + return getCache(key, valueType, null, expire.toLong(), TimeUnit.SECONDS) } - @Nullable - public T getCache(final String key, Class valueType, Supplier onMiss) { - return getCache(key, valueType, onMiss, expire, TimeUnit.SECONDS); + fun getCache(key: String, valueType: Class, onMiss: Supplier?): T? { + return getCache(key, valueType, onMiss, expire.toLong(), TimeUnit.SECONDS) } - @Nullable - public T getCache(final String key, Class valueType, Supplier onMiss, long timeout) { - return getCache(key, valueType, onMiss, timeout, TimeUnit.SECONDS); + fun getCache(key: String, valueType: Class, onMiss: Supplier?, timeout: Long): T? { + return getCache(key, valueType, onMiss, timeout, TimeUnit.SECONDS) } - @Nullable - public T getCache(final String key, Class valueType, Supplier onMiss, long timeout, TimeUnit timeUnit) { - T result; + fun getCache(key: String, valueType: Class, onMiss: Supplier?, timeout: Long, timeUnit: TimeUnit): T? { try { - String json = redisTemplate.opsForValue().get(key); + var json = redisTemplate!!.opsForValue()[key] if (StringUtils.isEmpty(json)) { if (onMiss != null) { //上锁 - synchronized (RedisCache.class) { + synchronized(RedisCache::class.java) { //再次查询缓存,目的是判断是否前面的线程已经set过了 - json = redisTemplate.opsForValue().get(key); + json = redisTemplate.opsForValue()[key] //第二次校验缓存是否存在 if (StringUtils.isEmpty(json)) { - result = onMiss.get(); + val result = onMiss.get() ?: return null //数据库中不存在 - if (result == null) { - return null; - } - setCache(key, result, timeout, timeUnit); - return result; + setCache(key, result, timeout, timeUnit) + return result } } } else { - return null; + return null } } - result = readMapper.readValue(json, valueType); - } catch (Exception e) { - log.error(e.getMessage(), e); - return null; + return readMapper.readValue(json, valueType) + } catch (e: Exception) { + log.error(e) { e.message } + return null } - return result; } - public void updateCache(final String key, Class valueType, T defaultValue, Function onUpdate) { - updateCache(key, valueType, defaultValue, onUpdate, expire, TimeUnit.SECONDS); + fun updateCache(key: String, valueType: Class, defaultValue: T, onUpdate: Function) { + updateCache(key, valueType, defaultValue, onUpdate, expire.toLong(), TimeUnit.SECONDS) } - public void updateCache(final String key, Class valueType, T defaultValue, Function onUpdate, long timeout) { - updateCache(key, valueType, defaultValue, onUpdate, timeout, TimeUnit.SECONDS); + fun updateCache(key: String, valueType: Class?, defaultValue: T, onUpdate: Function, timeout: Long) { + updateCache(key, valueType, defaultValue, onUpdate, timeout, TimeUnit.SECONDS) } - public void updateCache(final String key, Class valueType, T defaultValue, Function onUpdate, long timeout, TimeUnit timeUnit) { - T result; + fun updateCache( + key: String, + valueType: Class?, + defaultValue: T, + onUpdate: Function, + timeout: Long, + timeUnit: TimeUnit + ) { + var result: T try { - synchronized (RedisCache.class) { - String json = redisTemplate.opsForValue().get(key); - if (StringUtils.isEmpty(json)) { - result = defaultValue; + synchronized(RedisCache::class.java) { + val json = redisTemplate!!.opsForValue()[key] + result = if (StringUtils.isEmpty(json)) { + defaultValue } else { - result = readMapper.readValue(json, valueType); + readMapper.readValue(json, valueType) } - result = onUpdate.apply(result); - setCache(key, result, timeout, timeUnit); + result = onUpdate.apply(result) + setCache(key, result, timeout, timeUnit) } - } catch (Exception e) { - log.error(e.getMessage(), e); + } catch (e: Exception) { + log.error(e) { e.message } } } - @Nullable - public String getCacheLevelCommit() { - return getCache("level:commit", String.class); - } - - public void setCacheLevelCommit(String commit) { - setData("level:commit", commit); - } - - public void removeCache(String key) { - removeCache(key, false); - } - - public void removeCache(String key, boolean notUseUnlink) { - removeCache(List.of(key), notUseUnlink); - } + var cacheLevelCommit: String? + get() = getCache("level:commit", String::class.java) + set(commit) { + setData("level:commit", commit) + } - public void removeCache(Collection keys) { - removeCache(keys, false); + @JvmOverloads + fun removeCache(key: String, notUseUnlink: Boolean = false) { + removeCache(listOf(key), notUseUnlink) } - public void removeCache(Collection keys, boolean notUseUnlink) { - + @JvmOverloads + fun removeCache(keys: Collection, notUseUnlink: Boolean = false) { if (!notUseUnlink && supportUnlink.get()) { try { - redisTemplate.unlink(keys); - return; - } catch (InvalidDataAccessApiUsageException | RedisSystemException e) { + redisTemplate!!.unlink(keys) + return + } catch (e: InvalidDataAccessApiUsageException) { // Redisson、Jedis、Lettuce - Throwable cause = e.getCause(); + val cause = e.cause if (cause == null || !StringUtils.containsAny( - cause.getMessage(), "unknown command", "not support")) { - throw e; + cause.message, "unknown command", "not support" + ) + ) { + throw e } if (supportUnlink.compareAndSet(true, false)) { - log.warn("当前连接的 Redis Service 可能不支持 Unlink 命令,切换为 Del"); + log.warn { "当前连接的 Redis Service 可能不支持 Unlink 命令,切换为 Del" } + } + } catch (e: RedisSystemException) { + val cause = e.cause + if (cause == null || !StringUtils.containsAny( + cause.message, "unknown command", "not support" + ) + ) { + throw e + } + if (supportUnlink.compareAndSet(true, false)) { + log.warn { "当前连接的 Redis Service 可能不支持 Unlink 命令,切换为 Del" } } } } // 兜底的 Del 命令 - redisTemplate.delete(keys); + redisTemplate!!.delete(keys) } /** @@ -323,79 +316,73 @@ public class RedisCache { * @param value 待比较的值 * @return 是否删除 */ - public boolean removeKVIfEquals(String key, T value) { - String json = getJson(value); - if (json == null) return false; - return Boolean.TRUE.equals( - redisTemplate.execute(removeKVIfEqualsScript, List.of(key), json) - ); + fun removeKVIfEquals(key: String, value: T): Boolean { + val json = getJson(value) ?: return false + return java.lang.Boolean.TRUE == redisTemplate!!.execute(removeKVIfEqualsScript, listOf(key), json) } /** - * 模糊删除缓存。不保证立即删除,不保证完全删除。
+ * 模糊删除缓存。不保证立即删除,不保证完全删除。

* 异步,因为 Scan 虽然不会阻塞 Redis,但客户端会阻塞 * * @param pattern 待删除的 Key 表达式,例如 "home:*" 表示删除 Key 以 "home:" 开头的所有缓存 * @author Lixuhuilll */ @Async - public void removeCacheByPattern(String pattern) { - syncRemoveCacheByPattern(pattern); + fun removeCacheByPattern(pattern: String) { + syncRemoveCacheByPattern(pattern) } /** - * 模糊删除缓存。不保证立即删除,不保证完全删除。
+ * 模糊删除缓存。不保证立即删除,不保证完全删除。

* 同步调用 Scan,不会长时间阻塞 Redis,但会阻塞客户端,阻塞时间视 Redis 中 key 的数量而定。 * 删除期间,其他线程或客户端可对 Redis 进行 CURD(因为不阻塞 Redis),因此不保证删除的时机,也不保证完全删除干净 * * @param pattern 待删除的 Key 表达式,例如 "home:*" 表示删除 Key 以 "home:" 开头的所有缓存 * @author Lixuhuilll */ - public void syncRemoveCacheByPattern(String pattern) { + fun syncRemoveCacheByPattern(pattern: String) { // 批量删除的阈值 - final int batchSize = 2000; + val batchSize = 2000 // 构造 ScanOptions - ScanOptions scanOptions = ScanOptions.scanOptions() - .count(batchSize) - .match(pattern) - .build(); + val scanOptions = ScanOptions.scanOptions() + .count(batchSize.toLong()) + .match(pattern) + .build() // 保存要删除的键 - List keysToDelete = new ArrayList<>(batchSize); + val keysToDelete: MutableList = ArrayList(batchSize) - // try-with-resources 自动关闭 SCAN - try (Cursor cursor = redisTemplate.scan(scanOptions)) { + redisTemplate!!.scan(scanOptions).use { cursor -> while (cursor.hasNext()) { - String key = cursor.next(); + val key = cursor.next() // 将要删除的键添加到列表中 - keysToDelete.add(key); + keysToDelete.add(key) // 如果达到批量删除的阈值,则执行批量删除 - if (keysToDelete.size() >= batchSize) { - removeCache(keysToDelete); - keysToDelete.clear(); + if (keysToDelete.size >= batchSize) { + removeCache(keysToDelete) + keysToDelete.clear() } } } - // 删除剩余的键(不足 batchSize 的最后一批) if (!keysToDelete.isEmpty()) { - removeCache(keysToDelete); + removeCache(keysToDelete) } } - @Nullable - private String getJson(T value) { - String json; + private fun getJson(value: T): String? { + val json: String try { - json = writeMapper.writeValueAsString(value); - } catch (JsonProcessingException e) { + json = writeMapper.writeValueAsString(value) + } catch (e: JsonProcessingException) { if (log.isDebugEnabled()) { - log.debug(e.getMessage(), e); + log.debug(e) { e.message } } - return null; + return null } - return json; + return json } } diff --git a/src/main/kotlin/plus/maa/backend/config/NativeReflectionConfig.kt b/src/main/kotlin/plus/maa/backend/config/NativeReflectionConfig.kt index a5ea3eb8..1e112e9f 100644 --- a/src/main/kotlin/plus/maa/backend/config/NativeReflectionConfig.kt +++ b/src/main/kotlin/plus/maa/backend/config/NativeReflectionConfig.kt @@ -8,7 +8,6 @@ import plus.maa.backend.controller.request.copilot.CopilotDTO import plus.maa.backend.repository.entity.gamedata.* import plus.maa.backend.repository.entity.gamedata.ArkTilePos.Tile import plus.maa.backend.service.model.RatingCache -import plus.maa.backend.service.session.UserSession /** * 添加所有需要用到反射的类到此处,用于 native image @@ -28,7 +27,6 @@ import plus.maa.backend.service.session.UserSession ArkZone::class, CopilotDTO::class, RatingCache::class, - UserSession::class, PropertyNamingStrategies.SnakeCaseStrategy::class, LowerCamelCaseStrategy::class ) diff --git a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt index 9dcbddd6..4b8b77c2 100644 --- a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt @@ -183,7 +183,7 @@ class CopilotService( // 增加一次views update.inc("views") mongoTemplate.updateFirst(query, update, Copilot::class.java) - if (Objects.isNull(cache)) { + if (cache == null) { redisCache.setCache("views:$userIdOrIpAddress", RatingCache(Sets.newHashSet(id))) } else { redisCache.updateCache( @@ -233,7 +233,7 @@ class CopilotService( cacheTimeout.set(t) setKey.set(String.format("home:%s:copilotIds", request.orderBy)) cacheKey.set(String.format("home:%s:%s", request.orderBy, request.hashCode())) - redisCache.getCache(cacheKey.get(), CopilotPageInfo::class.java) + redisCache.getCache(cacheKey.get()!!, CopilotPageInfo::class.java) }?.let { return it } } @@ -368,7 +368,7 @@ class CopilotService( // 记录存在的作业id redisCache.addSet(setKey.get(), copilotIds, cacheTimeout.get()) // 缓存数据 - redisCache.setCache(cacheKey.get(), data, cacheTimeout.get()) + redisCache.setCache(cacheKey.get()!!, data, cacheTimeout.get()) } return data } diff --git a/src/main/kotlin/plus/maa/backend/service/session/UserSession.kt b/src/main/kotlin/plus/maa/backend/service/session/UserSession.kt deleted file mode 100644 index 93813643..00000000 --- a/src/main/kotlin/plus/maa/backend/service/session/UserSession.kt +++ /dev/null @@ -1,3 +0,0 @@ -package plus.maa.backend.service.session - -class UserSession diff --git a/src/main/kotlin/plus/maa/backend/service/session/UserSessionService.kt b/src/main/kotlin/plus/maa/backend/service/session/UserSessionService.kt deleted file mode 100644 index 93edb82d..00000000 --- a/src/main/kotlin/plus/maa/backend/service/session/UserSessionService.kt +++ /dev/null @@ -1,43 +0,0 @@ -package plus.maa.backend.service.session - -import org.springframework.stereotype.Service -import plus.maa.backend.config.external.MaaCopilotProperties -import plus.maa.backend.repository.RedisCache - -@Service -class UserSessionService(private val cache: RedisCache, properties: MaaCopilotProperties) { - private val sessionExpiration = properties.jwt.refreshExpire - - fun getSession(id: String): UserSession? { - return cache.getCache(buildUserCacheKey(id), UserSession::class.java, null, sessionExpiration) - } - - fun setSession(id: String, session: UserSession) { - cache.setCache(buildUserCacheKey(id), session, sessionExpiration) - } - - fun setSession(id: String, consumer: (UserSession) -> Unit) { - val session = UserSession() - consumer(session) - cache.setCache(buildUserCacheKey(id), session, sessionExpiration) - } - - fun updateSessionIfPresent(id: String, consumer: (UserSession) -> Unit){ - cache.updateCache(id, UserSession::class.java, null, { session: UserSession? -> - if (session != null) consumer(session) - session - }, sessionExpiration) - } - - fun removeSession(id: String) { - cache.removeCache(buildUserCacheKey(id)) - } - - companion object { - private const val REDIS_USER_SESSION_PREFIX = "USER_SESSION_" - - private fun buildUserCacheKey(userId: String): String { - return REDIS_USER_SESSION_PREFIX + userId - } - } -} From de18347b22036dec50705ebd052cc8bb991d2593 Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 23:23:54 +0800 Subject: [PATCH 124/168] Rename .java to .kt --- .../repository/{RatingRepository.java => RatingRepository.kt} | 0 .../backend/repository/{UserRepository.java => UserRepository.kt} | 0 .../plus/maa/backend/repository/entity/{Rating.java => Rating.kt} | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/repository/{RatingRepository.java => RatingRepository.kt} (100%) rename src/main/java/plus/maa/backend/repository/{UserRepository.java => UserRepository.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/{Rating.java => Rating.kt} (100%) diff --git a/src/main/java/plus/maa/backend/repository/RatingRepository.java b/src/main/java/plus/maa/backend/repository/RatingRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/RatingRepository.java rename to src/main/java/plus/maa/backend/repository/RatingRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/UserRepository.java b/src/main/java/plus/maa/backend/repository/UserRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/UserRepository.java rename to src/main/java/plus/maa/backend/repository/UserRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/Rating.java b/src/main/java/plus/maa/backend/repository/entity/Rating.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/Rating.java rename to src/main/java/plus/maa/backend/repository/entity/Rating.kt From 9d0caf907498caf54b93a24d614684db68a3ffde Mon Sep 17 00:00:00 2001 From: dragove Date: Mon, 12 Feb 2024 23:23:54 +0800 Subject: [PATCH 125/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20Reposi?= =?UTF-8?q?tory=20=E7=B1=BB=E5=9E=8B=E5=88=B0=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/repository/RatingRepository.kt | 19 +++---- .../maa/backend/repository/UserRepository.kt | 27 ++++------ .../maa/backend/repository/entity/Rating.kt | 54 +++++++------------ .../controller/CopilotSetController.kt | 2 - .../backend/service/CommentsAreaService.kt | 37 +++++++------ .../maa/backend/service/CopilotService.kt | 46 ++++++++-------- .../maa/backend/service/CopilotSetService.kt | 5 +- .../plus/maa/backend/service/UserService.kt | 2 +- 8 files changed, 79 insertions(+), 113 deletions(-) diff --git a/src/main/java/plus/maa/backend/repository/RatingRepository.kt b/src/main/java/plus/maa/backend/repository/RatingRepository.kt index 646adcb6..a46fa0e8 100644 --- a/src/main/java/plus/maa/backend/repository/RatingRepository.kt +++ b/src/main/java/plus/maa/backend/repository/RatingRepository.kt @@ -1,23 +1,16 @@ -package plus.maa.backend.repository; +package plus.maa.backend.repository -import org.springframework.data.mongodb.repository.MongoRepository; -import org.springframework.stereotype.Repository; -import plus.maa.backend.repository.entity.Rating; -import plus.maa.backend.service.model.RatingType; - -import java.util.Optional; +import org.springframework.data.mongodb.repository.MongoRepository +import org.springframework.stereotype.Repository +import plus.maa.backend.repository.entity.Rating /** * @author lixuhuilll * Date 2023-08-20 12:06 */ - @Repository -public interface RatingRepository extends MongoRepository { - Optional findByTypeAndKeyAndUserId(Rating.KeyType type, String key, String userId); - - long countByTypeAndKeyAndRating(Rating.KeyType type, String key, RatingType rating); +interface RatingRepository : MongoRepository { + fun findByTypeAndKeyAndUserId(type: Rating.KeyType, key: String, userId: String): Rating? - long countByTypeAndKey(Rating.KeyType type, String key); } diff --git a/src/main/java/plus/maa/backend/repository/UserRepository.kt b/src/main/java/plus/maa/backend/repository/UserRepository.kt index d9a4fde5..fdb06410 100644 --- a/src/main/java/plus/maa/backend/repository/UserRepository.kt +++ b/src/main/java/plus/maa/backend/repository/UserRepository.kt @@ -1,32 +1,25 @@ -package plus.maa.backend.repository; +package plus.maa.backend.repository -import org.springframework.data.mongodb.repository.MongoRepository; -import plus.maa.backend.repository.entity.MaaUser; - -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.function.Function; -import java.util.stream.Collectors; +import org.springframework.data.mongodb.repository.MongoRepository +import plus.maa.backend.repository.entity.MaaUser /** * @author AnselYuki */ -public interface UserRepository extends MongoRepository { +interface UserRepository : MongoRepository { /** * 根据邮箱(用户唯一登录凭据)查询 * * @param email 邮箱字段 * @return 查询用户 */ - MaaUser findByEmail(String email); - - Optional findByUserId(String userId); + fun findByEmail(email: String): MaaUser? - default Map findByUsersId(List userId) { - return findAllById(userId) - .stream().collect(Collectors.toMap(MaaUser::getUserId, Function.identity())); - } + fun findByUserId(userId: String): MaaUser? +} +fun UserRepository.findByUsersId(userId: List): Map { + return findAllById(userId).associateBy { it.userId } } + diff --git a/src/main/java/plus/maa/backend/repository/entity/Rating.kt b/src/main/java/plus/maa/backend/repository/entity/Rating.kt index 911fc5ca..2e977f84 100644 --- a/src/main/java/plus/maa/backend/repository/entity/Rating.kt +++ b/src/main/java/plus/maa/backend/repository/entity/Rating.kt @@ -1,49 +1,31 @@ -package plus.maa.backend.repository.entity; +package plus.maa.backend.repository.entity -import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.index.CompoundIndex; -import org.springframework.data.mongodb.core.index.CompoundIndexes; -import org.springframework.data.mongodb.core.mapping.Document; -import plus.maa.backend.service.model.RatingType; - -import java.time.LocalDateTime; +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.index.CompoundIndex +import org.springframework.data.mongodb.core.index.CompoundIndexes +import org.springframework.data.mongodb.core.mapping.Document +import plus.maa.backend.service.model.RatingType +import java.time.LocalDateTime /** * @author lixuhuilll * Date 2023-08-20 11:20 */ - -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor -@Document(collection = "maa_rating") -// 复合索引 -@CompoundIndexes({ - // 一个用户对一个对象只能有一种评级 - @CompoundIndex(name = "idx_rating", def = "{'type': 1, 'key': 1, 'userId': 1}", unique = true) -}) -public class Rating { +@Document(collection = "maa_rating") // 复合索引 +@CompoundIndexes(CompoundIndex(name = "idx_rating", def = "{'type': 1, 'key': 1, 'userId': 1}", unique = true)) +data class Rating( @Id - private String id; + val id: String? = null, // 下面三个字段组成复合索引,一个用户对一个对象只能有一种评级 - @NotNull - private KeyType type; // 评级的类型,如作业(copilot)、评论(comment) - @NotNull - private String key; // 被评级对象的唯一标识,如作业id、评论id - @NotNull - private String userId; // 评级的用户id - - private RatingType rating; // 评级,如 "Like"、"Dislike"、"None" - private LocalDateTime rateTime; // 评级时间 + val type: KeyType, // 评级的类型,如作业(copilot)、评论(comment) + val key: String, // 被评级对象的唯一标识,如作业id、评论id + val userId: String, // 评级的用户id - public enum KeyType { + var rating: RatingType, // 评级,如 "Like"、"Dislike"、"None" + var rateTime: LocalDateTime // 评级时间 +) { + enum class KeyType { COPILOT, COMMENT } } diff --git a/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt b/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt index 6c27da0f..28de18a3 100644 --- a/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt @@ -5,7 +5,6 @@ import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.tags.Tag import jakarta.validation.Valid -import lombok.RequiredArgsConstructor import org.springframework.web.bind.annotation.* import plus.maa.backend.config.doc.RequireJwt import plus.maa.backend.config.security.AuthenticationHelper @@ -27,7 +26,6 @@ import plus.maa.backend.service.CopilotSetService @Tag(name = "CopilotSet", description = "作业集相关接口") @RequestMapping("/set") @RestController -@RequiredArgsConstructor class CopilotSetController( private val service: CopilotSetService, private val helper: AuthenticationHelper diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 55b9dfe1..38490b03 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -14,10 +14,7 @@ import plus.maa.backend.controller.request.comments.CommentsQueriesDTO import plus.maa.backend.controller.request.comments.CommentsRatingDTO import plus.maa.backend.controller.request.comments.CommentsToppingDTO import plus.maa.backend.controller.response.comments.CommentsAreaInfo -import plus.maa.backend.repository.CommentsAreaRepository -import plus.maa.backend.repository.CopilotRepository -import plus.maa.backend.repository.RatingRepository -import plus.maa.backend.repository.UserRepository +import plus.maa.backend.repository.* import plus.maa.backend.repository.entity.CommentsArea import plus.maa.backend.repository.entity.Copilot import plus.maa.backend.repository.entity.MaaUser @@ -175,7 +172,7 @@ class CommentsAreaService( * @param userId 登录用户 id * @param commentsRatingDTO CommentsRatingDTO */ - fun rates(userId: String?, commentsRatingDTO: CommentsRatingDTO) { + fun rates(userId: String, commentsRatingDTO: CommentsRatingDTO) { val rating = commentsRatingDTO.rating val commentsArea = findCommentsById(commentsRatingDTO.commentId) @@ -186,13 +183,13 @@ class CommentsAreaService( val ratingOptional = ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COMMENT, commentsArea.id, userId) // 判断该用户是否存在评分 - if (ratingOptional.isPresent) { + if (ratingOptional != null) { // 如果评分发生变化则更新 - if (ratingOptional.get().rating != RatingType.fromRatingType(rating)) { - val oldRatingType = ratingOptional.get().rating - ratingOptional.get().setRating(RatingType.fromRatingType(rating)) - ratingOptional.get().setRateTime(LocalDateTime.now()) - val newRatingType = ratingRepository.save(ratingOptional.get()).rating + if (ratingOptional.rating != RatingType.fromRatingType(rating)) { + val oldRatingType = ratingOptional.rating + ratingOptional.rating = RatingType.fromRatingType(rating) + ratingOptional.rateTime = LocalDateTime.now() + val newRatingType = ratingRepository.save(ratingOptional).rating // 更新评分后更新评论的点赞数 likeCountChange = (if (newRatingType == RatingType.LIKE) 1 else (if (oldRatingType != RatingType.LIKE) 0 else -1)).toLong() @@ -204,12 +201,14 @@ class CommentsAreaService( } } else { // 不存在评分则创建 - val newRating = Rating() - .setType(Rating.KeyType.COMMENT) - .setKey(commentsArea.id) - .setUserId(userId) - .setRating(RatingType.fromRatingType(rating)) - .setRateTime(LocalDateTime.now()) + val newRating = Rating( + null, + Rating.KeyType.COMMENT, + commentsArea.id, + userId, + RatingType.fromRatingType(rating), + LocalDateTime.now() + ) ratingRepository.insert(newRating) likeCountChange = (if (newRating.rating == RatingType.LIKE) 1 else 0).toLong() @@ -324,8 +323,8 @@ class CommentsAreaService( allComments.addAll(subCommentsList) //获取所有评论用户 - val userId = allComments.map { obj: CommentsArea -> obj.uploaderId }.distinct().toList() - val maaUserMap = userRepository.findByUsersId(userId) + val userIds = allComments.map { obj: CommentsArea -> obj.uploaderId }.distinct().toList() + val maaUserMap = userRepository.findByUsersId(userIds) //转换主评论数据并填充用户名 diff --git a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt index 4b8b77c2..f589ea2c 100644 --- a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt @@ -195,17 +195,15 @@ class CopilotService( ) } } - val maaUser = userRepository.findByUsersId(listOf(copilot.uploaderId)) + val maaUser = userRepository.findByUserId(copilot.uploaderId) // 新评分系统 val ratingType = ratingRepository.findByTypeAndKeyAndUserId( Rating.KeyType.COPILOT, copilot.copilotId.toString(), userIdOrIpAddress - ) - .map { obj: Rating -> obj.rating } - .orElse(null) + )?.rating formatCopilot( - copilot, ratingType, maaUser[copilot.uploaderId]!!.userName, + copilot, ratingType, maaUser!!.userName, commentsAreaRepository.countByCopilotIdAndDelete(copilot.copilotId, false) ) } @@ -396,7 +394,7 @@ class CopilotService( * @param request 评分 * @param userIdOrIpAddress 用于已登录用户作出评分 */ - fun rates(userIdOrIpAddress: String?, request: CopilotRatingReq) { + fun rates(userIdOrIpAddress: String, request: CopilotRatingReq) { val rating = request.rating Assert.isTrue(copilotRepository.existsCopilotsByCopilotId(request.id), "作业id不存在") @@ -405,35 +403,37 @@ class CopilotService( var dislikeCountChange = 0 val ratingOptional = ratingRepository.findByTypeAndKeyAndUserId( Rating.KeyType.COPILOT, - request.id.toString(), userIdOrIpAddress + request.id.toString(), + userIdOrIpAddress ) // 如果评分存在则更新评分 - if (ratingOptional.isPresent) { - val rating1 = ratingOptional.get() + if (ratingOptional != null) { // 如果评分相同,则不做任何操作 - if (rating1.rating == RatingType.fromRatingType(rating)) { + if (ratingOptional.rating == RatingType.fromRatingType(rating)) { return } // 如果评分不同则更新评分 - val oldRatingType = rating1.rating - rating1.setRating(RatingType.fromRatingType(rating)) - rating1.setRateTime(LocalDateTime.now()) - ratingRepository.save(rating1) + val oldRatingType = ratingOptional.rating + ratingOptional.rating = RatingType.fromRatingType(rating) + ratingOptional.rateTime = LocalDateTime.now() + ratingRepository.save(ratingOptional) // 计算评分变化 likeCountChange = - if (rating1.rating == RatingType.LIKE) 1 else (if (oldRatingType != RatingType.LIKE) 0 else -1) + if (ratingOptional.rating == RatingType.LIKE) 1 else (if (oldRatingType != RatingType.LIKE) 0 else -1) dislikeCountChange = - if (rating1.rating == RatingType.DISLIKE) 1 else (if (oldRatingType != RatingType.DISLIKE) 0 else -1) + if (ratingOptional.rating == RatingType.DISLIKE) 1 else (if (oldRatingType != RatingType.DISLIKE) 0 else -1) } // 不存在评分 则添加新的评分 - if (ratingOptional.isEmpty) { - val newRating = Rating() - .setType(Rating.KeyType.COPILOT) - .setKey(request.id.toString()) - .setUserId(userIdOrIpAddress) - .setRating(RatingType.fromRatingType(rating)) - .setRateTime(LocalDateTime.now()) + if (ratingOptional == null) { + val newRating = Rating( + null, + Rating.KeyType.COPILOT, + request.id.toString(), + userIdOrIpAddress, + RatingType.fromRatingType(rating), + LocalDateTime.now() + ) ratingRepository.insert(newRating) // 计算评分变化 diff --git a/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt index ec6c4c9e..3f502a69 100644 --- a/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CopilotSetService.kt @@ -17,9 +17,10 @@ import plus.maa.backend.repository.CopilotSetRepository import plus.maa.backend.repository.UserRepository import plus.maa.backend.repository.entity.CopilotSet import plus.maa.backend.repository.entity.MaaUser +import plus.maa.backend.repository.findByUsersId import java.time.LocalDateTime -private val log = KotlinLogging.logger { } +private val log = KotlinLogging.logger { } /** * @author dragove @@ -130,7 +131,7 @@ class CopilotSetService( fun get(id: Long): CopilotSetRes { return repository.findById(id).map { copilotSet: CopilotSet -> - val userName = userRepository.findByUserId(copilotSet.creatorId).orElse(MaaUser.UNKNOWN).userName + val userName = (userRepository.findByUserId(copilotSet.creatorId) ?: MaaUser.UNKNOWN).userName converter.convertDetail(copilotSet, userName) }.orElseThrow { IllegalArgumentException("作业不存在") } } diff --git a/src/main/kotlin/plus/maa/backend/service/UserService.kt b/src/main/kotlin/plus/maa/backend/service/UserService.kt index 0d10f4ce..f22d8428 100644 --- a/src/main/kotlin/plus/maa/backend/service/UserService.kt +++ b/src/main/kotlin/plus/maa/backend/service/UserService.kt @@ -180,7 +180,7 @@ class UserService( fun modifyPasswordByActiveCode(passwordResetDTO: PasswordResetDTO) { emailService.verifyVCode(passwordResetDTO.email, passwordResetDTO.activeCode) val maaUser = userRepository.findByEmail(passwordResetDTO.email) - modifyPassword(maaUser.userId, passwordResetDTO.password) + modifyPassword(maaUser!!.userId, passwordResetDTO.password) } /** From 5c59307157e0c2852a24dd5bbaf2e6703a0ce40f Mon Sep 17 00:00:00 2001 From: KevinT3Hu Date: Tue, 13 Feb 2024 21:11:20 +0800 Subject: [PATCH 126/168] perf: remove some uses of java Consumer and Supplier --- .../plus/maa/backend/repository/RedisCache.kt | 76 ++++++++----------- .../backend/service/CommentsAreaService.kt | 11 +-- 2 files changed, 37 insertions(+), 50 deletions(-) diff --git a/src/main/java/plus/maa/backend/repository/RedisCache.kt b/src/main/java/plus/maa/backend/repository/RedisCache.kt index efc4a3ce..d0baa3b9 100644 --- a/src/main/java/plus/maa/backend/repository/RedisCache.kt +++ b/src/main/java/plus/maa/backend/repository/RedisCache.kt @@ -6,9 +6,6 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import io.github.oshai.kotlinlogging.KotlinLogging -import lombok.RequiredArgsConstructor -import lombok.Setter -import lombok.extern.slf4j.Slf4j import org.apache.commons.lang3.StringUtils import org.springframework.beans.factory.annotation.Value import org.springframework.core.io.ClassPathResource @@ -21,8 +18,6 @@ import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Component import java.util.concurrent.TimeUnit import java.util.concurrent.atomic.AtomicBoolean -import java.util.function.Function -import java.util.function.Supplier private val log = KotlinLogging.logger { } @@ -31,14 +26,11 @@ private val log = KotlinLogging.logger { } * * @author AnselYuki */ -@Slf4j -@Setter @Component -@RequiredArgsConstructor class RedisCache( @Value("\${maa-copilot.cache.default-expire}") - private val expire: Int = 0, - private val redisTemplate: StringRedisTemplate? = null + private val expire: Int, + private val redisTemplate: StringRedisTemplate ) { // 添加 JSR310 模块,以便顺利序列化 LocalDateTime 等类型 @@ -75,9 +67,9 @@ class RedisCache( fun setCache(key: String, value: T, timeout: Long, timeUnit: TimeUnit) { val json = getJson(value) ?: return if (timeout <= 0) { - redisTemplate!!.opsForValue()[key] = json + redisTemplate.opsForValue()[key] = json } else { - redisTemplate!!.opsForValue()[key, json, timeout] = timeUnit + redisTemplate.opsForValue()[key, json, timeout] = timeUnit } } @@ -116,9 +108,9 @@ class RedisCache( fun setCacheIfAbsent(key: String, value: T, timeout: Long, timeUnit: TimeUnit): Boolean { val json = getJson(value) ?: return false val result = if (timeout <= 0) { - java.lang.Boolean.TRUE == redisTemplate!!.opsForValue().setIfAbsent(key, json) + java.lang.Boolean.TRUE == redisTemplate.opsForValue().setIfAbsent(key, json) } else { - java.lang.Boolean.TRUE == redisTemplate!!.opsForValue().setIfAbsent(key, json, timeout, timeUnit) + java.lang.Boolean.TRUE == redisTemplate.opsForValue().setIfAbsent(key, json, timeout, timeUnit) } return result } @@ -132,16 +124,15 @@ class RedisCache( return } val jsonList = arrayOfNulls(set.size) - var i = 0 - for (t in set) { + for ((i, t) in set.withIndex()) { val json = getJson(t) ?: return - jsonList[i++] = json + jsonList[i] = json } if (timeout <= 0) { - redisTemplate!!.opsForSet().add(key, *jsonList) + redisTemplate.opsForSet().add(key, *jsonList) } else { - redisTemplate!!.opsForSet().add(key, *jsonList) + redisTemplate.opsForSet().add(key, *jsonList) redisTemplate.expire(key, timeout, timeUnit) } } @@ -159,7 +150,7 @@ class RedisCache( * @param timeout ZSet 的过期时间 */ fun incZSet(key: String, member: String?, incScore: Double, size: Long, timeout: Long) { - redisTemplate!!.execute( + redisTemplate.execute( incZSetRedisScript, listOf(key), member, @@ -171,18 +162,18 @@ class RedisCache( // 获取的元素是按照 score 从小到大排列的 fun getZSet(key: String, start: Long, end: Long): Set? { - return redisTemplate!!.opsForZSet().range(key, start, end) + return redisTemplate.opsForZSet().range(key, start, end) } // 获取的元素是按照 score 从大到小排列的 fun getZSetReverse(key: String, start: Long, end: Long): Set? { - return redisTemplate!!.opsForZSet().reverseRange(key, start, end) + return redisTemplate.opsForZSet().reverseRange(key, start, end) } fun valueMemberInSet(key: String, value: T): Boolean { try { val json = getJson(value) ?: return false - return java.lang.Boolean.TRUE == redisTemplate!!.opsForSet().isMember(key, json) + return java.lang.Boolean.TRUE == redisTemplate.opsForSet().isMember(key, json) } catch (e: Exception) { log.error(e) { e.message } } @@ -193,34 +184,33 @@ class RedisCache( return getCache(key, valueType, null, expire.toLong(), TimeUnit.SECONDS) } - fun getCache(key: String, valueType: Class, onMiss: Supplier?): T? { + fun getCache(key: String, valueType: Class, onMiss: (()->T)?): T? { return getCache(key, valueType, onMiss, expire.toLong(), TimeUnit.SECONDS) } - fun getCache(key: String, valueType: Class, onMiss: Supplier?, timeout: Long): T? { + fun getCache(key: String, valueType: Class, onMiss: (()->T)?, timeout: Long): T? { return getCache(key, valueType, onMiss, timeout, TimeUnit.SECONDS) } - fun getCache(key: String, valueType: Class, onMiss: Supplier?, timeout: Long, timeUnit: TimeUnit): T? { + fun getCache(key: String, valueType: Class, onMiss: (()->T)?, timeout: Long, timeUnit: TimeUnit): T? { try { - var json = redisTemplate!!.opsForValue()[key] + var json = redisTemplate.opsForValue()[key] if (StringUtils.isEmpty(json)) { - if (onMiss != null) { + if (onMiss == null){ + return null + } //上锁 synchronized(RedisCache::class.java) { //再次查询缓存,目的是判断是否前面的线程已经set过了 json = redisTemplate.opsForValue()[key] //第二次校验缓存是否存在 if (StringUtils.isEmpty(json)) { - val result = onMiss.get() ?: return null + val result = onMiss() //数据库中不存在 - setCache(key, result, timeout, timeUnit) + setCache(key, result, timeout, timeUnit) return result } } - } else { - return null - } } return readMapper.readValue(json, valueType) } catch (e: Exception) { @@ -229,11 +219,11 @@ class RedisCache( } } - fun updateCache(key: String, valueType: Class, defaultValue: T, onUpdate: Function) { + fun updateCache(key: String, valueType: Class, defaultValue: T, onUpdate: (T)->T) { updateCache(key, valueType, defaultValue, onUpdate, expire.toLong(), TimeUnit.SECONDS) } - fun updateCache(key: String, valueType: Class?, defaultValue: T, onUpdate: Function, timeout: Long) { + fun updateCache(key: String, valueType: Class?, defaultValue: T, onUpdate: (T)->T, timeout: Long) { updateCache(key, valueType, defaultValue, onUpdate, timeout, TimeUnit.SECONDS) } @@ -241,20 +231,20 @@ class RedisCache( key: String, valueType: Class?, defaultValue: T, - onUpdate: Function, + onUpdate: (T)->T, timeout: Long, timeUnit: TimeUnit ) { var result: T try { synchronized(RedisCache::class.java) { - val json = redisTemplate!!.opsForValue()[key] + val json = redisTemplate.opsForValue()[key] result = if (StringUtils.isEmpty(json)) { defaultValue } else { readMapper.readValue(json, valueType) } - result = onUpdate.apply(result) + result = onUpdate(result) setCache(key, result, timeout, timeUnit) } } catch (e: Exception) { @@ -277,7 +267,7 @@ class RedisCache( fun removeCache(keys: Collection, notUseUnlink: Boolean = false) { if (!notUseUnlink && supportUnlink.get()) { try { - redisTemplate!!.unlink(keys) + redisTemplate.unlink(keys) return } catch (e: InvalidDataAccessApiUsageException) { // Redisson、Jedis、Lettuce @@ -306,7 +296,7 @@ class RedisCache( } // 兜底的 Del 命令 - redisTemplate!!.delete(keys) + redisTemplate.delete(keys) } /** @@ -318,7 +308,7 @@ class RedisCache( */ fun removeKVIfEquals(key: String, value: T): Boolean { val json = getJson(value) ?: return false - return java.lang.Boolean.TRUE == redisTemplate!!.execute(removeKVIfEqualsScript, listOf(key), json) + return java.lang.Boolean.TRUE == redisTemplate.execute(removeKVIfEqualsScript, listOf(key), json) } /** @@ -353,7 +343,7 @@ class RedisCache( // 保存要删除的键 val keysToDelete: MutableList = ArrayList(batchSize) - redisTemplate!!.scan(scanOptions).use { cursor -> + redisTemplate.scan(scanOptions).use { cursor -> while (cursor.hasNext()) { val key = cursor.next() // 将要删除的键添加到列表中 @@ -367,7 +357,7 @@ class RedisCache( } } // 删除剩余的键(不足 batchSize 的最后一批) - if (!keysToDelete.isEmpty()) { + if (keysToDelete.isNotEmpty()) { removeCache(keysToDelete) } } diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 38490b03..54885e36 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -24,8 +24,7 @@ import plus.maa.backend.service.model.RatingType import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.* -import java.util.function.Consumer - +import kotlin.collections.ArrayList /** * @author LoMu @@ -154,12 +153,10 @@ class CommentsAreaService( //删除所有回复 if (StringUtils.isBlank(commentsArea.mainCommentId)) { val commentsAreaList = commentsAreaRepository.findByMainCommentId(commentsArea.id) - commentsAreaList.forEach( - Consumer { ca: CommentsArea -> + commentsAreaList.forEach{ ca: CommentsArea -> ca.setDeleteTime(now) .setDelete(true) } - ) commentsAreaRepository.saveAll(commentsAreaList) } commentsAreaRepository.save(commentsArea) @@ -311,11 +308,11 @@ class CommentsAreaService( ) //将已删除评论内容替换为空 - subCommentsList.forEach(Consumer { comment: CommentsArea -> + subCommentsList.forEach{ comment: CommentsArea -> if (comment.isDelete) { comment.setMessage("") } - }) + } //所有评论 From 58097ed0dc69db5b700eb807de37e2459d9bf78d Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 01:35:18 +0800 Subject: [PATCH 127/168] Rename .java to .kt --- .../maa/backend/repository/entity/{ArkLevel.java => ArkLevel.kt} | 0 .../repository/entity/{ArkLevelSha.java => ArkLevelSha.kt} | 0 .../repository/entity/{CommentsArea.java => CommentsArea.kt} | 0 .../maa/backend/repository/entity/{MaaUser.java => MaaUser.kt} | 0 .../entity/gamedata/{ArkActivity.java => ArkActivity.kt} | 0 .../entity/gamedata/{ArkCrisisV2Info.java => ArkCrisisV2Info.kt} | 0 .../repository/entity/gamedata/{ArkTower.java => ArkTower.kt} | 0 .../repository/entity/gamedata/{ArkZone.java => ArkZone.kt} | 0 .../entity/gamedata/{MaaArkStage.java => MaaArkStage.kt} | 0 .../entity/github/{GithubCommit.java => GithubCommit.kt} | 0 .../entity/github/{GithubContent.java => GithubContent.kt} | 0 .../repository/entity/github/{GithubTree.java => GithubTree.kt} | 0 .../repository/entity/github/{GithubTrees.java => GithubTrees.kt} | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/repository/entity/{ArkLevel.java => ArkLevel.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/{ArkLevelSha.java => ArkLevelSha.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/{CommentsArea.java => CommentsArea.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/{MaaUser.java => MaaUser.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/gamedata/{ArkActivity.java => ArkActivity.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/gamedata/{ArkCrisisV2Info.java => ArkCrisisV2Info.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/gamedata/{ArkTower.java => ArkTower.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/gamedata/{ArkZone.java => ArkZone.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/gamedata/{MaaArkStage.java => MaaArkStage.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/github/{GithubCommit.java => GithubCommit.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/github/{GithubContent.java => GithubContent.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/github/{GithubTree.java => GithubTree.kt} (100%) rename src/main/java/plus/maa/backend/repository/entity/github/{GithubTrees.java => GithubTrees.kt} (100%) diff --git a/src/main/java/plus/maa/backend/repository/entity/ArkLevel.java b/src/main/java/plus/maa/backend/repository/entity/ArkLevel.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/ArkLevel.java rename to src/main/java/plus/maa/backend/repository/entity/ArkLevel.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.java b/src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.java rename to src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/CommentsArea.java b/src/main/java/plus/maa/backend/repository/entity/CommentsArea.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/CommentsArea.java rename to src/main/java/plus/maa/backend/repository/entity/CommentsArea.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/MaaUser.java b/src/main/java/plus/maa/backend/repository/entity/MaaUser.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/MaaUser.java rename to src/main/java/plus/maa/backend/repository/entity/MaaUser.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.java rename to src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.java rename to src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.java rename to src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.java rename to src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.java b/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.java rename to src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.java b/src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.java rename to src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java b/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/github/GithubContent.java rename to src/main/java/plus/maa/backend/repository/entity/github/GithubContent.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubTree.java b/src/main/java/plus/maa/backend/repository/entity/github/GithubTree.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/github/GithubTree.java rename to src/main/java/plus/maa/backend/repository/entity/github/GithubTree.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.java b/src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.java rename to src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.kt From b307285c92957b1fc13fa9fa1183c8ea92f4407c Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 01:35:18 +0800 Subject: [PATCH 128/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20reposi?= =?UTF-8?q?tory=20=E4=B8=AD=E9=99=A4=E4=BA=86=20Copilot=20=E7=B1=BB?= =?UTF-8?q?=E4=B9=8B=E5=A4=96=E7=9A=84=E6=89=80=E6=9C=89=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E7=B1=BB=E5=88=B0=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/repository/ArkLevelRepository.kt | 4 -- .../maa/backend/repository/UserRepository.kt | 2 +- .../maa/backend/repository/entity/ArkLevel.kt | 64 +++++++++---------- .../backend/repository/entity/ArkLevelSha.kt | 6 +- .../backend/repository/entity/CommentsArea.kt | 58 ++++++++--------- .../maa/backend/repository/entity/MaaUser.kt | 64 +++++++++---------- .../repository/entity/gamedata/ArkActivity.kt | 16 ++--- .../entity/gamedata/ArkCrisisV2Info.kt | 20 ++---- .../repository/entity/gamedata/ArkTower.kt | 19 ++---- .../repository/entity/gamedata/ArkZone.kt | 21 +++--- .../repository/entity/gamedata/MaaArkStage.kt | 15 ++--- .../repository/entity/github/GithubCommit.kt | 15 ++--- .../repository/entity/github/GithubContent.kt | 64 +++++++------------ .../repository/entity/github/GithubTree.kt | 23 +++---- .../repository/entity/github/GithubTrees.kt | 21 ++---- .../controller/response/user/MaaUserInfo.kt | 2 +- .../maa/backend/service/ArkGameDataService.kt | 5 +- .../backend/service/ArkLevelParserService.kt | 22 +++---- .../maa/backend/service/ArkLevelService.kt | 3 + .../backend/service/CommentsAreaService.kt | 51 ++++++++------- .../plus/maa/backend/service/UserService.kt | 18 ++++-- .../plus/maa/backend/task/ArkLevelSyncTask.kt | 5 +- 22 files changed, 225 insertions(+), 293 deletions(-) diff --git a/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt b/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt index c4a786ee..7fc8b6ab 100644 --- a/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt +++ b/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt @@ -48,8 +48,4 @@ interface ArkLevelRepository : MongoRepository { ) fun queryLevelByKeyword(keyword: String): List - /** - * 根据stageId列表查询 - */ - fun findByStageIdIn(stageIds: Collection): List } diff --git a/src/main/java/plus/maa/backend/repository/UserRepository.kt b/src/main/java/plus/maa/backend/repository/UserRepository.kt index fdb06410..5325dff8 100644 --- a/src/main/java/plus/maa/backend/repository/UserRepository.kt +++ b/src/main/java/plus/maa/backend/repository/UserRepository.kt @@ -20,6 +20,6 @@ interface UserRepository : MongoRepository { } fun UserRepository.findByUsersId(userId: List): Map { - return findAllById(userId).associateBy { it.userId } + return findAllById(userId).associateBy { it.userId!! } } diff --git a/src/main/java/plus/maa/backend/repository/entity/ArkLevel.kt b/src/main/java/plus/maa/backend/repository/entity/ArkLevel.kt index beca9be4..9e841118 100644 --- a/src/main/java/plus/maa/backend/repository/entity/ArkLevel.kt +++ b/src/main/java/plus/maa/backend/repository/entity/ArkLevel.kt @@ -1,50 +1,50 @@ -package plus.maa.backend.repository.entity; +package plus.maa.backend.repository.entity -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.jetbrains.annotations.Nullable; -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.index.Indexed; -import org.springframework.data.mongodb.core.mapping.Document; - -import java.time.LocalDateTime; +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.index.Indexed +import org.springframework.data.mongodb.core.mapping.Document +import java.time.LocalDateTime /** * 地图数据 * * @author john180 */ -@Data -@Builder -@NoArgsConstructor -@AllArgsConstructor @Document("maa_level") -public class ArkLevel { - public static final ArkLevel EMPTY = new ArkLevel(); - +data class ArkLevel ( @Id - private String id; - private String levelId; + val id: String? = null, + val levelId: String? = null, + @Indexed - private String stageId; + val stageId: String? = null, + //文件版本, 用于判断是否需要更新 - private String sha; + val sha: String = "", + //地图类型, 例: 主线、活动、危机合约 - private String catOne; + var catOne: String? = null, + //所属章节, 例: 怒号光明、寻昼行动 - private String catTwo; + var catTwo: String? = null, + //地图ID, 例: 7-18、FC-1 - private String catThree; + var catThree: String? = null, + //地图名, 例: 冬逝、爱国者之死 - private String name; - private int width; - private int height; + val name: String? = null, + val width: Int = 0, + val height: Int = 0, + // 只是服务器认为的当前版本地图是否开放 - @Nullable - private Boolean isOpen; + var isOpen: Boolean? = null, + // 非实际意义上的活动地图关闭时间,只是服务器认为的关闭时间 - @Nullable - private LocalDateTime closeTime; + var closeTime: LocalDateTime? = null + +) { + companion object { + // 暂时这么做,有机会用和类型分别处理成功、失败以及解析器未实现的情况 + val EMPTY: ArkLevel = ArkLevel() + } } diff --git a/src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.kt b/src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.kt index 9657a7ff..81df48d8 100644 --- a/src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.kt +++ b/src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.kt @@ -1,8 +1,8 @@ -package plus.maa.backend.repository.entity; +package plus.maa.backend.repository.entity /** * @author john180 */ -public interface ArkLevelSha { - String getSha(); +interface ArkLevelSha { + val sha: String } diff --git a/src/main/java/plus/maa/backend/repository/entity/CommentsArea.kt b/src/main/java/plus/maa/backend/repository/entity/CommentsArea.kt index 6d1a37c1..225ac19f 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CommentsArea.kt +++ b/src/main/java/plus/maa/backend/repository/entity/CommentsArea.kt @@ -1,13 +1,12 @@ -package plus.maa.backend.repository.entity; +package plus.maa.backend.repository.entity -import lombok.Data; -import lombok.experimental.Accessors; -import org.springframework.data.annotation.Id; -import org.springframework.data.mongodb.core.index.Indexed; -import org.springframework.data.mongodb.core.mapping.Document; - -import java.io.Serializable; -import java.time.LocalDateTime; +import lombok.Data +import lombok.experimental.Accessors +import org.springframework.data.annotation.Id +import org.springframework.data.mongodb.core.index.Indexed +import org.springframework.data.mongodb.core.mapping.Document +import java.io.Serializable +import java.time.LocalDateTime /** * @author LoMu @@ -16,42 +15,39 @@ import java.time.LocalDateTime; @Data @Accessors(chain = true) @Document("maa_comments_area") -public class CommentsArea implements Serializable { - +class CommentsArea( @Id - private String id; + val id: String? = null, @Indexed - private Long copilotId; + val copilotId: Long, - //答复某个评论 - private String fromCommentId; + // 答复某个评论 + val fromCommentId: String? = null, + val uploaderId: String, - private String uploaderId; + // 评论内容 + var message: String, - //评论内容 - private String message; + var likeCount: Long = 0, - private long likeCount; + var dislikeCount: Long = 0, - private long dislikeCount; - - private LocalDateTime uploadTime = LocalDateTime.now(); + val uploadTime: LocalDateTime = LocalDateTime.now(), // 是否将该评论置顶 - private boolean topping; - - private boolean delete; + var topping: Boolean = false, - private LocalDateTime deleteTime; + var delete: Boolean = false, - //其主评论id(如果自身为主评论则为null) - private String mainCommentId; + var deleteTime: LocalDateTime? = null, - //邮件通知 - private Boolean notification; + // 其主评论id(如果自身为主评论则为null) + val mainCommentId: String? = null, -} + // 邮件通知 + var notification: Boolean = false +) : Serializable diff --git a/src/main/java/plus/maa/backend/repository/entity/MaaUser.kt b/src/main/java/plus/maa/backend/repository/entity/MaaUser.kt index 81849409..0cfb032b 100644 --- a/src/main/java/plus/maa/backend/repository/entity/MaaUser.kt +++ b/src/main/java/plus/maa/backend/repository/entity/MaaUser.kt @@ -1,47 +1,43 @@ -package plus.maa.backend.repository.entity; +package plus.maa.backend.repository.entity -import com.fasterxml.jackson.annotation.JsonInclude; -import jakarta.validation.constraints.NotBlank; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; -import org.springframework.data.annotation.Id; -import org.springframework.data.annotation.Transient; -import org.springframework.data.mongodb.core.index.Indexed; -import org.springframework.data.mongodb.core.mapping.Document; -import plus.maa.backend.controller.request.user.UserInfoUpdateDTO; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; +import com.fasterxml.jackson.annotation.JsonInclude +import org.springframework.data.annotation.Id +import org.springframework.data.annotation.Transient +import org.springframework.data.mongodb.core.index.Indexed +import org.springframework.data.mongodb.core.mapping.Document +import plus.maa.backend.controller.request.user.UserInfoUpdateDTO +import java.io.Serializable /** * @author AnselYuki */ -@Data -@Accessors(chain = true) -@NoArgsConstructor -@AllArgsConstructor @JsonInclude(JsonInclude.Include.NON_NULL) @Document("maa_user") -public class MaaUser implements Serializable { - @Transient - public static final MaaUser UNKNOWN = new MaaUser().setUserName("未知用户:("); +data class MaaUser( @Id - private String userId; - private String userName; + val userId: String? = null, + var userName: String, + @Indexed(unique = true) - @NotBlank(message = "邮箱为唯一身份标识,不能为空") - private String email; - private String password; - private Integer status = 0; - private List refreshJwtIds = new ArrayList<>(); + val email: String, + var password: String, + var status: Int = 0, + var refreshJwtIds: MutableList = ArrayList() +) : Serializable { - public void updateAttribute(UserInfoUpdateDTO updateDTO) { - String userName = updateDTO.getUserName(); - if (!userName.isBlank()) { - this.userName = userName; + fun updateAttribute(updateDTO: UserInfoUpdateDTO) { + val userName = updateDTO.userName + if (userName.isNotBlank()) { + this.userName = userName } } + + companion object { + @Transient + val UNKNOWN: MaaUser = MaaUser( + userName = "未知用户:(", + email = "unknown@unkown.unkown", + password = "unknown" + ) + } } diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt index 215b80bf..1f65c8b0 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt @@ -1,13 +1,7 @@ -package plus.maa.backend.repository.entity.gamedata; +package plus.maa.backend.repository.entity.gamedata -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -@Data -@NoArgsConstructor -@AllArgsConstructor -public class ArkActivity { - private String id; - private String name; -} +data class ArkActivity( + val id: String, + val name: String +) diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt index 373a0ef0..429634d6 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt @@ -1,16 +1,10 @@ -package plus.maa.backend.repository.entity.gamedata; +package plus.maa.backend.repository.entity.gamedata -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +data class ArkCrisisV2Info ( + val seasonId: String, + val name: String, -@Data -@NoArgsConstructor -@AllArgsConstructor -public class ArkCrisisV2Info { - private String seasonId; - private String name; // 时间戳,单位:秒 - private long startTs; - private long endTs; -} + val startTs: Long, + val endTs: Long +) diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.kt index 0f07dd95..4842e555 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.kt @@ -1,14 +1,7 @@ -package plus.maa.backend.repository.entity.gamedata; +package plus.maa.backend.repository.entity.gamedata -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class ArkTower { - private String id; - private String name; - private String subName; -} +data class ArkTower( + val id: String, + val name: String, + val subName: String +) diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.kt index 557b5443..a58c0848 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.kt @@ -1,23 +1,18 @@ -package plus.maa.backend.repository.entity.gamedata; +package plus.maa.backend.repository.entity.gamedata -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class ArkZone { +data class ArkZone( /** * 例: main_1 */ - private String zoneId; + val zoneID: String, + /** * 例: 第一章 */ - private String zoneNameFirst; + val zoneNameFirst: String?, + /** * 例: 黑暗时代·下 */ - private String zoneNameSecond; -} + val zoneNameSecond: String? +) diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt b/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt index 1c16ceed..262a0e20 100644 --- a/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt +++ b/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt @@ -1,20 +1,17 @@ -package plus.maa.backend.repository.entity.gamedata; +package plus.maa.backend.repository.entity.gamedata -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import lombok.Data; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties -@Data // 忽略对服务器无用的数据 @JsonIgnoreProperties(ignoreUnknown = true) -public class MaaArkStage { - +data class MaaArkStage( /** * 例: CB-EX8 */ - private String code; + val code: String, /** * 例: act5d0_ex08 */ - private String stageId; -} + val stageId: String? +) diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.kt b/src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.kt index 16a5218f..10110ddf 100644 --- a/src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.kt +++ b/src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.kt @@ -1,15 +1,8 @@ -package plus.maa.backend.repository.entity.github; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +package plus.maa.backend.repository.entity.github /** * @author john180 */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class GithubCommit { - private String sha; -} +data class GithubCommit( + val sha: String +) diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.kt b/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.kt index 4a544fdf..b0ace716 100644 --- a/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.kt +++ b/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.kt @@ -1,53 +1,37 @@ -package plus.maa.backend.repository.entity.github; - -import lombok.Data; -import org.apache.commons.lang3.StringUtils; - -import java.util.Objects; +package plus.maa.backend.repository.entity.github /** * @author dragove * created on 2022/12/23 */ -@Data -public class GithubContent { - +data class GithubContent( // 文件名 - private String name; + val name: String, + // 路径 - private String path; - private String sha; + val path: String, + val sha: String, + // 文件大小(Byte) - private Long size; - // 路径类型 file-文件 dir-目录 - private String type; - // 下载地址 - private String downloadUrl; - // 访问地址 - private String htmlUrl; - // 对应commit地址 - private String gitUrl; + val size: Long, - /** - * 仿照File类,判断是否目录类型 - * - * @return 如果是目录类型,则返回 true,文件类型则返回 false - */ - public boolean isDir() { - return Objects.equals(type, "dir"); - } + // 路径类型 file-文件 dir-目录 + val type: String, - public boolean isFile() { - return Objects.equals(type, "file"); - } + // 下载地址 + val downloadUrl: String?, - public String getFileExtension() { - return name == null ? - StringUtils.EMPTY : - (name.contains(".") ? - name.substring(name.lastIndexOf(".") + 1) : - StringUtils.EMPTY - ); - } + // 访问地址 + val htmlUrl: String, + // 对应commit地址 + val gitUrl: String +) { + val isFile: Boolean + /** + * 仿照File类,判断是否问类型 + * + * @return 如果是文件类型,则返回 true,目录类型则返回 false + */ + get() = type == "file" } diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubTree.kt b/src/main/java/plus/maa/backend/repository/entity/github/GithubTree.kt index 1234c0fa..699777cc 100644 --- a/src/main/java/plus/maa/backend/repository/entity/github/GithubTree.kt +++ b/src/main/java/plus/maa/backend/repository/entity/github/GithubTree.kt @@ -1,19 +1,12 @@ -package plus.maa.backend.repository.entity.github; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; +package plus.maa.backend.repository.entity.github /** * @author john180 */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class GithubTree { - private String path; - private String mode; - private String type; - private String sha; - private String url; -} +data class GithubTree ( + val path: String, + val mode: String, + val type: String, + val sha: String, + val url: String +) diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.kt b/src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.kt index af0f8922..2b3047df 100644 --- a/src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.kt +++ b/src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.kt @@ -1,19 +1,10 @@ -package plus.maa.backend.repository.entity.github; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; +package plus.maa.backend.repository.entity.github /** * @author john180 */ -@Data -@NoArgsConstructor -@AllArgsConstructor -public class GithubTrees { - private String sha; - private String url; - private List tree; -} +class GithubTrees ( + val sha: String, + val url: String, + val tree: List, +) diff --git a/src/main/kotlin/plus/maa/backend/controller/response/user/MaaUserInfo.kt b/src/main/kotlin/plus/maa/backend/controller/response/user/MaaUserInfo.kt index 6ba0a7dc..decbb2ea 100644 --- a/src/main/kotlin/plus/maa/backend/controller/response/user/MaaUserInfo.kt +++ b/src/main/kotlin/plus/maa/backend/controller/response/user/MaaUserInfo.kt @@ -10,5 +10,5 @@ data class MaaUserInfo( val userName: String, val activated: Boolean = false ) { - constructor(user: MaaUser) : this(user.userId, user.userName, user.status == 1) + constructor(user: MaaUser) : this(user.userId!!, user.userName, user.status == 1) } diff --git a/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt b/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt index 989ab167..2130d676 100644 --- a/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt +++ b/src/main/kotlin/plus/maa/backend/service/ArkGameDataService.kt @@ -2,7 +2,7 @@ package plus.maa.backend.service import com.fasterxml.jackson.core.type.TypeReference import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.module.kotlin.jacksonMapperBuilder +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import io.github.oshai.kotlinlogging.KotlinLogging import okhttp3.OkHttpClient import okhttp3.Request @@ -35,9 +35,8 @@ class ArkGameDataService(private val okHttpClient: OkHttpClient) { "https://raw.githubusercontent.com/yuanyan3060/ArknightsGameResource/main/gamedata/excel/crisis_v2_table.json" } - private final val mapper = jacksonMapperBuilder() + private final val mapper = jacksonObjectMapper() .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) - .build() private val stageMap = ConcurrentHashMap() private val levelStageMap = ConcurrentHashMap() private val zoneMap = ConcurrentHashMap() diff --git a/src/main/kotlin/plus/maa/backend/service/ArkLevelParserService.kt b/src/main/kotlin/plus/maa/backend/service/ArkLevelParserService.kt index dedb5a66..40eeeb1b 100644 --- a/src/main/kotlin/plus/maa/backend/service/ArkLevelParserService.kt +++ b/src/main/kotlin/plus/maa/backend/service/ArkLevelParserService.kt @@ -8,7 +8,7 @@ import plus.maa.backend.repository.entity.gamedata.ArkTilePos import plus.maa.backend.service.model.ArkLevelType import plus.maa.backend.service.model.parser.ArkLevelParser -private val log = KotlinLogging.logger { } +private val log = KotlinLogging.logger { } /** * @author john180 @@ -23,16 +23,16 @@ class ArkLevelParserService(private val parsers: List) { * TODO 完成剩余字段实现 */ @Nullable - fun parseLevel(tilePos: ArkTilePos, sha: String?): ArkLevel? { - val level = ArkLevel.builder() - .levelId(tilePos.levelId) - .stageId(tilePos.stageId) - .sha(sha) - .catThree(tilePos.code) - .name(tilePos.name) - .width(tilePos.width) - .height(tilePos.height) - .build() + fun parseLevel(tilePos: ArkTilePos, sha: String): ArkLevel? { + val level = ArkLevel( + levelId = tilePos.levelId, + stageId = tilePos.stageId, + sha = sha, + catThree = tilePos.code, + name = tilePos.name, + width = tilePos.width, + height = tilePos.height, + ) return parseLevel(level, tilePos) } diff --git a/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt b/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt index 84466db0..fbec4887 100644 --- a/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt +++ b/src/main/kotlin/plus/maa/backend/service/ArkLevelService.kt @@ -180,6 +180,9 @@ class ArkLevelService( log.info { "[ACTIVITIES-OPEN-STATUS]开始更新活动地图开放状态" } // 就一个文件,直接在当前线程下载数据 try { + if (stages.downloadUrl == null) { + return + } okHttpClient .newCall(Request.Builder().url(stages.downloadUrl).build()) .execute().use { response -> diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 54885e36..1db91880 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -70,7 +70,7 @@ class CommentsAreaService( val commentsAreaOptional = commentsAreaRepository.findById(commentsAddDTO.fromCommentId) Assert.isTrue(commentsAreaOptional.isPresent, "回复的评论不存在") commentsArea = commentsAreaOptional.get() - Assert.isTrue(!commentsArea.isDelete, "回复的评论不存在") + Assert.isTrue(!commentsArea.delete, "回复的评论不存在") mainCommentsId = if (StringUtils .isNoneBlank(commentsArea.mainCommentId) @@ -127,12 +127,14 @@ class CommentsAreaService( //创建评论表 commentsAreaRepository.insert( - CommentsArea().setCopilotId(copilotId) - .setUploaderId(userId) - .setFromCommentId(fromCommentsId) - .setMainCommentId(mainCommentsId) - .setMessage(message) - .setNotification(commentsAddDTO.notification) + CommentsArea( + copilotId = copilotId, + uploaderId = userId, + fromCommentId = fromCommentsId, + mainCommentId = mainCommentsId, + message = message, + notification = commentsAddDTO.notification + ) ) } @@ -147,16 +149,16 @@ class CommentsAreaService( ) } val now = LocalDateTime.now() - commentsArea.setDelete(true) - commentsArea.setDeleteTime(now) + commentsArea.delete = true + commentsArea.deleteTime = now //删除所有回复 if (StringUtils.isBlank(commentsArea.mainCommentId)) { - val commentsAreaList = commentsAreaRepository.findByMainCommentId(commentsArea.id) - commentsAreaList.forEach{ ca: CommentsArea -> - ca.setDeleteTime(now) - .setDelete(true) - } + val commentsAreaList = commentsAreaRepository.findByMainCommentId(commentsArea.id!!) + commentsAreaList.forEach { ca: CommentsArea -> + ca.deleteTime = now + ca.delete = true + } commentsAreaRepository.saveAll(commentsAreaList) } commentsAreaRepository.save(commentsArea) @@ -178,7 +180,8 @@ class CommentsAreaService( val dislikeCountChange: Long val ratingOptional = - ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COMMENT, commentsArea.id, userId) + ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COMMENT, + commentsArea.id!!, userId) // 判断该用户是否存在评分 if (ratingOptional != null) { // 如果评分发生变化则更新 @@ -223,8 +226,8 @@ class CommentsAreaService( dislikeCount = 0 } - commentsArea.setLikeCount(likeCount) - commentsArea.setDislikeCount(dislikeCount) + commentsArea.likeCount = likeCount + commentsArea.dislikeCount = dislikeCount commentsAreaRepository.save(commentsArea) } @@ -237,14 +240,14 @@ class CommentsAreaService( */ fun topping(userId: String, commentsToppingDTO: CommentsToppingDTO) { val commentsArea = findCommentsById(commentsToppingDTO.commentId) - Assert.isTrue(!commentsArea.isDelete, "评论不存在") + Assert.isTrue(!commentsArea.delete, "评论不存在") // 只允许作者置顶评论 copilotRepository.findByCopilotId(commentsArea.copilotId)?.let { copilot: Copilot -> Assert.isTrue( userId == copilot.uploaderId, "只有作者才能置顶评论" ) - commentsArea.setTopping(commentsToppingDTO.topping) + commentsArea.topping = commentsToppingDTO.topping commentsAreaRepository.save(commentsArea) } } @@ -303,14 +306,14 @@ class CommentsAreaService( //获取子评论 val subCommentsList = commentsAreaRepository.findByMainCommentIdIn( mainCommentsList - .map { obj: CommentsArea -> obj.id } + .map { obj: CommentsArea -> requireNotNull(obj.id) } .toList() ) //将已删除评论内容替换为空 - subCommentsList.forEach{ comment: CommentsArea -> - if (comment.isDelete) { - comment.setMessage("") + subCommentsList.forEach { comment: CommentsArea -> + if (comment.delete) { + comment.message = "" } } @@ -364,7 +367,7 @@ class CommentsAreaService( Assert.isTrue(commentsAreaOptional.isPresent, "评论不存在") val commentsArea = commentsAreaOptional.get() Assert.isTrue(userId == commentsArea.uploaderId, "您没有权限修改") - commentsArea.setNotification(status) + commentsArea.notification = status commentsAreaRepository.save(commentsArea) } } diff --git a/src/main/kotlin/plus/maa/backend/service/UserService.kt b/src/main/kotlin/plus/maa/backend/service/UserService.kt index f22d8428..e0d6b168 100644 --- a/src/main/kotlin/plus/maa/backend/service/UserService.kt +++ b/src/main/kotlin/plus/maa/backend/service/UserService.kt @@ -84,8 +84,8 @@ class UserService( if (userResult.isEmpty) return val maaUser = userResult.get() // 修改密码的逻辑,应当使用与 authentication provider 一致的编码器 - maaUser.setPassword(passwordEncoder.encode(rawPassword)) - maaUser.setRefreshJwtIds(ArrayList()) + maaUser.password = passwordEncoder.encode(rawPassword) + maaUser.refreshJwtIds = ArrayList() userRepository.save(maaUser) } @@ -101,10 +101,14 @@ class UserService( // 校验验证码 emailService.verifyVCode(registerDTO.email, registerDTO.registrationToken) - val user = MaaUser() + val user = MaaUser( + userName = registerDTO.userName, + email = registerDTO.email, + password = registerDTO.password + ) BeanUtils.copyProperties(registerDTO, user) - user.setPassword(encode) - user.setStatus(1) + user.password = encode + user.status = 1 val userInfo: MaaUserInfo try { val save = userRepository.save(user) @@ -121,7 +125,7 @@ class UserService( * @param userId 用户id * @param updateDTO 更新参数 */ - fun updateUserInfo(userId: String, updateDTO: UserInfoUpdateDTO?) { + fun updateUserInfo(userId: String, updateDTO: UserInfoUpdateDTO) { userRepository.findById(userId).ifPresent { maaUser: MaaUser -> maaUser.updateAttribute(updateDTO) userRepository.save(maaUser) @@ -180,7 +184,7 @@ class UserService( fun modifyPasswordByActiveCode(passwordResetDTO: PasswordResetDTO) { emailService.verifyVCode(passwordResetDTO.email, passwordResetDTO.activeCode) val maaUser = userRepository.findByEmail(passwordResetDTO.email) - modifyPassword(maaUser!!.userId, passwordResetDTO.password) + modifyPassword(maaUser!!.userId!!, passwordResetDTO.password) } /** diff --git a/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt index fc0b1284..42ca864c 100644 --- a/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt @@ -3,6 +3,7 @@ package plus.maa.backend.task import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Component import plus.maa.backend.service.ArkLevelService +import java.util.concurrent.TimeUnit @Component class ArkLevelSyncTask( @@ -13,7 +14,7 @@ class ArkLevelSyncTask( * 地图数据同步定时任务,每10分钟执行一次 * 应用启动时自动同步一次 */ - @Scheduled(cron = "\${maa-copilot.task-cron.ark-level:-}") + @Scheduled(fixedDelay = 1000L, timeUnit = TimeUnit.MINUTES) fun syncArkLevels() { arkLevelService.runSyncLevelDataTask() } @@ -22,7 +23,7 @@ class ArkLevelSyncTask( * 更新开放状态,每天凌晨执行,最好和热度值刷入任务保持相对顺序 * 4:00、4:15 各执行一次,避免网络波动导致更新失败 */ - @Scheduled(cron = "0 0-15/15 4 * * ?") + @Scheduled(fixedDelay = 1000L, timeUnit = TimeUnit.MINUTES) fun updateOpenStatus() { arkLevelService.updateActivitiesOpenStatus() arkLevelService.updateCrisisV2OpenStatus() From 4c8928ca0a4ff5cb60e4787d8bbf2f360b1c078c Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 13:47:38 +0800 Subject: [PATCH 129/168] Rename .java to .kt --- .../maa/backend/repository/entity/{Copilot.java => Copilot.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/repository/entity/{Copilot.java => Copilot.kt} (100%) diff --git a/src/main/java/plus/maa/backend/repository/entity/Copilot.java b/src/main/java/plus/maa/backend/repository/entity/Copilot.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/Copilot.java rename to src/main/java/plus/maa/backend/repository/entity/Copilot.kt From 9c0edd4279a78e9ff19ae247b2851cfc7c79edf8 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 13:47:38 +0800 Subject: [PATCH 130/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BBCopilot?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=88=B0kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/entity/CollectionMeta.kt | 5 +- .../maa/backend/repository/entity/Copilot.kt | 240 +++++++++--------- .../backend/service/CommentsAreaService.kt | 5 +- .../maa/backend/service/CopilotService.kt | 16 +- .../maa/backend/task/CopilotBackupTask.kt | 4 +- .../backend/task/CopilotScoreRefreshTask.kt | 9 +- 6 files changed, 134 insertions(+), 145 deletions(-) diff --git a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt index 5f8a706e..cc491cdf 100644 --- a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt +++ b/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt @@ -1,7 +1,6 @@ package plus.maa.backend.repository.entity import java.io.Serializable -import java.util.function.Function /** * mongodb 集合元数据 @@ -9,6 +8,6 @@ import java.util.function.Function * @param 集合对应实体数据类型 * @author dragove * created on 2023-12-27 - */ -data class CollectionMeta(val idGetter: (T)->Long, val incIdField: String, val entityClass: Class) : + */ +data class CollectionMeta(val idGetter: (T) -> Long, val incIdField: String, val entityClass: Class) : Serializable diff --git a/src/main/java/plus/maa/backend/repository/entity/Copilot.kt b/src/main/java/plus/maa/backend/repository/entity/Copilot.kt index 3ebda8f1..017871ba 100644 --- a/src/main/java/plus/maa/backend/repository/entity/Copilot.kt +++ b/src/main/java/plus/maa/backend/repository/entity/Copilot.kt @@ -1,199 +1,189 @@ -package plus.maa.backend.repository.entity; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.databind.PropertyNamingStrategies; -import com.fasterxml.jackson.databind.annotation.JsonNaming; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.Accessors; -import org.springframework.data.annotation.Id; -import org.springframework.data.annotation.Transient; -import org.springframework.data.mongodb.core.index.Indexed; -import org.springframework.data.mongodb.core.mapping.Document; - -import java.io.Serializable; -import java.time.LocalDateTime; -import java.util.List; +package plus.maa.backend.repository.entity + +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.databind.PropertyNamingStrategies +import com.fasterxml.jackson.databind.annotation.JsonNaming +import org.springframework.data.annotation.Id +import org.springframework.data.annotation.Transient +import org.springframework.data.mongodb.core.index.Indexed +import org.springframework.data.mongodb.core.mapping.Document +import java.io.Serializable +import java.time.LocalDateTime /** * @author LoMu * Date 2022-12-25 17:56 */ -@Data -@NoArgsConstructor -@AllArgsConstructor -@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) @Document("maa_copilot") -public class Copilot implements Serializable { - - @Transient - public static final CollectionMeta META = new CollectionMeta<>(Copilot::getCopilotId, - "copilotId", Copilot.class); - +class Copilot( @Id - // 作业id - private String id; + var id: String? = null, + // 自增数字ID @Indexed(unique = true) - private Long copilotId; + var copilotId: Long? = null, + // 关卡名 @Indexed - private String stageName; + var stageName: String? = null, // 上传者id - private String uploaderId; + var uploaderId: String? = null, // 查看次数 - private Long views = 0L; + var views: Long = 0L, //评级 - private int ratingLevel; + var ratingLevel: Int = 0, //评级比率 十分之一代表半星 - private double ratingRatio; + var ratingRatio: Double = 0.0, - private long likeCount; + var likeCount: Long = 0, - private long dislikeCount; + var dislikeCount: Long = 0, // 热度 - private double hotScore; + var hotScore: Double = 0.0, // 难度 - private int difficulty; + var difficulty: Int = 0, // 版本号(文档中说明:最低要求 maa 版本号,必选。保留字段) - - private String minimumRequired; + var minimumRequired: String? = null, // 指定干员 - private List opers; + var opers: List? = null, + // 群组 - private List groups; + var groups: List? = null, + // 战斗中的操作 - private List actions; + var actions: List? = null, // 描述 - private Doc doc; + var doc: Doc? = null, - private LocalDateTime firstUploadTime; - private LocalDateTime uploadTime; + var firstUploadTime: LocalDateTime? = null, + var uploadTime: LocalDateTime? = null, // 原始数据 - private String content; + var content: String? = null, @JsonIgnore - private boolean delete; + var delete: Boolean = false, + @JsonIgnore - private LocalDateTime deleteTime; + var deleteTime: LocalDateTime? = null, + @JsonIgnore - private Boolean notification; + var notification: Boolean? = null +) : Serializable { - @Data - @NoArgsConstructor - @AllArgsConstructor - @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) - public static class OperationGroup implements Serializable { + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) + data class OperationGroup ( // 干员名 - private String name; + var name: String? = null, + // 技能序号。可选,默认 1 - private int skill = 1; + var skill: Int = 1, + // 技能用法。可选,默认 0 - private int skillUsage; + var skillUsage: Int = 0 - } + ): Serializable - @Data - @NoArgsConstructor - @AllArgsConstructor - @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) - public static class Operators implements Serializable { + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) + data class Operators ( // 干员名 - private String name; + var name: String? = null, + // 技能序号。可选,默认 1 - private int skill = 1; + var skill: Int = 1, + // 技能用法。可选,默认 0 - private int skillUsage; - private Requirements requirements = new Requirements(); - - @Data - @NoArgsConstructor - @AllArgsConstructor - @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) - public static class Requirements implements Serializable { + var skillUsage: Int = 0, + var requirements: Requirements = Requirements() + ): Serializable { + + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) + data class Requirements ( // 精英化等级。可选,默认为 0, 不要求精英化等级 - private int elite; + var elite: Int = 0, + // 干员等级。可选,默认为 0 - private int level; + var level: Int = 0, // 技能等级。可选,默认为 0 - private int skillLevel; + var skillLevel: Int = 0, + // 模组编号。可选,默认为 0 - private int module; - // 潜能要求。可选,默认为 0 - private int potentiality; + var module: Int = 0, - } + // 潜能要求。可选,默认为 0 + var potentiality: Int = 0 + ): Serializable } - @Data - @NoArgsConstructor - @AllArgsConstructor - @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) - public static class Groups implements Serializable { + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) + data class Groups( // 群组名 - private String name; - - private List opers; + var name: String? = null, - private List operators; - } + val opers: List? = null, + var operators: List? = null + ) : Serializable - @Data - @NoArgsConstructor - @AllArgsConstructor - @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) - public static class Action implements Serializable { + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) + data class Action( // 操作类型,可选,默认 "Deploy" - private String type = "Deploy"; - private int kills; - private int costs; - private int costChanges; + var type: String? = "Deploy", + var kills: Int? = 0, + var costs: Int? = 0, + var costChanges: Int? = 0, + // 默认 -1 - private int cooling = -1; + var cooling: Int? = -1, - private String name; + var name: String? = null, // 部署干员的位置。 - private Integer[] location; + var location: Array?, + // 部署干员的干员朝向 中英文皆可 - private String direction = "None"; + var direction: String? = "None", + // 修改技能用法。当 type 为 "技能用法" 时必选 - private int skillUsage; + var skillUsage: Int? = 0, + // 前置延时 - private int preDelay; + var preDelay: Int? = 0, + // 后置延时 - private int postDelay; + var postDelay: Int? = 0, + // maa:保留字段,暂未实现 - private long timeout; + var timeout: Int? = 0, // 描述 - private String doc = ""; - private String docColor = "Gray"; - - } - - @Data - @NoArgsConstructor - @AllArgsConstructor - @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) - public static class Doc implements Serializable { - - private String title; - private String titleColor = "Gray"; - private String details = ""; - private String detailsColor = "Gray"; - + var doc: String? = "", + var docColor: String? = "Gray" + ) : Serializable + + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) + data class Doc( + var title: String? = null, + var titleColor: String? = "Gray", + var details: String? = "", + var detailsColor: String? = "Gray" + ) : Serializable + + companion object { + @Transient + val META: CollectionMeta = CollectionMeta( + { obj: Copilot -> obj.copilotId!! }, + "copilotId", Copilot::class.java + ) } } diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 1db91880..46fe9591 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -24,7 +24,6 @@ import plus.maa.backend.service.model.RatingType import java.time.LocalDateTime import java.time.format.DateTimeFormatter import java.util.* -import kotlin.collections.ArrayList /** * @author LoMu @@ -95,7 +94,7 @@ class CommentsAreaService( val replyUserId = if (isCopilotAuthor!!) copilot.uploaderId else commentsArea!!.uploaderId - val maaUserMap = userRepository.findByUsersId(listOf(userId, replyUserId)) + val maaUserMap = userRepository.findByUsersId(listOf(userId, replyUserId!!)) //防止通知自己 if (replyUserId != userId) { @@ -107,7 +106,7 @@ class CommentsAreaService( val authorName = maaUserMap.getOrDefault(replyUserId, MaaUser.UNKNOWN).userName val reName = maaUserMap.getOrDefault(userId, MaaUser.UNKNOWN).userName - val title = if (isCopilotAuthor) copilot.doc.title else commentsArea!!.message + val title = if (isCopilotAuthor) copilot.doc?.title else commentsArea!!.message commentNotification .setTitle(title) diff --git a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt index f589ea2c..65d0f263 100644 --- a/src/main/kotlin/plus/maa/backend/service/CopilotService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CopilotService.kt @@ -92,7 +92,7 @@ class CopilotService( // actions name 不是必须 if (copilotDTO.actions != null) { copilotDTO.actions.forEach { action: Copilot.Action -> - action.name = if (action.name == null) null else action.name.replace("[\"“”]".toRegex(), "") + action.name = if (action.name == null) null else action.name!!.replace("[\"“”]".toRegex(), "") } } // 使用stageId存储作业关卡信息 @@ -141,7 +141,7 @@ class CopilotService( idComponent.getId(Copilot.META), loginUserId, LocalDateTime.now(), content ) copilotRepository.insert(copilot) - return copilot.copilotId + return copilot.copilotId!! } /** @@ -150,7 +150,7 @@ class CopilotService( fun delete(loginUserId: String, request: CopilotCUDRequest) { copilotRepository.findByCopilotId(request.id!!)?.let { copilot: Copilot -> Assert.state(copilot.uploaderId == loginUserId, "您无法修改不属于您的作业") - copilot.isDelete = true + copilot.delete = true copilotRepository.save(copilot) /* * 删除作业时,如果被删除的项在 Redis 首页缓存中存在,则清空对应的首页缓存 @@ -195,7 +195,7 @@ class CopilotService( ) } } - val maaUser = userRepository.findByUserId(copilot.uploaderId) + val maaUser = userRepository.findByUserId(copilot.uploaderId!!) // 新评分系统 val ratingType = ratingRepository.findByTypeAndKeyAndUserId( @@ -204,7 +204,7 @@ class CopilotService( )?.rating formatCopilot( copilot, ratingType, maaUser!!.userName, - commentsAreaRepository.countByCopilotIdAndDelete(copilot.copilotId, false) + commentsAreaRepository.countByCopilotIdAndDelete(copilot.copilotId!!, false) ) } } @@ -335,9 +335,9 @@ class CopilotService( // 填充前端所需信息 val copilotIds = copilots.map { - it.copilotId + it.copilotId!! }.toSet() - val maaUsers = userRepository.findByUsersId(copilots.map { it.uploaderId }.toList()) + val maaUsers = userRepository.findByUsersId(copilots.map { it.uploaderId!! }.toList()) val commentsCount = commentsAreaRepository.findByCopilotIdInAndDelete(copilotIds, false) .groupBy { it.copilotId } .mapValues { it.value.size.toLong() } @@ -492,7 +492,7 @@ class CopilotService( commentsCount: Long? ): CopilotInfo { val info = copilotConverter.toCopilotInfo( - copilot, userName, copilot.copilotId, + copilot, userName, copilot.copilotId!!, commentsCount ) diff --git a/src/main/kotlin/plus/maa/backend/task/CopilotBackupTask.kt b/src/main/kotlin/plus/maa/backend/task/CopilotBackupTask.kt index 5511cbd4..428658d3 100644 --- a/src/main/kotlin/plus/maa/backend/task/CopilotBackupTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/CopilotBackupTask.kt @@ -91,7 +91,7 @@ class CopilotBackupTask( val baseDirectory = git.repository.workTree val copilots = copilotRepository.findAll() copilots.forEach{ copilot: Copilot -> - val level = levelService.findByLevelIdFuzzy(copilot.stageName) ?: return@forEach + val level = levelService.findByLevelIdFuzzy(copilot.stageName!!) ?: return@forEach // 暂时使用 copilotId 作为文件名 val filePath = File( java.lang.String.join( @@ -100,7 +100,7 @@ class CopilotBackupTask( ) ) val content = copilot.content ?: return@forEach - if (copilot.isDelete) { + if (copilot.delete) { // 删除文件 deleteCopilot(filePath) } else { diff --git a/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt b/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt index ea70b5cc..4c42818a 100644 --- a/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/CopilotScoreRefreshTask.kt @@ -95,11 +95,12 @@ class CopilotScoreRefreshTask( val dislikeCount = dislikeCountMap.getOrDefault(copilot.copilotId.toString(), 0L) var hotScore = getHotScore(copilot, likeCount, dislikeCount) // 判断关卡是否开放 - val level = arkLevelService.findByLevelIdFuzzy(copilot.stageName) + val level = arkLevelService.findByLevelIdFuzzy(copilot.stageName!!) // 关卡已关闭,且作业在关闭前上传 - if (level!!.closeTime != null && copilot.firstUploadTime != null && false == level.isOpen && copilot.firstUploadTime.isBefore( - level.closeTime - ) + if (level!!.closeTime != null + && copilot.firstUploadTime != null + && false == level.isOpen + && copilot.firstUploadTime!!.isBefore(level.closeTime) ) { // 非开放关卡打入冷宫 From cd855a8d756f7adbf55f785dfa3402e09a2716ef Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 13:51:16 +0800 Subject: [PATCH 131/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Did=E7=94=9F?= =?UTF-8?q?=E6=88=90=E5=8A=9F=E8=83=BD=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt b/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt index 99cc0f0d..55b0e8f4 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/IdComponent.kt @@ -33,10 +33,12 @@ class IdComponent( val nv = AtomicLong(getMax(cls, meta.idGetter, meta.incIdField)) log.info { "初始化获取 collection: $collectionName 的最大 id,id: ${nv.get()}" } currentIdMap[collectionName] = nv + return nv.incrementAndGet() } + return rv.incrementAndGet() } } - return v!!.incrementAndGet() + return v.incrementAndGet() } private fun getMax(entityClass: Class, idGetter: (T) -> Long, fieldName: String) = From ba741826153a58ace2debd80225147c1de8df8f7 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 13:53:52 +0800 Subject: [PATCH 132/168] =?UTF-8?q?revert:=20=E5=9B=9E=E6=BB=9A=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E4=BF=AE=E6=94=B9=E7=9A=84=E4=BB=BB=E5=8A=A1=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E8=8A=82=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt index 42ca864c..fc0b1284 100644 --- a/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt @@ -3,7 +3,6 @@ package plus.maa.backend.task import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Component import plus.maa.backend.service.ArkLevelService -import java.util.concurrent.TimeUnit @Component class ArkLevelSyncTask( @@ -14,7 +13,7 @@ class ArkLevelSyncTask( * 地图数据同步定时任务,每10分钟执行一次 * 应用启动时自动同步一次 */ - @Scheduled(fixedDelay = 1000L, timeUnit = TimeUnit.MINUTES) + @Scheduled(cron = "\${maa-copilot.task-cron.ark-level:-}") fun syncArkLevels() { arkLevelService.runSyncLevelDataTask() } @@ -23,7 +22,7 @@ class ArkLevelSyncTask( * 更新开放状态,每天凌晨执行,最好和热度值刷入任务保持相对顺序 * 4:00、4:15 各执行一次,避免网络波动导致更新失败 */ - @Scheduled(fixedDelay = 1000L, timeUnit = TimeUnit.MINUTES) + @Scheduled(cron = "0 0-15/15 4 * * ?") fun updateOpenStatus() { arkLevelService.updateActivitiesOpenStatus() arkLevelService.updateCrisisV2OpenStatus() From 9fa7d895cda7b8da45a895fcd535af92cbf964bf Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 13:54:49 +0800 Subject: [PATCH 133/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20reposi?= =?UTF-8?q?tory=20=E5=88=B0=20kotlin=20=E7=9B=AE=E5=BD=95=E4=B8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/repository/ArkLevelRepository.kt | 0 .../plus/maa/backend/repository/CommentsAreaRepository.kt | 0 .../plus/maa/backend/repository/CopilotRepository.kt | 0 .../plus/maa/backend/repository/CopilotSetRepository.kt | 0 .../plus/maa/backend/repository/GithubRepository.kt | 0 .../plus/maa/backend/repository/RatingRepository.kt | 0 .../{java => kotlin}/plus/maa/backend/repository/RedisCache.kt | 0 .../plus/maa/backend/repository/UserRepository.kt | 0 .../plus/maa/backend/repository/entity/ArkLevel.kt | 0 .../plus/maa/backend/repository/entity/ArkLevelSha.kt | 0 .../plus/maa/backend/repository/entity/CollectionMeta.kt | 0 .../plus/maa/backend/repository/entity/CommentsArea.kt | 0 .../plus/maa/backend/repository/entity/Copilot.kt | 0 .../plus/maa/backend/repository/entity/CopilotSet.kt | 0 .../plus/maa/backend/repository/entity/MaaUser.kt | 0 .../{java => kotlin}/plus/maa/backend/repository/entity/Rating.kt | 0 .../plus/maa/backend/repository/entity/gamedata/ArkActivity.kt | 0 .../plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt | 0 .../maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt | 0 .../plus/maa/backend/repository/entity/gamedata/ArkStage.kt | 0 .../plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt | 0 .../plus/maa/backend/repository/entity/gamedata/ArkTower.kt | 0 .../plus/maa/backend/repository/entity/gamedata/ArkZone.kt | 0 .../plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt | 0 .../plus/maa/backend/repository/entity/github/GithubCommit.kt | 0 .../plus/maa/backend/repository/entity/github/GithubContent.kt | 0 .../plus/maa/backend/repository/entity/github/GithubTree.kt | 0 .../plus/maa/backend/repository/entity/github/GithubTrees.kt | 0 28 files changed, 0 insertions(+), 0 deletions(-) rename src/main/{java => kotlin}/plus/maa/backend/repository/ArkLevelRepository.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/CommentsAreaRepository.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/CopilotRepository.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/CopilotSetRepository.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/GithubRepository.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/RatingRepository.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/RedisCache.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/UserRepository.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/ArkLevel.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/ArkLevelSha.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/CollectionMeta.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/CommentsArea.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/Copilot.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/CopilotSet.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/MaaUser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/Rating.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/gamedata/ArkStage.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/gamedata/ArkTower.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/gamedata/ArkZone.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/github/GithubCommit.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/github/GithubContent.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/github/GithubTree.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/repository/entity/github/GithubTrees.kt (100%) diff --git a/src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt b/src/main/kotlin/plus/maa/backend/repository/ArkLevelRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/ArkLevelRepository.kt rename to src/main/kotlin/plus/maa/backend/repository/ArkLevelRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/CommentsAreaRepository.kt b/src/main/kotlin/plus/maa/backend/repository/CommentsAreaRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/CommentsAreaRepository.kt rename to src/main/kotlin/plus/maa/backend/repository/CommentsAreaRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/CopilotRepository.kt b/src/main/kotlin/plus/maa/backend/repository/CopilotRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/CopilotRepository.kt rename to src/main/kotlin/plus/maa/backend/repository/CopilotRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/CopilotSetRepository.kt b/src/main/kotlin/plus/maa/backend/repository/CopilotSetRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/CopilotSetRepository.kt rename to src/main/kotlin/plus/maa/backend/repository/CopilotSetRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/GithubRepository.kt b/src/main/kotlin/plus/maa/backend/repository/GithubRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/GithubRepository.kt rename to src/main/kotlin/plus/maa/backend/repository/GithubRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/RatingRepository.kt b/src/main/kotlin/plus/maa/backend/repository/RatingRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/RatingRepository.kt rename to src/main/kotlin/plus/maa/backend/repository/RatingRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/RedisCache.kt b/src/main/kotlin/plus/maa/backend/repository/RedisCache.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/RedisCache.kt rename to src/main/kotlin/plus/maa/backend/repository/RedisCache.kt diff --git a/src/main/java/plus/maa/backend/repository/UserRepository.kt b/src/main/kotlin/plus/maa/backend/repository/UserRepository.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/UserRepository.kt rename to src/main/kotlin/plus/maa/backend/repository/UserRepository.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/ArkLevel.kt b/src/main/kotlin/plus/maa/backend/repository/entity/ArkLevel.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/ArkLevel.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/ArkLevel.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.kt b/src/main/kotlin/plus/maa/backend/repository/entity/ArkLevelSha.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/ArkLevelSha.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/ArkLevelSha.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt b/src/main/kotlin/plus/maa/backend/repository/entity/CollectionMeta.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/CollectionMeta.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/CollectionMeta.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/CommentsArea.kt b/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/CommentsArea.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/Copilot.kt b/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/Copilot.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/CopilotSet.kt b/src/main/kotlin/plus/maa/backend/repository/entity/CopilotSet.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/CopilotSet.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/CopilotSet.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/MaaUser.kt b/src/main/kotlin/plus/maa/backend/repository/entity/MaaUser.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/MaaUser.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/MaaUser.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/Rating.kt b/src/main/kotlin/plus/maa/backend/repository/entity/Rating.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/Rating.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/Rating.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt b/src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkActivity.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt b/src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkCharacter.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt b/src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkCrisisV2Info.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt b/src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkStage.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkStage.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkStage.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt b/src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkTilePos.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.kt b/src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkTower.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkTower.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkTower.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.kt b/src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkZone.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/ArkZone.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/gamedata/ArkZone.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt b/src/main/kotlin/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/gamedata/MaaArkStage.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.kt b/src/main/kotlin/plus/maa/backend/repository/entity/github/GithubCommit.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/github/GithubCommit.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/github/GithubCommit.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubContent.kt b/src/main/kotlin/plus/maa/backend/repository/entity/github/GithubContent.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/github/GithubContent.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/github/GithubContent.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubTree.kt b/src/main/kotlin/plus/maa/backend/repository/entity/github/GithubTree.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/github/GithubTree.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/github/GithubTree.kt diff --git a/src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.kt b/src/main/kotlin/plus/maa/backend/repository/entity/github/GithubTrees.kt similarity index 100% rename from src/main/java/plus/maa/backend/repository/entity/github/GithubTrees.kt rename to src/main/kotlin/plus/maa/backend/repository/entity/github/GithubTrees.kt From 6e244bd5a48bb18770af1c94d204d544f881218b Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 16:02:27 +0800 Subject: [PATCH 134/168] Rename .java to .kt --- .../model/parser/{ActivityParser.java => ActivityParser.kt} | 0 .../model/parser/{ArkLevelParser.java => ArkLevelParser.kt} | 0 .../model/parser/{CampaignParser.java => CampaignParser.kt} | 0 .../service/model/parser/{LegionParser.java => LegionParser.kt} | 0 .../model/parser/{MainlineParser.java => MainlineParser.kt} | 0 .../service/model/parser/{MemoryParser.java => MemoryParser.kt} | 0 .../service/model/parser/{RuneParser.java => RuneParser.kt} | 0 .../service/model/parser/{UnknownParser.java => UnknownParser.kt} | 0 .../service/model/parser/{WeeklyParser.java => WeeklyParser.kt} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/service/model/parser/{ActivityParser.java => ActivityParser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/parser/{ArkLevelParser.java => ArkLevelParser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/parser/{CampaignParser.java => CampaignParser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/parser/{LegionParser.java => LegionParser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/parser/{MainlineParser.java => MainlineParser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/parser/{MemoryParser.java => MemoryParser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/parser/{RuneParser.java => RuneParser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/parser/{UnknownParser.java => UnknownParser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/parser/{WeeklyParser.java => WeeklyParser.kt} (100%) diff --git a/src/main/java/plus/maa/backend/service/model/parser/ActivityParser.java b/src/main/java/plus/maa/backend/service/model/parser/ActivityParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/ActivityParser.java rename to src/main/java/plus/maa/backend/service/model/parser/ActivityParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.java b/src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.java rename to src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/CampaignParser.java b/src/main/java/plus/maa/backend/service/model/parser/CampaignParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/CampaignParser.java rename to src/main/java/plus/maa/backend/service/model/parser/CampaignParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/LegionParser.java b/src/main/java/plus/maa/backend/service/model/parser/LegionParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/LegionParser.java rename to src/main/java/plus/maa/backend/service/model/parser/LegionParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/MainlineParser.java b/src/main/java/plus/maa/backend/service/model/parser/MainlineParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/MainlineParser.java rename to src/main/java/plus/maa/backend/service/model/parser/MainlineParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/MemoryParser.java b/src/main/java/plus/maa/backend/service/model/parser/MemoryParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/MemoryParser.java rename to src/main/java/plus/maa/backend/service/model/parser/MemoryParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/RuneParser.java b/src/main/java/plus/maa/backend/service/model/parser/RuneParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/RuneParser.java rename to src/main/java/plus/maa/backend/service/model/parser/RuneParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/UnknownParser.java b/src/main/java/plus/maa/backend/service/model/parser/UnknownParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/UnknownParser.java rename to src/main/java/plus/maa/backend/service/model/parser/UnknownParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.java b/src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.java rename to src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.kt From c3fd0f82b74f6c2b83c2294616615f61a5a64458 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 16:02:27 +0800 Subject: [PATCH 135/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=E5=85=B3?= =?UTF-8?q?=E5=8D=A1=E8=A7=A3=E6=9E=90=E6=A8=A1=E5=9D=97=E5=88=B0=20kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/model/parser/ActivityParser.kt | 59 ++++------ .../service/model/parser/ArkLevelParser.kt | 16 ++- .../service/model/parser/CampaignParser.kt | 39 ++++--- .../service/model/parser/LegionParser.kt | 64 +++++------ .../service/model/parser/MainlineParser.kt | 106 +++++++++--------- .../service/model/parser/MemoryParser.kt | 94 ++++++++-------- .../service/model/parser/RuneParser.kt | 47 ++++---- .../service/model/parser/UnknownParser.kt | 31 ++--- .../service/model/parser/WeeklyParser.kt | 53 ++++----- 9 files changed, 237 insertions(+), 272 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/model/parser/ActivityParser.kt b/src/main/java/plus/maa/backend/service/model/parser/ActivityParser.kt index 7cc8a804..22eb9db9 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/ActivityParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/ActivityParser.kt @@ -1,48 +1,37 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkActivity; -import plus.maa.backend.repository.entity.gamedata.ArkStage; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.service.ArkGameDataService; -import plus.maa.backend.service.model.ArkLevelType; +import org.springframework.stereotype.Component +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.ArkGameDataService +import plus.maa.backend.service.model.ArkLevelType -import java.util.Optional; /** * @author john180 - *

- * Activity level will be tagged like this:
- * Activity -> ACT_NAME -> StageCode == activities/ACT_ID/LEVEL_ID
- * eg:
- * 活动关卡 -> 战地秘闻 -> SW-EV-1 == activities/act4d0/level_act4d0_01
+ * + * + * Activity level will be tagged like this:

+ * Activity -> ACT_NAME -> StageCode == activities/ACT_ID/LEVEL_ID

+ * eg:

+ * 活动关卡 -> 战地秘闻 -> SW-EV-1 == activities/act4d0/level_act4d0_01

*/ -@Slf4j @Component -@RequiredArgsConstructor -public class ActivityParser implements ArkLevelParser { - private final ArkGameDataService dataService; +class ActivityParser( + private val dataService: ArkGameDataService +) : ArkLevelParser { - @Override - public boolean supportType(ArkLevelType type) { - return ArkLevelType.ACTIVITIES.equals(type); + override fun supportType(type: ArkLevelType): Boolean { + return ArkLevelType.ACTIVITIES == type } - @Override - public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - level.setCatOne(ArkLevelType.ACTIVITIES.getDisplay()); + override fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + level.catOne = ArkLevelType.ACTIVITIES.display - ArkStage stage = dataService.findStage(level.getLevelId(), tilePos.getCode(), tilePos.getStageId()); - level.setCatTwo( - Optional.ofNullable(stage) - .map(ArkStage::getZoneId) - .map(dataService::findActivityByZoneId) - .map(ArkActivity::getName) - .orElse(StringUtils.EMPTY)); - return level; + val stage = dataService.findStage(level.levelId!!, tilePos.code!!, tilePos.stageId!!) + level.catTwo = stage?.zoneId + ?.let { dataService.findActivityByZoneId(it) } + ?.name ?: "" + return level } } diff --git a/src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.kt b/src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.kt index fff07c55..b95eb069 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.kt @@ -1,25 +1,23 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.service.model.ArkLevelType; +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.model.ArkLevelType /** * @author john180 */ -public interface ArkLevelParser { - +interface ArkLevelParser { /** * 是否支持解析该关卡类型 * * @param type 关卡类型 * @return 是否支持 */ - boolean supportType(ArkLevelType type); + fun supportType(type: ArkLevelType): Boolean /** * 解析关卡 */ - ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos); - + fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? } diff --git a/src/main/java/plus/maa/backend/service/model/parser/CampaignParser.kt b/src/main/java/plus/maa/backend/service/model/parser/CampaignParser.kt index 4438d869..63e69acc 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/CampaignParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/CampaignParser.kt @@ -1,30 +1,29 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.service.model.ArkLevelType; +import org.springframework.stereotype.Component +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.model.ArkLevelType /** * @author john180 - *

- * Campaign level will be tagged like this:
- * CAMPAIGN -> CAMPAIGN_CODE -> CAMPAIGN_NAME == obt/campaign/LEVEL_ID
- * eg:
- * 剿灭作战 -> 炎国 -> 龙门外环 == obt/campaign/level_camp_02
+ * + * + * Campaign level will be tagged like this:

+ * CAMPAIGN -> CAMPAIGN_CODE -> CAMPAIGN_NAME == obt/campaign/LEVEL_ID

+ * eg:

+ * 剿灭作战 -> 炎国 -> 龙门外环 == obt/campaign/level_camp_02

*/ @Component -public class CampaignParser implements ArkLevelParser { - @Override - public boolean supportType(ArkLevelType type) { - return ArkLevelType.CAMPAIGN.equals(type); +class CampaignParser : ArkLevelParser { + override fun supportType(type: ArkLevelType): Boolean { + return ArkLevelType.CAMPAIGN == type } - @Override - public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - level.setCatOne(ArkLevelType.CAMPAIGN.getDisplay()); - level.setCatTwo(tilePos.getCode()); - level.setCatThree(level.getName()); - return level; + override fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + level.catOne = ArkLevelType.CAMPAIGN.display + level.catTwo = tilePos.code + level.catThree = level.name + return level } } diff --git a/src/main/java/plus/maa/backend/service/model/parser/LegionParser.kt b/src/main/java/plus/maa/backend/service/model/parser/LegionParser.kt index 66ff3b8d..afd8d71a 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/LegionParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/LegionParser.kt @@ -1,53 +1,45 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkStage; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.repository.entity.gamedata.ArkTower; -import plus.maa.backend.service.ArkGameDataService; -import plus.maa.backend.service.model.ArkLevelType; +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.stereotype.Component +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.ArkGameDataService +import plus.maa.backend.service.model.ArkLevelType -import java.util.Optional; +private val log = KotlinLogging.logger { } /** * @author john180 - *

- * Legion level will be tagged like this:
- * LEGION -> POSITION -> StageCode == obt/legion/TOWER_ID/LEVEL_ID
- * eg:
- * 保全派驻 -> 阿卡胡拉丛林 -> LT-1 == obt/legion/lt06/level_lt06_01
+ * + * + * Legion level will be tagged like this:

+ * LEGION -> POSITION -> StageCode == obt/legion/TOWER_ID/LEVEL_ID

+ * eg:

+ * 保全派驻 -> 阿卡胡拉丛林 -> LT-1 == obt/legion/lt06/level_lt06_01

*/ -@Slf4j @Component -@RequiredArgsConstructor -public class LegionParser implements ArkLevelParser { - private final ArkGameDataService dataService; +class LegionParser( + private val dataService: ArkGameDataService +) : ArkLevelParser { - @Override - public boolean supportType(ArkLevelType type) { - return ArkLevelType.LEGION.equals(type); + override fun supportType(type: ArkLevelType): Boolean { + return ArkLevelType.LEGION == type } - @Override - public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - level.setCatOne(ArkLevelType.LEGION.getDisplay()); + override fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + level.catOne = ArkLevelType.LEGION.display - ArkStage stage = dataService.findStage(level.getLevelId(), tilePos.getCode(), tilePos.getStageId()); + val stage = dataService.findStage(level.levelId!!, tilePos.code!!, tilePos.stageId!!) if (stage == null) { - log.error("[PARSER]保全派驻关卡未找到stage信息:{}", level.getLevelId()); - return null; + log.error { "[PARSER]保全派驻关卡未找到stage信息: ${level.levelId}" } + return null } - String catTwo= Optional.ofNullable(dataService.findTower(stage.getZoneId())) - .map(ArkTower::getName) - .orElse(StringUtils.EMPTY); + val catTwo: String = dataService.findTower(stage.zoneId)?.name ?: "" - level.setCatTwo(catTwo); - level.setCatThree(tilePos.getCode()); - return level; + level.catTwo = catTwo + level.catThree = tilePos.code + return level } } diff --git a/src/main/java/plus/maa/backend/service/model/parser/MainlineParser.kt b/src/main/java/plus/maa/backend/service/model/parser/MainlineParser.kt index 3653d03b..1f1472d1 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/MainlineParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/MainlineParser.kt @@ -1,75 +1,75 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import org.springframework.util.ObjectUtils; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.repository.entity.gamedata.ArkZone; -import plus.maa.backend.service.ArkGameDataService; -import plus.maa.backend.service.model.ArkLevelType; +import org.springframework.stereotype.Component +import org.springframework.util.ObjectUtils +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.repository.entity.gamedata.ArkZone +import plus.maa.backend.service.ArkGameDataService +import plus.maa.backend.service.model.ArkLevelType +import java.util.* /** * @author john180 - *

- * Main story level will be tagged like this:
- * MAINLINE -> CHAPTER_NAME -> StageCode == obt/main/LEVEL_ID
- * eg:
- * 主题曲 -> 序章:黑暗时代·上 -> 0-1 == obt/main/level_main_00-01
- * 主题曲 -> 第四章:急性衰竭 -> S4-7 == obt/main/level_sub_04-3-1
+ * + * + * Main story level will be tagged like this:

+ * MAINLINE -> CHAPTER_NAME -> StageCode == obt/main/LEVEL_ID

+ * eg:

+ * 主题曲 -> 序章:黑暗时代·上 -> 0-1 == obt/main/level_main_00-01

+ * 主题曲 -> 第四章:急性衰竭 -> S4-7 == obt/main/level_sub_04-3-1

*/ @Component -@RequiredArgsConstructor -public class MainlineParser implements ArkLevelParser { - private final ArkGameDataService dataService; +class MainlineParser( + private val dataService: ArkGameDataService +) : ArkLevelParser { - @Override - public boolean supportType(ArkLevelType type) { - return ArkLevelType.MAINLINE.equals(type); + override fun supportType(type: ArkLevelType): Boolean { + return ArkLevelType.MAINLINE == type } - @Override - public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - level.setCatOne(ArkLevelType.MAINLINE.getDisplay()); + override fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + level.catOne = ArkLevelType.MAINLINE.display - String chapterLevelId = level.getLevelId().split("/")[2]; // level_main_10-02 - String[] chapterStrSplit = chapterLevelId.split("_"); // level main 10-02 - String diff = parseDifficulty(chapterStrSplit[1]); // easy、main - String stageCodeEncoded = chapterStrSplit[chapterStrSplit.length - 1]; // 10-02 remark: obt/main/level_easy_sub_09-1-1 - String chapterStr = stageCodeEncoded.split("-")[0]; // 10 (str) - int chapter = Integer.parseInt(chapterStr); // 10 (int) + val chapterLevelId = + level.levelId!!.split("/".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[2] // level_main_10-02 + val chapterStrSplit = + chapterLevelId.split("_".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() // level main 10-02 + val diff = parseDifficulty(chapterStrSplit[1]) // easy、main + val stageCodeEncoded = + chapterStrSplit[chapterStrSplit.size - 1] // 10-02 remark: obt/main/level_easy_sub_09-1-1 + val chapterStr = + stageCodeEncoded.split("-".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()[0] // 10 (str) + val chapter = chapterStr.toInt() // 10 (int) - ArkZone zone = dataService.findZone(level.getLevelId(), tilePos.getCode(), tilePos.getStageId()); - if (zone == null) { - return null; - } + val zone = dataService.findZone(level.levelId, tilePos.code!!, tilePos.stageId!!) ?: return null - String catTwo = parseZoneName(zone); - level.setCatTwo(catTwo); + val catTwo = parseZoneName(zone) + level.catTwo = catTwo - String catThreeEx = (chapter >= 9) ? String.format("(%s)", diff) : ""; - level.setCatThree(level.getCatThree() + catThreeEx); + val catThreeEx = if ((chapter >= 9)) String.format("(%s)", diff) else "" + level.catThree += catThreeEx - return level; + return level } - private String parseDifficulty(String diff) { - return switch (diff.toLowerCase()) { - case "easy" -> "简单"; - case "tough" -> "磨难"; - default -> "标准"; - }; + private fun parseDifficulty(diff: String): String { + return when (diff.lowercase(Locale.getDefault())) { + "easy" -> "简单" + "tough" -> "磨难" + else -> "标准" + } } - private String parseZoneName(ArkZone zone) { - StringBuilder builder = new StringBuilder(); - if (!ObjectUtils.isEmpty(zone.getZoneNameFirst())) { - builder.append(zone.getZoneNameFirst()); + private fun parseZoneName(zone: ArkZone): String { + val builder = StringBuilder() + if (!ObjectUtils.isEmpty(zone.zoneNameFirst)) { + builder.append(zone.zoneNameFirst) } - builder.append(" "); - if (!ObjectUtils.isEmpty(zone.getZoneNameSecond())) { - builder.append(zone.getZoneNameSecond()); + builder.append(" ") + if (!ObjectUtils.isEmpty(zone.zoneNameSecond)) { + builder.append(zone.zoneNameSecond) } - return builder.toString().trim(); + return builder.toString().trim { it <= ' ' } } } diff --git a/src/main/java/plus/maa/backend/service/model/parser/MemoryParser.kt b/src/main/java/plus/maa/backend/service/model/parser/MemoryParser.kt index ac82a737..df191a8c 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/MemoryParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/MemoryParser.kt @@ -1,66 +1,66 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkCharacter; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.service.ArkGameDataService; -import plus.maa.backend.service.model.ArkLevelType; +import io.github.oshai.kotlinlogging.KotlinLogging +import org.springframework.stereotype.Component +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.ArkGameDataService +import plus.maa.backend.service.model.ArkLevelType +import java.util.* + +private val log = KotlinLogging.logger { } /** * @author john180 - *

- * Memory level will be tagged like this:
- * MEMORY -> POSITION -> OPERATOR_NAME == obt/memory/LEVEL_ID
- * eg:
- * 悖论模拟 -> 狙击 -> 克洛丝 == obt/memory/level_memory_kroos_1
+ * + * + * Memory level will be tagged like this:

+ * MEMORY -> POSITION -> OPERATOR_NAME == obt/memory/LEVEL_ID

+ * eg:

+ * 悖论模拟 -> 狙击 -> 克洛丝 == obt/memory/level_memory_kroos_1

*/ -@Slf4j @Component -@RequiredArgsConstructor -public class MemoryParser implements ArkLevelParser { - private final ArkGameDataService dataService; +class MemoryParser( + val dataService: ArkGameDataService +) : ArkLevelParser { - @Override - public boolean supportType(ArkLevelType type) { - return ArkLevelType.MEMORY.equals(type); + override fun supportType(type: ArkLevelType): Boolean { + return ArkLevelType.MEMORY == type } - @Override - public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - level.setCatOne(ArkLevelType.MEMORY.getDisplay()); + override fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + level.catOne = ArkLevelType.MEMORY.display - String[] chIdSplit = level.getStageId().split("_"); //mem_aurora_1 - if (chIdSplit.length != 3) { - log.error("[PARSER]悖论模拟关卡stageId异常:{}, level:{}", level.getStageId(), level.getLevelId()); - return null; + val chIdSplit = + level.stageId!!.split("_".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() //mem_aurora_1 + if (chIdSplit.size != 3) { + log.error { "[PARSER]悖论模拟关卡stageId异常: ${level.stageId}, level: ${level.levelId}" } + return null } - String chId = chIdSplit[1]; //aurora - ArkCharacter character = dataService.findCharacter(chId); + val chId = chIdSplit[1] //aurora + val character = dataService.findCharacter(chId) if (character == null) { - log.error("[PARSER]悖论模拟关卡未找到角色信息:{}, level:{}", level.getStageId(), level.getLevelId()); - return null; + log.error { "[PARSER]悖论模拟关卡未找到角色信息: ${level.stageId}, level: ${level.levelId}" } + return null } - level.setCatTwo(parseProfession(character.getProfession())); - level.setCatThree(character.getName()); + level.catTwo = parseProfession(character.profession) + level.catThree = character.name - return level; + return level } - private String parseProfession(String professionId) { - return switch (professionId.toLowerCase()) { - case "medic" -> "医疗"; - case "special" -> "特种"; - case "warrior" -> "近卫"; - case "sniper" -> "狙击"; - case "tank" -> "重装"; - case "caster" -> "术师"; - case "pioneer" -> "先锋"; - case "support" -> "辅助"; - default -> "未知"; - }; + private fun parseProfession(professionId: String): String { + return when (professionId.lowercase(Locale.getDefault())) { + "medic" -> "医疗" + "special" -> "特种" + "warrior" -> "近卫" + "sniper" -> "狙击" + "tank" -> "重装" + "caster" -> "术师" + "pioneer" -> "先锋" + "support" -> "辅助" + else -> "未知" + } } } diff --git a/src/main/java/plus/maa/backend/service/model/parser/RuneParser.kt b/src/main/java/plus/maa/backend/service/model/parser/RuneParser.kt index 2ca223b8..ce281d49 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/RuneParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/RuneParser.kt @@ -1,36 +1,27 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkCrisisV2Info; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.service.ArkGameDataService; -import plus.maa.backend.service.model.ArkLevelType; - -import java.util.Optional; +import org.springframework.stereotype.Component +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.ArkGameDataService +import plus.maa.backend.service.model.ArkLevelType @Component -@RequiredArgsConstructor -public class RuneParser implements ArkLevelParser { - - private final ArkGameDataService dataService; +class RuneParser( + private val dataService: ArkGameDataService +) : ArkLevelParser { - @Override - public boolean supportType(ArkLevelType type) { - return ArkLevelType.RUNE.equals(type); + override fun supportType(type: ArkLevelType): Boolean { + return ArkLevelType.RUNE == type } - @Override - public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - level.setCatOne(ArkLevelType.RUNE.getDisplay()); - level.setCatTwo( - Optional.ofNullable(level.getStageId()) - .map(dataService::findCrisisV2InfoById) - .map(ArkCrisisV2Info::getName) - .orElse(tilePos.getCode()) - ); - level.setCatThree(level.getName()); - return level; + override fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + level.catOne = ArkLevelType.RUNE.display + level.catTwo = level.stageId + ?.let { dataService.findCrisisV2InfoById(it) } + ?.name ?: tilePos.code + + level.catThree = level.name + return level } } diff --git a/src/main/java/plus/maa/backend/service/model/parser/UnknownParser.kt b/src/main/java/plus/maa/backend/service/model/parser/UnknownParser.kt index d2b3861a..840df945 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/UnknownParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/UnknownParser.kt @@ -1,23 +1,24 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.service.model.ArkLevelType; +import org.springframework.stereotype.Component +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.model.ArkLevelType +import java.util.* @Component -public class UnknownParser implements ArkLevelParser { - @Override - public boolean supportType(ArkLevelType type) { - return ArkLevelType.UNKNOWN.equals(type); +class UnknownParser : ArkLevelParser { + override fun supportType(type: ArkLevelType): Boolean { + return ArkLevelType.UNKNOWN == type } - @Override - public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - String[] ids = level.getLevelId().toLowerCase().split("/"); - String type = (ids[0].equals("obt")) ? ids[1] : ids[0]; + override fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + val ids = level.levelId!!.lowercase(Locale.getDefault()) + .split("/".toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray() + val type = if ((ids[0] == "obt")) ids[1] else ids[0] - level.setCatOne(ArkLevelType.UNKNOWN.getDisplay() + type); - return level; + level.catOne = ArkLevelType.UNKNOWN.display + type + return level } } diff --git a/src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.kt b/src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.kt index 70c239f1..ab818bf9 100644 --- a/src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.kt +++ b/src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.kt @@ -1,42 +1,37 @@ -package plus.maa.backend.service.model.parser; +package plus.maa.backend.service.model.parser -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import plus.maa.backend.repository.entity.ArkLevel; -import plus.maa.backend.repository.entity.gamedata.ArkTilePos; -import plus.maa.backend.repository.entity.gamedata.ArkZone; -import plus.maa.backend.service.ArkGameDataService; -import plus.maa.backend.service.model.ArkLevelType; +import org.springframework.stereotype.Component +import plus.maa.backend.repository.entity.ArkLevel +import plus.maa.backend.repository.entity.gamedata.ArkTilePos +import plus.maa.backend.service.ArkGameDataService +import plus.maa.backend.service.model.ArkLevelType /** * @author john180 - *

- * Weekly level will be tagged like this:
- * WEEKLY -> WEEKLY_ZONE_NAME -> StageCode == obt/weekly/LEVEL_ID
- * eg:
- * 资源收集 -> 空中威胁 -> CA-5 == obt/weekly/level_weekly_fly_5
- * 资源收集 -> 身先士卒 -> PR-D-2 == obt/promote/level_promote_d_2
+ * + * + * Weekly level will be tagged like this:

+ * WEEKLY -> WEEKLY_ZONE_NAME -> StageCode == obt/weekly/LEVEL_ID

+ * eg:

+ * 资源收集 -> 空中威胁 -> CA-5 == obt/weekly/level_weekly_fly_5

+ * 资源收集 -> 身先士卒 -> PR-D-2 == obt/promote/level_promote_d_2

*/ @Component -@RequiredArgsConstructor -public class WeeklyParser implements ArkLevelParser { - private final ArkGameDataService dataService; +class WeeklyParser( + private val dataService: ArkGameDataService +) : ArkLevelParser { - @Override - public boolean supportType(ArkLevelType type) { - return ArkLevelType.WEEKLY.equals(type); + override fun supportType(type: ArkLevelType): Boolean { + return ArkLevelType.WEEKLY == type } - @Override - public ArkLevel parseLevel(ArkLevel level, ArkTilePos tilePos) { - level.setCatOne(ArkLevelType.WEEKLY.getDisplay()); + override fun parseLevel(level: ArkLevel, tilePos: ArkTilePos): ArkLevel? { + level.catOne = ArkLevelType.WEEKLY.display - ArkZone zone = dataService.findZone(level.getLevelId(), tilePos.getCode(), tilePos.getStageId()); - if (zone == null) { - return null; - } + val zone = dataService.findZone(level.levelId!!, tilePos.code!!, tilePos.stageId!!) + ?: return null - level.setCatTwo(zone.getZoneNameSecond()); - return level; + level.catTwo = zone.zoneNameSecond + return level } } From 8e9df8577ca04b99e7c93f606e2956aac39b095f Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 16:31:59 +0800 Subject: [PATCH 136/168] Rename .java to .kt --- .../backend/service/model/{ArkLevelType.java => ArkLevelType.kt} | 0 .../model/{CommentNotification.java => CommentNotification.kt} | 0 .../maa/backend/service/model/{LoginUser.java => LoginUser.kt} | 0 .../backend/service/model/{RatingCache.java => RatingCache.kt} | 0 .../backend/service/model/{RatingCount.java => RatingCount.kt} | 0 .../maa/backend/service/model/{RatingType.java => RatingType.kt} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/service/model/{ArkLevelType.java => ArkLevelType.kt} (100%) rename src/main/java/plus/maa/backend/service/model/{CommentNotification.java => CommentNotification.kt} (100%) rename src/main/java/plus/maa/backend/service/model/{LoginUser.java => LoginUser.kt} (100%) rename src/main/java/plus/maa/backend/service/model/{RatingCache.java => RatingCache.kt} (100%) rename src/main/java/plus/maa/backend/service/model/{RatingCount.java => RatingCount.kt} (100%) rename src/main/java/plus/maa/backend/service/model/{RatingType.java => RatingType.kt} (100%) diff --git a/src/main/java/plus/maa/backend/service/model/ArkLevelType.java b/src/main/java/plus/maa/backend/service/model/ArkLevelType.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/ArkLevelType.java rename to src/main/java/plus/maa/backend/service/model/ArkLevelType.kt diff --git a/src/main/java/plus/maa/backend/service/model/CommentNotification.java b/src/main/java/plus/maa/backend/service/model/CommentNotification.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/CommentNotification.java rename to src/main/java/plus/maa/backend/service/model/CommentNotification.kt diff --git a/src/main/java/plus/maa/backend/service/model/LoginUser.java b/src/main/java/plus/maa/backend/service/model/LoginUser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/LoginUser.java rename to src/main/java/plus/maa/backend/service/model/LoginUser.kt diff --git a/src/main/java/plus/maa/backend/service/model/RatingCache.java b/src/main/java/plus/maa/backend/service/model/RatingCache.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/RatingCache.java rename to src/main/java/plus/maa/backend/service/model/RatingCache.kt diff --git a/src/main/java/plus/maa/backend/service/model/RatingCount.java b/src/main/java/plus/maa/backend/service/model/RatingCount.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/RatingCount.java rename to src/main/java/plus/maa/backend/service/model/RatingCount.kt diff --git a/src/main/java/plus/maa/backend/service/model/RatingType.java b/src/main/java/plus/maa/backend/service/model/RatingType.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/RatingType.java rename to src/main/java/plus/maa/backend/service/model/RatingType.kt From df21eb017188b565972bb560b3e4fa9246eee5fc Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 16:31:59 +0800 Subject: [PATCH 137/168] =?UTF-8?q?refactor:=20=E9=80=9A=E7=94=A8model?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E8=BF=81=E7=A7=BB=E8=87=B3kotlin?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/service/model/ArkLevelType.kt | 54 +++++++------- .../service/model/CommentNotification.kt | 23 +++--- .../maa/backend/service/model/LoginUser.kt | 72 +++++++------------ .../maa/backend/service/model/RatingCache.kt | 18 ++--- .../maa/backend/service/model/RatingCount.kt | 17 ++--- .../maa/backend/service/model/RatingType.kt | 42 +++++------ .../backend/repository/entity/CommentsArea.kt | 2 +- .../maa/backend/repository/entity/Copilot.kt | 4 +- .../backend/service/CommentsAreaService.kt | 12 +--- .../plus/maa/backend/service/EmailService.kt | 5 +- .../plus/maa/backend/task/ArkLevelSyncTask.kt | 7 +- 11 files changed, 97 insertions(+), 159 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/model/ArkLevelType.kt b/src/main/java/plus/maa/backend/service/model/ArkLevelType.kt index b5ea677b..7e972309 100644 --- a/src/main/java/plus/maa/backend/service/model/ArkLevelType.kt +++ b/src/main/java/plus/maa/backend/service/model/ArkLevelType.kt @@ -1,10 +1,8 @@ -package plus.maa.backend.service.model; +package plus.maa.backend.service.model -import lombok.Getter; -import org.springframework.util.ObjectUtils; +import java.util.* -@Getter -public enum ArkLevelType { +enum class ArkLevelType(val display: String) { MAINLINE("主题曲"), WEEKLY("资源收集"), ACTIVITIES("活动关卡"), @@ -12,32 +10,30 @@ public enum ArkLevelType { MEMORY("悖论模拟"), RUNE("危机合约"), LEGION("保全派驻"), - ROGUELIKE("集成战略"), //实际不进行解析 - TRAINING("训练关卡"), //实际不进行解析 + ROGUELIKE("集成战略"), //实际不进行解析 + TRAINING("训练关卡"), //实际不进行解析 UNKNOWN("未知类型"); - private final String display; - ArkLevelType(String display) { - this.display = display; - } - - public static ArkLevelType fromLevelId(String levelId) { - if (ObjectUtils.isEmpty(levelId)) { - return UNKNOWN; + companion object { + fun fromLevelId(levelId: String?): ArkLevelType { + if (levelId.isNullOrBlank()) { + return UNKNOWN + } + val ids = levelId.lowercase(Locale.getDefault()).split("/".toRegex()).dropLastWhile { it.isEmpty() } + .toTypedArray() + val type = if ((ids[0] == "obt")) ids[1] else ids[0] + return when (type) { + "main", "hard" -> MAINLINE + "weekly", "promote" -> WEEKLY + "activities" -> ACTIVITIES + "campaign" -> CAMPAIGN + "memory" -> MEMORY + "rune", "crisis" -> RUNE + "legion" -> LEGION + "roguelike" -> ROGUELIKE + "training" -> TRAINING + else -> UNKNOWN + } } - String[] ids = levelId.toLowerCase().split("/"); - String type = (ids[0].equals("obt")) ? ids[1] : ids[0]; - return switch (type) { - case "main", "hard" -> MAINLINE; - case "weekly", "promote" -> WEEKLY; - case "activities" -> ACTIVITIES; - case "campaign" -> CAMPAIGN; - case "memory" -> MEMORY; - case "rune", "crisis" -> RUNE; - case "legion" -> LEGION; - case "roguelike" -> ROGUELIKE; - case "training" -> TRAINING; - default -> UNKNOWN; - }; } } diff --git a/src/main/java/plus/maa/backend/service/model/CommentNotification.kt b/src/main/java/plus/maa/backend/service/model/CommentNotification.kt index ed0bfae5..ee5482db 100644 --- a/src/main/java/plus/maa/backend/service/model/CommentNotification.kt +++ b/src/main/java/plus/maa/backend/service/model/CommentNotification.kt @@ -1,20 +1,13 @@ -package plus.maa.backend.service.model; - -import lombok.Data; -import lombok.experimental.Accessors; +package plus.maa.backend.service.model /** * @author LoMu * Date 2023-05-18 1:18 */ - -@Data -@Accessors(chain = true) -public class CommentNotification { - private String authorName; - private String reName; - private String date; - private String title; - private String reMessage; - private String forntEndLink; -} +data class CommentNotification( + val authorName: String, + val reName: String, + val date: String, + val title: String, + val reMessage: String +) diff --git a/src/main/java/plus/maa/backend/service/model/LoginUser.kt b/src/main/java/plus/maa/backend/service/model/LoginUser.kt index d8e9f311..7e782dea 100644 --- a/src/main/java/plus/maa/backend/service/model/LoginUser.kt +++ b/src/main/java/plus/maa/backend/service/model/LoginUser.kt @@ -1,40 +1,28 @@ -package plus.maa.backend.service.model; +package plus.maa.backend.service.model -import com.fasterxml.jackson.annotation.JsonIgnore; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.userdetails.UserDetails; -import plus.maa.backend.repository.entity.MaaUser; - -import java.util.Collection; +import com.fasterxml.jackson.annotation.JsonIgnore +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.userdetails.UserDetails +import plus.maa.backend.repository.entity.MaaUser /** * @author AnselYuki */ -public class LoginUser implements UserDetails { - - private final MaaUser maaUser; - private final Collection authorities; - - public LoginUser(MaaUser maaUser, Collection authorities) { - this.maaUser = maaUser; - this.authorities = authorities; - } - - @Override +class LoginUser( + private val maaUser: MaaUser, + private val authorities: Collection) : UserDetails { @JsonIgnore - public Collection getAuthorities() { - return authorities; + override fun getAuthorities(): Collection { + return authorities } - @Override @JsonIgnore - public String getPassword() { - return maaUser.getPassword(); + override fun getPassword(): String { + return maaUser.password } - public String getUserId() { - return maaUser.getUserId(); - } + val userId: String? + get() = maaUser.userId /** * Spring Security框架中的username即唯一身份标识(ID) @@ -42,30 +30,25 @@ public class LoginUser implements UserDetails { * * @return 用户邮箱 */ - @Override @JsonIgnore - public String getUsername() { - return maaUser.getEmail(); + override fun getUsername(): String { + return maaUser.email } - @JsonIgnore - public String getEmail() { - return maaUser.getEmail(); - } + @get:JsonIgnore + val email: String + get() = maaUser.email - @Override - public boolean isAccountNonExpired() { - return true; + override fun isAccountNonExpired(): Boolean { + return true } - @Override - public boolean isAccountNonLocked() { - return true; + override fun isAccountNonLocked(): Boolean { + return true } - @Override - public boolean isCredentialsNonExpired() { - return true; + override fun isCredentialsNonExpired(): Boolean { + return true } /** @@ -73,8 +56,7 @@ public class LoginUser implements UserDetails { * * @return 账户启用状态 */ - @Override - public boolean isEnabled() { - return true; + override fun isEnabled(): Boolean { + return true } } diff --git a/src/main/java/plus/maa/backend/service/model/RatingCache.kt b/src/main/java/plus/maa/backend/service/model/RatingCache.kt index 6e7e7031..6af878e3 100644 --- a/src/main/java/plus/maa/backend/service/model/RatingCache.kt +++ b/src/main/java/plus/maa/backend/service/model/RatingCache.kt @@ -1,19 +1,9 @@ -package plus.maa.backend.service.model; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.Set; +package plus.maa.backend.service.model /** * @author LoMu * Date 2023-01-28 11:37 */ - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class RatingCache { - private Set copilotIds; -} +data class RatingCache( + val copilotIds: MutableSet +) diff --git a/src/main/java/plus/maa/backend/service/model/RatingCount.kt b/src/main/java/plus/maa/backend/service/model/RatingCount.kt index 18864111..5362df7c 100644 --- a/src/main/java/plus/maa/backend/service/model/RatingCount.kt +++ b/src/main/java/plus/maa/backend/service/model/RatingCount.kt @@ -1,13 +1,6 @@ -package plus.maa.backend.service.model; +package plus.maa.backend.service.model -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -public class RatingCount { - private String key; - private long count; -} +data class RatingCount( + val key: String, + val count: Long = 0 +) diff --git a/src/main/java/plus/maa/backend/service/model/RatingType.kt b/src/main/java/plus/maa/backend/service/model/RatingType.kt index ca4173cb..e63b19be 100644 --- a/src/main/java/plus/maa/backend/service/model/RatingType.kt +++ b/src/main/java/plus/maa/backend/service/model/RatingType.kt @@ -1,38 +1,28 @@ -package plus.maa.backend.service.model; - -import lombok.Getter; - +package plus.maa.backend.service.model /** * @author LoMu * Date 2023-01-22 19:48 */ -@Getter -public enum RatingType { - +enum class RatingType(val display: Int) { LIKE(1), DISLIKE(2), NONE(0); - private final int display; - - RatingType(int display) { - this.display = display; - } - - /** - * 将rating转换为 0 = NONE 1 = LIKE 2 = DISLIKE - * - * @param type rating - * @return type - */ - public static RatingType fromRatingType(String type) { - return switch (type) { - case "Like" -> LIKE; - case "Dislike" -> DISLIKE; - default -> NONE; - }; - + companion object { + /** + * 将rating转换为 0 = NONE 1 = LIKE 2 = DISLIKE + * + * @param type rating + * @return type + */ + fun fromRatingType(type: String?): RatingType { + return when (type) { + "Like" -> LIKE + "Dislike" -> DISLIKE + else -> NONE + } + } } } diff --git a/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt b/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt index 225ac19f..2e0f3f7b 100644 --- a/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt +++ b/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt @@ -17,7 +17,7 @@ import java.time.LocalDateTime @Document("maa_comments_area") class CommentsArea( @Id - val id: String? = null, + var id: String? = null, @Indexed val copilotId: Long, diff --git a/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt b/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt index 017871ba..098ac2c5 100644 --- a/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt +++ b/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt @@ -63,7 +63,7 @@ class Copilot( var actions: List? = null, // 描述 - var doc: Doc? = null, + var doc: Doc, var firstUploadTime: LocalDateTime? = null, var uploadTime: LocalDateTime? = null, @@ -173,7 +173,7 @@ class Copilot( @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) data class Doc( - var title: String? = null, + var title: String, var titleColor: String? = "Gray", var details: String? = "", var detailsColor: String? = "Gray" diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 46fe9591..9da1b29a 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -100,20 +100,14 @@ class CommentsAreaService( if (replyUserId != userId) { val time = LocalDateTime.now() val timeStr = time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) - val commentNotification = CommentNotification() val authorName = maaUserMap.getOrDefault(replyUserId, MaaUser.UNKNOWN).userName val reName = maaUserMap.getOrDefault(userId, MaaUser.UNKNOWN).userName - val title = if (isCopilotAuthor) copilot.doc?.title else commentsArea!!.message + val title = if (isCopilotAuthor) copilot.doc.title else commentsArea!!.message - commentNotification - .setTitle(title) - .setDate(timeStr) - .setAuthorName(authorName) - .setReName(reName) - .setReMessage(message) + val commentNotification = CommentNotification(authorName, reName, timeStr, title, message) val maaUser = maaUserMap[replyUserId] @@ -203,7 +197,7 @@ class CommentsAreaService( val newRating = Rating( null, Rating.KeyType.COMMENT, - commentsArea.id, + commentsArea.id!!, userId, RatingType.fromRatingType(rating), LocalDateTime.now() diff --git a/src/main/kotlin/plus/maa/backend/service/EmailService.kt b/src/main/kotlin/plus/maa/backend/service/EmailService.kt index e7d179cb..36d6d23c 100644 --- a/src/main/kotlin/plus/maa/backend/service/EmailService.kt +++ b/src/main/kotlin/plus/maa/backend/service/EmailService.kt @@ -5,7 +5,6 @@ import io.github.oshai.kotlinlogging.KotlinLogging import jakarta.annotation.PostConstruct import jakarta.annotation.Resource import org.apache.commons.lang3.RandomStringUtils -import org.apache.logging.log4j.util.Strings import org.springframework.beans.factory.annotation.Value import org.springframework.core.task.AsyncTaskExecutor import org.springframework.scheduling.annotation.Async @@ -27,8 +26,6 @@ private val log = KotlinLogging.logger { } class EmailService( @Value("\${maa-copilot.vcode.expire:600}") private val expire: Int, - @Value("\${maa-copilot.info.domain}") - private val domain: String, private val maaCopilotProperties: MaaCopilotProperties, @Value("\${debug.email.no-send:false}") private val flagNoSend: Boolean = false, @@ -110,7 +107,7 @@ class EmailService( val limit = 25 var title = commentNotification.title - if (Strings.isNotBlank(title)) { + if (title.isNotBlank()) { if (title.length > limit) { title = title.substring(0, limit) + "...." } diff --git a/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt index fc0b1284..ec5ef0ab 100644 --- a/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt @@ -3,6 +3,7 @@ package plus.maa.backend.task import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Component import plus.maa.backend.service.ArkLevelService +import java.util.concurrent.TimeUnit @Component class ArkLevelSyncTask( @@ -13,7 +14,8 @@ class ArkLevelSyncTask( * 地图数据同步定时任务,每10分钟执行一次 * 应用启动时自动同步一次 */ - @Scheduled(cron = "\${maa-copilot.task-cron.ark-level:-}") +// @Scheduled(cron = "\${maa-copilot.task-cron.ark-level:-}") + @Scheduled(fixedDelay = 1000, timeUnit = TimeUnit.MINUTES) fun syncArkLevels() { arkLevelService.runSyncLevelDataTask() } @@ -22,7 +24,8 @@ class ArkLevelSyncTask( * 更新开放状态,每天凌晨执行,最好和热度值刷入任务保持相对顺序 * 4:00、4:15 各执行一次,避免网络波动导致更新失败 */ - @Scheduled(cron = "0 0-15/15 4 * * ?") +// @Scheduled(cron = "0 0-15/15 4 * * ?") + @Scheduled(fixedDelay = 1000, timeUnit = TimeUnit.MINUTES) fun updateOpenStatus() { arkLevelService.updateActivitiesOpenStatus() arkLevelService.updateCrisisV2OpenStatus() From 853974f40167a617888075d7fa9d16419fbf5c01 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 17:29:29 +0800 Subject: [PATCH 138/168] Rename .java to .kt --- .../jwt/{JwtExpiredException.java => JwtExpiredException.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/service/jwt/{JwtExpiredException.java => JwtExpiredException.kt} (100%) diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.java b/src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.java rename to src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.kt From cc94035fae2607141cd3ce6229ecac524ba8a942 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 17:29:29 +0800 Subject: [PATCH 139/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95=E7=BC=96=E8=AF=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/service/jwt/JwtExpiredException.kt | 8 ++------ .../kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt | 7 ++----- .../plus/maa/backend/service/CopilotServiceTest.kt | 10 +++++----- .../maa/backend/task/CopilotScoreRefreshTaskTest.kt | 12 ++++++------ 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.kt b/src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.kt index f723e627..7e693683 100644 --- a/src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.kt +++ b/src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.kt @@ -1,7 +1,3 @@ -package plus.maa.backend.service.jwt; +package plus.maa.backend.service.jwt -public class JwtExpiredException extends Exception { - public JwtExpiredException(String message) { - super(message); - } -} +class JwtExpiredException(message: String) : Exception(message) diff --git a/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt index ec5ef0ab..fc0b1284 100644 --- a/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt +++ b/src/main/kotlin/plus/maa/backend/task/ArkLevelSyncTask.kt @@ -3,7 +3,6 @@ package plus.maa.backend.task import org.springframework.scheduling.annotation.Scheduled import org.springframework.stereotype.Component import plus.maa.backend.service.ArkLevelService -import java.util.concurrent.TimeUnit @Component class ArkLevelSyncTask( @@ -14,8 +13,7 @@ class ArkLevelSyncTask( * 地图数据同步定时任务,每10分钟执行一次 * 应用启动时自动同步一次 */ -// @Scheduled(cron = "\${maa-copilot.task-cron.ark-level:-}") - @Scheduled(fixedDelay = 1000, timeUnit = TimeUnit.MINUTES) + @Scheduled(cron = "\${maa-copilot.task-cron.ark-level:-}") fun syncArkLevels() { arkLevelService.runSyncLevelDataTask() } @@ -24,8 +22,7 @@ class ArkLevelSyncTask( * 更新开放状态,每天凌晨执行,最好和热度值刷入任务保持相对顺序 * 4:00、4:15 各执行一次,避免网络波动导致更新失败 */ -// @Scheduled(cron = "0 0-15/15 4 * * ?") - @Scheduled(fixedDelay = 1000, timeUnit = TimeUnit.MINUTES) + @Scheduled(cron = "0 0-15/15 4 * * ?") fun updateOpenStatus() { arkLevelService.updateActivitiesOpenStatus() arkLevelService.updateCrisisV2OpenStatus() diff --git a/src/test/kotlin/plus/maa/backend/service/CopilotServiceTest.kt b/src/test/kotlin/plus/maa/backend/service/CopilotServiceTest.kt index 88423bcd..368aceed 100644 --- a/src/test/kotlin/plus/maa/backend/service/CopilotServiceTest.kt +++ b/src/test/kotlin/plus/maa/backend/service/CopilotServiceTest.kt @@ -14,7 +14,7 @@ class CopilotServiceTest { val lastWeekLikeCounts = LongArray(5) val lastWeekDislikeCounts = LongArray(5) // 一月前的作业,评分高,但是只有一条近期好评,浏览量高 - val oldGreat = Copilot() + val oldGreat = Copilot(doc = Copilot.Doc(title = "test")) oldGreat.uploadTime = beforeWeek.minusDays(14) oldGreat.views = 20000L copilots[0] = oldGreat @@ -22,7 +22,7 @@ class CopilotServiceTest { lastWeekDislikeCounts[0] = 0L // 近期作业,含有差评,但是均为近期评分 - val newGreat = Copilot() + val newGreat = Copilot(doc = Copilot.Doc(title = "test")) newGreat.uploadTime = now newGreat.views = 1000L copilots[1] = newGreat @@ -31,7 +31,7 @@ class CopilotServiceTest { // 近期作业,差评较多,均为近期评分 - val newBad = Copilot() + val newBad = Copilot(doc = Copilot.Doc(title = "test")) newBad.uploadTime = now newBad.views = 500L copilots[2] = newBad @@ -40,7 +40,7 @@ class CopilotServiceTest { // 一月前的作业,评分高,但是只有一条近期好评,浏览量尚可 - val oldNormal = Copilot() + val oldNormal = Copilot(doc = Copilot.Doc(title = "test")) oldNormal.uploadTime = beforeWeek.minusDays(21L) oldNormal.views = 4000L copilots[3] = oldNormal @@ -49,7 +49,7 @@ class CopilotServiceTest { // 新增作业,暂无评分 - val newEmpty = Copilot() + val newEmpty = Copilot(doc = Copilot.Doc(title = "test")) newEmpty.uploadTime = now newEmpty.views = 100L copilots[4] = newEmpty diff --git a/src/test/kotlin/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt b/src/test/kotlin/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt index e857fe65..17326c1d 100644 --- a/src/test/kotlin/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt +++ b/src/test/kotlin/plus/maa/backend/task/CopilotScoreRefreshTaskTest.kt @@ -34,17 +34,17 @@ class CopilotScoreRefreshTaskTest { @Test fun testRefreshScores() { val now = LocalDateTime.now() - val copilot1 = Copilot() + val copilot1 = Copilot(doc = Copilot.Doc(title = "test")) copilot1.copilotId = 1L copilot1.views = 100L copilot1.uploadTime = now copilot1.stageName = "stage1" - val copilot2 = Copilot() + val copilot2 = Copilot(doc = Copilot.Doc(title = "test")) copilot2.copilotId = 2L copilot2.views = 200L copilot2.uploadTime = now copilot2.stageName = "stage2" - val copilot3 = Copilot() + val copilot3 = Copilot(doc = Copilot.Doc(title = "test")) copilot3.copilotId = 3L copilot3.views = 200L copilot3.uploadTime = now @@ -82,17 +82,17 @@ class CopilotScoreRefreshTaskTest { @Test fun testRefreshTop100HotScores() { val now = LocalDateTime.now() - val copilot1 = Copilot() + val copilot1 = Copilot(doc = Copilot.Doc(title = "test")) copilot1.copilotId = 1L copilot1.views = 100L copilot1.uploadTime = now copilot1.stageName = "stage1" - val copilot2 = Copilot() + val copilot2 = Copilot(doc = Copilot.Doc(title = "test")) copilot2.copilotId = 2L copilot2.views = 200L copilot2.uploadTime = now copilot2.stageName = "stage2" - val copilot3 = Copilot() + val copilot3 = Copilot(doc = Copilot.Doc(title = "test")) copilot3.copilotId = 3L copilot3.views = 200L copilot3.uploadTime = now From c670b761c98376e0f188b4620c8f5be51d498e0f Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 17:37:44 +0800 Subject: [PATCH 140/168] Rename .java to .kt --- .../backend/service/jwt/{JwtAuthToken.java => JwtAuthToken.kt} | 0 .../jwt/{JwtInvalidException.java => JwtInvalidException.kt} | 0 .../service/jwt/{JwtRefreshToken.java => JwtRefreshToken.kt} | 0 .../maa/backend/service/jwt/{JwtService.java => JwtService.kt} | 0 .../plus/maa/backend/service/jwt/{JwtToken.java => JwtToken.kt} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename src/main/java/plus/maa/backend/service/jwt/{JwtAuthToken.java => JwtAuthToken.kt} (100%) rename src/main/java/plus/maa/backend/service/jwt/{JwtInvalidException.java => JwtInvalidException.kt} (100%) rename src/main/java/plus/maa/backend/service/jwt/{JwtRefreshToken.java => JwtRefreshToken.kt} (100%) rename src/main/java/plus/maa/backend/service/jwt/{JwtService.java => JwtService.kt} (100%) rename src/main/java/plus/maa/backend/service/jwt/{JwtToken.java => JwtToken.kt} (100%) diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.java b/src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.java rename to src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.java b/src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.java rename to src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.java b/src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.java rename to src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtService.java b/src/main/java/plus/maa/backend/service/jwt/JwtService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtService.java rename to src/main/java/plus/maa/backend/service/jwt/JwtService.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtToken.java b/src/main/java/plus/maa/backend/service/jwt/JwtToken.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtToken.java rename to src/main/java/plus/maa/backend/service/jwt/JwtToken.kt From 6d730e1b2e1cc4e8e6f5623a23b15326f30f0b30 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 17:37:44 +0800 Subject: [PATCH 141/168] =?UTF-8?q?refactor:=20=E5=AE=8C=E6=88=90jwt?= =?UTF-8?q?=E7=9B=B8=E5=85=B3=E7=B1=BB=E5=9E=8B=E5=88=B0kotlin=E7=9A=84?= =?UTF-8?q?=E8=BF=81=E7=A7=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/service/jwt/JwtAuthToken.kt | 108 ++++++------ .../service/jwt/JwtInvalidException.kt | 5 +- .../backend/service/jwt/JwtRefreshToken.kt | 39 ++--- .../maa/backend/service/jwt/JwtService.kt | 77 ++++----- .../plus/maa/backend/service/jwt/JwtToken.kt | 154 +++++++++--------- .../service/model/CommentNotification.kt | 2 +- .../maa/backend/repository/entity/Copilot.kt | 2 +- .../backend/service/CommentsAreaService.kt | 2 +- .../plus/maa/backend/service/EmailService.kt | 2 +- 9 files changed, 178 insertions(+), 213 deletions(-) diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.kt b/src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.kt index a091f54a..9aa42f22 100644 --- a/src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.kt +++ b/src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.kt @@ -1,27 +1,17 @@ -package plus.maa.backend.service.jwt; +package plus.maa.backend.service.jwt -import cn.hutool.jwt.JWT; -import lombok.Getter; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.util.StringUtils; - -import java.time.LocalDateTime; -import java.util.Collection; +import org.springframework.security.core.Authentication +import org.springframework.security.core.GrantedAuthority +import org.springframework.security.core.authority.SimpleGrantedAuthority +import org.springframework.util.StringUtils +import java.time.LocalDateTime /** - * 基于 {@link JWT} 的 AuthToken. 本类实现了 {@link Authentication}, 可直接用于 Spring Security + * 基于 JWT 的 AuthToken. 本类实现了 Authentication, 可直接用于 Spring Security * 的认证流程 */ -@Getter -public final class JwtAuthToken extends JwtToken implements Authentication { - /** - * AuthToken 类型值 - */ - public static final String TYPE = "auth"; - private static final String CLAIM_AUTHORITIES = "Authorities"; - private boolean authenticated = false; +class JwtAuthToken : JwtToken, Authentication { + private var authenticated = false /** * 从 jwt 构建 token @@ -30,74 +20,72 @@ public final class JwtAuthToken extends JwtToken implements Authentication { * @param key 签名密钥 * @throws JwtInvalidException jwt 未通过签名验证或不符合要求 */ - public JwtAuthToken(String jwt, byte[] key) throws JwtInvalidException { - super(jwt, TYPE, key); - } + constructor(jwt: String?, key: ByteArray?) : super(jwt, TYPE, key) - public JwtAuthToken( - String sub, - String jti, - LocalDateTime iat, - LocalDateTime exp, - LocalDateTime nbf, - Collection authorities, - byte[] key - ) { - super(sub, jti, iat, exp, nbf, TYPE, key); - this.setAuthorities(authorities); + constructor( + sub: String, + jti: String?, + iat: LocalDateTime, + exp: LocalDateTime, + nbf: LocalDateTime, + authorities: Collection, + key: ByteArray + ) : super(sub, jti, iat, exp, nbf, TYPE, key) { + this.authorities = authorities } - @Override - public Collection getAuthorities() { - var authorityStrings = getJwt().getPayloads().getStr(CLAIM_AUTHORITIES); + override fun getAuthorities(): Collection { + val authorityStrings = jwt.payloads.getStr(CLAIM_AUTHORITIES) return StringUtils.commaDelimitedListToSet(authorityStrings).stream() - .map(SimpleGrantedAuthority::new) - .toList(); + .map { role: String? -> SimpleGrantedAuthority(role) } + .toList() } - public void setAuthorities(Collection authorities) { - var authorityStrings = authorities.stream().map(GrantedAuthority::getAuthority).toList(); - var encodedAuthorities = StringUtils.collectionToCommaDelimitedString(authorityStrings); - getJwt().setPayload(CLAIM_AUTHORITIES, encodedAuthorities); + fun setAuthorities(authorities: Collection) { + val authorityStrings = authorities.stream().map { obj: GrantedAuthority -> obj.authority }.toList() + val encodedAuthorities = StringUtils.collectionToCommaDelimitedString(authorityStrings) + jwt.setPayload(CLAIM_AUTHORITIES, encodedAuthorities) } /** * @return credentials,采用 jwt 的 id * @inheritDoc */ - @Override - public Object getCredentials() { - return getJwtId(); + override fun getCredentials(): Any { + return jwtId } - @Override - public Object getDetails() { - return null; + override fun getDetails(): Any? { + return null } /** * @return principal,采用 jwt 的 subject * @inheritDoc */ - @Override - public Object getPrincipal() { - return getSubject(); + override fun getPrincipal(): Any { + return subject } - @Override - public boolean isAuthenticated() { - return this.authenticated; + override fun isAuthenticated(): Boolean { + return this.authenticated } - @Override - public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { - this.authenticated = isAuthenticated; + @Throws(IllegalArgumentException::class) + override fun setAuthenticated(isAuthenticated: Boolean) { + this.authenticated = isAuthenticated } - @Override - public String getName() { - return getSubject(); + override fun getName(): String { + return subject } + companion object { + /** + * AuthToken 类型值 + */ + const val TYPE: String = "auth" + private const val CLAIM_AUTHORITIES = "Authorities" + } } diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.kt b/src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.kt index 7d124e19..492b70ef 100644 --- a/src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.kt +++ b/src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.kt @@ -1,4 +1,3 @@ -package plus.maa.backend.service.jwt; +package plus.maa.backend.service.jwt -public class JwtInvalidException extends Exception{ -} +class JwtInvalidException : Exception() diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.kt b/src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.kt index ccd319c8..8b905578 100644 --- a/src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.kt +++ b/src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.kt @@ -1,13 +1,8 @@ -package plus.maa.backend.service.jwt; +package plus.maa.backend.service.jwt -import java.time.LocalDateTime; - -public class JwtRefreshToken extends JwtToken { - /** - * RefreshToken 类型值 - */ - public static final String TYPE = "refresh"; +import java.time.LocalDateTime +class JwtRefreshToken : JwtToken { /** * 从 jwt 构建 token * @@ -15,19 +10,21 @@ public class JwtRefreshToken extends JwtToken { * @param key 签名密钥 * @throws JwtInvalidException jwt 未通过签名验证或不符合要求 */ - public JwtRefreshToken(String token, byte[] key) throws JwtInvalidException { - super(token, TYPE, key); - } + constructor(token: String?, key: ByteArray?) : super(token, TYPE, key) - public JwtRefreshToken( - String sub, - String jti, - LocalDateTime iat, - LocalDateTime exp, - LocalDateTime nbf, - byte[] key - ) { - super(sub, jti, iat, exp, nbf, TYPE, key); - } + constructor( + sub: String, + jti: String?, + iat: LocalDateTime, + exp: LocalDateTime, + nbf: LocalDateTime, + key: ByteArray + ) : super(sub, jti, iat, exp, nbf, TYPE, key) + companion object { + /** + * RefreshToken 类型值 + */ + const val TYPE: String = "refresh" + } } diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtService.kt b/src/main/java/plus/maa/backend/service/jwt/JwtService.kt index 9c7dd48c..90c562d8 100644 --- a/src/main/java/plus/maa/backend/service/jwt/JwtService.kt +++ b/src/main/java/plus/maa/backend/service/jwt/JwtService.kt @@ -1,41 +1,31 @@ -package plus.maa.backend.service.jwt; +package plus.maa.backend.service.jwt -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.stereotype.Service; -import plus.maa.backend.config.external.Jwt; -import plus.maa.backend.config.external.MaaCopilotProperties; - -import java.time.LocalDateTime; -import java.util.Collection; +import org.springframework.security.core.GrantedAuthority +import org.springframework.stereotype.Service +import plus.maa.backend.config.external.MaaCopilotProperties +import java.time.LocalDateTime /** * 基于 Jwt 的 token 服务。 可直接用于 stateless 情境下的签发和认证, 或结合数据库进行状态管理。 * 建议 AuthToken 使用无状态方案, RefreshToken 使用有状态方案 */ @Service -public class JwtService { - private final Jwt jwtProperties; - private final byte[] key; - - public JwtService(MaaCopilotProperties properties) { - jwtProperties = properties.getJwt(); - key = jwtProperties.getSecret().getBytes(); - } +class JwtService(properties: MaaCopilotProperties) { + private val jwtProperties = properties.jwt + private val key = jwtProperties.secret.toByteArray() /** - * 签发 AuthToken. 过期时间由配置的 {@link Jwt#getExpire()} 计算而来 + * 签发 AuthToken. 过期时间由配置的 jwt.expire 计算而来 * * @param subject 签发对象,一般设置为对象的标识符 * @param jwtId jwt 的 id, 一般用于 stateful 场景下 * @param authorities 授予的权限 * @return JwtAuthToken */ - public JwtAuthToken issueAuthToken(String subject, @Nullable String jwtId, Collection authorities) { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime expireAt = now.plusSeconds(jwtProperties.getExpire()); - return new JwtAuthToken(subject, jwtId, now, expireAt, now, authorities, key); + fun issueAuthToken(subject: String?, jwtId: String?, authorities: Collection): JwtAuthToken { + val now = LocalDateTime.now() + val expireAt = now.plusSeconds(jwtProperties.expire) + return JwtAuthToken(subject!!, jwtId, now, expireAt, now, authorities, key) } /** @@ -46,26 +36,25 @@ public class JwtService { * @throws JwtInvalidException jwt不符合要求 * @throws JwtExpiredException jwt未生效或者已过期 */ - @NotNull - public JwtAuthToken verifyAndParseAuthToken(String authToken) throws JwtInvalidException, JwtExpiredException { - var token = new JwtAuthToken(authToken, key); - token.validateDate(LocalDateTime.now()); - token.setAuthenticated(true); - return token; + @Throws(JwtInvalidException::class, JwtExpiredException::class) + fun verifyAndParseAuthToken(authToken: String?): JwtAuthToken { + val token = JwtAuthToken(authToken, key) + token.validateDate(LocalDateTime.now()) + token.isAuthenticated = true + return token } /** - * 签发 RefreshToken. 过期时间由配置的 {@link Jwt#getRefreshExpire()} 计算而来 + * 签发 RefreshToken. 过期时间由配置的 Jwt.getRefreshExpire 计算而来 * * @param subject 签发对象,一般设置为对象的标识符 * @param jwtId jwt 的 id, 一般用于 stateful 场景下 * @return JwtAuthToken */ - @NotNull - public JwtRefreshToken issueRefreshToken(String subject, @Nullable String jwtId) { - LocalDateTime now = LocalDateTime.now(); - LocalDateTime expireAt = now.plusSeconds(jwtProperties.getRefreshExpire()); - return new JwtRefreshToken(subject, jwtId, now, expireAt, now, key); + fun issueRefreshToken(subject: String?, jwtId: String?): JwtRefreshToken { + val now = LocalDateTime.now() + val expireAt = now.plusSeconds(jwtProperties.refreshExpire) + return JwtRefreshToken(subject!!, jwtId, now, expireAt, now, key) } /** @@ -75,10 +64,9 @@ public class JwtService { * @param old 原 token * @return 新的 RefreshToken */ - @NotNull - public JwtRefreshToken newRefreshToken(JwtRefreshToken old, @Nullable String jwtId) { - LocalDateTime now = LocalDateTime.now(); - return new JwtRefreshToken(old.getSubject(), jwtId, now, old.getExpiresAt(), now, key); + fun newRefreshToken(old: JwtRefreshToken, jwtId: String?): JwtRefreshToken { + val now = LocalDateTime.now() + return JwtRefreshToken(old.subject, jwtId, now, old.expiresAt, now, key) } /** @@ -89,11 +77,10 @@ public class JwtService { * @throws JwtInvalidException jwt不符合要求 * @throws JwtExpiredException jwt未生效或者已过期 */ - @NotNull - public JwtRefreshToken verifyAndParseRefreshToken(String refreshToken) throws JwtInvalidException, JwtExpiredException { - var token = new JwtRefreshToken(refreshToken, key); - token.validateDate(LocalDateTime.now()); - return token; + @Throws(JwtInvalidException::class, JwtExpiredException::class) + fun verifyAndParseRefreshToken(refreshToken: String?): JwtRefreshToken { + val token = JwtRefreshToken(refreshToken, key) + token.validateDate(LocalDateTime.now()) + return token } - } diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtToken.kt b/src/main/java/plus/maa/backend/service/jwt/JwtToken.kt index d0c7d4fb..7ed3800f 100644 --- a/src/main/java/plus/maa/backend/service/jwt/JwtToken.kt +++ b/src/main/java/plus/maa/backend/service/jwt/JwtToken.kt @@ -1,110 +1,104 @@ -package plus.maa.backend.service.jwt; +package plus.maa.backend.service.jwt -import cn.hutool.json.JSONObject; -import cn.hutool.jwt.JWT; -import cn.hutool.jwt.JWTUtil; -import cn.hutool.jwt.RegisteredPayload; -import lombok.Getter; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.OffsetDateTime; -import java.util.TimeZone; +import cn.hutool.json.JSONObject +import cn.hutool.jwt.JWT +import cn.hutool.jwt.JWTUtil +import cn.hutool.jwt.RegisteredPayload +import java.time.Instant +import java.time.LocalDateTime +import java.time.OffsetDateTime +import java.util.* /** - * 对 {@link JWT} 的包装增强,某些 payload 被标记为 MUST + * 对 [JWT] 的包装增强,某些 payload 被标记为 MUST */ -public class JwtToken { - private static final String CLAIM_TYPE = "typ"; - @Getter - private final JWT jwt; +open class JwtToken { + protected val jwt: JWT - private final JSONObject payload; + private val payload: JSONObject - public JwtToken(String token, String requiredType, byte[] key) throws JwtInvalidException { - if (!JWTUtil.verify(token, key)) throw new JwtInvalidException(); - this.jwt = JWTUtil.parseToken(token); - this.jwt.setKey(key); - this.payload = jwt.getPayloads(); + constructor(token: String?, requiredType: String, key: ByteArray?) { + if (!JWTUtil.verify(token, key)) throw JwtInvalidException() + this.jwt = JWTUtil.parseToken(token) + jwt.setKey(key) + this.payload = jwt.payloads // jwtId is nullable - if (null == getSubject() - || null == getIssuedAt() - || null == getExpiresAt() - || null == getNotBefore() - || !requiredType.equals(getType()) - ) throw new JwtInvalidException(); + if (null == issuedAt || requiredType != type + ) throw JwtInvalidException() } - public JwtToken( - String sub, - String jti, - LocalDateTime iat, - LocalDateTime exp, - LocalDateTime nbf, - String typ, - byte[] key + constructor( + sub: String?, + jti: String?, + iat: LocalDateTime, + exp: LocalDateTime, + nbf: LocalDateTime, + typ: String?, + key: ByteArray? ) { - jwt = JWT.create(); - jwt.setPayload(RegisteredPayload.SUBJECT, sub); - jwt.setPayload(RegisteredPayload.JWT_ID, jti); - jwt.setPayload(RegisteredPayload.ISSUED_AT, iat.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli()); - jwt.setPayload(RegisteredPayload.EXPIRES_AT, exp.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli()); - jwt.setPayload(RegisteredPayload.NOT_BEFORE, nbf.toInstant(OffsetDateTime.now().getOffset()).toEpochMilli()); - jwt.setPayload(CLAIM_TYPE, typ); - jwt.setKey(key); - payload = jwt.getPayloads(); + jwt = JWT.create() + jwt.setPayload(RegisteredPayload.SUBJECT, sub) + jwt.setPayload(RegisteredPayload.JWT_ID, jti) + jwt.setPayload(RegisteredPayload.ISSUED_AT, iat.toInstant(OffsetDateTime.now().offset).toEpochMilli()) + jwt.setPayload(RegisteredPayload.EXPIRES_AT, exp.toInstant(OffsetDateTime.now().offset).toEpochMilli()) + jwt.setPayload(RegisteredPayload.NOT_BEFORE, nbf.toInstant(OffsetDateTime.now().offset).toEpochMilli()) + jwt.setPayload(CLAIM_TYPE, typ) + jwt.setKey(key) + payload = jwt.payloads } - public String getSubject() { - return payload.getStr(RegisteredPayload.SUBJECT); - } + val subject: String + get() = payload.getStr(RegisteredPayload.SUBJECT) - public String getJwtId() { - return payload.getStr(RegisteredPayload.JWT_ID); - } + val jwtId: String + get() = payload.getStr(RegisteredPayload.JWT_ID) - public LocalDateTime getIssuedAt() { - return LocalDateTime.ofInstant(Instant.ofEpochMilli(payload.getLong(RegisteredPayload.ISSUED_AT)), - TimeZone.getDefault().toZoneId()); - } + val issuedAt: LocalDateTime? + get() = LocalDateTime.ofInstant( + Instant.ofEpochMilli(payload.getLong(RegisteredPayload.ISSUED_AT)), + TimeZone.getDefault().toZoneId() + ) - public LocalDateTime getExpiresAt() { - return LocalDateTime.ofInstant(Instant.ofEpochMilli(payload.getLong(RegisteredPayload.EXPIRES_AT)), - TimeZone.getDefault().toZoneId()); - } + val expiresAt: LocalDateTime + get() = LocalDateTime.ofInstant( + Instant.ofEpochMilli(payload.getLong(RegisteredPayload.EXPIRES_AT)), + TimeZone.getDefault().toZoneId() + ) - public LocalDateTime getNotBefore() { - return LocalDateTime.ofInstant(Instant.ofEpochMilli(payload.getLong(RegisteredPayload.NOT_BEFORE)), - TimeZone.getDefault().toZoneId()); - } + val notBefore: LocalDateTime + get() = LocalDateTime.ofInstant( + Instant.ofEpochMilli(payload.getLong(RegisteredPayload.NOT_BEFORE)), + TimeZone.getDefault().toZoneId() + ) - public String getType() { - return payload.getStr(CLAIM_TYPE); - } + var type: String? + get() = payload.getStr(CLAIM_TYPE) + set(type) { + payload[CLAIM_TYPE] = type + } - public void setType(String type) { - payload.set(CLAIM_TYPE, type); - } + val value: String + /** + * 生成 jwt 字符串 + * + * @return 签名后的 jwt 字符串 + */ + get() = jwt.sign() - /** - * 生成 jwt 字符串 - * - * @return 签名后的 jwt 字符串 - */ - public String getValue() { - return jwt.sign(); + @Throws(JwtExpiredException::class) + fun validateDate(moment: LocalDateTime) { + if (!moment.isBefore(expiresAt)) throw JwtExpiredException("expired") + if (moment.isBefore(notBefore)) throw JwtExpiredException("haven't take effect") } - public void validateDate(LocalDateTime moment) throws JwtExpiredException { - if (!moment.isBefore(getExpiresAt())) throw new JwtExpiredException("expired"); - if (moment.isBefore(getNotBefore())) throw new JwtExpiredException("haven't take effect"); + companion object { + private const val CLAIM_TYPE = "typ" } - } diff --git a/src/main/java/plus/maa/backend/service/model/CommentNotification.kt b/src/main/java/plus/maa/backend/service/model/CommentNotification.kt index ee5482db..29553803 100644 --- a/src/main/java/plus/maa/backend/service/model/CommentNotification.kt +++ b/src/main/java/plus/maa/backend/service/model/CommentNotification.kt @@ -8,6 +8,6 @@ data class CommentNotification( val authorName: String, val reName: String, val date: String, - val title: String, + val title: String?, val reMessage: String ) diff --git a/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt b/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt index 098ac2c5..a86bc637 100644 --- a/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt +++ b/src/main/kotlin/plus/maa/backend/repository/entity/Copilot.kt @@ -63,7 +63,7 @@ class Copilot( var actions: List? = null, // 描述 - var doc: Doc, + var doc: Doc?, var firstUploadTime: LocalDateTime? = null, var uploadTime: LocalDateTime? = null, diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 9da1b29a..5976f2a1 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -105,7 +105,7 @@ class CommentsAreaService( val authorName = maaUserMap.getOrDefault(replyUserId, MaaUser.UNKNOWN).userName val reName = maaUserMap.getOrDefault(userId, MaaUser.UNKNOWN).userName - val title = if (isCopilotAuthor) copilot.doc.title else commentsArea!!.message + val title = if (isCopilotAuthor) copilot.doc?.title else commentsArea!!.message val commentNotification = CommentNotification(authorName, reName, timeStr, title, message) diff --git a/src/main/kotlin/plus/maa/backend/service/EmailService.kt b/src/main/kotlin/plus/maa/backend/service/EmailService.kt index 36d6d23c..f4d7f68d 100644 --- a/src/main/kotlin/plus/maa/backend/service/EmailService.kt +++ b/src/main/kotlin/plus/maa/backend/service/EmailService.kt @@ -106,7 +106,7 @@ class EmailService( fun sendCommentNotification(email: String, commentNotification: CommentNotification) { val limit = 25 - var title = commentNotification.title + var title = commentNotification.title ?: "" if (title.isNotBlank()) { if (title.length > limit) { title = title.substring(0, limit) + "...." From 12245720b29dd4419715f8d3d3a81ef7d63b6ee7 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 17:38:58 +0800 Subject: [PATCH 142/168] =?UTF-8?q?chore:=20=E6=B8=85=E7=90=86=E6=AE=8B?= =?UTF-8?q?=E7=95=99=E7=9A=84=20lombok=20=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../plus/maa/backend/repository/entity/CommentsArea.kt | 4 ---- .../kotlin/plus/maa/backend/repository/entity/CopilotSet.kt | 4 ---- .../kotlin/plus/maa/backend/service/CommentsAreaService.kt | 2 -- src/main/kotlin/plus/maa/backend/service/UserService.kt | 6 ------ 4 files changed, 16 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt b/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt index 2e0f3f7b..303e769c 100644 --- a/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt +++ b/src/main/kotlin/plus/maa/backend/repository/entity/CommentsArea.kt @@ -1,7 +1,5 @@ package plus.maa.backend.repository.entity -import lombok.Data -import lombok.experimental.Accessors import org.springframework.data.annotation.Id import org.springframework.data.mongodb.core.index.Indexed import org.springframework.data.mongodb.core.mapping.Document @@ -12,8 +10,6 @@ import java.time.LocalDateTime * @author LoMu * Date 2023-02-17 14:50 */ -@Data -@Accessors(chain = true) @Document("maa_comments_area") class CommentsArea( @Id diff --git a/src/main/kotlin/plus/maa/backend/repository/entity/CopilotSet.kt b/src/main/kotlin/plus/maa/backend/repository/entity/CopilotSet.kt index 6a80fae6..8980d296 100644 --- a/src/main/kotlin/plus/maa/backend/repository/entity/CopilotSet.kt +++ b/src/main/kotlin/plus/maa/backend/repository/entity/CopilotSet.kt @@ -3,8 +3,6 @@ package plus.maa.backend.repository.entity import com.fasterxml.jackson.annotation.JsonIgnore import com.fasterxml.jackson.databind.PropertyNamingStrategies import com.fasterxml.jackson.databind.annotation.JsonNaming -import lombok.Data -import lombok.experimental.Accessors import org.springframework.data.annotation.Id import org.springframework.data.annotation.Transient import org.springframework.data.mongodb.core.mapping.Document @@ -16,9 +14,7 @@ import java.time.LocalDateTime /** * 作业集数据 */ -@Data @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy::class) -@Accessors(chain = true) @Document("maa_copilot_set") data class CopilotSet( /** diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 5976f2a1..0aa3d6b9 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -1,6 +1,5 @@ package plus.maa.backend.service -import lombok.RequiredArgsConstructor import org.apache.commons.lang3.StringUtils import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Pageable @@ -30,7 +29,6 @@ import java.util.* * Date 2023-02-17 15:00 */ @Service -@RequiredArgsConstructor class CommentsAreaService( private val commentsAreaRepository: CommentsAreaRepository, private val ratingRepository: RatingRepository, diff --git a/src/main/kotlin/plus/maa/backend/service/UserService.kt b/src/main/kotlin/plus/maa/backend/service/UserService.kt index e0d6b168..88ba9fdf 100644 --- a/src/main/kotlin/plus/maa/backend/service/UserService.kt +++ b/src/main/kotlin/plus/maa/backend/service/UserService.kt @@ -1,8 +1,5 @@ package plus.maa.backend.service -import lombok.RequiredArgsConstructor -import lombok.Setter -import lombok.extern.slf4j.Slf4j import org.springframework.beans.BeanUtils import org.springframework.dao.DuplicateKeyException import org.springframework.security.crypto.password.PasswordEncoder @@ -23,10 +20,7 @@ import java.util.* /** * @author AnselYuki */ -@Setter -@Slf4j @Service -@RequiredArgsConstructor class UserService( private val userRepository: UserRepository, private val emailService: EmailService, From b37cf89e8c5edb5014c4d4bf6d3cdc87e1afe655 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 17:40:37 +0800 Subject: [PATCH 143/168] =?UTF-8?q?refactor:=20=E5=B0=86=E5=89=A9=E4=BD=99?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E8=BF=81=E7=A7=BB=E5=88=B0kotlin=E7=9B=AE?= =?UTF-8?q?=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{java => kotlin}/plus/maa/backend/service/jwt/JwtAuthToken.kt | 0 .../plus/maa/backend/service/jwt/JwtExpiredException.kt | 0 .../plus/maa/backend/service/jwt/JwtInvalidException.kt | 0 .../plus/maa/backend/service/jwt/JwtRefreshToken.kt | 0 .../{java => kotlin}/plus/maa/backend/service/jwt/JwtService.kt | 0 .../{java => kotlin}/plus/maa/backend/service/jwt/JwtToken.kt | 0 .../plus/maa/backend/service/model/ArkLevelType.kt | 0 .../plus/maa/backend/service/model/CommentNotification.kt | 0 .../plus/maa/backend/service/model/CopilotSetStatus.kt | 0 .../{java => kotlin}/plus/maa/backend/service/model/LoginUser.kt | 0 .../plus/maa/backend/service/model/RatingCache.kt | 0 .../plus/maa/backend/service/model/RatingCount.kt | 0 .../{java => kotlin}/plus/maa/backend/service/model/RatingType.kt | 0 .../plus/maa/backend/service/model/parser/ActivityParser.kt | 0 .../plus/maa/backend/service/model/parser/ArkLevelParser.kt | 0 .../plus/maa/backend/service/model/parser/CampaignParser.kt | 0 .../plus/maa/backend/service/model/parser/LegionParser.kt | 0 .../plus/maa/backend/service/model/parser/MainlineParser.kt | 0 .../plus/maa/backend/service/model/parser/MemoryParser.kt | 0 .../plus/maa/backend/service/model/parser/RuneParser.kt | 0 .../plus/maa/backend/service/model/parser/UnknownParser.kt | 0 .../plus/maa/backend/service/model/parser/WeeklyParser.kt | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename src/main/{java => kotlin}/plus/maa/backend/service/jwt/JwtAuthToken.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/jwt/JwtExpiredException.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/jwt/JwtInvalidException.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/jwt/JwtRefreshToken.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/jwt/JwtService.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/jwt/JwtToken.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/ArkLevelType.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/CommentNotification.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/CopilotSetStatus.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/LoginUser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/RatingCache.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/RatingCount.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/RatingType.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/ActivityParser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/ArkLevelParser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/CampaignParser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/LegionParser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/MainlineParser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/MemoryParser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/RuneParser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/UnknownParser.kt (100%) rename src/main/{java => kotlin}/plus/maa/backend/service/model/parser/WeeklyParser.kt (100%) diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtAuthToken.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtAuthToken.kt rename to src/main/kotlin/plus/maa/backend/service/jwt/JwtAuthToken.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtExpiredException.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtExpiredException.kt rename to src/main/kotlin/plus/maa/backend/service/jwt/JwtExpiredException.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtInvalidException.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtInvalidException.kt rename to src/main/kotlin/plus/maa/backend/service/jwt/JwtInvalidException.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtRefreshToken.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtRefreshToken.kt rename to src/main/kotlin/plus/maa/backend/service/jwt/JwtRefreshToken.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtService.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtService.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtService.kt rename to src/main/kotlin/plus/maa/backend/service/jwt/JwtService.kt diff --git a/src/main/java/plus/maa/backend/service/jwt/JwtToken.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/jwt/JwtToken.kt rename to src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt diff --git a/src/main/java/plus/maa/backend/service/model/ArkLevelType.kt b/src/main/kotlin/plus/maa/backend/service/model/ArkLevelType.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/ArkLevelType.kt rename to src/main/kotlin/plus/maa/backend/service/model/ArkLevelType.kt diff --git a/src/main/java/plus/maa/backend/service/model/CommentNotification.kt b/src/main/kotlin/plus/maa/backend/service/model/CommentNotification.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/CommentNotification.kt rename to src/main/kotlin/plus/maa/backend/service/model/CommentNotification.kt diff --git a/src/main/java/plus/maa/backend/service/model/CopilotSetStatus.kt b/src/main/kotlin/plus/maa/backend/service/model/CopilotSetStatus.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/CopilotSetStatus.kt rename to src/main/kotlin/plus/maa/backend/service/model/CopilotSetStatus.kt diff --git a/src/main/java/plus/maa/backend/service/model/LoginUser.kt b/src/main/kotlin/plus/maa/backend/service/model/LoginUser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/LoginUser.kt rename to src/main/kotlin/plus/maa/backend/service/model/LoginUser.kt diff --git a/src/main/java/plus/maa/backend/service/model/RatingCache.kt b/src/main/kotlin/plus/maa/backend/service/model/RatingCache.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/RatingCache.kt rename to src/main/kotlin/plus/maa/backend/service/model/RatingCache.kt diff --git a/src/main/java/plus/maa/backend/service/model/RatingCount.kt b/src/main/kotlin/plus/maa/backend/service/model/RatingCount.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/RatingCount.kt rename to src/main/kotlin/plus/maa/backend/service/model/RatingCount.kt diff --git a/src/main/java/plus/maa/backend/service/model/RatingType.kt b/src/main/kotlin/plus/maa/backend/service/model/RatingType.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/RatingType.kt rename to src/main/kotlin/plus/maa/backend/service/model/RatingType.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/ActivityParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/ActivityParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/ActivityParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/ActivityParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/ArkLevelParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/ArkLevelParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/ArkLevelParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/CampaignParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/CampaignParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/CampaignParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/CampaignParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/LegionParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/LegionParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/LegionParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/LegionParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/MainlineParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/MainlineParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/MainlineParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/MainlineParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/MemoryParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/MemoryParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/MemoryParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/MemoryParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/RuneParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/RuneParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/RuneParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/RuneParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/UnknownParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/UnknownParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/UnknownParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/UnknownParser.kt diff --git a/src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.kt b/src/main/kotlin/plus/maa/backend/service/model/parser/WeeklyParser.kt similarity index 100% rename from src/main/java/plus/maa/backend/service/model/parser/WeeklyParser.kt rename to src/main/kotlin/plus/maa/backend/service/model/parser/WeeklyParser.kt From 576d9d83381b0c0fecab6fa731d8f439e3a9ac1e Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 18:07:25 +0800 Subject: [PATCH 144/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=81=97?= =?UTF-8?q?=E6=BC=8F=E7=9A=84jwt=E8=BF=94=E5=9B=9E=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt index 7ed3800f..5ebc508a 100644 --- a/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt +++ b/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt @@ -57,7 +57,7 @@ open class JwtToken { get() = payload.getStr(RegisteredPayload.JWT_ID) - val issuedAt: LocalDateTime? + val issuedAt: LocalDateTime get() = LocalDateTime.ofInstant( Instant.ofEpochMilli(payload.getLong(RegisteredPayload.ISSUED_AT)), TimeZone.getDefault().toZoneId() From 83f6e515c5fb3b03d765ff3cc99e7be54fd365e5 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 18:07:43 +0800 Subject: [PATCH 145/168] =?UTF-8?q?chore:=20=E5=8E=BB=E9=99=A4=20lombok=20?= =?UTF-8?q?=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index bbc690e3..f3269cf0 100644 --- a/build.gradle +++ b/build.gradle @@ -2,8 +2,6 @@ plugins { id 'java' id 'org.springframework.boot' version '3.1.5' id 'io.spring.dependency-management' version '1.1.3' - id 'org.jetbrains.kotlin.plugin.lombok' version '1.9.22' - id 'io.freefair.lombok' version '8.4' id 'org.springdoc.openapi-gradle-plugin' version '1.8.0' id 'org.hidetake.swagger.generator' version '2.19.2' // id 'org.graalvm.buildtools.native' version '0.9.28' @@ -66,9 +64,8 @@ dependencies { implementation "cn.hutool:hutool-jwt:$hutoolVersion" implementation "cn.hutool:hutool-dfa:$hutoolVersion" - // mapstruct and lombok + // mapstruct implementation "org.mapstruct:mapstruct:${mapstructVersion}" - kapt "org.projectlombok:lombok-mapstruct-binding:0.2.0" kapt "org.mapstruct:mapstruct-processor:${mapstructVersion}" implementation 'org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r' From e0cb0a6f8e133dbfb6049ecb54d25bd04542742a Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 22:02:22 +0800 Subject: [PATCH 146/168] build: bump gradle version to 8.6 to support java 21 --- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 63375 bytes gradle/wrapper/gradle-wrapper.properties | 3 ++- gradlew | 30 +++++++++++++++++------ gradlew.bat | 15 +++++++----- 4 files changed, 33 insertions(+), 15 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..033e24c4cdf41af1ab109bc7f253b2b887023340 100644 GIT binary patch delta 41134 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 delta 38514 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

Ed3W8DKk=GWZ^H1%j3(j1_6^9H~ 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 17a8ddce..a80b22ce 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c7873..fcb6fca1 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +130,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,6 +197,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in @@ -205,6 +213,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd32..93e3f59f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal From 81da68d9e4e1d6e004bb22cb23a7a74224cc12d7 Mon Sep 17 00:00:00 2001 From: dragove Date: Wed, 14 Feb 2024 22:03:14 +0800 Subject: [PATCH 147/168] =?UTF-8?q?chore:=20=E5=8E=BB=E9=99=A4=E6=97=A0?= =?UTF-8?q?=E7=94=A8=E5=88=A4=E6=96=AD=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt index 5ebc508a..f8fb906f 100644 --- a/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt +++ b/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt @@ -24,8 +24,7 @@ open class JwtToken { this.payload = jwt.payloads // jwtId is nullable - if (null == issuedAt || requiredType != type - ) throw JwtInvalidException() + if (requiredType != type) throw JwtInvalidException() } constructor( From 4e67165b2831bfdfc1095c9c3b5d07358449c794 Mon Sep 17 00:00:00 2001 From: dragove Date: Thu, 15 Feb 2024 00:22:49 +0800 Subject: [PATCH 148/168] =?UTF-8?q?refactor:=20=E8=BF=81=E7=A7=BB=20groovy?= =?UTF-8?q?=20=E8=84=9A=E6=9C=AC=E5=88=B0=20kotlin=EF=BC=8C=E5=8D=87?= =?UTF-8?q?=E7=BA=A7=E4=BE=9D=E8=B5=96=E7=89=88=E6=9C=AC=EF=BC=8Cjava21?= =?UTF-8?q?=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 154 ----------------- build.gradle.kts | 156 ++++++++++++++++++ settings.gradle | 2 - settings.gradle.kts | 1 + .../maa/backend/config/HttpInterfaceConfig.kt | 2 +- .../maa/backend/config/ThreadPoolConfig.kt | 11 +- 6 files changed, 165 insertions(+), 161 deletions(-) delete mode 100644 build.gradle create mode 100644 build.gradle.kts delete mode 100644 settings.gradle create mode 100644 settings.gradle.kts diff --git a/build.gradle b/build.gradle deleted file mode 100644 index f3269cf0..00000000 --- a/build.gradle +++ /dev/null @@ -1,154 +0,0 @@ -plugins { - id 'java' - id 'org.springframework.boot' version '3.1.5' - id 'io.spring.dependency-management' version '1.1.3' - id 'org.springdoc.openapi-gradle-plugin' version '1.8.0' - id 'org.hidetake.swagger.generator' version '2.19.2' -// id 'org.graalvm.buildtools.native' version '0.9.28' - id 'com.gorylenko.gradle-git-properties' version '2.4.1' - id 'org.jetbrains.kotlin.jvm' version '1.9.22' - id "org.jetbrains.kotlin.plugin.spring" version "1.9.22" - id "org.jetbrains.kotlin.kapt" version "1.9.22" -} - -group 'plus.maa' -version '1.0-SNAPSHOT' - -repositories { - maven { - url 'https://maven.aliyun.com/repository/public/' - } - maven { - url 'https://maven.aliyun.com/repository/spring/' - } - mavenCentral() -} - -ext { - // 统一管理版本号 - hutoolVersion = '5.8.22' - mapstructVersion = '1.5.5.Final' -} - -dependencies { - - kapt 'org.springframework.boot:spring-boot-configuration-processor' - - testImplementation 'io.mockk:mockk:1.13.9' - testImplementation 'org.springframework.boot:spring-boot-starter-test' - implementation 'org.springframework.boot:spring-boot-starter-web' - implementation 'org.springframework.boot:spring-boot-starter-webflux' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.boot:spring-boot-starter-data-redis' - implementation 'org.springframework.boot:spring-boot-starter-data-mongodb' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.boot:spring-boot-starter-cache' - - //springdoc相关依赖没有被自动管理,必须保留版本号 - implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0' - implementation 'com.github.therapi:therapi-runtime-javadoc:0.13.0' - kapt 'com.github.therapi:therapi-runtime-javadoc-scribe:0.15.0' - - // kotlin - implementation "com.fasterxml.jackson.module:jackson-module-kotlin" - implementation "org.jetbrains.kotlin:kotlin-reflect" - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - - // kotlin-logging - implementation 'io.github.oshai:kotlin-logging-jvm:5.1.0' - - implementation 'com.squareup.okhttp3:okhttp:4.10.0' - implementation 'com.sun.mail:javax.mail:1.6.2' - // 双引号才能使用变量 - implementation "cn.hutool:hutool-extra:$hutoolVersion" - implementation "cn.hutool:hutool-jwt:$hutoolVersion" - implementation "cn.hutool:hutool-dfa:$hutoolVersion" - - // mapstruct - implementation "org.mapstruct:mapstruct:${mapstructVersion}" - kapt "org.mapstruct:mapstruct-processor:${mapstructVersion}" - - implementation 'org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r' - implementation 'org.eclipse.jgit:org.eclipse.jgit.ssh.apache.agent:6.6.0.202305301015-r' - implementation 'org.freemarker:freemarker:2.3.32' - implementation 'com.github.ben-manes.caffeine:caffeine:3.1.6' - implementation 'com.github.erosb:everit-json-schema:1.14.2' - implementation 'com.google.guava:guava:32.1.1-jre' - implementation 'org.aspectj:aspectjweaver:1.9.19' - implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' - - swaggerCodegen 'org.openapitools:openapi-generator-cli:6.5.0' - -} - -kapt { - keepJavacAnnotationProcessors = true -} - -test { - useJUnitPlatform() -} - -def swagger_output_dir = "$buildDir/docs" -def swagger_output_name = 'swagger.json' - - -openApi { - apiDocsUrl.set("http://localhost:8848/v3/api-docs") - outputDir.set(file(swagger_output_dir)) - outputFileName.set(swagger_output_name) - waitTimeInSeconds.set(30) -} - -swaggerSources { - def client_dir = "$buildDir/clients" - TsFetch { - inputFile = file("$swagger_output_dir/$swagger_output_name") - code { - language = 'typescript-fetch' - configFile = file('client-config/ts-fetch.json') -// templateDir = file('client-config/typescript-fetch') - rawOptions = ["-e", "mustache"] - outputDir = file("$client_dir/ts-fetch-client") - } - } - CSharp { - inputFile = file("$swagger_output_dir/$swagger_output_name") - code { - language = 'csharp-netcore' - configFile = file('client-config/csharp-netcore.json') - outputDir = file("$client_dir/csharp-client") -// rawOptions = [ -// "--type-mappings", "binary=System.IO.Stream" -// ] - } - } - Cpp { - inputFile = file("$swagger_output_dir/$swagger_output_name") - code { - language = 'cpp-restsdk' - configFile = file('client-config/cpp.json') - outputDir = file("$client_dir/cpp-client") - } - } - Rust { - inputFile = file("$swagger_output_dir/$swagger_output_name") - code { - language = 'rust' - configFile = file('client-config/rust.json') - outputDir = file("$client_dir/rust-client") - } - } -} - -rootProject.afterEvaluate() { - def forkedSpringBootRun = project.tasks.named("forkedSpringBootRun") - forkedSpringBootRun.configure { - doNotTrackState("See https://github.com/springdoc/springdoc-openapi-gradle-plugin/issues/102") - } -} - -gitProperties { - failOnNoGitDirectory = false - keys = ["git.branch", "git.commit.id", "git.commit.id.abbrev", "git.commit.time"] -} diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 00000000..e4d6e1a8 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,156 @@ +import org.hidetake.gradle.swagger.generator.GenerateSwaggerCode +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + java + id("org.springframework.boot") version "3.2.2" + id("io.spring.dependency-management") version "1.1.4" + id("org.springdoc.openapi-gradle-plugin") version "1.8.0" +// id("org.graalvm.buildtools.native") version "0.9.28" + id("org.hidetake.swagger.generator") version "2.19.2" + id("com.gorylenko.gradle-git-properties") version "2.4.1" + + kotlin("jvm") version "1.9.22" + kotlin("plugin.spring") version "1.9.22" + kotlin("kapt") version "1.9.22" +} + +group = "plus.maa" +version = "2.0" + +java { + sourceCompatibility = JavaVersion.VERSION_21 +} + +repositories { + maven(url = "https://maven.aliyun.com/repository/public/") + maven(url = "https://maven.aliyun.com/repository/spring/") + mavenCentral() +} + + +dependencies { + val hutoolVersion = "5.8.26" + val mapstructVersion = "1.5.5.Final" + + kapt("org.springframework.boot:spring-boot-configuration-processor") + + testImplementation("io.mockk:mockk:1.13.9") + testImplementation("org.springframework.boot:spring-boot-starter-test") + + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-webflux") + implementation("org.springframework.boot:spring-boot-starter-security") + implementation("org.springframework.boot:spring-boot-starter-data-redis") + implementation("org.springframework.boot:spring-boot-starter-data-mongodb") + implementation("org.springframework.boot:spring-boot-starter-validation") + implementation("org.springframework.boot:spring-boot-starter-cache") + + // springdoc相关依赖没有被自动管理,必须保留版本号 + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") + implementation("com.github.therapi:therapi-runtime-javadoc:0.15.0") + kapt("com.github.therapi:therapi-runtime-javadoc-scribe:0.15.0") + + // kotlin + implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + implementation("org.jetbrains.kotlin:kotlin-reflect") + + // kotlin-logging + implementation("io.github.oshai:kotlin-logging-jvm:6.0.3") + + implementation("com.squareup.okhttp3:okhttp:4.12.0") + // hutool 的邮箱工具类依赖 + implementation("com.sun.mail:javax.mail:1.6.2") + implementation("cn.hutool:hutool-extra:$hutoolVersion") + implementation("cn.hutool:hutool-jwt:$hutoolVersion") + implementation("cn.hutool:hutool-dfa:$hutoolVersion") + + // mapstruct + implementation("org.mapstruct:mapstruct:${mapstructVersion}") + kapt("org.mapstruct:mapstruct-processor:${mapstructVersion}") + + implementation("org.eclipse.jgit:org.eclipse.jgit:6.8.0.202311291450-r") + implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache.agent:6.8.0.202311291450-r") + implementation("org.freemarker:freemarker:2.3.32") + implementation("com.github.ben-manes.caffeine:caffeine:3.1.8") + implementation("com.github.erosb:everit-json-schema:1.14.4") + implementation("com.google.guava:guava:32.1.3-jre") + implementation("org.aspectj:aspectjweaver:1.9.21") + + implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") + + swaggerCodegen("org.openapitools:openapi-generator-cli:7.3.0") + +} + +kapt { + keepJavacAnnotationProcessors = true +} + +tasks.withType { + kotlinOptions { + freeCompilerArgs += "-Xjsr305=strict" + jvmTarget = "21" + } +} + +tasks.withType { + useJUnitPlatform() +} + + +val swaggerOutputDir = "${project.layout.buildDirectory}/docs" +val swaggerOutputName = "swagger.json" + + +openApi { + apiDocsUrl.set("http://localhost:8848/v3/api-docs") + outputDir.set(file(swaggerOutputDir)) + outputFileName.set(swaggerOutputName) + waitTimeInSeconds.set(30) +} + +swaggerSources { + val clientDir = "${project.layout.buildDirectory}/clients" + create("TsFetch") { + setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) + code(closureOf { + language = "typescript-fetch" + configFile = file("client-config/ts-fetch.json") +// templateDir = file('client-config/typescript-fetch') + rawOptions = listOf("-e", "mustache") + outputDir = file("$clientDir/ts-fetch-client") + }) + } + create("CSharp") { + setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) + code(closureOf { + language = "csharp-netcore" + configFile = file("client-config/csharp-netcore.json") + outputDir = file("$clientDir/csharp-client") +// rawOptions = listOf("--type-mappings", "binary=System.IO.Stream") + }) + } + create("Cpp") { + setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) + code(closureOf { + language = "cpp-restsdk" + configFile = file("client-config/cpp.json") + outputDir = file("$clientDir/cpp-client") + }) + } + create("Rust") { + setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) + code(closureOf { + language = "rust" + configFile = file("client-config/rust.json") + outputDir = file("$clientDir/rust-client") + }) + } +} + + +gitProperties { + failOnNoGitDirectory = false + keys = listOf("git.branch", "git.commit.id", "git.commit.id.abbrev", "git.commit.time") +} diff --git a/settings.gradle b/settings.gradle deleted file mode 100644 index 143ed513..00000000 --- a/settings.gradle +++ /dev/null @@ -1,2 +0,0 @@ -rootProject.name = 'MaaBackendCenter' - diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 00000000..6e011c5f --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name = "MaaBackendCenter" diff --git a/src/main/kotlin/plus/maa/backend/config/HttpInterfaceConfig.kt b/src/main/kotlin/plus/maa/backend/config/HttpInterfaceConfig.kt index 223811bb..9f22afdc 100644 --- a/src/main/kotlin/plus/maa/backend/config/HttpInterfaceConfig.kt +++ b/src/main/kotlin/plus/maa/backend/config/HttpInterfaceConfig.kt @@ -41,7 +41,7 @@ class HttpInterfaceConfig { headers.add("X-GitHub-Api-Version", "2022-11-28") } .build() - return HttpServiceProxyFactory.builder(WebClientAdapter.forClient(client)) + return HttpServiceProxyFactory.builderFor(WebClientAdapter.create(client)) .build() .createClient(GithubRepository::class.java) } diff --git a/src/main/kotlin/plus/maa/backend/config/ThreadPoolConfig.kt b/src/main/kotlin/plus/maa/backend/config/ThreadPoolConfig.kt index 4c9dbb7a..99a04010 100644 --- a/src/main/kotlin/plus/maa/backend/config/ThreadPoolConfig.kt +++ b/src/main/kotlin/plus/maa/backend/config/ThreadPoolConfig.kt @@ -1,7 +1,7 @@ package plus.maa.backend.config import org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration -import org.springframework.boot.task.TaskExecutorBuilder +import org.springframework.boot.task.ThreadPoolTaskExecutorBuilder import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Lazy @@ -14,9 +14,12 @@ class ThreadPoolConfig { @Lazy @Primary @Bean( - name = [TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME, AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME] + name = [ + TaskExecutionAutoConfiguration.APPLICATION_TASK_EXECUTOR_BEAN_NAME, + AsyncAnnotationBeanPostProcessor.DEFAULT_TASK_EXECUTOR_BEAN_NAME + ] ) - fun defaultTaskExecutor(builder: TaskExecutorBuilder): ThreadPoolTaskExecutor = builder.build() + fun defaultTaskExecutor(builder: ThreadPoolTaskExecutorBuilder): ThreadPoolTaskExecutor = builder.build() @Bean fun emailTaskExecutor(): ThreadPoolTaskExecutor { @@ -24,7 +27,7 @@ class ThreadPoolConfig { val taskExecutor = ThreadPoolTaskExecutor() // I/O 密集型配置 taskExecutor.corePoolSize = Runtime.getRuntime().availableProcessors() * 2 - taskExecutor.threadNamePrefix = "email-task-" + taskExecutor.setThreadNamePrefix("email-task-") // 动态的核心线程数量 taskExecutor.setAllowCoreThreadTimeOut(true) return taskExecutor From 1bfb71ac8a8db0ca7bab9ffcb9a38876dbd1b598 Mon Sep 17 00:00:00 2001 From: dragove Date: Thu, 15 Feb 2024 01:46:07 +0800 Subject: [PATCH 149/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8Dswagger?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E7=94=9F=E6=88=90=E4=BD=8D=E7=BD=AE=E9=94=99?= =?UTF-8?q?=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index e4d6e1a8..6fe07f77 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -99,7 +99,7 @@ tasks.withType { } -val swaggerOutputDir = "${project.layout.buildDirectory}/docs" +val swaggerOutputDir = layout.buildDirectory.dir("docs") val swaggerOutputName = "swagger.json" @@ -111,7 +111,7 @@ openApi { } swaggerSources { - val clientDir = "${project.layout.buildDirectory}/clients" + val clientDir = layout.buildDirectory.dir("clients").get() create("TsFetch") { setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) code(closureOf { @@ -119,7 +119,7 @@ swaggerSources { configFile = file("client-config/ts-fetch.json") // templateDir = file('client-config/typescript-fetch') rawOptions = listOf("-e", "mustache") - outputDir = file("$clientDir/ts-fetch-client") + outputDir = file(clientDir.dir("ts-fetch-client")) }) } create("CSharp") { @@ -127,7 +127,7 @@ swaggerSources { code(closureOf { language = "csharp-netcore" configFile = file("client-config/csharp-netcore.json") - outputDir = file("$clientDir/csharp-client") + outputDir = file(clientDir.dir("csharp-client")) // rawOptions = listOf("--type-mappings", "binary=System.IO.Stream") }) } @@ -136,7 +136,7 @@ swaggerSources { code(closureOf { language = "cpp-restsdk" configFile = file("client-config/cpp.json") - outputDir = file("$clientDir/cpp-client") + outputDir = file(clientDir.dir("cpp-client")) }) } create("Rust") { @@ -144,7 +144,7 @@ swaggerSources { code(closureOf { language = "rust" configFile = file("client-config/rust.json") - outputDir = file("$clientDir/rust-client") + outputDir = file(clientDir.dir("rust-client")) }) } } From 417fb64b6c996369d2b74f1bda65a5394f46c7f0 Mon Sep 17 00:00:00 2001 From: dragove Date: Thu, 15 Feb 2024 01:52:27 +0800 Subject: [PATCH 150/168] =?UTF-8?q?chore:=20=E6=9B=B4=E6=96=B0ci=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E5=92=8Cdocker=E6=96=87=E4=BB=B6=EF=BC=8C=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3swagger=E4=BB=A3=E7=A0=81=E7=94=9F=E6=88=90=E4=BD=BF?= =?UTF-8?q?=E7=94=A8=E6=96=87=E4=BB=B6=E9=94=99=E8=AF=AF=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/openapi.yml | 10 +++++----- Dockerfile | 2 +- build.gradle.kts | 13 +++++++------ dev-docker/test-docker/docker-compose.yml | 2 +- 4 files changed, 14 insertions(+), 13 deletions(-) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index 9cc0ba66..a1bac7c5 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -39,10 +39,10 @@ jobs: major-identifier: "breaking:" minor-identifier: "feature:" - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: - distribution: zulu - java-version: 17 + distribution: temurin + java-version: 21 # - name: Startup Mongodb # uses: supercharge/mongodb-github-action@1.8.0 @@ -52,11 +52,11 @@ jobs: - name: Remove aliyun maven mirror run: | - sed -i '/maven {/,+2d' build.gradle + sed -i '/maven(url/d' build.gradle.kts - name: Set versions run: | - sed -i "s/^version.*$/version '${{ steps.version.outputs.version }}'/g" build.gradle + sed -i "s/^version.*$/version = \"${{ steps.version.outputs.version }}\"/g" build.gradle.kts sed -i 's/"packageVersion.*,/"packageVersion": "${{ steps.version.outputs.version }}",/g' client-config/cpp.json sed -i 's/"packageVersion.*,/"packageVersion": "${{ steps.version.outputs.version }}",/g' client-config/csharp-netcore.json sed -i 's/"packageVersion.*,/"packageVersion": "${{ steps.version.outputs.version }}",/g' client-config/rust.json diff --git a/Dockerfile b/Dockerfile index 0e3fb809..75f496fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM amazoncorretto:17-alpine as runner +FROM amazoncorretto:21-alpine as runner WORKDIR /app COPY ./build/libs/MaaBackendCenter*.jar /MaaBackendCenter.jar EXPOSE 7000-9000 diff --git a/build.gradle.kts b/build.gradle.kts index 6fe07f77..eef678bf 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -79,7 +79,7 @@ dependencies { implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") - swaggerCodegen("org.openapitools:openapi-generator-cli:7.3.0") + swaggerCodegen("org.openapitools:openapi-generator-cli:7.2.0") } @@ -112,8 +112,9 @@ openApi { swaggerSources { val clientDir = layout.buildDirectory.dir("clients").get() + val swaggerOutputFile = swaggerOutputDir.get().file(swaggerOutputName) create("TsFetch") { - setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) + setInputFile(file(swaggerOutputFile)) code(closureOf { language = "typescript-fetch" configFile = file("client-config/ts-fetch.json") @@ -123,16 +124,16 @@ swaggerSources { }) } create("CSharp") { - setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) + setInputFile(file(swaggerOutputFile)) code(closureOf { - language = "csharp-netcore" + language = "csharp" configFile = file("client-config/csharp-netcore.json") outputDir = file(clientDir.dir("csharp-client")) // rawOptions = listOf("--type-mappings", "binary=System.IO.Stream") }) } create("Cpp") { - setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) + setInputFile(file(swaggerOutputFile)) code(closureOf { language = "cpp-restsdk" configFile = file("client-config/cpp.json") @@ -140,7 +141,7 @@ swaggerSources { }) } create("Rust") { - setInputFile(file("$swaggerOutputDir/$swaggerOutputName")) + setInputFile(file(swaggerOutputFile)) code(closureOf { language = "rust" configFile = file("client-config/rust.json") diff --git a/dev-docker/test-docker/docker-compose.yml b/dev-docker/test-docker/docker-compose.yml index f4da9ca3..442c915d 100644 --- a/dev-docker/test-docker/docker-compose.yml +++ b/dev-docker/test-docker/docker-compose.yml @@ -15,7 +15,7 @@ services: networks: - maa maa_backend: - image: dragove/maa-backend-center:latest + image: ghcr.io/maaassistantarknights/maabackendcenter:dev container_name: maa-backend environment: - SPRING_DATA_MONGODB_URI=mongodb://mongo/MaaBackend From 9221f13d9cdc4998e7c8fb3c8d4bc83e04d7c2a0 Mon Sep 17 00:00:00 2001 From: dragove Date: Fri, 16 Feb 2024 22:46:37 +0800 Subject: [PATCH 151/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=9F?= =?UTF-8?q?=E4=BA=A7api=E5=AE=A2=E6=88=B7=E7=AB=AF=E9=94=99=E8=AF=AF?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index eef678bf..350b48fa 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -45,9 +45,9 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-data-mongodb") implementation("org.springframework.boot:spring-boot-starter-validation") implementation("org.springframework.boot:spring-boot-starter-cache") - - // springdoc相关依赖没有被自动管理,必须保留版本号 - implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0") + // springdoc 相关依赖没有被自动管理,必须保留版本号, + // springdoc-openapi-starter-webmvc-ui 升级到 2.3.0 以及以上版本会导致 therapi 不兼容 + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0") implementation("com.github.therapi:therapi-runtime-javadoc:0.15.0") kapt("com.github.therapi:therapi-runtime-javadoc-scribe:0.15.0") @@ -73,7 +73,9 @@ dependencies { implementation("org.eclipse.jgit:org.eclipse.jgit.ssh.apache.agent:6.8.0.202311291450-r") implementation("org.freemarker:freemarker:2.3.32") implementation("com.github.ben-manes.caffeine:caffeine:3.1.8") - implementation("com.github.erosb:everit-json-schema:1.14.4") + implementation("com.github.erosb:everit-json-schema:1.14.4") { + exclude("commons-logging", "commons-logging") + } implementation("com.google.guava:guava:32.1.3-jre") implementation("org.aspectj:aspectjweaver:1.9.21") @@ -104,10 +106,10 @@ val swaggerOutputName = "swagger.json" openApi { - apiDocsUrl.set("http://localhost:8848/v3/api-docs") - outputDir.set(file(swaggerOutputDir)) - outputFileName.set(swaggerOutputName) - waitTimeInSeconds.set(30) + apiDocsUrl = "http://localhost:8848/v3/api-docs" + outputDir = swaggerOutputDir + outputFileName = swaggerOutputName + waitTimeInSeconds = 30 } swaggerSources { From 95bd748b8918cb649894d09fe937e60969ced308 Mon Sep 17 00:00:00 2001 From: dragove Date: Fri, 16 Feb 2024 22:52:55 +0800 Subject: [PATCH 152/168] =?UTF-8?q?ci:=20=E4=BF=AE=E5=A4=8D=20ci=20?= =?UTF-8?q?=E4=B8=AD=20url=20=E6=9B=BF=E6=8D=A2=E9=94=99=E8=AF=AF=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/release.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 9baba734..4ff5b38f 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -42,18 +42,18 @@ jobs: export TRUNCATED_GITHUB_SHA=$(echo ${{ github.sha }} | cut -c1-7); echo "VERSION_TAG=${GITHUB_REF/refs\/heads\//}-${TRUNCATED_GITHUB_SHA}" >> $GITHUB_ENV - - uses: actions/setup-java@v3 + - uses: actions/setup-java@v4 with: - distribution: zulu - java-version: 17 + distribution: temurin + java-version: 21 - name: Remove aliyun maven mirror run: | - sed -i '/maven {/,+2d' build.gradle + sed -i '/maven(url/d' build.gradle.kts - name: Set Java version run: | - sed -i "s/^version.*$/version '${{ steps.version.outputs.version }}'/g" build.gradle + sed -i "s/^version.*$/version = \"${{ steps.version.outputs.version }}\"/g" build.gradle.kts - name: Build jar run: ./gradlew bootJar From 168dbb4fad3f744a480b8de469740227ac759408 Mon Sep 17 00:00:00 2001 From: dragove Date: Fri, 16 Feb 2024 23:10:04 +0800 Subject: [PATCH 153/168] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E4=BF=AE=E6=94=B9=E5=AF=86=E7=A0=81=E6=97=B6=E6=9C=AA?= =?UTF-8?q?=E6=A0=A1=E9=AA=8C=E5=8E=9F=E5=AF=86=E7=A0=81=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../maa/backend/controller/UserController.kt | 2 +- .../plus/maa/backend/service/UserService.kt | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/controller/UserController.kt b/src/main/kotlin/plus/maa/backend/controller/UserController.kt index a8871f36..b084d319 100644 --- a/src/main/kotlin/plus/maa/backend/controller/UserController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/UserController.kt @@ -48,7 +48,7 @@ class UserController( fun updatePassword( @Parameter(description = "修改密码请求") @RequestBody updateDTO: @Valid PasswordUpdateDTO ): MaaResult { - userService.modifyPassword(helper.requireUserId(), updateDTO.newPassword) + userService.modifyPassword(helper.requireUserId(), updateDTO.newPassword, updateDTO.originalPassword) return success() } diff --git a/src/main/kotlin/plus/maa/backend/service/UserService.kt b/src/main/kotlin/plus/maa/backend/service/UserService.kt index 88ba9fdf..f5aa4211 100644 --- a/src/main/kotlin/plus/maa/backend/service/UserService.kt +++ b/src/main/kotlin/plus/maa/backend/service/UserService.kt @@ -73,10 +73,22 @@ class UserService( * @param userId 当前用户 * @param rawPassword 新密码 */ - fun modifyPassword(userId: String, rawPassword: String?) { + fun modifyPassword( + userId: String, rawPassword: String, + originPassword: String? = null, + verifyOriginPassword: Boolean = true + ) { val userResult = userRepository.findById(userId) if (userResult.isEmpty) return val maaUser = userResult.get() + if (verifyOriginPassword) { + check(!originPassword.isNullOrEmpty()) { + "请输入原密码" + } + check(passwordEncoder.matches(originPassword, maaUser.password)) { + "原密码错误" + } + } // 修改密码的逻辑,应当使用与 authentication provider 一致的编码器 maaUser.password = passwordEncoder.encode(rawPassword) maaUser.refreshJwtIds = ArrayList() @@ -178,7 +190,7 @@ class UserService( fun modifyPasswordByActiveCode(passwordResetDTO: PasswordResetDTO) { emailService.verifyVCode(passwordResetDTO.email, passwordResetDTO.activeCode) val maaUser = userRepository.findByEmail(passwordResetDTO.email) - modifyPassword(maaUser!!.userId!!, passwordResetDTO.password) + modifyPassword(maaUser!!.userId!!, passwordResetDTO.password, verifyOriginPassword = false) } /** From 92d4cd8ed2b1797fb2b15d318919ce70f4aa5fa9 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Sun, 18 Feb 2024 22:06:16 +0800 Subject: [PATCH 154/168] work-around: change MaaResult from sealed interface to data class to make swagger doc clear --- .../maa/backend/controller/response/MaaResult.kt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/controller/response/MaaResult.kt b/src/main/kotlin/plus/maa/backend/controller/response/MaaResult.kt index 9c5c93d2..ea3f8356 100644 --- a/src/main/kotlin/plus/maa/backend/controller/response/MaaResult.kt +++ b/src/main/kotlin/plus/maa/backend/controller/response/MaaResult.kt @@ -6,24 +6,22 @@ import com.fasterxml.jackson.annotation.JsonInclude * @author AnselYuki */ @JsonInclude(JsonInclude.Include.NON_NULL) -sealed interface MaaResult { - data class Success(val statusCode: Int, val message: String?, val data: T) : MaaResult - data class Fail(val statusCode: Int, val message: String?) : MaaResult +data class MaaResult(val statusCode: Int, val message: String?, val data: T?) { companion object { - fun success(data: T): Success { + fun success(data: T): MaaResult { return success(null, data) } - fun success(): Success { + fun success(): MaaResult { return success(null, Unit) } - fun success(msg: String?, data: T): Success { - return Success(200, msg, data) + fun success(msg: String?, data: T?): MaaResult { + return MaaResult(200, msg, data) } - fun fail(code: Int, msg: String?): Fail { - return Fail(code, msg) + fun fail(code: Int, msg: String?): MaaResult { + return MaaResult(code, msg, null) } } From 33edc35ab0bc38d364287a50a7cd079b8473df8a Mon Sep 17 00:00:00 2001 From: Handiwork Date: Sun, 18 Feb 2024 22:07:27 +0800 Subject: [PATCH 155/168] feat: add basic support of kotlin coroutines --- build.gradle.kts | 8 ++++++++ .../maa/backend/controller/SystemController.kt | 18 +++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 350b48fa..7c424e37 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -54,6 +54,8 @@ dependencies { // kotlin implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor") // kotlin-logging implementation("io.github.oshai:kotlin-logging-jvm:6.0.3") @@ -152,6 +154,12 @@ swaggerSources { } } +tasks { + forkedSpringBootRun { + doNotTrackState("See https://github.com/springdoc/springdoc-openapi-gradle-plugin/issues/102") + } +} + gitProperties { failOnNoGitDirectory = false diff --git a/src/main/kotlin/plus/maa/backend/controller/SystemController.kt b/src/main/kotlin/plus/maa/backend/controller/SystemController.kt index 742d31ea..cbc8a389 100644 --- a/src/main/kotlin/plus/maa/backend/controller/SystemController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/SystemController.kt @@ -1,6 +1,7 @@ package plus.maa.backend.controller import io.swagger.v3.oas.annotations.tags.Tag +import kotlinx.coroutines.delay import org.springframework.boot.info.GitProperties import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping @@ -15,8 +16,8 @@ import plus.maa.backend.controller.response.MaaResult @RequestMapping("") @RestController class SystemController( - private val properties: MaaCopilotProperties, - private val gitProperties: GitProperties + private val properties: MaaCopilotProperties, + private val gitProperties: GitProperties ) { /** @@ -24,7 +25,10 @@ class SystemController( * @return 系统启动信息 */ @GetMapping("/") - fun test() = MaaResult.success("Maa Copilot Server is Running", null) + suspend fun test(): MaaResult { + delay(1000L) + return MaaResult.success("Maa Copilot Server is Running", null) + } /** @@ -39,9 +43,9 @@ class SystemController( } data class MaaSystemInfo( - val title: String, - val description: String, - val version: String, - val git: GitProperties, + val title: String, + val description: String, + val version: String, + val git: GitProperties, ) } \ No newline at end of file From 5df1fa8ff970faf036e841de3879fa665dfed626 Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 18 Feb 2024 22:39:11 +0800 Subject: [PATCH 156/168] ci: update ci action versions to make GitHub happy --- .github/workflows/openapi.yml | 12 ++++++------ .github/workflows/release.yaml | 8 ++++---- .github/workflows/workflow.yml | 12 +++++------- 3 files changed, 15 insertions(+), 17 deletions(-) diff --git a/.github/workflows/openapi.yml b/.github/workflows/openapi.yml index a1bac7c5..f1d7ec25 100644 --- a/.github/workflows/openapi.yml +++ b/.github/workflows/openapi.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 # fetch the whole repo history @@ -71,31 +71,31 @@ jobs: run: ./gradlew generateSwaggerCode - name: upload openapi - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: openapi-${{ steps.version.outputs.version }} path: ./build/docs/swagger.json - name: upload cpp client - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cpp-client path: ./build/clients/cpp-client/* - name: upload csharp client - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: csharp-client path: ./build/clients/csharp-client/* - name: upload rust client - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: rust-client path: ./build/clients/rust-client/* - name: upload ts client - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ts-client path: ./build/clients/ts-fetch-client/* \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4ff5b38f..b334034b 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: ref: ${{ github.head_ref }} # checkout the correct branch name fetch-depth: 0 # fetch the whole repo history @@ -65,7 +65,7 @@ jobs: path: ./build/libs/* - name: Log in to the Container registry - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -73,7 +73,7 @@ jobs: - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | @@ -84,7 +84,7 @@ jobs: type=raw,value={{branch}}-{{sha}} - name: Build and push Docker image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v5 with: context: . push: true diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 16678a4a..037b9056 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -23,35 +23,33 @@ jobs: runs-on: ubuntu-latest steps: #checkout代码 - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 #安装graalvm - name: 安装graalvm uses: graalvm/setup-graalvm@v1 with: version: 'latest' - java-version: '17' - components: 'native-image' + java-version: '21' #查看版本信息 - name: 查看版本信息 run: | echo "GRAALVM_HOME: $GRAALVM_HOME" echo "JAVA_HOME: $JAVA_HOME" java --version - gu --version native-image --version #校验Gradle wrapper - name: 校验Gradle wrapper - uses: gradle/wrapper-validation-action@v1 + uses: gradle/wrapper-validation-action@v2 #使用Gradle编译项目 - name: 使用Gradle编译项目 - uses: gradle/gradle-build-action@v2 + uses: gradle/gradle-build-action@v3 with: arguments: bootBuildImage # 登录docker仓库 - name: 登录docker仓库 ${{ env.REGISTRY }} if: github.event_name != 'pull_request' - uses: docker/login-action@v2 + uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.DOCKER_USERNAME }} From 733d25e396bc87ac760880ba1be0f2dd4e6964cf Mon Sep 17 00:00:00 2001 From: dragove Date: Sun, 18 Feb 2024 22:45:18 +0800 Subject: [PATCH 157/168] ci: update ci action versions to make GitHub happy --- .github/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index b334034b..688ab1e0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -59,7 +59,7 @@ jobs: run: ./gradlew bootJar - name: Upload jar - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: jar path: ./build/libs/* From 1a665563df9e39569ccdae638d3862b1f41b8c10 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Tue, 20 Feb 2024 21:53:03 +0800 Subject: [PATCH 158/168] fix: timezone is missing when serializing LocalDateTime --- .../plus/maa/backend/config/JacksonConfig.kt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/main/kotlin/plus/maa/backend/config/JacksonConfig.kt diff --git a/src/main/kotlin/plus/maa/backend/config/JacksonConfig.kt b/src/main/kotlin/plus/maa/backend/config/JacksonConfig.kt new file mode 100644 index 00000000..0ccc8281 --- /dev/null +++ b/src/main/kotlin/plus/maa/backend/config/JacksonConfig.kt @@ -0,0 +1,38 @@ +package plus.maa.backend.config + +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.ser.std.StdSerializer +import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer +import org.springframework.boot.autoconfigure.jackson.JacksonProperties +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer +import java.io.IOException +import java.time.* +import java.time.format.DateTimeFormatter + +@Configuration +class JacksonConfig(private val jacksonProperties: JacksonProperties) : WebMvcConfigurer { + @Bean + fun jsonCustomizer(): Jackson2ObjectMapperBuilderCustomizer { + return Jackson2ObjectMapperBuilderCustomizer { builder: Jackson2ObjectMapperBuilder -> + val format = jacksonProperties.dateFormat + val timeZone = jacksonProperties.timeZone + + builder.simpleDateFormat(format) + + val formatter = DateTimeFormatter.ofPattern(format).withZone(ZoneId.of(timeZone.id)) + builder.serializers(LocalDateTimeSerializer(formatter)) + } + } + + class LocalDateTimeSerializer(private val formatter: DateTimeFormatter) : + StdSerializer(LocalDateTime::class.java) { + @Throws(IOException::class) + override fun serialize(value: LocalDateTime, gen: JsonGenerator, provider: SerializerProvider) { + gen.writeString(value.atZone(ZoneId.systemDefault()).format(formatter)) + } + } +} \ No newline at end of file From 901e3bd7fdbe44c8617d3567afb084453b220c60 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Thu, 22 Feb 2024 00:00:56 +0800 Subject: [PATCH 159/168] refactor: simplify AccessLimitInterceptor and remove SpringUtil class which counters Spring pattern --- .../maa/backend/common/utils/SpringUtil.kt | 40 ------- .../plus/maa/backend/config/CorsConfig.kt | 7 -- .../plus/maa/backend/config/JacksonConfig.kt | 8 +- .../accesslimit}/AccessLimit.kt | 6 +- .../config/accesslimit/AccessLimitConfig.kt | 18 +++ .../accesslimit/AccessLimitInterceptor.kt | 53 +++++++++ .../backend/controller/file/FileController.kt | 2 +- .../AccessLimitInterceptHandlerImpl.kt | 108 ------------------ 8 files changed, 77 insertions(+), 165 deletions(-) delete mode 100644 src/main/kotlin/plus/maa/backend/common/utils/SpringUtil.kt rename src/main/kotlin/plus/maa/backend/{common/annotation => config/accesslimit}/AccessLimit.kt (73%) create mode 100644 src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimitConfig.kt create mode 100644 src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimitInterceptor.kt delete mode 100644 src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt diff --git a/src/main/kotlin/plus/maa/backend/common/utils/SpringUtil.kt b/src/main/kotlin/plus/maa/backend/common/utils/SpringUtil.kt deleted file mode 100644 index 74654b11..00000000 --- a/src/main/kotlin/plus/maa/backend/common/utils/SpringUtil.kt +++ /dev/null @@ -1,40 +0,0 @@ -package plus.maa.backend.common.utils - -import org.springframework.beans.BeansException -import org.springframework.context.ApplicationContext -import org.springframework.context.ApplicationContextAware -import org.springframework.context.annotation.Lazy -import org.springframework.stereotype.Component - -/** - * @Author leaves - * @Date 2023/1/20 19:14 - */ -@Component -@Lazy(false) -class SpringUtil : ApplicationContextAware { - @Throws(BeansException::class) - override fun setApplicationContext(applicationContext: ApplicationContext) { - // TODO Auto-generated method stub - if (Companion.applicationContext == null) { - Companion.applicationContext = applicationContext - } - } - - companion object { - var applicationContext: ApplicationContext? = null - private set - - fun getBean(name: String): Any { - return applicationContext!!.getBean(name) - } - - fun getBean(clazz: Class): T { - return applicationContext!!.getBean(clazz) - } - - fun getBean(name: String, clazz: Class): T { - return applicationContext!!.getBean(name, clazz) - } - } -} diff --git a/src/main/kotlin/plus/maa/backend/config/CorsConfig.kt b/src/main/kotlin/plus/maa/backend/config/CorsConfig.kt index 28bee1ee..5f3a60eb 100644 --- a/src/main/kotlin/plus/maa/backend/config/CorsConfig.kt +++ b/src/main/kotlin/plus/maa/backend/config/CorsConfig.kt @@ -2,9 +2,7 @@ package plus.maa.backend.config import org.springframework.context.annotation.Configuration import org.springframework.web.servlet.config.annotation.CorsRegistry -import org.springframework.web.servlet.config.annotation.InterceptorRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurer -import plus.maa.backend.handler.AccessLimitInterceptHandlerImpl /** * @author AnselYuki @@ -21,9 +19,4 @@ class CorsConfig : WebMvcConfigurer { .allowedHeaders("*") // 跨域允许时间 .maxAge(3600) } - - - override fun addInterceptors(registry: InterceptorRegistry) { - registry.addInterceptor(AccessLimitInterceptHandlerImpl()) - } } diff --git a/src/main/kotlin/plus/maa/backend/config/JacksonConfig.kt b/src/main/kotlin/plus/maa/backend/config/JacksonConfig.kt index 0ccc8281..7fa35089 100644 --- a/src/main/kotlin/plus/maa/backend/config/JacksonConfig.kt +++ b/src/main/kotlin/plus/maa/backend/config/JacksonConfig.kt @@ -8,22 +8,18 @@ import org.springframework.boot.autoconfigure.jackson.JacksonProperties import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer import java.io.IOException import java.time.* import java.time.format.DateTimeFormatter @Configuration -class JacksonConfig(private val jacksonProperties: JacksonProperties) : WebMvcConfigurer { +class JacksonConfig(private val jacksonProperties: JacksonProperties) { @Bean fun jsonCustomizer(): Jackson2ObjectMapperBuilderCustomizer { return Jackson2ObjectMapperBuilderCustomizer { builder: Jackson2ObjectMapperBuilder -> val format = jacksonProperties.dateFormat val timeZone = jacksonProperties.timeZone - - builder.simpleDateFormat(format) - - val formatter = DateTimeFormatter.ofPattern(format).withZone(ZoneId.of(timeZone.id)) + val formatter = DateTimeFormatter.ofPattern(format).withZone(timeZone.toZoneId()) builder.serializers(LocalDateTimeSerializer(formatter)) } } diff --git a/src/main/kotlin/plus/maa/backend/common/annotation/AccessLimit.kt b/src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimit.kt similarity index 73% rename from src/main/kotlin/plus/maa/backend/common/annotation/AccessLimit.kt rename to src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimit.kt index b9bcd0b0..cb1af520 100644 --- a/src/main/kotlin/plus/maa/backend/common/annotation/AccessLimit.kt +++ b/src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimit.kt @@ -1,4 +1,4 @@ -package plus.maa.backend.common.annotation +package plus.maa.backend.config.accesslimit import java.lang.annotation.Inherited @@ -19,11 +19,11 @@ import java.lang.annotation.Inherited ) annotation class AccessLimit( /** - * 指定second 时间内,API最多的请求次数 + * 指定 second 时间内,API 最多的请求次数 */ val times: Int = 3, /** - * 指定时间second,redis数据过期时间 + * 指定时间 second,redis 数据过期时间 */ val second: Int = 10 ) diff --git a/src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimitConfig.kt b/src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimitConfig.kt new file mode 100644 index 00000000..39d67add --- /dev/null +++ b/src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimitConfig.kt @@ -0,0 +1,18 @@ +package plus.maa.backend.config.accesslimit + +import com.fasterxml.jackson.databind.ObjectMapper +import org.springframework.context.annotation.Configuration +import org.springframework.data.redis.core.StringRedisTemplate +import org.springframework.web.servlet.config.annotation.InterceptorRegistry +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer + +@Configuration +class AccessLimitConfig( + private val stringRedisTemplate: StringRedisTemplate, + private val objectMapper: ObjectMapper, +) : WebMvcConfigurer { + + override fun addInterceptors(registry: InterceptorRegistry) { + registry.addInterceptor(AccessLimitInterceptor(stringRedisTemplate, objectMapper)) + } +} \ No newline at end of file diff --git a/src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimitInterceptor.kt b/src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimitInterceptor.kt new file mode 100644 index 00000000..10e484a5 --- /dev/null +++ b/src/main/kotlin/plus/maa/backend/config/accesslimit/AccessLimitInterceptor.kt @@ -0,0 +1,53 @@ +package plus.maa.backend.config.accesslimit + +import com.fasterxml.jackson.databind.ObjectMapper +import io.github.oshai.kotlinlogging.KotlinLogging +import jakarta.servlet.http.HttpServletRequest +import jakarta.servlet.http.HttpServletResponse +import org.springframework.data.redis.core.StringRedisTemplate +import org.springframework.http.HttpStatus +import org.springframework.web.method.HandlerMethod +import org.springframework.web.servlet.HandlerInterceptor +import plus.maa.backend.common.utils.IpUtil +import plus.maa.backend.common.utils.WebUtils +import plus.maa.backend.controller.response.MaaResult.Companion.fail +import java.util.concurrent.TimeUnit + +/** + * @author Baip1995 + */ +class AccessLimitInterceptor( + private val stringRedisTemplate: StringRedisTemplate, + private val objectMapper: ObjectMapper, +) : HandlerInterceptor { + + private val log = KotlinLogging.logger { } + + @Throws(Exception::class) + override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { + val ann = (handler as? HandlerMethod)?.method?.getAnnotation(AccessLimit::class.java) ?: return true + // 拼接 redis key = IP + Api 限流 + val key = IpUtil.getIpAddr(request) + request.requestURI + + // 获取 redis 的 value + val count = stringRedisTemplate.opsForValue()[key]?.toInt() ?: 0 + if (count < ann.times) { + // 如果 redis 中的时间比注解上的时间小则表示可以允许访问,这时修改 redis 的 value 时间 + stringRedisTemplate.opsForValue().set( + key, + (count + 1).toString(), + ann.second.toLong(), + TimeUnit.SECONDS + ) + } else { + // 请求过于频繁 + log.info { "$key 请求过于频繁" } + val result = fail(HttpStatus.TOO_MANY_REQUESTS.value(), "请求过于频繁") + val json = objectMapper.writeValueAsString(result) + WebUtils.renderString(response, json, HttpStatus.TOO_MANY_REQUESTS.value()) + return false + } + + return true + } +} diff --git a/src/main/kotlin/plus/maa/backend/controller/file/FileController.kt b/src/main/kotlin/plus/maa/backend/controller/file/FileController.kt index 87528075..85226975 100644 --- a/src/main/kotlin/plus/maa/backend/controller/file/FileController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/file/FileController.kt @@ -10,7 +10,7 @@ import jakarta.validation.Valid import org.springframework.http.MediaType import org.springframework.web.bind.annotation.* import org.springframework.web.multipart.MultipartFile -import plus.maa.backend.common.annotation.AccessLimit +import plus.maa.backend.config.accesslimit.AccessLimit import plus.maa.backend.config.doc.RequireJwt import plus.maa.backend.config.security.AuthenticationHelper import plus.maa.backend.controller.response.MaaResult diff --git a/src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt b/src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt deleted file mode 100644 index 2af15f8a..00000000 --- a/src/main/kotlin/plus/maa/backend/handler/AccessLimitInterceptHandlerImpl.kt +++ /dev/null @@ -1,108 +0,0 @@ -package plus.maa.backend.handler - -import com.fasterxml.jackson.databind.ObjectMapper -import io.github.oshai.kotlinlogging.KotlinLogging -import jakarta.servlet.http.HttpServletRequest -import jakarta.servlet.http.HttpServletResponse -import org.springframework.data.redis.core.StringRedisTemplate -import org.springframework.http.HttpStatus -import org.springframework.lang.Nullable -import org.springframework.stereotype.Component -import org.springframework.web.method.HandlerMethod -import org.springframework.web.servlet.HandlerInterceptor -import org.springframework.web.servlet.ModelAndView -import plus.maa.backend.common.annotation.AccessLimit -import plus.maa.backend.common.utils.IpUtil -import plus.maa.backend.common.utils.SpringUtil -import plus.maa.backend.common.utils.WebUtils -import plus.maa.backend.controller.response.MaaResult.Companion.fail -import java.util.concurrent.TimeUnit - -private val log = KotlinLogging.logger { } - -/** - * @author Baip1995 - */ -@Component -class AccessLimitInterceptHandlerImpl : HandlerInterceptor { - /** - * 接口调用前检查对方ip是否频繁调用接口 - * - * @param request - * @param response - * @param handler - * @return - * @throws Exception - */ - @Throws(Exception::class) - override fun preHandle(request: HttpServletRequest, response: HttpServletResponse, handler: Any): Boolean { - try { - // handler是否为 HandleMethod 实例 - if (handler is HandlerMethod) { - // 强转 - // 获取方法 - val method = handler.method - // 判断方式是否有AccessLimit注解,有的才需要做限流 - if (!method.isAnnotationPresent(AccessLimit::class.java)) { - return true - } - val stringRedisTemplate = SpringUtil.applicationContext!!.getBean(StringRedisTemplate::class.java) - - // 获取注解上的内容 - val accessLimit = method.getAnnotation(AccessLimit::class.java) ?: return true - // 获取方法注解上的请求次数 - val times = accessLimit.times - // 获取方法注解上的请求时间 - val second = accessLimit.second - - // 拼接redis key = IP + Api限流 - val key = IpUtil.getIpAddr(request) + request.requestURI - - // 获取redis的value - var maxTimes: Int? = null - - val value = stringRedisTemplate.opsForValue()[key] - if (!value.isNullOrEmpty()) { - maxTimes = value.toInt() - } - if (maxTimes == null) { - // 如果redis中没有该ip对应的时间则表示第一次调用,保存key到redis - stringRedisTemplate.opsForValue()[key, "1", second.toLong()] = TimeUnit.SECONDS - } else if (maxTimes < times) { - // 如果redis中的时间比注解上的时间小则表示可以允许访问,这是修改redis的value时间 - stringRedisTemplate.opsForValue()[key, (maxTimes + 1).toString() + "", second.toLong()] = - TimeUnit.SECONDS - } else { - // 请求过于频繁 - log.info { "$key 请求过于频繁" } - val result = fail(HttpStatus.TOO_MANY_REQUESTS.value(), "请求过于频繁") - val json = ObjectMapper().writeValueAsString(result) - WebUtils.renderString(response, json, HttpStatus.TOO_MANY_REQUESTS.value()) - return false - } - } - } catch (e: Exception) { - log.error(e) { "API请求限流拦截异常,异常原因:" } - // throw new Exception(""); - } - return true - } - - @Throws(Exception::class) - override fun postHandle( - request: HttpServletRequest, - response: HttpServletResponse, - handler: Any, - @Nullable modelAndView: ModelAndView? - ) { - } - - @Throws(Exception::class) - override fun afterCompletion( - request: HttpServletRequest, - response: HttpServletResponse, - handler: Any, - @Nullable ex: java.lang.Exception? - ) { - } -} From c77be4f0206ce5ad80016258cef603b0a7ad5487 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Thu, 22 Feb 2024 21:10:22 +0800 Subject: [PATCH 160/168] fix: incorrect usage of openapi @Parameter annotation --- .../controller/CommentsAreaController.kt | 24 ++++---------- .../backend/controller/CopilotController.kt | 19 ++++------- .../controller/CopilotSetController.kt | 32 ++++++------------- .../maa/backend/controller/UserController.kt | 21 +++++------- 4 files changed, 31 insertions(+), 65 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/controller/CommentsAreaController.kt b/src/main/kotlin/plus/maa/backend/controller/CommentsAreaController.kt index ea392ac3..1e696c27 100644 --- a/src/main/kotlin/plus/maa/backend/controller/CommentsAreaController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/CommentsAreaController.kt @@ -1,11 +1,11 @@ package plus.maa.backend.controller import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.tags.Tag import jakarta.validation.Valid import jakarta.validation.constraints.NotBlank +import org.springdoc.core.annotations.ParameterObject import org.springframework.web.bind.annotation.* import plus.maa.backend.common.annotation.JsonSchema import plus.maa.backend.common.annotation.SensitiveWordDetection @@ -33,9 +33,7 @@ class CommentsAreaController( @Operation(summary = "发送评论") @ApiResponse(description = "发送评论结果") @RequireJwt - fun sendComments( - @Parameter(description = "评论") @RequestBody comments: @Valid CommentsAddDTO - ): MaaResult { + fun sendComments(@RequestBody comments: @Valid CommentsAddDTO): MaaResult { commentsAreaService.addComments(authHelper.requireUserId(), comments) return success("评论成功") } @@ -43,9 +41,7 @@ class CommentsAreaController( @GetMapping("/query") @Operation(summary = "分页查询评论") @ApiResponse(description = "评论区信息") - fun queriesCommentsArea( - @Parameter(description = "评论查询对象") parsed: @Valid CommentsQueriesDTO - ): MaaResult { + fun queriesCommentsArea(@ParameterObject parsed: @Valid CommentsQueriesDTO): MaaResult { return success(commentsAreaService.queriesCommentsArea(parsed)) } @@ -53,9 +49,7 @@ class CommentsAreaController( @Operation(summary = "删除评论") @ApiResponse(description = "评论删除结果") @RequireJwt - fun deleteComments( - @Parameter(description = "评论删除对象") @RequestBody comments: @Valid CommentsDeleteDTO - ): MaaResult { + fun deleteComments(@RequestBody comments: @Valid CommentsDeleteDTO): MaaResult { commentsAreaService.deleteComments(authHelper.requireUserId(), comments.commentId) return success("评论已删除") } @@ -65,9 +59,7 @@ class CommentsAreaController( @ApiResponse(description = "点赞结果") @RequireJwt @PostMapping("/rating") - fun ratesComments( - @Parameter(description = "评论点赞对象") @RequestBody commentsRatingDTO: @Valid CommentsRatingDTO - ): MaaResult { + fun ratesComments(@RequestBody commentsRatingDTO: @Valid CommentsRatingDTO): MaaResult { commentsAreaService.rates(authHelper.requireUserId(), commentsRatingDTO) return success("成功") } @@ -76,9 +68,7 @@ class CommentsAreaController( @ApiResponse(description = "置顶/取消置顶结果") @RequireJwt @PostMapping("/topping") - fun toppingComments( - @Parameter(description = "评论置顶对象") @RequestBody commentsToppingDTO: @Valid CommentsToppingDTO - ): MaaResult { + fun toppingComments(@RequestBody commentsToppingDTO: @Valid CommentsToppingDTO): MaaResult { commentsAreaService.topping(authHelper.requireUserId(), commentsToppingDTO) return success("成功") } @@ -87,7 +77,7 @@ class CommentsAreaController( @RequireJwt @GetMapping("/status") fun modifyStatus(@RequestParam id: @NotBlank String, @RequestParam status: Boolean): MaaResult { - commentsAreaService.notificationStatus(authHelper.userId!!, id, status) + commentsAreaService.notificationStatus(authHelper.requireUserId(), id, status) return success("success") } } diff --git a/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt b/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt index f454b95d..6e0b88e4 100644 --- a/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/CopilotController.kt @@ -7,6 +7,7 @@ import io.swagger.v3.oas.annotations.tags.Tag import jakarta.servlet.http.HttpServletResponse import jakarta.validation.Valid import jakarta.validation.constraints.NotBlank +import org.springdoc.core.annotations.ParameterObject import org.springframework.http.HttpHeaders import org.springframework.web.bind.annotation.* import plus.maa.backend.common.annotation.JsonSchema @@ -42,9 +43,7 @@ class CopilotController( @JsonSchema @SensitiveWordDetection("#request.content != null ? #objectMapper.readTree(#request.content).get('doc')?.toString() : null") @PostMapping("/upload") - fun uploadCopilot( - @Parameter(description = "作业操作请求") @RequestBody request: CopilotCUDRequest - ): MaaResult { + fun uploadCopilot(@RequestBody request: CopilotCUDRequest): MaaResult { return success(copilotService.upload(helper.requireUserId(), request.content)) } @@ -52,9 +51,7 @@ class CopilotController( @ApiResponse(description = "删除作业结果") @RequireJwt @PostMapping("/delete") - fun deleteCopilot( - @Parameter(description = "作业操作请求") @RequestBody request: CopilotCUDRequest? - ): MaaResult { + fun deleteCopilot(@RequestBody request: CopilotCUDRequest?): MaaResult { copilotService.delete(helper.requireUserId(), request!!) return success() } @@ -75,7 +72,7 @@ class CopilotController( @ApiResponse(description = "作业信息") @GetMapping("/query") fun queriesCopilot( - @Parameter(description = "作业查询请求") parsed: @Valid CopilotQueriesRequest + @ParameterObject parsed: @Valid CopilotQueriesRequest ): MaaResult { // 三秒防抖,缓解前端重复请求问题 response.setHeader(HttpHeaders.CACHE_CONTROL, "private, max-age=3, must-revalidate") @@ -88,9 +85,7 @@ class CopilotController( @JsonSchema @SensitiveWordDetection("#copilotCUDRequest.content != null ? #objectMapper.readTree(#copilotCUDRequest.content).get('doc')?.toString() : null") @PostMapping("/update") - fun updateCopilot( - @Parameter(description = "作业操作请求") @RequestBody copilotCUDRequest: CopilotCUDRequest - ): MaaResult { + fun updateCopilot(@RequestBody copilotCUDRequest: CopilotCUDRequest): MaaResult { copilotService.update(helper.requireUserId(), copilotCUDRequest) return success() } @@ -99,9 +94,7 @@ class CopilotController( @ApiResponse(description = "评分结果") @JsonSchema @PostMapping("/rating") - fun ratesCopilotOperation( - @Parameter(description = "作业评分请求") @RequestBody copilotRatingReq: CopilotRatingReq - ): MaaResult { + fun ratesCopilotOperation(@RequestBody copilotRatingReq: CopilotRatingReq): MaaResult { copilotService.rates(helper.userIdOrIpAddress, copilotRatingReq) return success("评分成功") } diff --git a/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt b/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt index 28de18a3..30b4bfc2 100644 --- a/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/CopilotSetController.kt @@ -34,9 +34,7 @@ class CopilotSetController( @Operation(summary = "查询作业集列表") @ApiResponse(description = "作业集id") @PostMapping("/query") - fun querySets( - @Parameter(description = "作业集列表查询请求") @RequestBody req: @Valid CopilotSetQuery - ): MaaResult { + fun querySets(@RequestBody req: @Valid CopilotSetQuery): MaaResult { return success(service.query(req)) } @@ -51,49 +49,39 @@ class CopilotSetController( @ApiResponse(description = "作业集id") @RequireJwt @PostMapping("/create") - fun createSet( - @Parameter(description = "作业集新增请求") @RequestBody req: @Valid CopilotSetCreateReq - ): MaaResult { + fun createSet(@RequestBody req: @Valid CopilotSetCreateReq): MaaResult { return success(service.create(req, helper.userId)) } @Operation(summary = "添加作业集作业列表") @RequireJwt @PostMapping("/add") - fun addCopilotIds( - @Parameter(description = "作业集中加入新作业请求") @RequestBody req: @Valid CopilotSetModCopilotsReq - ): MaaResult { - service.addCopilotIds(req, helper.userId!!) + fun addCopilotIds(@RequestBody req: @Valid CopilotSetModCopilotsReq): MaaResult { + service.addCopilotIds(req, helper.requireUserId()) return success() } @Operation(summary = "添加作业集作业列表") @RequireJwt @PostMapping("/remove") - fun removeCopilotIds( - @Parameter(description = "作业集中删除作业请求") @RequestBody req: @Valid CopilotSetModCopilotsReq - ): MaaResult { - service.removeCopilotIds(req, helper.userId!!) + fun removeCopilotIds(@RequestBody req: @Valid CopilotSetModCopilotsReq): MaaResult { + service.removeCopilotIds(req, helper.requireUserId()) return success() } @Operation(summary = "更新作业集信息") @RequireJwt @PostMapping("/update") - fun updateCopilotSet( - @Parameter(description = "更新作业集信息请求") @RequestBody req: @Valid CopilotSetUpdateReq - ): MaaResult { - service.update(req, helper.userId!!) + fun updateCopilotSet(@RequestBody req: @Valid CopilotSetUpdateReq): MaaResult { + service.update(req, helper.requireUserId()) return success() } @Operation(summary = "删除作业集") @RequireJwt @PostMapping("/delete") - fun deleteCopilotSet( - @Parameter(description = "删除作业集信息请求") @RequestBody req: @Valid CommonIdReq - ): MaaResult { - service.delete(req.id, helper.userId!!) + fun deleteCopilotSet(@RequestBody req: @Valid CommonIdReq): MaaResult { + service.delete(req.id, helper.requireUserId()) return success() } } diff --git a/src/main/kotlin/plus/maa/backend/controller/UserController.kt b/src/main/kotlin/plus/maa/backend/controller/UserController.kt index b084d319..a5ba5754 100644 --- a/src/main/kotlin/plus/maa/backend/controller/UserController.kt +++ b/src/main/kotlin/plus/maa/backend/controller/UserController.kt @@ -1,7 +1,6 @@ package plus.maa.backend.controller import io.swagger.v3.oas.annotations.Operation -import io.swagger.v3.oas.annotations.Parameter import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.tags.Tag import jakarta.validation.Valid @@ -45,9 +44,7 @@ class UserController( @ApiResponse(description = "修改密码结果") @RequireJwt @PostMapping("/update/password") - fun updatePassword( - @Parameter(description = "修改密码请求") @RequestBody updateDTO: @Valid PasswordUpdateDTO - ): MaaResult { + fun updatePassword(@RequestBody updateDTO: @Valid PasswordUpdateDTO): MaaResult { userService.modifyPassword(helper.requireUserId(), updateDTO.newPassword, updateDTO.originalPassword) return success() } @@ -62,9 +59,7 @@ class UserController( @ApiResponse(description = "更新结果") @RequireJwt @PostMapping("/update/info") - fun updateInfo( - @Parameter(description = "更新用户详细信息请求") @RequestBody updateDTO: @Valid UserInfoUpdateDTO - ): MaaResult { + fun updateInfo(@RequestBody updateDTO: @Valid UserInfoUpdateDTO): MaaResult { userService.updateUserInfo(helper.requireUserId(), updateDTO) return success() } @@ -78,7 +73,7 @@ class UserController( @PostMapping("/password/reset") @Operation(summary = "重置密码") @ApiResponse(description = "重置密码结果") - fun passwordReset(@Parameter(description = "重置密码请求") @RequestBody passwordResetDTO: @Valid PasswordResetDTO): MaaResult { + fun passwordReset(@RequestBody passwordResetDTO: @Valid PasswordResetDTO): MaaResult { // 校验用户邮箱是否存在 userService.checkUserExistByEmail(passwordResetDTO.email) userService.modifyPasswordByActiveCode(passwordResetDTO) @@ -94,7 +89,7 @@ class UserController( @PostMapping("/password/reset_request") @Operation(summary = "发送用于重置密码的验证码") @ApiResponse(description = "验证码发送结果") - fun passwordResetRequest(@Parameter(description = "发送重置密码的验证码请求") @RequestBody passwordResetVCodeDTO: @Valid PasswordResetVCodeDTO): MaaResult { + fun passwordResetRequest(@RequestBody passwordResetVCodeDTO: @Valid PasswordResetVCodeDTO): MaaResult { // 校验用户邮箱是否存在 userService.checkUserExistByEmail(passwordResetVCodeDTO.email) emailService.sendVCode(passwordResetVCodeDTO.email) @@ -110,7 +105,7 @@ class UserController( @PostMapping("/refresh") @Operation(summary = "刷新token") @ApiResponse(description = "刷新token结果") - fun refresh(@Parameter(description = "刷新token请求") @RequestBody request: RefreshReq): MaaResult { + fun refresh(@RequestBody request: RefreshReq): MaaResult { val res = userService.refreshToken(request.refreshToken) return success(res) } @@ -124,7 +119,7 @@ class UserController( @PostMapping("/register") @Operation(summary = "用户注册") @ApiResponse(description = "注册结果") - fun register(@Parameter(description = "用户注册请求") @RequestBody user: @Valid RegisterDTO): MaaResult { + fun register(@RequestBody user: @Valid RegisterDTO): MaaResult { return success(userService.register(user)) } @@ -134,7 +129,7 @@ class UserController( @PostMapping("/sendRegistrationToken") @Operation(summary = "注册时发送验证码") @ApiResponse(description = "发送验证码结果", responseCode = "204") - fun sendRegistrationToken(@Parameter(description = "发送注册验证码请求") @RequestBody regDTO: @Valid SendRegistrationTokenDTO): MaaResult { + fun sendRegistrationToken(@RequestBody regDTO: @Valid SendRegistrationTokenDTO): MaaResult { userService.sendRegistrationToken(regDTO) return success() } @@ -148,7 +143,7 @@ class UserController( @PostMapping("/login") @Operation(summary = "用户登录") @ApiResponse(description = "登录结果") - fun login(@Parameter(description = "登录请求") @RequestBody user: @Valid LoginDTO): MaaResult { + fun login(@RequestBody user: @Valid LoginDTO): MaaResult { return success("登陆成功", userService.login(user)) } } From 22856f5e0ed07183ab3cd4f267cead26636def48 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Thu, 22 Feb 2024 21:18:43 +0800 Subject: [PATCH 161/168] refactor: change type of CommentsAddDTO#copilotId from String to Long --- .../backend/controller/request/comments/CommentsAddDTO.kt | 3 +-- .../plus/maa/backend/service/CommentsAreaService.kt | 8 +++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt index 3404df3a..2a9012c0 100644 --- a/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt +++ b/src/main/kotlin/plus/maa/backend/controller/request/comments/CommentsAddDTO.kt @@ -13,8 +13,7 @@ data class CommentsAddDTO( @field:NotBlank(message = "请填写评论内容") val message: String, // 评论的作业id - @field:NotBlank(message = "作业id不可为空") - val copilotId: String, + val copilotId: Long, // 子评论来源评论id(回复评论) val fromCommentId: String? = null, val notification: Boolean = true diff --git a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt index 0aa3d6b9..3bea2ac8 100644 --- a/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt +++ b/src/main/kotlin/plus/maa/backend/service/CommentsAreaService.kt @@ -48,7 +48,7 @@ class CommentsAreaService( * @param commentsAddDTO CommentsRequest */ fun addComments(userId: String, commentsAddDTO: CommentsAddDTO) { - val copilotId = commentsAddDTO.copilotId.toLong() + val copilotId = commentsAddDTO.copilotId val message = commentsAddDTO.message val copilotOptional = copilotRepository.findByCopilotId(copilotId) Assert.isTrue(StringUtils.isNotBlank(message), "评论不可为空") @@ -171,8 +171,10 @@ class CommentsAreaService( val dislikeCountChange: Long val ratingOptional = - ratingRepository.findByTypeAndKeyAndUserId(Rating.KeyType.COMMENT, - commentsArea.id!!, userId) + ratingRepository.findByTypeAndKeyAndUserId( + Rating.KeyType.COMMENT, + commentsArea.id!!, userId + ) // 判断该用户是否存在评分 if (ratingOptional != null) { // 如果评分发生变化则更新 From 925ee5d742fe82504d001e4fb099387c3f8f3fa4 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Fri, 23 Feb 2024 21:51:18 +0800 Subject: [PATCH 162/168] refactor: remove `@CurrentUser` --- .../backend/common/annotation/CurrentUser.kt | 11 -- .../backend/common/annotation/JsonSchema.kt | 4 +- .../annotation/SensitiveWordDetection.kt | 4 +- .../maa/backend/config/doc/SpringDocConfig.kt | 101 ++++++------------ 4 files changed, 32 insertions(+), 88 deletions(-) delete mode 100644 src/main/kotlin/plus/maa/backend/common/annotation/CurrentUser.kt diff --git a/src/main/kotlin/plus/maa/backend/common/annotation/CurrentUser.kt b/src/main/kotlin/plus/maa/backend/common/annotation/CurrentUser.kt deleted file mode 100644 index b4aa1a83..00000000 --- a/src/main/kotlin/plus/maa/backend/common/annotation/CurrentUser.kt +++ /dev/null @@ -1,11 +0,0 @@ -package plus.maa.backend.common.annotation - -import org.springframework.security.core.annotation.AuthenticationPrincipal - -/** - * @author john180 - */ -@Target(AnnotationTarget.VALUE_PARAMETER) -@Retention(AnnotationRetention.RUNTIME) -@AuthenticationPrincipal -annotation class CurrentUser diff --git a/src/main/kotlin/plus/maa/backend/common/annotation/JsonSchema.kt b/src/main/kotlin/plus/maa/backend/common/annotation/JsonSchema.kt index 7bca737d..32826528 100644 --- a/src/main/kotlin/plus/maa/backend/common/annotation/JsonSchema.kt +++ b/src/main/kotlin/plus/maa/backend/common/annotation/JsonSchema.kt @@ -5,7 +5,5 @@ package plus.maa.backend.common.annotation * Date 2023-01-22 17:49 */ @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) -@Retention( - AnnotationRetention.RUNTIME -) +@Retention(AnnotationRetention.RUNTIME) annotation class JsonSchema diff --git a/src/main/kotlin/plus/maa/backend/common/annotation/SensitiveWordDetection.kt b/src/main/kotlin/plus/maa/backend/common/annotation/SensitiveWordDetection.kt index 78de8081..6f8e22e0 100644 --- a/src/main/kotlin/plus/maa/backend/common/annotation/SensitiveWordDetection.kt +++ b/src/main/kotlin/plus/maa/backend/common/annotation/SensitiveWordDetection.kt @@ -10,9 +10,7 @@ package plus.maa.backend.common.annotation */ @MustBeDocumented @Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER) -@Retention( - AnnotationRetention.RUNTIME -) +@Retention(AnnotationRetention.RUNTIME) annotation class SensitiveWordDetection( /** * SpEL 表达式 diff --git a/src/main/kotlin/plus/maa/backend/config/doc/SpringDocConfig.kt b/src/main/kotlin/plus/maa/backend/config/doc/SpringDocConfig.kt index 186d47d8..5e21f73a 100644 --- a/src/main/kotlin/plus/maa/backend/config/doc/SpringDocConfig.kt +++ b/src/main/kotlin/plus/maa/backend/config/doc/SpringDocConfig.kt @@ -5,92 +5,51 @@ import io.swagger.v3.core.jackson.ModelResolver import io.swagger.v3.oas.models.Components import io.swagger.v3.oas.models.ExternalDocumentation import io.swagger.v3.oas.models.OpenAPI -import io.swagger.v3.oas.models.Operation import io.swagger.v3.oas.models.info.Info import io.swagger.v3.oas.models.info.License -import io.swagger.v3.oas.models.security.SecurityRequirement import io.swagger.v3.oas.models.security.SecurityScheme -import org.springdoc.core.customizers.OperationCustomizer -import org.springframework.beans.factory.annotation.Value import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import org.springframework.web.method.HandlerMethod -import plus.maa.backend.common.annotation.CurrentUser +import plus.maa.backend.config.external.MaaCopilotProperties /** * @author AnselYuki */ @Configuration -class SpringDocConfig( - @Value("\${maa-copilot.info.version}") - private val version: String, - @Value("\${maa-copilot.info.title}") - private val title: String, - @Value("\${maa-copilot.info.description}") - private val description: String, - @Value("\${maa-copilot.jwt.header}") - private val securitySchemeHeader: String -) { +class SpringDocConfig(properties: MaaCopilotProperties) { + private val _info = properties.info + private val jwt = properties.jwt @Bean - fun emergencyLogistics(): OpenAPI { - return OpenAPI() - .info(docInfos()) - .externalDocs( - ExternalDocumentation() - .description("GitHub repo") - .url("https://github.com/MaaAssistantArknights/MaaBackendCenter") - ) - .components( - Components() - .addSecuritySchemes( - SECURITY_SCHEME_JWT, - SecurityScheme() - .type(SecurityScheme.Type.HTTP) - .scheme("bearer") - .`in`(SecurityScheme.In.HEADER) - .name(securitySchemeHeader) - .description( - "JWT Authorization header using the Bearer scheme. Raw head example: \"$securitySchemeHeader: Bearer {token}\"" - ) - ) - ) + fun emergencyLogistics(): OpenAPI = OpenAPI().apply { + info(Info().apply { + title(_info.title) + description(_info.description) + version(_info.version) + license(License().apply { + name("GNU Affero General Public License v3.0") + url("https://www.gnu.org/licenses/agpl-3.0.html") + }) + }) + externalDocs(ExternalDocumentation().apply { + description("GitHub repo") + url("https://github.com/MaaAssistantArknights/MaaBackendCenter") + }) + components(Components().apply { + addSecuritySchemes(SECURITY_SCHEME_JWT, SecurityScheme().apply { + type(SecurityScheme.Type.HTTP) + scheme("bearer") + `in`(SecurityScheme.In.HEADER) + name(jwt.header) + val s = "JWT Authorization header using the Bearer scheme. Raw head example: " + + "\"${jwt.header}: Bearer {token}\"" + description(s) + }) + }) } - /** - * 为使用了 [CurrentUser] 注解的接口在 OpenAPI 上添加 security scheme - */ @Bean - fun currentUserOperationCustomizer(): OperationCustomizer { - return OperationCustomizer { operation: Operation, handlerMethod: HandlerMethod -> - for (parameter in handlerMethod.methodParameters) { - if (parameter.hasParameterAnnotation(CurrentUser::class.java)) { - // 已有 security scheme - if (operation.security.any { it.containsKey(SECURITY_SCHEME_JWT) }) { - break - } - - // 添加 security scheme - operation.security.add(SecurityRequirement().addList(SECURITY_SCHEME_JWT)) - break - } - } - operation - } - } - - private fun docInfos() = Info() - .title(title) - .description(description) - .version(version) - .license( - License() - .name("GNU Affero General Public License v3.0") - .url("https://www.gnu.org/licenses/agpl-3.0.html") - ) - - @Bean - fun modelResolver(objectMapper: ObjectMapper?) = ModelResolver(objectMapper) + fun modelResolver(objectMapper: ObjectMapper) = ModelResolver(objectMapper) companion object { const val SECURITY_SCHEME_JWT: String = "Jwt" From 3c59af5a1b5f48cf9a512962f5f0511f48f18748 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Sat, 24 Feb 2024 23:36:14 +0800 Subject: [PATCH 163/168] refactor: remove `EmailBusinessObject` --- .../backend/common/bo/EmailBusinessObject.kt | 181 ------------------ .../backend/common/utils/FreeMarkerUtils.kt | 2 +- .../plus/maa/backend/service/EmailService.kt | 108 +++++------ .../ftlh/mail-comment-notification.ftlh | 4 +- 4 files changed, 48 insertions(+), 247 deletions(-) delete mode 100644 src/main/kotlin/plus/maa/backend/common/bo/EmailBusinessObject.kt diff --git a/src/main/kotlin/plus/maa/backend/common/bo/EmailBusinessObject.kt b/src/main/kotlin/plus/maa/backend/common/bo/EmailBusinessObject.kt deleted file mode 100644 index 87c1c259..00000000 --- a/src/main/kotlin/plus/maa/backend/common/bo/EmailBusinessObject.kt +++ /dev/null @@ -1,181 +0,0 @@ -package plus.maa.backend.common.bo - -import cn.hutool.extra.mail.MailAccount -import cn.hutool.extra.mail.MailUtil -import io.github.oshai.kotlinlogging.KotlinLogging -import plus.maa.backend.common.utils.FreeMarkerUtils -import java.io.File -import kotlin.collections.ArrayList -import kotlin.collections.Collection -import kotlin.collections.MutableList -import kotlin.collections.MutableMap -import kotlin.collections.set - -private val log = KotlinLogging.logger { } - -/** - * @author LoMu - * Date 2022-12-23 23:57 - */ -class EmailBusinessObject( - // 发件人信息 - private val mailAccount: MailAccount, - // 自定义标题 - private val title: String = DEFAULT_TITLE_PREFIX, - // 邮件内容 - private val message: String? = null, - // html标签是否被识别使用 - private val isHtml: Boolean = true, - -) { - - private val emailList: MutableList = ArrayList() - - fun setEmail(email: String): EmailBusinessObject { - emailList.add(email) - return this - } - - /** - * 发送自定义信息 - * - * @param content 邮件动态内容 - * @param templateName ftlh名称,例如 mail.ftlh - */ - fun sendCustomStaticTemplates(content: String?, templateName: String?) { - sendCustomStaticTemplatesFiles(content, templateName) - } - - /** - * 通过默认模板发送自定义Message内容 - */ - fun sendCustomMessage() { - sendCustomStaticTemplates(message, DEFAULT_MAIL_TEMPLATE) - } - - /** - * 通过默认模板发送自定义Message内容和附件 - * - * @param files 附件 - */ - fun sendCustomMessageFiles(vararg files: File?) { - sendCustomStaticTemplatesFiles(message, DEFAULT_MAIL_TEMPLATE, *files) - } - - - /** - * 发送自定义带文件的邮件 - * - * @param content 邮件动态内容 - * @param templateName ftl路径 - * @param files 附件 - */ - fun sendCustomStaticTemplatesFiles(content: String?, templateName: String?, vararg files: File?) { - try { - log.info { - "send email to: $emailList, templateName: $templateName, content: $content" - } - send(this.mailAccount, emailList, title, parseMessages(content, templateName), isHtml, *files) - } catch (ex: Exception) { - throw RuntimeException(ex) - } - } - - - /** - * 发送验证码 - */ - fun sendVerificationCodeMessage(code: String) { - try { - send( - this.mailAccount, this.emailList, - this.title + " 验证码", - defaultMailIncludeHtmlTemplates( - "mail-vCode.ftlh", code - ), - this.isHtml - ) - } catch (ex: Exception) { - throw RuntimeException("邮件发送失败", ex) - } - } - - fun sendCommentNotification(map: MutableMap) { - try { - send( - this.mailAccount, - this.emailList, - this.title, - defaultMailIncludeHtmlTemplates("mail-comment-notification.ftlh", map), - this.isHtml - ) - } catch (ex: Exception) { - throw RuntimeException("邮件发送失败", ex) - } - } - - private fun defaultMailIncludeHtmlTemplates(content: String, obj: String): String { - return parseMessages(content, obj, DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE) - } - - private fun defaultMailIncludeHtmlTemplates(content: String, map: MutableMap): String { - return parseMessages(content, DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE, map) - } - - - /** - * @param content 自定义内容 - * @param templateName ftlh路径 - * @return String - */ - private fun parseMessages(content: String?, templateName: String?): String { - return FreeMarkerUtils.parseData(mapOf("content" to content), templateName) - } - - /** - * ftlh多个参数下 - * - * @param content 邮件内嵌ftlh路径 - * @return String - */ - private fun parseMessages(content: String, templateName: String, map: MutableMap): String { - map["content"] = content - return FreeMarkerUtils.parseData(map, templateName) - } - - private fun parseMessages(content: String, obj: String, templateName: String): String { - return FreeMarkerUtils.parseData(mapOf("content" to content, "obj" to obj), templateName) - } - - - /** - * 发送邮件给多人 - * - * @param mailAccount 邮件帐户信息 - * @param tos 收件人列表 - * @param subject 标题 - * @param content 正文 - * @param isHtml 是否为HTML格式 - * @param files 附件列表 - */ - private fun send( - mailAccount: MailAccount?, - tos: Collection, - subject: String, - content: String, - isHtml: Boolean, - vararg files: File? - ) { - MailUtil.send(mailAccount, tos, null, null, subject, content, null, isHtml, *files) - } - - companion object { - // 默认邮件模板 - private const val DEFAULT_MAIL_TEMPLATE = "mail.ftlh" - - - private const val DEFAULT_MAIL_INCLUDE_HTML_TEMPLATE = "mail-includeHtml.ftlh" - - private const val DEFAULT_TITLE_PREFIX = "Maa Backend Center" - } -} diff --git a/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt b/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt index 80f83b97..8ac47eb0 100644 --- a/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt +++ b/src/main/kotlin/plus/maa/backend/common/utils/FreeMarkerUtils.kt @@ -20,7 +20,7 @@ object FreeMarkerUtils { cfg.setEncoding(Locale.CHINA, StandardCharsets.UTF_8.name()) } - fun parseData(dataModel: Any?, templateName: String?): String { + fun parseData(templateName: String, dataModel: Any?): String { try { val template = cfg.getTemplate(templateName) val sw = StringWriter() diff --git a/src/main/kotlin/plus/maa/backend/service/EmailService.kt b/src/main/kotlin/plus/maa/backend/service/EmailService.kt index f4d7f68d..fbd52f8b 100644 --- a/src/main/kotlin/plus/maa/backend/service/EmailService.kt +++ b/src/main/kotlin/plus/maa/backend/service/EmailService.kt @@ -1,31 +1,26 @@ package plus.maa.backend.service import cn.hutool.extra.mail.MailAccount +import cn.hutool.extra.mail.MailUtil import io.github.oshai.kotlinlogging.KotlinLogging -import jakarta.annotation.PostConstruct import jakarta.annotation.Resource import org.apache.commons.lang3.RandomStringUtils import org.springframework.beans.factory.annotation.Value import org.springframework.core.task.AsyncTaskExecutor -import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Service -import plus.maa.backend.common.bo.EmailBusinessObject +import plus.maa.backend.common.utils.FreeMarkerUtils import plus.maa.backend.config.external.MaaCopilotProperties import plus.maa.backend.controller.response.MaaResultException import plus.maa.backend.repository.RedisCache import plus.maa.backend.service.model.CommentNotification import java.util.* -private val log = KotlinLogging.logger { } - /** * @author LoMu * Date 2022-12-24 11:05 */ @Service class EmailService( - @Value("\${maa-copilot.vcode.expire:600}") - private val expire: Int, private val maaCopilotProperties: MaaCopilotProperties, @Value("\${debug.email.no-send:false}") private val flagNoSend: Boolean = false, @@ -33,27 +28,16 @@ class EmailService( @Resource(name = "emailTaskExecutor") private val emailTaskExecutor: AsyncTaskExecutor ) { - - private val mainAccount = MailAccount() - - - /** - * 初始化邮件账户信息 - */ - @PostConstruct - private fun initMailAccount() { - val mail = maaCopilotProperties.mail - mainAccount - .setHost(mail.host) - .setPort(mail.port) - .setFrom(mail.from) - .setUser(mail.user) - .setPass(mail.pass) - .setSslEnable(mail.ssl) - .setStarttlsEnable(mail.starttls) - - log.info { "邮件账户信息初始化完成: $mainAccount" } - } + private val log = KotlinLogging.logger { } + private val mail = maaCopilotProperties.mail + private val mailAccount = MailAccount() + .setHost(mail.host) + .setPort(mail.port) + .setFrom(mail.from) + .setUser(mail.user) + .setPass(mail.pass) + .setSslEnable(mail.ssl) + .setStarttlsEnable(mail.starttls) /** * 发送验证码 @@ -64,8 +48,8 @@ class EmailService( */ fun sendVCode(email: String) { // 一个过期周期最多重发十条,记录已发送的邮箱以及间隔时间 - val timeout = expire / 10 - if (!redisCache.setCacheIfAbsent("HasBeenSentVCode:$email", timeout, timeout.toLong())) { + val timeout = maaCopilotProperties.vcode.expire / 10 + if (!redisCache.setCacheIfAbsent("HasBeenSentVCode:$email", timeout, timeout)) { // 设置失败,说明 key 已存在 throw MaaResultException(403, String.format("发送验证码的请求至少需要间隔 %d 秒", timeout)) } @@ -73,21 +57,22 @@ class EmailService( asyncSendVCode(email) } - private fun asyncSendVCode(email: String) { - emailTaskExecutor.execute { - // 6位随机数验证码 - val vcode = RandomStringUtils.random(6, true, true).uppercase(Locale.getDefault()) - if (flagNoSend) { - log.debug { "vcode is $vcode" } - log.warn { "Email not sent, no-send enabled" } - } else { - EmailBusinessObject( - mailAccount = mainAccount - ).setEmail(email).sendVerificationCodeMessage(vcode) - } - // 存redis - redisCache.setCache("vCodeEmail:$email", vcode, expire.toLong()) + private fun asyncSendVCode(email: String) = emailTaskExecutor.execute { + // 6位随机数验证码 + val vCode = RandomStringUtils.random(6, true, true).uppercase(Locale.getDefault()) + if (flagNoSend) { + log.warn { "Email not sent, no-send enabled, vcode is $vCode" } + } else { + val subject = "Maa Backend Center 验证码" + val dataModel = mapOf( + "content" to "mail-vCode.ftlh", + "obj" to vCode, + ) + val content = FreeMarkerUtils.parseData("mail-includeHtml.ftlh", dataModel) + MailUtil.send(mailAccount, listOf(email), subject, content, true) } + // 存redis + redisCache.setCache("vCodeEmail:$email", vCode, maaCopilotProperties.vcode.expire) } /** @@ -102,27 +87,24 @@ class EmailService( } } - @Async("emailTaskExecutor") - fun sendCommentNotification(email: String, commentNotification: CommentNotification) { + fun sendCommentNotification(email: String, commentNotification: CommentNotification) = emailTaskExecutor.execute { val limit = 25 - - var title = commentNotification.title ?: "" - if (title.isNotBlank()) { - if (title.length > limit) { - title = title.substring(0, limit) + "...." - } + val title = (commentNotification.title ?: "").let { + if (it.length > limit) it.substring(0, limit - 4) + "...." else it } - val map: MutableMap = HashMap() - map["authorName"] = commentNotification.authorName - map["forntEndLink"] = maaCopilotProperties.info.frontendDomain - map["reName"] = commentNotification.reName - map["date"] = commentNotification.date - map["title"] = title - map["reMessage"] = commentNotification.reMessage - EmailBusinessObject( - mailAccount = mainAccount, - title = "收到新回复 来自用户@" + commentNotification.reName + " Re: " + map["title"] - ).setEmail(email).sendCommentNotification(map) + val subject = "收到新回复 来自用户@${commentNotification.reName} Re: $title" + val dataModel = mapOf( + "content" to "mail-comment-notification.ftlh", + "authorName" to commentNotification.authorName, + "frontendLink" to maaCopilotProperties.info.frontendDomain, + "reName" to commentNotification.reName, + "date" to commentNotification.date, + "title" to title, + "reMessage" to commentNotification.reMessage, + ) + val content = FreeMarkerUtils.parseData("mail-includeHtml.ftlh", dataModel) + + MailUtil.send(mailAccount, listOf(email), subject, content, true) } } diff --git a/src/main/resources/static/templates/ftlh/mail-comment-notification.ftlh b/src/main/resources/static/templates/ftlh/mail-comment-notification.ftlh index 1de4e5e7..67efeb01 100644 --- a/src/main/resources/static/templates/ftlh/mail-comment-notification.ftlh +++ b/src/main/resources/static/templates/ftlh/mail-comment-notification.ftlh @@ -1,6 +1,6 @@ -

Hi,${authorName}

+

Hi, ${authorName}

- 在Maa Copilot + 在Maa Copilot 收到了${reName}新回复${date}

From 7966ea85b63573473cc03e03373411219becbc91 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Tue, 27 Feb 2024 23:12:43 +0800 Subject: [PATCH 164/168] doc: update README.md --- README.md | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 389347e5..36ee338d 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ # MaaBackendCenter -使用 Java 重写的 MAA 作业服务器后端 +使用 Kotlin(Java) 重写的 MAA 作业服务器后端 ## 开发技术栈 -- Java 17 +- kotlin 1.9 (Java 21) - SpringBoot 3 - spring-security - springdoc-openapi @@ -12,31 +12,30 @@ - Redis ## 本地开发指南 - -1. 下载安装 jdk 17 或者以上版本的 jdk,可以考虑从 [zuluJDK](https://www.azul.com/downloads/?version=java-17-lts&package=jdk) 或者 [libreicaJDK](https://bell-sw.com/pages/downloads/#/java-17-lts) 下载安装 -2. 你需要一个有redis和mongoDB的环境,如果你是windows用户,可以从 https://github.com/tporadowski/redis 中下载版本较旧的 redis 使用 -3. 使用你喜欢的 IDE 导入此项目,修改 /src/main/resources/application-template.yml 中的数据库配置以符合你自己配置的环境 -4. 运行 MainApplication 类里的 main 方法 -5. 首次运行建议修改 ArkLevelSyncTask 类的scheduled注解的参数,这样可以将明日方舟中的关卡数据同步到你本地的 mongodb 中,为了防止反复调用造成调试的麻烦,建议首次运行同步成功后再将代码修改回去 +1. 使用你喜欢的 IDE 导入此项目,修改 /src/main/resources/application-template.yml 中的数据库配置以符合你自己配置的环境 +2. 下载安装 JDK 21 或者以上版本的 jdk,可以考虑从 [zuluJDK](https://www.azul.com/downloads/?version=java-17-lts&package=jdk) 或者 [libreicaJDK](https://bell-sw.com/pages/downloads/#/java-17-lts) 下载安装。 Jetbrains Idea 可以使用自带的 JDK 管理器进行下载。 +3. 你需要一个有redis和mongoDB的环境,如果你是windows用户,可以从 https://github.com/tporadowski/redis 中下载版本较旧的 redis 使用。 您也可以直接使用 `./dev-docker/docker-compose.yml` 来启动 docker 服务。 +4. 运行 `./gradlew bootRun`, windows 环境为 `./gradlew.bat bootRun` +5. 首次运行建议修改 ArkLevelSyncTask 类的 scheduled 注解的参数,这样可以将明日方舟中的关卡数据同步到你本地的 mongodb 中,为了防止反复调用造成调试的麻烦,建议首次运行同步成功后再将代码修改回去 ## 项目结构 -- config 存放spring配置 -- controller 交互层 - - request 入参类型 - - response 响应类型 -- repository 数据仓库层,用于和数据库交互 - - entity 与数据库字段对应的类型 -- service 业务处理层,复杂或者公用逻辑放在这里(注:您无需为每个类型都提供对应接口,只有当接口在可见未来有多个实现的时候才考虑建立接口) - - model 应用内传输用类型放这里 -- utils 工具类 +- config # 存放 spring 配置 +- common # 共享的逻辑 +- controller # 交互层 + - request # 入参类型 + - response # 响应类型 +- repository # 数据仓库层,用于和数据库交互 + - entity # 与数据库字段对应的类型 +- service # 业务处理层,复杂或者公用逻辑放在这里(注:您无需为每个类型都提供对应接口,只有当接口在可见未来有多个实现的时候才考虑建立接口) + - model # 应用内传输用类型放这里 ## 编译与部署 -1. 安装 jdk17,可以考虑从 [zuluJDK](https://www.azul.com/downloads/?version=java-17-lts&package=jdk) 或者 [libreicaJDK](https://bell-sw.com/pages/downloads/#/java-17-lts) 下载 +1. 安装 JDK 21,可以考虑从 [zuluJDK](https://www.azul.com/downloads/?version=java-17-lts&package=jdk) 或者 [libreicaJDK](https://bell-sw.com/pages/downloads/#/java-17-lts) 下载 2. clone 此项目 `git clone https://github.com/MaaAssistantArknights/MaaBackendCenter.git` 3. 进入此项目目录 `cd MaaBackendCenter` -4. 编译项目 `./gradlew bootJar -x processAot`,windows环境下请使用 `gradlew.bat bootJar -x processAot` +4. 编译项目 `./gradlew bootJar -x processAot`,windows 环境下请使用 `gradlew.bat bootJar -x processAot` 5. 获得编译后的 jar 文件 `cp ./build/libs/MaaBackendCenter-1.0-SNAPSHOT.jar .` 6. 复制一份配置文件 `cp ./build/resources/main/application-template.yml ./application-prod.yml` 7. 修改配置文件 `application-prod.yml` @@ -45,7 +44,7 @@ ## native 编译(暂时废弃,如果希望协助维护,请查看native分支) 1. 安装 [GraalVM](https://github.com/graalvm/graalvm-ce-builds/releases) - Java17,并配置好环境变量,部分功能需要正确配置 `JAVA_HOME` 变量为 GraalVM 安装目录才能正常使用 + Java21,并配置好环境变量,部分功能需要正确配置 `JAVA_HOME` 变量为 GraalVM 安装目录才能正常使用 2. 如果您处于 Windows 环境下,需要安装 `Visual Studio` 并且安装 C++ 组件,Linux 环境下则需要安装 `gcc` 工具链,Mac 下需要安装 `xcode` 工具链,详情查看 [native-image#prerequisites](https://www.graalvm.org/22.3/reference-manual/native-image/#prerequisites) From 03c94bd964b1801d0da58cdc5cb7dba074fd9687 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Thu, 29 Feb 2024 22:48:23 +0800 Subject: [PATCH 165/168] fix: type of GithubTree#url --- .../plus/maa/backend/repository/entity/github/GithubTree.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/plus/maa/backend/repository/entity/github/GithubTree.kt b/src/main/kotlin/plus/maa/backend/repository/entity/github/GithubTree.kt index 699777cc..97595811 100644 --- a/src/main/kotlin/plus/maa/backend/repository/entity/github/GithubTree.kt +++ b/src/main/kotlin/plus/maa/backend/repository/entity/github/GithubTree.kt @@ -8,5 +8,5 @@ data class GithubTree ( val mode: String, val type: String, val sha: String, - val url: String + val url: String? ) From 3d192879f2dc5db3ea4479b2d47efa78cb983970 Mon Sep 17 00:00:00 2001 From: Handiwork Date: Thu, 29 Feb 2024 22:48:45 +0800 Subject: [PATCH 166/168] fix: jwt type checking --- .../controller/response/user/MaaLoginRsp.kt | 10 +-- .../plus/maa/backend/service/UserService.kt | 2 +- .../maa/backend/service/jwt/JwtAuthToken.kt | 12 ++-- .../backend/service/jwt/JwtRefreshToken.kt | 10 +-- .../maa/backend/service/jwt/JwtService.kt | 24 +++---- .../plus/maa/backend/service/jwt/JwtToken.kt | 68 +++++++------------ 6 files changed, 53 insertions(+), 73 deletions(-) diff --git a/src/main/kotlin/plus/maa/backend/controller/response/user/MaaLoginRsp.kt b/src/main/kotlin/plus/maa/backend/controller/response/user/MaaLoginRsp.kt index aab4ac31..9e98b05f 100644 --- a/src/main/kotlin/plus/maa/backend/controller/response/user/MaaLoginRsp.kt +++ b/src/main/kotlin/plus/maa/backend/controller/response/user/MaaLoginRsp.kt @@ -1,13 +1,13 @@ package plus.maa.backend.controller.response.user -import java.time.LocalDateTime +import java.time.Instant data class MaaLoginRsp( val token: String, - val validBefore: LocalDateTime, - val validAfter: LocalDateTime, + val validBefore: Instant, + val validAfter: Instant, val refreshToken: String, - val refreshTokenValidBefore: LocalDateTime, - val refreshTokenValidAfter: LocalDateTime, + val refreshTokenValidBefore: Instant, + val refreshTokenValidAfter: Instant, val userInfo: MaaUserInfo ) diff --git a/src/main/kotlin/plus/maa/backend/service/UserService.kt b/src/main/kotlin/plus/maa/backend/service/UserService.kt index f5aa4211..a8fd5cff 100644 --- a/src/main/kotlin/plus/maa/backend/service/UserService.kt +++ b/src/main/kotlin/plus/maa/backend/service/UserService.kt @@ -53,7 +53,7 @@ class UserService( userRepository.save(user) val authorities = userDetailService.collectAuthoritiesFor(user) - val authToken = jwtService.issueAuthToken(user.userId, null, authorities) + val authToken = jwtService.issueAuthToken(user.userId!!, null, authorities) val refreshToken = jwtService.issueRefreshToken(user.userId, jwtId) return MaaLoginRsp( diff --git a/src/main/kotlin/plus/maa/backend/service/jwt/JwtAuthToken.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtAuthToken.kt index 9aa42f22..ad47fbc7 100644 --- a/src/main/kotlin/plus/maa/backend/service/jwt/JwtAuthToken.kt +++ b/src/main/kotlin/plus/maa/backend/service/jwt/JwtAuthToken.kt @@ -4,7 +4,7 @@ import org.springframework.security.core.Authentication import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority import org.springframework.util.StringUtils -import java.time.LocalDateTime +import java.time.Instant /** * 基于 JWT 的 AuthToken. 本类实现了 Authentication, 可直接用于 Spring Security @@ -20,14 +20,14 @@ class JwtAuthToken : JwtToken, Authentication { * @param key 签名密钥 * @throws JwtInvalidException jwt 未通过签名验证或不符合要求 */ - constructor(jwt: String?, key: ByteArray?) : super(jwt, TYPE, key) + constructor(jwt: String, key: ByteArray) : super(jwt, TYPE, key) constructor( sub: String, jti: String?, - iat: LocalDateTime, - exp: LocalDateTime, - nbf: LocalDateTime, + iat: Instant, + exp: Instant, + nbf: Instant, authorities: Collection, key: ByteArray ) : super(sub, jti, iat, exp, nbf, TYPE, key) { @@ -53,7 +53,7 @@ class JwtAuthToken : JwtToken, Authentication { * @inheritDoc */ override fun getCredentials(): Any { - return jwtId + return jwtId!! } override fun getDetails(): Any? { diff --git a/src/main/kotlin/plus/maa/backend/service/jwt/JwtRefreshToken.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtRefreshToken.kt index 8b905578..c85c817c 100644 --- a/src/main/kotlin/plus/maa/backend/service/jwt/JwtRefreshToken.kt +++ b/src/main/kotlin/plus/maa/backend/service/jwt/JwtRefreshToken.kt @@ -1,6 +1,6 @@ package plus.maa.backend.service.jwt -import java.time.LocalDateTime +import java.time.Instant class JwtRefreshToken : JwtToken { /** @@ -10,14 +10,14 @@ class JwtRefreshToken : JwtToken { * @param key 签名密钥 * @throws JwtInvalidException jwt 未通过签名验证或不符合要求 */ - constructor(token: String?, key: ByteArray?) : super(token, TYPE, key) + constructor(token: String, key: ByteArray) : super(token, TYPE, key) constructor( sub: String, jti: String?, - iat: LocalDateTime, - exp: LocalDateTime, - nbf: LocalDateTime, + iat: Instant, + exp: Instant, + nbf: Instant, key: ByteArray ) : super(sub, jti, iat, exp, nbf, TYPE, key) diff --git a/src/main/kotlin/plus/maa/backend/service/jwt/JwtService.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtService.kt index 90c562d8..328492d0 100644 --- a/src/main/kotlin/plus/maa/backend/service/jwt/JwtService.kt +++ b/src/main/kotlin/plus/maa/backend/service/jwt/JwtService.kt @@ -3,7 +3,7 @@ package plus.maa.backend.service.jwt import org.springframework.security.core.GrantedAuthority import org.springframework.stereotype.Service import plus.maa.backend.config.external.MaaCopilotProperties -import java.time.LocalDateTime +import java.time.Instant /** * 基于 Jwt 的 token 服务。 可直接用于 stateless 情境下的签发和认证, 或结合数据库进行状态管理。 @@ -22,10 +22,10 @@ class JwtService(properties: MaaCopilotProperties) { * @param authorities 授予的权限 * @return JwtAuthToken */ - fun issueAuthToken(subject: String?, jwtId: String?, authorities: Collection): JwtAuthToken { - val now = LocalDateTime.now() + fun issueAuthToken(subject: String, jwtId: String?, authorities: Collection): JwtAuthToken { + val now = Instant.now() val expireAt = now.plusSeconds(jwtProperties.expire) - return JwtAuthToken(subject!!, jwtId, now, expireAt, now, authorities, key) + return JwtAuthToken(subject, jwtId, now, expireAt, now, authorities, key) } /** @@ -37,9 +37,9 @@ class JwtService(properties: MaaCopilotProperties) { * @throws JwtExpiredException jwt未生效或者已过期 */ @Throws(JwtInvalidException::class, JwtExpiredException::class) - fun verifyAndParseAuthToken(authToken: String?): JwtAuthToken { + fun verifyAndParseAuthToken(authToken: String): JwtAuthToken { val token = JwtAuthToken(authToken, key) - token.validateDate(LocalDateTime.now()) + token.validateDate(Instant.now()) token.isAuthenticated = true return token } @@ -51,10 +51,10 @@ class JwtService(properties: MaaCopilotProperties) { * @param jwtId jwt 的 id, 一般用于 stateful 场景下 * @return JwtAuthToken */ - fun issueRefreshToken(subject: String?, jwtId: String?): JwtRefreshToken { - val now = LocalDateTime.now() + fun issueRefreshToken(subject: String, jwtId: String?): JwtRefreshToken { + val now = Instant.now() val expireAt = now.plusSeconds(jwtProperties.refreshExpire) - return JwtRefreshToken(subject!!, jwtId, now, expireAt, now, key) + return JwtRefreshToken(subject, jwtId, now, expireAt, now, key) } /** @@ -65,7 +65,7 @@ class JwtService(properties: MaaCopilotProperties) { * @return 新的 RefreshToken */ fun newRefreshToken(old: JwtRefreshToken, jwtId: String?): JwtRefreshToken { - val now = LocalDateTime.now() + val now = Instant.now() return JwtRefreshToken(old.subject, jwtId, now, old.expiresAt, now, key) } @@ -78,9 +78,9 @@ class JwtService(properties: MaaCopilotProperties) { * @throws JwtExpiredException jwt未生效或者已过期 */ @Throws(JwtInvalidException::class, JwtExpiredException::class) - fun verifyAndParseRefreshToken(refreshToken: String?): JwtRefreshToken { + fun verifyAndParseRefreshToken(refreshToken: String): JwtRefreshToken { val token = JwtRefreshToken(refreshToken, key) - token.validateDate(LocalDateTime.now()) + token.validateDate(Instant.now()) return token } } diff --git a/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt b/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt index f8fb906f..f87a5910 100644 --- a/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt +++ b/src/main/kotlin/plus/maa/backend/service/jwt/JwtToken.kt @@ -5,8 +5,6 @@ import cn.hutool.jwt.JWT import cn.hutool.jwt.JWTUtil import cn.hutool.jwt.RegisteredPayload import java.time.Instant -import java.time.LocalDateTime -import java.time.OffsetDateTime import java.util.* /** @@ -17,65 +15,50 @@ open class JwtToken { private val payload: JSONObject - constructor(token: String?, requiredType: String, key: ByteArray?) { + constructor(token: String, requiredType: String, key: ByteArray) { if (!JWTUtil.verify(token, key)) throw JwtInvalidException() this.jwt = JWTUtil.parseToken(token) jwt.setKey(key) this.payload = jwt.payloads // jwtId is nullable - if (requiredType != type) throw JwtInvalidException() + if (requiredType != type + || payload.getStr(RegisteredPayload.SUBJECT) == null + || payload.getLong(RegisteredPayload.ISSUED_AT) == null + || payload.getLong(RegisteredPayload.EXPIRES_AT) == null + || payload.getLong(RegisteredPayload.NOT_BEFORE) == null + ) throw JwtInvalidException() } constructor( sub: String?, jti: String?, - iat: LocalDateTime, - exp: LocalDateTime, - nbf: LocalDateTime, + iat: Instant, + exp: Instant, + nbf: Instant, typ: String?, - key: ByteArray? + key: ByteArray ) { jwt = JWT.create() jwt.setPayload(RegisteredPayload.SUBJECT, sub) jwt.setPayload(RegisteredPayload.JWT_ID, jti) - jwt.setPayload(RegisteredPayload.ISSUED_AT, iat.toInstant(OffsetDateTime.now().offset).toEpochMilli()) - jwt.setPayload(RegisteredPayload.EXPIRES_AT, exp.toInstant(OffsetDateTime.now().offset).toEpochMilli()) - jwt.setPayload(RegisteredPayload.NOT_BEFORE, nbf.toInstant(OffsetDateTime.now().offset).toEpochMilli()) + jwt.setPayload(RegisteredPayload.ISSUED_AT, iat.toEpochMilli()) + jwt.setPayload(RegisteredPayload.EXPIRES_AT, exp.toEpochMilli()) + jwt.setPayload(RegisteredPayload.NOT_BEFORE, nbf.toEpochMilli()) jwt.setPayload(CLAIM_TYPE, typ) jwt.setKey(key) payload = jwt.payloads } + val subject: String get() = payload.getStr(RegisteredPayload.SUBJECT) - val subject: String - get() = payload.getStr(RegisteredPayload.SUBJECT) + val jwtId: String? get() = payload.getStr(RegisteredPayload.JWT_ID) + val issuedAt: Instant get() = Instant.ofEpochMilli(payload.getLong(RegisteredPayload.ISSUED_AT)) - val jwtId: String - get() = payload.getStr(RegisteredPayload.JWT_ID) - - - val issuedAt: LocalDateTime - get() = LocalDateTime.ofInstant( - Instant.ofEpochMilli(payload.getLong(RegisteredPayload.ISSUED_AT)), - TimeZone.getDefault().toZoneId() - ) - - - val expiresAt: LocalDateTime - get() = LocalDateTime.ofInstant( - Instant.ofEpochMilli(payload.getLong(RegisteredPayload.EXPIRES_AT)), - TimeZone.getDefault().toZoneId() - ) - - - val notBefore: LocalDateTime - get() = LocalDateTime.ofInstant( - Instant.ofEpochMilli(payload.getLong(RegisteredPayload.NOT_BEFORE)), - TimeZone.getDefault().toZoneId() - ) + val expiresAt: Instant get() = Instant.ofEpochMilli(payload.getLong(RegisteredPayload.EXPIRES_AT)) + val notBefore: Instant get() = Instant.ofEpochMilli(payload.getLong(RegisteredPayload.NOT_BEFORE)) var type: String? get() = payload.getStr(CLAIM_TYPE) @@ -83,16 +66,13 @@ open class JwtToken { payload[CLAIM_TYPE] = type } - val value: String - /** - * 生成 jwt 字符串 - * - * @return 签名后的 jwt 字符串 - */ - get() = jwt.sign() + /** + * 签名后的 jwt 字符串 + */ + val value: String get() = jwt.sign() @Throws(JwtExpiredException::class) - fun validateDate(moment: LocalDateTime) { + fun validateDate(moment: Instant) { if (!moment.isBefore(expiresAt)) throw JwtExpiredException("expired") if (moment.isBefore(notBefore)) throw JwtExpiredException("haven't take effect") } From 08edb42ae0edc2406ea70cfb5b1615bc55fb625a Mon Sep 17 00:00:00 2001 From: dragove Date: Sat, 2 Mar 2024 13:45:59 +0800 Subject: [PATCH 167/168] ci: add options for dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 75f496fc..8c5c8d02 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,4 +2,4 @@ FROM amazoncorretto:21-alpine as runner WORKDIR /app COPY ./build/libs/MaaBackendCenter*.jar /MaaBackendCenter.jar EXPOSE 7000-9000 -ENTRYPOINT ["java", "-jar", "/MaaBackendCenter.jar"] +ENTRYPOINT ["java", "-jar", "/MaaBackendCenter.jar", "${JAVA_OPTS}"] From 745605bdebea584f9f9ec38721eb557766aaf8fa Mon Sep 17 00:00:00 2001 From: dragove Date: Sat, 2 Mar 2024 14:34:20 +0800 Subject: [PATCH 168/168] ci: update dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8c5c8d02..b6abd98f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ FROM amazoncorretto:21-alpine as runner WORKDIR /app -COPY ./build/libs/MaaBackendCenter*.jar /MaaBackendCenter.jar +COPY ./build/libs/MaaBackendCenter*.jar /app/app.jar EXPOSE 7000-9000 -ENTRYPOINT ["java", "-jar", "/MaaBackendCenter.jar", "${JAVA_OPTS}"] +ENTRYPOINT ["java", "-jar", "app.jar", "${JAVA_OPTS}"]