Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a24ebf9
[rename] dto 네이밍 수정 (#140)
buzz0331 Aug 5, 2025
61094ac
[rename] 방 상세보기 필드 이름 수정 (#140)
buzz0331 Aug 5, 2025
8d5bebf
[rename] 방 상세보기 필드 이름 수정 (#140)
buzz0331 Aug 5, 2025
ad53742
[refactor] count쿼리 jpql로 바꾸기 (ACTIVE 조건 추가) (#140)
buzz0331 Aug 5, 2025
1eb4255
[refactor] 람다 캡처 사용하도록 함수형 인터페이스 통합 (#140)
buzz0331 Aug 5, 2025
a6b40fd
[feat] 특정 책의 isbn을 통해 모집중인 모임방을 조회하는 쿼리 선언 (#140)
buzz0331 Aug 5, 2025
10807ad
[feat] 특정 책의 isbn을 통해 모집중인 모임방을 조회하는 api 구현 (#140)
buzz0331 Aug 5, 2025
4d5b14b
[refactor] Optional<Book> 반환하는 port 뚫기 (#140)
buzz0331 Aug 5, 2025
f89f269
[refactor] BookCommandPort에 default 메서드 정의 (#140)
buzz0331 Aug 5, 2025
2fd6da2
[feat] 특정 책의 isbn을 통해 모집중인 모임방을 조회하는 api 구현 (#140)
buzz0331 Aug 5, 2025
7c283d1
[test] 특정 책으로 모집중인 모임방을 조회하는 api 통합 테스트 (#140)
buzz0331 Aug 5, 2025
e22d3f0
[test] DisplayName 수정 (#140)
buzz0331 Aug 5, 2025
6152448
[refactor] RequestParam 명시 (#140)
buzz0331 Aug 5, 2025
48c20b0
[feat] Transactional 추가 (#140)
buzz0331 Aug 5, 2025
78c87cf
[feat] merge (#140)
buzz0331 Aug 5, 2025
6f45eed
[refactor] isbn으로 count 쿼리 날리도록 수정 (#140)
buzz0331 Aug 6, 2025
774075a
[refactor] 모집중인 방 조회시 totalRoomCount 추가 - 첫 요청만 (#140)
buzz0331 Aug 6, 2025
25d426f
[refactor] 팔로잉/팔로워 조회도 전체 데이터 갯수 첫 요청시에만 반환하도록 수정 (#140)
buzz0331 Aug 6, 2025
2bbee07
[refactor] 필요없는 정적 팩토리 메서드 제거 (#140)
buzz0331 Aug 6, 2025
244b6f9
[refactor] merge (#140)
buzz0331 Aug 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Pattern;
import konkuk.thip.book.adapter.in.web.request.PostBookIsSavedRequest;
import konkuk.thip.book.adapter.in.web.response.PostBookIsSavedResponse;
import konkuk.thip.book.adapter.in.web.request.BookIsSavedRequest;
import konkuk.thip.book.adapter.in.web.response.BookIsSavedResponse;
import konkuk.thip.book.application.port.in.BookSavedUseCase;
import konkuk.thip.common.dto.BaseResponse;
import konkuk.thip.common.security.annotation.UserId;
Expand Down Expand Up @@ -34,13 +34,13 @@ public class BookCommandController {
)
@ExceptionDescription(CHANGE_BOOK_SAVED_STATE)
@PostMapping("/books/{isbn}/saved")
public BaseResponse<PostBookIsSavedResponse> changeSavedBook(
public BaseResponse<BookIsSavedResponse> changeSavedBook(
@Parameter(description = "책의 ISBN 번호 (13자리 숫자)", example = "9781234567890")
@PathVariable("isbn") @Pattern(regexp = "\\d{13}") final String isbn,
@RequestBody @Valid final PostBookIsSavedRequest postBookIsSavedRequest,
@RequestBody @Valid final BookIsSavedRequest bookIsSavedRequest,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(PostBookIsSavedResponse.of(bookSavedUseCase.changeSavedBook(isbn,postBookIsSavedRequest.type(),userId)));
return BaseResponse.ok(BookIsSavedResponse.of(bookSavedUseCase.changeSavedBook(isbn, bookIsSavedRequest.type(),userId)));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.constraints.Pattern;
import konkuk.thip.book.adapter.in.web.response.GetBookDetailSearchResponse;
import konkuk.thip.book.adapter.in.web.response.GetBookMostSearchResponse;
import konkuk.thip.book.adapter.in.web.response.GetBookSearchListResponse;
import konkuk.thip.book.adapter.in.web.response.BookDetailSearchResponse;
import konkuk.thip.book.adapter.in.web.response.BookMostSearchResponse;
import konkuk.thip.book.adapter.in.web.response.BookRecruitingRoomsResponse;
import konkuk.thip.book.adapter.in.web.response.BookSearchListResponse;
import konkuk.thip.book.application.port.in.BookMostSearchUseCase;
import konkuk.thip.book.application.port.in.BookRecruitingRoomsUseCase;
import konkuk.thip.book.application.port.in.BookSearchUseCase;
import konkuk.thip.common.dto.BaseResponse;
import konkuk.thip.common.security.annotation.UserId;
Expand All @@ -29,18 +31,19 @@ public class BookQueryController {

private final BookSearchUseCase bookSearchUseCase;
private final BookMostSearchUseCase bookMostSearchUseCase;
private final BookRecruitingRoomsUseCase bookRecruitingRoomsUseCase;

@Operation(
summary = "책 검색결과 조회",
description = "사용자가 입력한 키워드로 책을 검색합니다."
)
@ExceptionDescription(BOOK_SEARCH)
@GetMapping("/books")
public BaseResponse<GetBookSearchListResponse> getBookSearchList(
public BaseResponse<BookSearchListResponse> showBookSearchList(
@Parameter(description = "검색 키워드", example = "해리포터") @RequestParam final String keyword,
@Parameter(description = "페이지 번호 (1부터 시작)", example = "1") @RequestParam final int page,
@Parameter(hidden = true) @UserId final Long userId) {
return BaseResponse.ok(GetBookSearchListResponse.of(bookSearchUseCase.searchBooks(keyword, page,userId), page));
return BaseResponse.ok(BookSearchListResponse.of(bookSearchUseCase.searchBooks(keyword, page,userId), page));
}

//책 상세검색 결과 조회
Expand All @@ -50,12 +53,12 @@ public BaseResponse<GetBookSearchListResponse> getBookSearchList(
)
@ExceptionDescription(BOOK_DETAIL_SEARCH)
@GetMapping("/books/{isbn}")
public BaseResponse<GetBookDetailSearchResponse> getBookDetailSearch(
public BaseResponse<BookDetailSearchResponse> showBookDetailSearch(
@Parameter(description = "책의 ISBN 번호 (13자리 숫자)", example = "9781234567890")
@PathVariable("isbn") @Pattern(regexp = "\\d{13}") final String isbn,
@Parameter(hidden = true) @UserId final Long userId
) {
return BaseResponse.ok(GetBookDetailSearchResponse.of(bookSearchUseCase.searchDetailBooks(isbn,userId)));
return BaseResponse.ok(BookDetailSearchResponse.of(bookSearchUseCase.searchDetailBooks(isbn,userId)));
}

//가장 많이 검색된 책 조회
Expand All @@ -65,9 +68,23 @@ public BaseResponse<GetBookDetailSearchResponse> getBookDetailSearch(
)
@ExceptionDescription(POPULAR_BOOK_SEARCH)
@GetMapping("/books/most-searched")
public BaseResponse<GetBookMostSearchResponse> getMostSearchedBooks(
public BaseResponse<BookMostSearchResponse> showMostSearchedBooks(
@Parameter(hidden = true) @UserId final Long userId) {
return BaseResponse.ok(GetBookMostSearchResponse.of(bookMostSearchUseCase.getMostSearchedBooks(userId)));
return BaseResponse.ok(BookMostSearchResponse.of(bookMostSearchUseCase.getMostSearchedBooks(userId)));
}

@Operation(
summary = "특정 책으로 모집중인 방 조회",
description = "책의 ISBN을 통해 해당 책과 관련된 모집중인 방들을 조회합니다."
)
@GetMapping("/books/{isbn}/recruiting-rooms")
public BaseResponse<BookRecruitingRoomsResponse> showRecruitingRoomsWithBook(
@Parameter(description = "책의 ISBN 번호 (13자리 숫자)", example = "9781234567890")
@PathVariable("isbn") @Pattern(regexp = "\\d{13}") final String isbn,
@Parameter(description = "커서 (첫번째 요청시 : null, 다음 요청시 : 이전 요청에서 반환받은 nextCursor 값)")
@RequestParam(required = false) final String cursor
) {
return BaseResponse.ok(bookRecruitingRoomsUseCase.getRecruitingRoomsWithBook(isbn, cursor));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import jakarta.validation.constraints.NotNull;

@Schema(description = "책 저장 상태 변경 요청 DTO")
public record PostBookIsSavedRequest(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

커컼.. 이게 아마 dto 컨벤션 바뀌기 전에 다 구현된것들이라.. 메서드명 다 붙어있던거 야무지게 빼주셧네요 감사합니다람쥐~~👍🏻

public record BookIsSavedRequest(
@Schema(description = "저장 여부 type (true -> 저장, false -> 저장 취소)", example = "true")
@NotNull(message = "type은 필수입니다.")
Boolean type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,28 @@
import lombok.Builder;

@Builder
public record GetBookDetailSearchResponse(
public record BookDetailSearchResponse(
String title,
String imageUrl,
String authorName,
String publisher,
String isbn,
String description,
int recruitingRoomCount,
int recruitingReadCount,
int readCount,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

붐업~~!!

boolean isSaved
) {
public static GetBookDetailSearchResponse of(BookDetailSearchResult result) {
public static BookDetailSearchResponse of(BookDetailSearchResult result) {

return new GetBookDetailSearchResponse(
return new BookDetailSearchResponse(
result.naverDetailBook().title(),
result.naverDetailBook().imageUrl(),
result.naverDetailBook().author(),
result.naverDetailBook().publisher(),
result.naverDetailBook().isbn(),
result.naverDetailBook().description(),
result.recruitingRoomCount(),
result.recruitingReadCount(),
result.readCount(),
result.isSaved());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package konkuk.thip.book.adapter.in.web.response;

import konkuk.thip.book.application.port.in.dto.BookIsSavedResult;
import lombok.Builder;

@Builder
public record BookIsSavedResponse(
String isbn,
boolean isSaved
) {
public static BookIsSavedResponse of(BookIsSavedResult bookIsSavedResult) {
return new BookIsSavedResponse(bookIsSavedResult.isbn(),bookIsSavedResult.isSaved());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package konkuk.thip.book.adapter.in.web.response;

import konkuk.thip.book.application.port.in.dto.BookMostSearchResult;

import java.util.List;

public record BookMostSearchResponse(
List<BookMostSearchResult.BookRankInfo> bookList
) {
public static BookMostSearchResponse of(BookMostSearchResult bookMostSearchResult) {
return new BookMostSearchResponse(bookMostSearchResult.bookList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package konkuk.thip.book.adapter.in.web.response;

import java.util.List;

public record BookRecruitingRoomsResponse(
List<RecruitingRoomDto> recruitingRoomList,
Integer totalRoomCount,
String nextCursor,
boolean isLast
) {
public static BookRecruitingRoomsResponse of(List<RecruitingRoomDto> recruitingRoomList, Integer totalRoomCount, String nextCursor, boolean isLast) {
return new BookRecruitingRoomsResponse(recruitingRoomList, totalRoomCount, nextCursor, isLast);
}

public record RecruitingRoomDto(
Long roomId,
String bookImageUrl,
String roomName,
int memberCount,
int recruitCount,
String deadlineEndDate
) {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import static konkuk.thip.book.adapter.out.api.naver.NaverApiUtil.PAGE_SIZE;

public record GetBookSearchListResponse(
public record BookSearchListResponse(
List<BookDto> searchResult, // 책 목록
int page, // 현재 페이지 (1부터 시작)
int size, // 한 페이지에 포함되는 데이터 수 (페이지 크기)
Expand All @@ -15,7 +15,7 @@ public record GetBookSearchListResponse(
boolean last, // 마지막 페이지 여부
boolean first // 첫 페이지 여부
) {
public static GetBookSearchListResponse of(NaverBookParseResult result, int page) {
public static BookSearchListResponse of(NaverBookParseResult result, int page) {
int totalElements = result.total();
int totalPages = (int) Math.ceil((double) totalElements / PAGE_SIZE);
boolean last = (page >= totalPages);
Expand All @@ -25,7 +25,7 @@ public static GetBookSearchListResponse of(NaverBookParseResult result, int page
.map(BookDto::of)
.toList();

return new GetBookSearchListResponse(
return new BookSearchListResponse(
bookDtos,
page,
PAGE_SIZE,
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.Optional;

import static konkuk.thip.common.exception.code.ErrorCode.BOOK_NOT_FOUND;
import static konkuk.thip.common.exception.code.ErrorCode.ROOM_NOT_FOUND;

Expand All @@ -22,13 +24,11 @@ public class BookCommandPersistenceAdapter implements BookCommandPort {
private final BookMapper bookMapper;

@Override
public Book findByIsbn(String isbn) {
BookJpaEntity bookJpaEntity = bookJpaRepository.findByIsbn(isbn).orElseThrow(
() -> new EntityNotFoundException(BOOK_NOT_FOUND));
return bookMapper.toDomainEntity(bookJpaEntity);
public Optional<Book> findByIsbn(String isbn) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

return bookJpaRepository.findByIsbn(isbn)
.map(bookMapper::toDomainEntity);
}


@Override
public Long save(Book book) {
BookJpaEntity bookJpaEntity = bookMapper.toJpaEntity(book);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package konkuk.thip.book.application.mapper;

import konkuk.thip.book.adapter.in.web.response.BookRecruitingRoomsResponse;
import konkuk.thip.common.util.DateUtil;
import konkuk.thip.room.application.port.out.dto.RoomQueryDto;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.ReportingPolicy;

import java.util.List;

@Mapper(
componentModel = "spring",
imports = DateUtil.class,
unmappedTargetPolicy = ReportingPolicy.IGNORE // 명시적으로 매핑하지 않은 필드를 무시하도록 설정
)
public interface BookQueryMapper {

@Mapping(
target = "deadlineEndDate",
expression = "java(DateUtil.formatAfterTime(dto.endDate()))"
)
BookRecruitingRoomsResponse.RecruitingRoomDto toRecruitingRoomDto(RoomQueryDto dto);

List<BookRecruitingRoomsResponse.RecruitingRoomDto> toRecruitingRoomDtoList(List<RoomQueryDto> roomDtos);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package konkuk.thip.book.application.port.in;

import konkuk.thip.book.adapter.in.web.response.BookRecruitingRoomsResponse;

public interface BookRecruitingRoomsUseCase {

BookRecruitingRoomsResponse getRecruitingRoomsWithBook(String isbn, String cursor);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@
public record BookDetailSearchResult(
NaverDetailBookParseResult naverDetailBook,
int recruitingRoomCount,
int recruitingReadCount,
int readCount,
boolean isSaved

)
{
public static BookDetailSearchResult of(NaverDetailBookParseResult naverDetailBook ,
int recruitingRoomCount,
int recruitingReadCount,
int readCount,
boolean isSaved) {
return new BookDetailSearchResult(
naverDetailBook,
recruitingRoomCount,
recruitingReadCount,
readCount,
isSaved);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package konkuk.thip.book.application.port.in.dto;

import konkuk.thip.book.adapter.in.web.response.GetBookMostSearchResponse;
import lombok.Builder;

import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,19 @@


import konkuk.thip.book.domain.Book;
import konkuk.thip.common.exception.EntityNotFoundException;
import konkuk.thip.common.exception.code.ErrorCode;

import java.util.Optional;

public interface BookCommandPort {

Book findByIsbn(String isbn);
Optional<Book> findByIsbn(String isbn);

default Book getByIsbnOrThrow(String isbn){
return findByIsbn(isbn)
.orElseThrow(() -> new EntityNotFoundException(ErrorCode.BOOK_NOT_FOUND));
}
Comment on lines +12 to +17
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굳굳 서비스에서 try catch 를 하나 더 없앨 수 있겠네요


Long save(Book book);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public void updateDailySearchRank() {
int rank = 1;
for (String isbn : isbns) {
try {
Book book = bookCommandPort.findByIsbn(isbn);
Book book = bookCommandPort.getByIsbnOrThrow(isbn);
bookRankDetails.add(BookMostSearchResult.BookRankInfo.builder()
.rank(rank++)
.title(book.getTitle())
Expand Down
Loading