Skip to content

Commit

Permalink
Merge pull request #123 from jisung-in/feature/115-refactor-get-best-…
Browse files Browse the repository at this point in the history
…seller-api

[Refactor] 베스트 셀러 조회 API 리팩토링
  • Loading branch information
jwooo authored Jun 18, 2024
2 parents b3bc7ff + 89ab816 commit 4a6c90a
Show file tree
Hide file tree
Showing 27 changed files with 396 additions and 338 deletions.
13 changes: 7 additions & 6 deletions src/main/java/com/jisungin/api/book/BookController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@

import com.jisungin.api.ApiResponse;
import com.jisungin.api.book.request.BookCreateRequest;
import com.jisungin.api.book.request.BookPageRequest;
import com.jisungin.application.OffsetLimit;
import com.jisungin.application.PageResponse;
import com.jisungin.application.book.BestSellerService;
import com.jisungin.application.book.BookService;
import com.jisungin.application.book.response.BestSellerResponse;
import com.jisungin.application.book.response.BookResponse;
import com.jisungin.application.book.response.BookFindAllResponse;
import com.jisungin.application.book.response.BookResponse;
import com.jisungin.application.book.response.BookWithRankingResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand Down Expand Up @@ -44,8 +42,11 @@ public ApiResponse<PageResponse<BookFindAllResponse>> getBooks(
}

@GetMapping("/books/best-seller")
public ApiResponse<PageResponse<BestSellerResponse>> getBestSellers(@ModelAttribute BookPageRequest page) {
return ApiResponse.ok(bestSellerService.getBestSellers(page.toService()));
public ApiResponse<PageResponse<BookWithRankingResponse>> getBestSellers(
@RequestParam(required = false, defaultValue = "1") Integer page,
@RequestParam(required = false, defaultValue = "5") Integer size
) {
return ApiResponse.ok(bestSellerService.getBestSellers(OffsetLimit.ofRange(page, size)));
}

@PostMapping("/books")
Expand Down
30 changes: 0 additions & 30 deletions src/main/java/com/jisungin/api/book/request/BookPageRequest.java

This file was deleted.

7 changes: 7 additions & 0 deletions src/main/java/com/jisungin/application/OffsetLimit.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@ public static OffsetLimit of(Integer page, Integer size, String order) {
.build();
}

public static OffsetLimit ofRange(Integer page, Integer size) {
return OffsetLimit.builder()
.offset(calculateOffset(page, size))
.limit(page * size - 1)
.build();
}

private static Integer calculateOffset(Integer page, Integer size) {
return (max(1, page) - 1) * min(size, MAX_SIZE);
}
Expand Down
23 changes: 14 additions & 9 deletions src/main/java/com/jisungin/application/book/BestSellerService.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package com.jisungin.application.book;

import com.jisungin.application.OffsetLimit;
import com.jisungin.application.PageResponse;
import com.jisungin.application.book.event.BestSellerUpdatedEvent;
import com.jisungin.application.book.request.BookServicePageRequest;
import com.jisungin.application.book.response.BestSellerResponse;
import com.jisungin.application.book.response.BookWithRankingResponse;
import com.jisungin.domain.book.repository.BestSellerRepository;
import com.jisungin.infra.crawler.CrawledBook;
import com.jisungin.infra.crawler.Crawler;
import com.jisungin.infra.crawler.CrawlingBook;
import java.util.List;
import java.util.Map;
import lombok.RequiredArgsConstructor;
import org.springframework.context.ApplicationEventPublisher;
Expand All @@ -20,16 +21,20 @@ public class BestSellerService {
private final BestSellerRepository bestSellerRepository;
private final ApplicationEventPublisher eventPublisher;

public PageResponse<BestSellerResponse> getBestSellers(BookServicePageRequest page) {
return bestSellerRepository.findBestSellerByPage(page);
}
public PageResponse<BookWithRankingResponse> getBestSellers(OffsetLimit offsetLimit) {
List<BookWithRankingResponse> response = bestSellerRepository.findBooksWithRank(offsetLimit.getOffset(),
offsetLimit.getLimit());

Long count = bestSellerRepository.count();

return PageResponse.of(response.size(), count, response);
}

public void updateBestSellers() {
Map<Long, CrawlingBook> crawledBooks = crawler.crawlBestSellerBook();
Map<Long, CrawledBook> crawledBookMap = crawler.crawlBestSellerBook();

bestSellerRepository.updateAll(crawledBooks);
eventPublisher.publishEvent(new BestSellerUpdatedEvent(crawledBooks));
bestSellerRepository.updateAll(crawledBookMap);
eventPublisher.publishEvent(new BestSellerUpdatedEvent(crawledBookMap));
}

}
17 changes: 6 additions & 11 deletions src/main/java/com/jisungin/application/book/BookService.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@
import com.jisungin.application.OffsetLimit;
import com.jisungin.application.PageResponse;
import com.jisungin.application.book.request.BookCreateServiceRequest;
import com.jisungin.application.book.request.BookCreateServiceRequests;
import com.jisungin.application.book.response.BookFindAllResponse;
import com.jisungin.application.book.response.BookResponse;
import com.jisungin.application.talkroom.response.TalkRoomQueryResponse;
import com.jisungin.domain.book.Book;
import com.jisungin.domain.book.repository.BookRepository;
import com.jisungin.domain.rating.repository.RatingRepository;
import com.jisungin.exception.BusinessException;
import com.jisungin.exception.ErrorCode;
import com.jisungin.infra.crawler.Crawler;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -56,17 +57,11 @@ public BookResponse createBook(BookCreateServiceRequest request) {
}

@Transactional
public void addNewBooks(List<BookCreateServiceRequest> requests) {
requests.stream()
.filter(request -> !bookRepository.existsBookByIsbn(request.getIsbn()))
.map(BookCreateServiceRequest::toEntity)
.forEach(bookRepository::save);
}
public void addNewBooks(BookCreateServiceRequests requests) {
Set<String> existIsbns = bookRepository.findExistIsbns(requests.getIsbns());
List<Book> newBooks = requests.toEntitiesNotInclude(existIsbns);

private List<Long> extractTalkRoomIds(List<TalkRoomQueryResponse> talkRooms) {
return talkRooms.stream()
.map(TalkRoomQueryResponse::getId)
.toList();
bookRepository.saveAll(newBooks);
}

}
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
package com.jisungin.application.book.event;

import com.jisungin.infra.crawler.CrawlingBook;
import com.jisungin.application.book.request.BookCreateServiceRequest;
import com.jisungin.infra.crawler.CrawledBook;
import java.util.List;
import java.util.Map;
import lombok.Getter;

@Getter
public class BestSellerUpdatedEvent {

private final Map<Long, CrawlingBook> crawledBooks;
private final Map<Long, CrawledBook> crawledBookMap;

public BestSellerUpdatedEvent(Map<Long, CrawlingBook> crawledBooks) {
this.crawledBooks = crawledBooks;
public BestSellerUpdatedEvent(Map<Long, CrawledBook> crawledBookMap) {
this.crawledBookMap = crawledBookMap;
}

public List<BookCreateServiceRequest> getServiceRequests() {
return crawledBookMap.values().stream()
.map(CrawledBook::toServiceRequest)
.toList();
}

}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.jisungin.application.book.event;

import com.jisungin.application.book.BookService;
import com.jisungin.application.book.request.BookCreateServiceRequest;
import com.jisungin.infra.crawler.CrawlingBook;
import java.util.List;
import java.util.Map;
import com.jisungin.application.book.request.BookCreateServiceRequests;
import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
Expand All @@ -17,13 +14,7 @@ public class BestSellerUpdatedEventListener {

@EventListener
public void handleBestSellerUpdatedEvent(BestSellerUpdatedEvent event) {
Map<Long, CrawlingBook> crawledBook = event.getCrawledBooks();

List<BookCreateServiceRequest> bookCreateServiceRequests = crawledBook.values().stream()
.map(CrawlingBook::toServiceRequest)
.toList();

bookService.addNewBooks(bookCreateServiceRequests);
bookService.addNewBooks(BookCreateServiceRequests.of(event.getServiceRequests()));
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.jisungin.application.book.request;

import com.jisungin.domain.book.Book;
import com.jisungin.infra.crawler.CrawlingBook;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.jisungin.application.book.request;

import com.jisungin.domain.book.Book;
import java.util.List;
import java.util.Set;
import lombok.Builder;
import lombok.Getter;

@Getter
public class BookCreateServiceRequests {

private final List<BookCreateServiceRequest> requests;

@Builder
private BookCreateServiceRequests(List<BookCreateServiceRequest> requests) {
this.requests = requests;
}

public static BookCreateServiceRequests of(List<BookCreateServiceRequest> requests) {
return BookCreateServiceRequests.builder()
.requests(requests)
.build();
}

public List<String> getIsbns() {
return requests.stream()
.map(BookCreateServiceRequest::getIsbn)
.toList();
}

public List<Book> toEntitiesNotInclude(Set<String> existIsbns) {
return requests.stream()
.filter(request -> !existIsbns.contains(request.getIsbn()))
.map(BookCreateServiceRequest::toEntity)
.toList();
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.jisungin.application.book.response;

import com.jisungin.infra.crawler.CrawledBook;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class BookWithRankingResponse {

private Long ranking;
private String isbn;
private String title;
private String publisher;
private String thumbnail;
private String[] authors;
private LocalDateTime dateTime;

@Builder
private BookWithRankingResponse(Long ranking, String isbn, String title, String publisher, String thumbnail,
String[] authors, LocalDateTime dateTime) {
this.ranking = ranking;
this.isbn = isbn;
this.title = title;
this.publisher = publisher;
this.thumbnail = thumbnail;
this.authors = authors;
this.dateTime = dateTime;
}

public static BookWithRankingResponse of(Long ranking, String isbn, String title, String publisher, String thumbnail,
String[] authors, LocalDateTime dateTime) {
return BookWithRankingResponse.builder()
.ranking(ranking)
.isbn(isbn)
.title(title)
.publisher(publisher)
.thumbnail(thumbnail)
.authors(authors)
.dateTime(dateTime)
.build();
}

public static BookWithRankingResponse ofRankIncrement(Long ranking, CrawledBook crawledBook) {
return BookWithRankingResponse.builder()
.ranking(ranking + 1)
.isbn(crawledBook.getIsbn())
.title(crawledBook.getTitle())
.publisher(crawledBook.getPublisher())
.thumbnail(crawledBook.getThumbnail())
.authors(crawledBook.getAuthors())
.dateTime(crawledBook.getDateTime())
.build();
}

}
Loading

0 comments on commit 4a6c90a

Please sign in to comment.