diff --git a/src/main/java/io/oduck/api/domain/anime/controller/AnimeController.java b/src/main/java/io/oduck/api/domain/anime/controller/AnimeController.java index 27475ce9..e795a985 100644 --- a/src/main/java/io/oduck/api/domain/anime/controller/AnimeController.java +++ b/src/main/java/io/oduck/api/domain/anime/controller/AnimeController.java @@ -7,6 +7,8 @@ import io.oduck.api.domain.anime.entity.Quarter; import io.oduck.api.domain.anime.entity.Status; import io.oduck.api.domain.anime.service.AnimeService; +import io.oduck.api.domain.weekly.dto.WeeklyRes.WeeklyAnimeRes; +import io.oduck.api.domain.weekly.service.WeeklyAnimeService; import io.oduck.api.global.common.OrderDirection; import io.oduck.api.global.common.SliceResponse; import io.oduck.api.global.exception.BadRequestException; @@ -36,6 +38,7 @@ public class AnimeController { private final AnimeService animeService; + private final WeeklyAnimeService weeklyAnimeService; // 애니 검색 조회 @GetMapping @@ -67,6 +70,12 @@ public ResponseEntity getAnimesBySearchCondition( return ResponseEntity.ok(res); } + @GetMapping("/weekly") + public ResponseEntity getWeeklyAnimes() { + List weeklyAnime = weeklyAnimeService.getWeeklyAnime(); + return ResponseEntity.ok(weeklyAnime); + } + // 애니 아이디로 상세 조회 @GetMapping("/{animeId}") public ResponseEntity getAnimeById(@PathVariable Long animeId){ diff --git a/src/main/java/io/oduck/api/domain/anime/entity/Anime.java b/src/main/java/io/oduck/api/domain/anime/entity/Anime.java index 578d2c7a..f2f69746 100644 --- a/src/main/java/io/oduck/api/domain/anime/entity/Anime.java +++ b/src/main/java/io/oduck/api/domain/anime/entity/Anime.java @@ -1,6 +1,7 @@ package io.oduck.api.domain.anime.entity; import io.oduck.api.domain.series.entity.Series; +import io.oduck.api.domain.weekly.entity.WeeklyAnime; import io.oduck.api.global.audit.BaseEntity; import io.oduck.api.global.exception.BadRequestException; import jakarta.persistence.CascadeType; @@ -15,6 +16,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -35,16 +37,16 @@ public class Anime extends BaseEntity { @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; - @Column(nullable = false, length = 50) + @Column(nullable = false, length = 100) private String title; - @Column(nullable = false, length = 600) + @Column(nullable = false, length = 1000) private String summary; @Enumerated(EnumType.STRING) private BroadcastType broadcastType; - @Column(nullable = false) + @Column(nullable = true) private int episodeCount; @Column(nullable = true, length = 500) @@ -100,32 +102,55 @@ public class Anime extends BaseEntity { @Builder.Default private List animeGenres = new ArrayList<>(); + @OneToOne(mappedBy = "anime", cascade = CascadeType.PERSIST) + private WeeklyAnime weeklyAnime; + /** * 비즈니스 메소드 */ // 조회수 증가 public void increaseViewCount(){ viewCount++; + if (weeklyAnime == null) { + weeklyAnime = WeeklyAnime.createWeeklyAnime(this); + } + weeklyAnime.increaseViewCount(); } // 리뷰수 증가(짧은 리뷰, 장문 리뷰) public void increaseReviewCount(){ reviewCount++; + if (weeklyAnime == null) { + weeklyAnime = WeeklyAnime.createWeeklyAnime(this); + } + weeklyAnime.increaseReviewCount(); } // 리뷰수 감소(짧은 리뷰, 장문 리뷰) public void decreaseReviewCount(){ reviewCount--; + if (weeklyAnime == null) { + weeklyAnime = WeeklyAnime.createWeeklyAnime(this); + } + weeklyAnime.decreaseReviewCount(); } // 북마크수 증가 public void increaseBookmarkCount(){ bookmarkCount++; + if (weeklyAnime == null) { + weeklyAnime = WeeklyAnime.createWeeklyAnime(this); + } + weeklyAnime.increaseBookmarkCount(); } // 북마크수 감소 public void decreaseBookmarkCount(){ bookmarkCount--; + if (weeklyAnime == null) { + weeklyAnime = WeeklyAnime.createWeeklyAnime(this); + } + weeklyAnime.decreaseBookmarkCount(); } // 애니 공개 전환 @@ -257,6 +282,10 @@ public void updateAnimeGenre(List animeGenres) { } } + public void updateWeeklyAnime(WeeklyAnime weeklyAnime) { + this.weeklyAnime = weeklyAnime; + } + public void update(String title, String summary, BroadcastType broadcastType, int episodeCount, String thumbnail, int year, Quarter quarter, Rating rating, Status status, boolean isReleased, List animeOriginalAuthors, List animeStudios, diff --git a/src/main/java/io/oduck/api/domain/anime/service/AnimeServiceImpl.java b/src/main/java/io/oduck/api/domain/anime/service/AnimeServiceImpl.java index 2240e62c..18a58bfd 100644 --- a/src/main/java/io/oduck/api/domain/anime/service/AnimeServiceImpl.java +++ b/src/main/java/io/oduck/api/domain/anime/service/AnimeServiceImpl.java @@ -129,7 +129,7 @@ public void save(PostReq postReq) { } @Override - @Transactional(readOnly = true) + @Transactional public DetailResult getAnimeById(Long animeId) { Anime anime = animeRepository.findAnimeByConditions(animeId, true) diff --git a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustom.java b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustom.java index 4c76e509..d0ab378d 100644 --- a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustom.java +++ b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustom.java @@ -1,5 +1,10 @@ package io.oduck.api.domain.genre.repository; +import io.oduck.api.domain.genre.entity.Genre; +import java.util.List; + public interface GenreRepositoryCustom { + + List findAllByAnimeId(Long animeId); boolean existsByName(String name); } diff --git a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java index 56c4ef08..0cfed9cd 100644 --- a/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java +++ b/src/main/java/io/oduck/api/domain/genre/repository/GenreRepositoryCustomImpl.java @@ -1,9 +1,14 @@ package io.oduck.api.domain.genre.repository; +import static io.oduck.api.domain.anime.entity.QAnimeGenre.animeGenre; import static io.oduck.api.domain.genre.entity.QGenre.genre; import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; +import io.oduck.api.domain.anime.entity.QAnimeGenre; +import io.oduck.api.domain.genre.entity.Genre; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -13,6 +18,17 @@ public class GenreRepositoryCustomImpl implements GenreRepositoryCustom{ private final JPAQueryFactory queryFactory; + @Override + public List findAllByAnimeId(Long animeId) { + JPAQuery genreJPAQuery = queryFactory.select(genre) + .from(genre) + .join(animeGenre).on(animeGenre.anime.id.eq(animeId)) + .where( + genre.deletedAt.isNull() + ); + return genreJPAQuery.fetch(); + } + @Override public boolean existsByName(String name) { Integer fetchOne = queryFactory diff --git a/src/main/java/io/oduck/api/domain/review/dto/ShortReviewResDto.java b/src/main/java/io/oduck/api/domain/review/dto/ShortReviewResDto.java index 2ae3164f..e282f3d1 100644 --- a/src/main/java/io/oduck/api/domain/review/dto/ShortReviewResDto.java +++ b/src/main/java/io/oduck/api/domain/review/dto/ShortReviewResDto.java @@ -75,13 +75,14 @@ public static class ShortReviewResWithTitle implements EntityBased { private LocalDateTime createdAt; public static ShortReviewResWithTitle of(ShortReviewDslWithTitle shortReviewDsl) { + Integer score = shortReviewDsl.getScore(); return ShortReviewResWithTitle .builder() .reviewId(shortReviewDsl.getReviewId()) .animeId(shortReviewDsl.getAnimeId()) .title(shortReviewDsl.getTitle()) .thumbnail(shortReviewDsl.getThumbnail()) - .score(shortReviewDsl.getScore()) + .score(score != null ? score : -1) .content(shortReviewDsl.getContent()) .isSpoiler(shortReviewDsl.getIsSpoiler()) .likeCount(shortReviewDsl.getLikeCount()) @@ -92,7 +93,7 @@ public static ShortReviewResWithTitle of(ShortReviewDslWithTitle shortReviewDsl) @Override public String bringCursor(String property) { return switch (property) { - case "title" -> this.title + ", " + this.createdAt.toString(); + case "title" -> this.title; case "score" -> this.score.toString() + ", " + this.createdAt.toString(); default -> this.createdAt.toString(); }; diff --git a/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepositoryImpl.java b/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepositoryImpl.java index 6ce62d77..8c0253e2 100644 --- a/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepositoryImpl.java +++ b/src/main/java/io/oduck/api/domain/review/repository/ShortReviewRepositoryImpl.java @@ -142,6 +142,12 @@ private BooleanExpression cursorCondition(String cursor, Pageable pageable) { .or(starRating.score.loe(score) .and(shortReview.createdAt.lt(scoreCreateAt))); } + case "title": + if (direction == Direction.ASC) { + return anime.title.gt(cursor); + } else { + return anime.title.lt(cursor); + } default: if (direction == Direction.ASC) { return shortReview.createdAt.gt(LocalDateTime.parse(cursor)); @@ -160,6 +166,8 @@ private List sortPath(String property) { case "score": path.add(starRating); path.add(shortReview); + case "title": + path.add(anime); default: path.add(shortReview); } diff --git a/src/main/java/io/oduck/api/domain/review/service/ShortReviewServiceImpl.java b/src/main/java/io/oduck/api/domain/review/service/ShortReviewServiceImpl.java index c5b5f16a..67ada982 100644 --- a/src/main/java/io/oduck/api/domain/review/service/ShortReviewServiceImpl.java +++ b/src/main/java/io/oduck/api/domain/review/service/ShortReviewServiceImpl.java @@ -47,23 +47,23 @@ public void save(Long memberId, ShortReviewReq shortReviewReq) { //애니 입력 Anime anime = animeRepository.findByIdForUpdate(shortReviewReq.getAnimeId()) - .orElseThrow( - () -> new NotFoundException("Anime") - ); + .orElseThrow( + () -> new NotFoundException("Anime") + ); //회원 입력 Member member = memberRepository.findById(memberId) - .orElseThrow( - () -> new NotFoundException("Member") - ); + .orElseThrow( + () -> new NotFoundException("Member") + ); ShortReview shortReview = ShortReview - .builder() - .anime(anime) - .member(member) - .content(shortReviewReq.getContent()) - .hasSpoiler(shortReviewReq.isHasSpoiler()) - .build(); + .builder() + .anime(anime) + .member(member) + .content(shortReviewReq.getContent()) + .hasSpoiler(shortReviewReq.isHasSpoiler()) + .build(); anime.increaseReviewCount(); shortReviewRepository.save(shortReview); @@ -95,9 +95,9 @@ public SliceResponse getShortReviews(Long animeId, String cursor ); List res = shortReviews.getContent() - .stream() - .map(ShortReviewRes::of) - .toList(); + .stream() + .map(ShortReviewRes::of) + .toList(); return SliceResponse.of(shortReviews, res, sort.getSort()); } @@ -106,8 +106,8 @@ public SliceResponse getShortReviews(Long animeId, String cursor public ShortReviewCountRes getShortReviewCountByMemberId(Long memberId) { Long count = shortReviewRepository.countByMemberId(memberId); return ShortReviewCountRes.builder() - .count(count) - .build(); + .count(count) + .build(); } @Override @@ -118,7 +118,7 @@ public SliceResponse getShortReviewsByMemberId(Long mem sort.getSort() ); - if(sort.equals(SortForProfile.TITLE) || sort.equals(SortForProfile.SCORE)){ + if(sort.equals(SortForProfile.SCORE)){ sortList = sortList.and(Sort.by(Direction.DESC, "createdAt")); } @@ -146,9 +146,9 @@ public void update(Long memberId, Long reviewId, ShortReviewReq req) { Long findMemberId = findShortReview.getMember().getId(); Anime findAnime = animeRepository.findByIdForUpdate(req.getAnimeId()) - .orElseThrow( - () -> new NotFoundException("Anime") - ); + .orElseThrow( + () -> new NotFoundException("Anime") + ); findAnime.decreaseReviewCount(); //리뷰 작성자 인지 확인 @@ -170,8 +170,8 @@ public void update(Long memberId, Long reviewId, ShortReviewReq req) { private ShortReview getShortReview(Long reviewId){ return shortReviewRepository.findById(reviewId) - .orElseThrow( - () -> new NotFoundException("shortReview") - ); + .orElseThrow( + () -> new NotFoundException("shortReview") + ); } } \ No newline at end of file diff --git a/src/main/java/io/oduck/api/domain/weekly/dto/WeeklyDsl.java b/src/main/java/io/oduck/api/domain/weekly/dto/WeeklyDsl.java new file mode 100644 index 00000000..007e79db --- /dev/null +++ b/src/main/java/io/oduck/api/domain/weekly/dto/WeeklyDsl.java @@ -0,0 +1,21 @@ +package io.oduck.api.domain.weekly.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class WeeklyDsl { + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class WeeklyAnimeDsl { + private Long animeId; + private String title; + private String thumbnail; + private Long scoreTotal; + private Long scoreCount; + private Double rankScore; + } +} \ No newline at end of file diff --git a/src/main/java/io/oduck/api/domain/weekly/dto/WeeklyRes.java b/src/main/java/io/oduck/api/domain/weekly/dto/WeeklyRes.java new file mode 100644 index 00000000..20f29874 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/weekly/dto/WeeklyRes.java @@ -0,0 +1,41 @@ +package io.oduck.api.domain.weekly.dto; + +import io.oduck.api.domain.weekly.dto.WeeklyDsl.WeeklyAnimeDsl; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +public class WeeklyRes { + + @Getter + @Builder + @NoArgsConstructor + @AllArgsConstructor + public static class WeeklyAnimeRes { + private Long animeId; + private String title; + private String thumbnail; + private List genres; + private Double avgScore; + private Double rankScore; + + public static WeeklyAnimeRes of(WeeklyAnimeDsl weeklyAnimeDsl) { + + Double avgScore = weeklyAnimeDsl.getScoreCount() == 0 ? 0 : Double.valueOf(weeklyAnimeDsl.getScoreTotal()) / weeklyAnimeDsl.getScoreCount(); + return WeeklyAnimeRes.builder() + .animeId(weeklyAnimeDsl.getAnimeId()) + .title(weeklyAnimeDsl.getTitle()) + .thumbnail(weeklyAnimeDsl.getThumbnail()) + .avgScore(avgScore) + .rankScore(weeklyAnimeDsl.getRankScore()) + .build(); + } + + public WeeklyAnimeRes withGenres(List genres) { + this.genres = genres; + return this; + } + } +} diff --git a/src/main/java/io/oduck/api/domain/weekly/entity/WeeklyAnime.java b/src/main/java/io/oduck/api/domain/weekly/entity/WeeklyAnime.java new file mode 100644 index 00000000..c5b5d4b2 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/weekly/entity/WeeklyAnime.java @@ -0,0 +1,78 @@ +package io.oduck.api.domain.weekly.entity; + +import io.oduck.api.domain.anime.entity.Anime; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.OneToOne; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = lombok.AccessLevel.PROTECTED) +@AllArgsConstructor +public class WeeklyAnime { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "anime_id") + private Anime anime; + + @ColumnDefault("0") + @Builder.Default + private Long reviewCount = 0L; + + @ColumnDefault("0") + @Builder.Default + private Long bookmarkCount = 0L; + + @ColumnDefault("0") + @Builder.Default + private Long viewCount = 0L; + + @Builder + public WeeklyAnime(Anime anime) { + this.anime = anime; + anime.updateWeeklyAnime(this); + } + + public static WeeklyAnime createWeeklyAnime(Anime anime) { + return WeeklyAnime.builder() + .anime(anime) + .build(); + } + + public void increaseViewCount(){ + viewCount++; + } + + // 리뷰수 증가(짧은 리뷰, 장문 리뷰) + public void increaseReviewCount(){ + reviewCount++; + } + + // 리뷰수 감소(짧은 리뷰, 장문 리뷰) + public void decreaseReviewCount(){ + reviewCount--; + } + + // 북마크수 증가 + public void increaseBookmarkCount(){ + bookmarkCount++; + } + + // 북마크수 감소 + public void decreaseBookmarkCount(){ + bookmarkCount--; + } +} diff --git a/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepository.java b/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepository.java new file mode 100644 index 00000000..6a36759c --- /dev/null +++ b/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepository.java @@ -0,0 +1,8 @@ +package io.oduck.api.domain.weekly.repository; + +import io.oduck.api.domain.weekly.entity.WeeklyAnime; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface WeeklyAnimeRepository extends JpaRepository, WeeklyAnimeRepositoryCustom { + +} diff --git a/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepositoryCustom.java b/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepositoryCustom.java new file mode 100644 index 00000000..fc0e5ffa --- /dev/null +++ b/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepositoryCustom.java @@ -0,0 +1,9 @@ +package io.oduck.api.domain.weekly.repository; + +import io.oduck.api.domain.weekly.dto.WeeklyDsl; +import io.oduck.api.domain.weekly.dto.WeeklyDsl.WeeklyAnimeDsl; +import java.util.List; + +public interface WeeklyAnimeRepositoryCustom { + List getWeeklyAnime(); +} diff --git a/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepositoryCustomImpl.java b/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepositoryCustomImpl.java new file mode 100644 index 00000000..91e2f2b4 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/weekly/repository/WeeklyAnimeRepositoryCustomImpl.java @@ -0,0 +1,49 @@ +package io.oduck.api.domain.weekly.repository; + +import static io.oduck.api.domain.anime.entity.QAnime.anime; +import static io.oduck.api.domain.weekly.entity.QWeeklyAnime.weeklyAnime; + +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.impl.JPAQuery; +import com.querydsl.jpa.impl.JPAQueryFactory; +import io.oduck.api.domain.weekly.dto.WeeklyDsl.WeeklyAnimeDsl; +import java.util.List; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +@Slf4j +@Repository +@RequiredArgsConstructor +public class WeeklyAnimeRepositoryCustomImpl implements WeeklyAnimeRepositoryCustom{ + private final JPAQueryFactory query; + + @Override + public List getWeeklyAnime() { + JPAQuery jpaQuery = query + .select( + Projections.constructor( + WeeklyAnimeDsl.class, + anime.id, + anime.title, + anime.thumbnail, + anime.starRatingScoreTotal, + anime.starRatingCount, + anime.starRatingScoreTotal.doubleValue().divide(anime.starRatingCount).multiply(0.2) + .add(weeklyAnime.reviewCount.doubleValue().multiply(0.3)) + .add(weeklyAnime.bookmarkCount.doubleValue().multiply(0.3)) + .add(weeklyAnime.viewCount.doubleValue().multiply(0.2)) + .as("rankScore") + ) + ) + .from(weeklyAnime) + .leftJoin(anime) + .on(weeklyAnime.anime.id.eq(anime.id).and(anime.isReleased.isTrue()).and(anime.deletedAt.isNull())) + .groupBy(anime.id) + .limit(10) + .orderBy(Expressions.numberPath(Double.class, "rankScore").desc()); + + return jpaQuery.fetch(); + } +} diff --git a/src/main/java/io/oduck/api/domain/weekly/service/WeeklyAnimeService.java b/src/main/java/io/oduck/api/domain/weekly/service/WeeklyAnimeService.java new file mode 100644 index 00000000..1c05ef01 --- /dev/null +++ b/src/main/java/io/oduck/api/domain/weekly/service/WeeklyAnimeService.java @@ -0,0 +1,10 @@ +package io.oduck.api.domain.weekly.service; + +import io.oduck.api.domain.weekly.dto.WeeklyRes.WeeklyAnimeRes; +import java.util.List; + +public interface WeeklyAnimeService { + List getWeeklyAnime(); + + void reset(); +} diff --git a/src/main/java/io/oduck/api/domain/weekly/service/WeeklyAnimeServiceImpl.java b/src/main/java/io/oduck/api/domain/weekly/service/WeeklyAnimeServiceImpl.java new file mode 100644 index 00000000..f5f20e5a --- /dev/null +++ b/src/main/java/io/oduck/api/domain/weekly/service/WeeklyAnimeServiceImpl.java @@ -0,0 +1,44 @@ +package io.oduck.api.domain.weekly.service; + +import io.oduck.api.domain.genre.entity.Genre; +import io.oduck.api.domain.genre.repository.GenreRepository; +import io.oduck.api.domain.weekly.dto.WeeklyDsl.WeeklyAnimeDsl; +import io.oduck.api.domain.weekly.dto.WeeklyRes; +import io.oduck.api.domain.weekly.dto.WeeklyRes.WeeklyAnimeRes; +import io.oduck.api.domain.weekly.repository.WeeklyAnimeRepository; +import java.util.List; +import java.util.stream.Stream; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +@Slf4j +public class WeeklyAnimeServiceImpl implements WeeklyAnimeService{ + private final WeeklyAnimeRepository weeklyAnimeRepository; + private final GenreRepository genreRepository; + + @Override + public List getWeeklyAnime() { + List animeDsls = weeklyAnimeRepository.getWeeklyAnime(); + List animeRes = animeDsls.stream().map(WeeklyAnimeRes::of).toList(); + for (WeeklyAnimeRes a : animeRes) { + a.withGenres( + genreRepository.findAllByAnimeId(a.getAnimeId()).stream().map(Genre::getName) + .toList() + ); + } + return animeRes; + } + + @Override + public void reset() { + try{ + weeklyAnimeRepository.deleteAll(); + } catch (Exception e) { + log.error("Weekly anime delete all failed", e); + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/io/oduck/api/global/scheduler/weekly/WeeklyAnimeScheduled.java b/src/main/java/io/oduck/api/global/scheduler/weekly/WeeklyAnimeScheduled.java new file mode 100644 index 00000000..9a007d5e --- /dev/null +++ b/src/main/java/io/oduck/api/global/scheduler/weekly/WeeklyAnimeScheduled.java @@ -0,0 +1,35 @@ +package io.oduck.api.global.scheduler.weekly; + +import io.oduck.api.domain.weekly.repository.WeeklyAnimeRepository; +import io.oduck.api.domain.weekly.service.WeeklyAnimeService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Slf4j +@RequiredArgsConstructor +@Transactional +@Component +@EnableScheduling +public class WeeklyAnimeScheduled { + private final WeeklyAnimeService weeklyAnimeService; + + @Scheduled(cron = "0 0 4 * * MON") + public void resetWeeklyAnime() { + sleep(); + weeklyAnimeService.reset(); + log.info("Weekly anime reset complete"); + } + + private void sleep() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + log.error("스케쥴러 비정상", e); + throw new RuntimeException(e); + } + } +} diff --git a/src/main/java/io/oduck/api/global/utils/QueryDslUtils.java b/src/main/java/io/oduck/api/global/utils/QueryDslUtils.java index 35d3c9d0..5368d32c 100644 --- a/src/main/java/io/oduck/api/global/utils/QueryDslUtils.java +++ b/src/main/java/io/oduck/api/global/utils/QueryDslUtils.java @@ -68,7 +68,8 @@ private static List convertToDslOrder(Sort sort, List path private static OrderSpecifier createOrderSpecifier(Order order, Path parent, String fieldName) { // count 메소드 컬럼을 기준으로 할 때의 OrderSpecifier - if (fieldName.equals("quantity") || fieldName.equals("likeCount")) { + // enum 값을 돌면서 해당 enum이 존재하는지 확인하고 존재하면 해당 enum에 맞는 컬럼을 기준으로 정렬걸로 수정하기. + if (fieldName.equals("rankScore") || fieldName.equals("likeCount")) { NumberPath aliasQuantity = Expressions.numberPath(Long.class, fieldName); return new OrderSpecifier(order, aliasQuantity);