-
Notifications
You must be signed in to change notification settings - Fork 0
[feat] 책 검색 api 개발 #33
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
0d4f66e
23c9591
a785e94
ae8d7ff
30972bb
30f235d
54df077
48b213f
546260b
683c964
7a08730
5f53721
c677a30
246d03f
fd16a79
02a8d41
f12ecc4
2a3b2a8
41e2ec4
1864fc3
4536fdc
3ddd511
f7a5ce8
0e752fe
7f884da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,23 @@ | ||
| package konkuk.thip.book.adapter.in.web; | ||
|
|
||
| import konkuk.thip.book.adapter.in.web.response.GetBookSearchListResponse; | ||
| import konkuk.thip.book.adapter.out.api.dto.NaverBookParseResult; | ||
| import konkuk.thip.book.application.port.in.BookSearchUseCase; | ||
| import konkuk.thip.common.dto.BaseResponse; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| public class BookQueryController { | ||
|
|
||
| private final BookSearchUseCase bookSearchUseCase; | ||
|
|
||
| @GetMapping("/books") | ||
| public BaseResponse<GetBookSearchListResponse> getBookSearchList(@RequestParam final String keyword, | ||
| @RequestParam final int page) { | ||
| NaverBookParseResult result = bookSearchUseCase.searchBooks(keyword, page); | ||
| return BaseResponse.ok(GetBookSearchListResponse.of(result, page)); | ||
| } | ||
|
|
||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,57 @@ | ||||||||||||||||||||||||||||||||||||||
| package konkuk.thip.book.adapter.in.web.response; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import konkuk.thip.book.adapter.out.api.dto.NaverBookParseResult; | ||||||||||||||||||||||||||||||||||||||
| import lombok.Builder; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import java.util.List; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| import static konkuk.thip.book.adapter.out.api.NaverApiUtil.PAGE_SIZE; | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| @Builder | ||||||||||||||||||||||||||||||||||||||
| public record GetBookSearchListResponse( | ||||||||||||||||||||||||||||||||||||||
| List<BookDto> searchResult, // 책 목록 | ||||||||||||||||||||||||||||||||||||||
| int page, // 현재 페이지 (1부터 시작) | ||||||||||||||||||||||||||||||||||||||
| int size, // 한 페이지에 포함되는 데이터 수 (페이지 크기) | ||||||||||||||||||||||||||||||||||||||
| long totalElements, // 전체 데이터 개수 | ||||||||||||||||||||||||||||||||||||||
| int totalPages, // 전체 페이지 수 | ||||||||||||||||||||||||||||||||||||||
| boolean last, // 마지막 페이지 여부 | ||||||||||||||||||||||||||||||||||||||
| boolean first // 첫 페이지 여부 | ||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||
| public static GetBookSearchListResponse of(NaverBookParseResult result, int page) { | ||||||||||||||||||||||||||||||||||||||
| int totalElements = result.total(); | ||||||||||||||||||||||||||||||||||||||
| int totalPages = (int) Math.ceil((double) totalElements / PAGE_SIZE); | ||||||||||||||||||||||||||||||||||||||
| boolean last = (page >= totalPages); | ||||||||||||||||||||||||||||||||||||||
| boolean first = (page == 1); | ||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+20
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 페이지네이션 로직에서 엣지 케이스 처리가 필요합니다. 다음과 같은 잠재적 문제들이 있습니다:
다음과 같이 개선할 수 있습니다: public static GetBookSearchListResponse of(NaverBookParseResult result, int page) {
+ if (page <= 0) {
+ throw new IllegalArgumentException("페이지 번호는 1 이상이어야 합니다");
+ }
+
int totalElements = result.total();
- int totalPages = (int) Math.ceil((double) totalElements / PAGE_SIZE);
- boolean last = (page >= totalPages);
+ int totalPages = totalElements == 0 ? 1 : (int) Math.ceil((double) totalElements / PAGE_SIZE);
+ boolean last = (page >= totalPages);
boolean first = (page == 1);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 검색 keyword에 대한 totalElements 값이 0일 경우, totalPages 또한 0이 되는데, 이 경우 response dto는 searchResult = emptyList, page = 1, size = 10, totalElements = 0, totalPages = 0, last = true, first = true 이므로 문제없을 것 같습니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @seongjunnoh 맞는 말씀입니다!
이는 유효한 설계 선택입니다. 빈 결과에 대해 다만 제가 언급한 🐰 |
||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| List<BookDto> bookDtos = result.naverBooks().stream() | ||||||||||||||||||||||||||||||||||||||
| .map(BookDto::of) | ||||||||||||||||||||||||||||||||||||||
| .toList(); | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| return new GetBookSearchListResponse( | ||||||||||||||||||||||||||||||||||||||
| bookDtos, | ||||||||||||||||||||||||||||||||||||||
| page, | ||||||||||||||||||||||||||||||||||||||
| PAGE_SIZE, | ||||||||||||||||||||||||||||||||||||||
| totalElements, | ||||||||||||||||||||||||||||||||||||||
| totalPages, | ||||||||||||||||||||||||||||||||||||||
| last, | ||||||||||||||||||||||||||||||||||||||
| first | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| public record BookDto( | ||||||||||||||||||||||||||||||||||||||
| String title, | ||||||||||||||||||||||||||||||||||||||
| String imageUrl, | ||||||||||||||||||||||||||||||||||||||
| String authorName, | ||||||||||||||||||||||||||||||||||||||
| String publisher, | ||||||||||||||||||||||||||||||||||||||
| String isbn | ||||||||||||||||||||||||||||||||||||||
| ) { | ||||||||||||||||||||||||||||||||||||||
| public static BookDto of(NaverBookParseResult.NaverBook naverBook) { | ||||||||||||||||||||||||||||||||||||||
| return new BookDto( | ||||||||||||||||||||||||||||||||||||||
| naverBook.title(), | ||||||||||||||||||||||||||||||||||||||
| naverBook.imageUrl(), | ||||||||||||||||||||||||||||||||||||||
| naverBook.author(), | ||||||||||||||||||||||||||||||||||||||
| naverBook.publisher(), | ||||||||||||||||||||||||||||||||||||||
| naverBook.isbn() | ||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| package konkuk.thip.book.adapter.out.api; | ||
|
|
||
| import konkuk.thip.book.adapter.out.api.dto.NaverBookParseResult; | ||
| import konkuk.thip.book.application.port.out.SearchBookQueryPort; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| public class BookApiAdapter implements SearchBookQueryPort { | ||
|
|
||
| private final NaverApiUtil naverApiUtil; | ||
|
|
||
| @Override | ||
| public NaverBookParseResult findBooksByKeyword(String keyword, int start) { | ||
| String xml = naverApiUtil.searchBook(keyword, start); // 네이버 API 호출 | ||
| return NaverBookXmlParser.parse(xml); // XML 파싱 + 페이징 정보 포함 | ||
| } | ||
|
Comment on lines
+15
to
+18
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion 입력 매개변수 검증과 예외 처리 개선이 필요합니다. 현재 구현에서 다음 사항들을 고려해보세요:
@Override
public NaverBookParseResult findBooksByKeyword(String keyword, int start) {
+ if (keyword == null || keyword.trim().isEmpty()) {
+ throw new IllegalArgumentException("검색 키워드는 필수입니다.");
+ }
+ if (start < 1) {
+ throw new IllegalArgumentException("시작 인덱스는 1 이상이어야 합니다.");
+ }
+
String xml = naverApiUtil.searchBook(keyword, start); // 네이버 API 호출
return NaverBookXmlParser.parse(xml); // XML 파싱 + 페이징 정보 포함
}🤖 Prompt for AI Agents |
||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,108 @@ | ||||||||||||||||||||||||||
| package konkuk.thip.book.adapter.out.api; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import konkuk.thip.common.exception.BusinessException; | ||||||||||||||||||||||||||
| import lombok.RequiredArgsConstructor; | ||||||||||||||||||||||||||
| import org.springframework.beans.factory.annotation.Value; | ||||||||||||||||||||||||||
| import org.springframework.stereotype.Component; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import java.io.*; | ||||||||||||||||||||||||||
| import java.net.HttpURLConnection; | ||||||||||||||||||||||||||
| import java.net.MalformedURLException; | ||||||||||||||||||||||||||
| import java.net.URL; | ||||||||||||||||||||||||||
| import java.net.URLEncoder; | ||||||||||||||||||||||||||
| import java.util.HashMap; | ||||||||||||||||||||||||||
| import java.util.Map; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import static konkuk.thip.common.exception.code.ErrorCode.*; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @RequiredArgsConstructor | ||||||||||||||||||||||||||
| @Component | ||||||||||||||||||||||||||
| public class NaverApiUtil { | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| @Value("${naver.clientId}") | ||||||||||||||||||||||||||
| private String clientId; | ||||||||||||||||||||||||||
| @Value("${naver.clientSecret}") | ||||||||||||||||||||||||||
| private String clientSecret; | ||||||||||||||||||||||||||
| @Value("${naver.bookSearchUrl}") | ||||||||||||||||||||||||||
| private String bookSearchUrl; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| public static final int PAGE_SIZE = 10; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| public String searchBook(String keyword, int start){ | ||||||||||||||||||||||||||
| String query = keywordToEncoding(keyword); | ||||||||||||||||||||||||||
| String url = buildSearchApiUrl(query, start); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Map<String, String> requestHeaders = new HashMap<>(); | ||||||||||||||||||||||||||
| requestHeaders.put("X-Naver-Client-Id", clientId); | ||||||||||||||||||||||||||
| requestHeaders.put("X-Naver-Client-Secret", clientSecret); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return get(url,requestHeaders); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private String buildSearchApiUrl(String query,Integer start) { | ||||||||||||||||||||||||||
| return bookSearchUrl+query+"&display="+PAGE_SIZE+"&start="+start; | ||||||||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. LGTM |
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private String keywordToEncoding(String keyword) { | ||||||||||||||||||||||||||
| String text = null; | ||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||
| text = URLEncoder.encode(keyword, "UTF-8"); | ||||||||||||||||||||||||||
| } catch (UnsupportedEncodingException e) { | ||||||||||||||||||||||||||
| throw new BusinessException(BOOK_KEYWORD_ENCODING_FAILED); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| return text; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| String get(String apiUrl, Map<String, String> requestHeaders){ | ||||||||||||||||||||||||||
| HttpURLConnection con = connect(apiUrl); | ||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||
| con.setRequestMethod("GET"); | ||||||||||||||||||||||||||
| for(Map.Entry<String, String> header :requestHeaders.entrySet()) { | ||||||||||||||||||||||||||
| con.setRequestProperty(header.getKey(), header.getValue()); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| int responseCode = con.getResponseCode(); | ||||||||||||||||||||||||||
| if (responseCode == HttpURLConnection.HTTP_OK) { // 정상 호출 | ||||||||||||||||||||||||||
| return readBody(con.getInputStream()); | ||||||||||||||||||||||||||
| } else { // 오류 발생 | ||||||||||||||||||||||||||
| return readBody(con.getErrorStream()); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
Comment on lines
+66
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion HTTP 에러 응답 처리 방식을 개선해주세요. 현재 HTTP 에러 상태 코드를 받았을 때 에러 스트림의 내용을 그대로 반환하고 있습니다. 이는 상위 계층에서 에러 응답을 정상 응답으로 오해할 수 있습니다. int responseCode = con.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) { // 정상 호출
return readBody(con.getInputStream());
} else { // 오류 발생
- return readBody(con.getErrorStream());
+ String errorBody = readBody(con.getErrorStream());
+ throw new BusinessException(BOOK_NAVER_API_REQUEST_ERROR);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||
| } catch (IOException e) { | ||||||||||||||||||||||||||
| throw new BusinessException(BOOK_NAVER_API_REQUEST_ERROR); | ||||||||||||||||||||||||||
| } finally { | ||||||||||||||||||||||||||
| con.disconnect(); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private HttpURLConnection connect(String apiUrl){ | ||||||||||||||||||||||||||
| try { | ||||||||||||||||||||||||||
| URL url = new URL(apiUrl); | ||||||||||||||||||||||||||
| return (HttpURLConnection)url.openConnection(); | ||||||||||||||||||||||||||
| } catch (MalformedURLException e) { | ||||||||||||||||||||||||||
| throw new BusinessException(BOOK_NAVER_API_URL_ERROR); | ||||||||||||||||||||||||||
| } catch (IOException e) { | ||||||||||||||||||||||||||
| throw new BusinessException(BOOK_NAVER_API_URL_HTTP_CONNECT_FAILED); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| private String readBody(InputStream body){ | ||||||||||||||||||||||||||
| InputStreamReader streamReader = new InputStreamReader(body); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| try (BufferedReader lineReader = new BufferedReader(streamReader)) { | ||||||||||||||||||||||||||
| StringBuilder responseBody = new StringBuilder(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| String line; | ||||||||||||||||||||||||||
| while ((line = lineReader.readLine()) != null) { | ||||||||||||||||||||||||||
| responseBody.append(line); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| return responseBody.toString(); | ||||||||||||||||||||||||||
| } catch (IOException e) { | ||||||||||||||||||||||||||
| throw new BusinessException(BOOK_NAVER_API_RESPONSE_ERROR); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| package konkuk.thip.book.adapter.out.api; | ||
|
|
||
| import konkuk.thip.book.adapter.out.api.dto.NaverBookParseResult; | ||
| import konkuk.thip.common.exception.BusinessException; | ||
| import konkuk.thip.common.exception.code.ErrorCode; | ||
| import org.w3c.dom.*; | ||
| import javax.xml.parsers.*; | ||
| import java.io.StringReader; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
| import org.xml.sax.InputSource; | ||
|
|
||
| public class NaverBookXmlParser { | ||
|
|
||
| public static NaverBookParseResult parse(String xml) { | ||
| List<NaverBookParseResult.NaverBook> Naverbooks = new ArrayList<>(); | ||
| int total = -1; | ||
| int start = -1; | ||
| try { | ||
| DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); | ||
| DocumentBuilder builder = factory.newDocumentBuilder(); | ||
| InputSource is = new InputSource(new StringReader(xml)); | ||
| Document doc = builder.parse(is); | ||
|
|
||
| NodeList channelNodes = doc.getElementsByTagName("channel"); | ||
| if (channelNodes.getLength() > 0) { | ||
| Element channel = (Element) channelNodes.item(0); | ||
| total = Integer.parseInt(getTagValue(channel, "total")); | ||
| start = Integer.parseInt(getTagValue(channel, "start")); | ||
|
|
||
| NodeList itemNodes = channel.getElementsByTagName("item"); | ||
| for (int i = 0; i < itemNodes.getLength(); i++) { | ||
| Element item = (Element) itemNodes.item(i); | ||
| String title = getTagValue(item, "title"); | ||
| String imageUrl = getTagValue(item, "image"); | ||
| String author = getTagValue(item, "author"); | ||
| String publisher = getTagValue(item, "publisher"); | ||
| String isbn = getTagValue(item, "isbn"); | ||
| NaverBookParseResult.NaverBook naverBook = NaverBookParseResult.NaverBook.builder() | ||
| .title(title) | ||
| .imageUrl(imageUrl) | ||
| .author(author) | ||
| .publisher(publisher) | ||
| .isbn(isbn) | ||
| .build(); | ||
| Naverbooks.add(naverBook); | ||
| } | ||
| } | ||
| } catch (Exception e) { | ||
| throw new BusinessException(ErrorCode.BOOK_NAVER_API_PARSING_ERROR); | ||
| } | ||
| return NaverBookParseResult.of(Naverbooks, total, start); | ||
| } | ||
|
|
||
| private static String getTagValue(Element element, String tag) { | ||
| NodeList nodeList = element.getElementsByTagName(tag); | ||
| if (nodeList.getLength() > 0 && nodeList.item(0).getFirstChild() != null) { | ||
| return nodeList.item(0).getFirstChild().getNodeValue(); | ||
| } | ||
| return ""; | ||
| } | ||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package konkuk.thip.book.adapter.out.api.dto; | ||
|
|
||
| import lombok.Builder; | ||
|
|
||
| import java.util.List; | ||
|
|
||
|
|
||
| public record NaverBookParseResult( | ||
| List<NaverBook> naverBooks, | ||
| int total, | ||
| int start) { | ||
| @Builder | ||
| public record NaverBook( | ||
| String title, | ||
| String imageUrl, | ||
| String author, | ||
| String publisher, | ||
| String isbn | ||
| ) {} | ||
| public static NaverBookParseResult of(List<NaverBook> books, int total, int start) { | ||
| return new NaverBookParseResult(books, total, start); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package konkuk.thip.book.application.port.in; | ||
|
|
||
| import konkuk.thip.book.adapter.out.api.dto.NaverBookParseResult; | ||
|
|
||
| public interface BookSearchUseCase { | ||
|
|
||
| NaverBookParseResult searchBooks(String keyword, int page); | ||
|
|
||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package konkuk.thip.book.application.port.out; | ||
|
|
||
| import konkuk.thip.book.adapter.out.api.dto.NaverBookParseResult; | ||
|
|
||
| public interface SearchBookQueryPort { | ||
| NaverBookParseResult findBooksByKeyword(String keyword, int start); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| package konkuk.thip.book.application.service; | ||
|
|
||
| import konkuk.thip.book.adapter.out.api.dto.NaverBookParseResult; | ||
| import konkuk.thip.book.application.port.in.BookSearchUseCase; | ||
| import konkuk.thip.book.application.port.out.SearchBookQueryPort; | ||
| import konkuk.thip.common.exception.BusinessException; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
|
|
||
| import static konkuk.thip.book.adapter.out.api.NaverApiUtil.PAGE_SIZE; | ||
| import static konkuk.thip.common.exception.code.ErrorCode.*; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class BookSearchService implements BookSearchUseCase { | ||
|
|
||
| private final SearchBookQueryPort searchBookQueryPort; | ||
|
|
||
| @Override | ||
| public NaverBookParseResult searchBooks(String keyword, int page) { | ||
|
|
||
| if (keyword == null || keyword.isBlank()) { | ||
| throw new BusinessException(BOOK_KEYWORD_REQUIRED); | ||
| } | ||
|
|
||
| if (page < 1) { | ||
| throw new BusinessException(BOOK_PAGE_NUMBER_INVALID); | ||
| } | ||
|
|
||
| //유저의 최근검색어 로직 추가 | ||
|
|
||
| int start = (page - 1) * PAGE_SIZE + 1; //검색 시작 위치 | ||
| NaverBookParseResult result = searchBookQueryPort.findBooksByKeyword(keyword, start); | ||
|
|
||
| int totalElements = result.total(); | ||
| int totalPages = (totalElements + PAGE_SIZE - 1) / PAGE_SIZE; | ||
| if ( totalElements!=0 && page > totalPages) { | ||
| throw new BusinessException(BOOK_SEARCH_PAGE_OUT_OF_RANGE); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,7 @@ | |
| @JsonPropertyOrder({"success", "code", "message"}) | ||
| public class ErrorResponse { | ||
|
|
||
| @JsonProperty("isSuccess:") | ||
| @JsonProperty("isSuccess") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍🏻 |
||
| private final boolean success; | ||
|
|
||
| private final int code; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM