diff --git a/src/main/java/com/book/backend/domain/book/controller/BookController.java b/src/main/java/com/book/backend/domain/book/controller/BookController.java index 4b62b684..d4663675 100644 --- a/src/main/java/com/book/backend/domain/book/controller/BookController.java +++ b/src/main/java/com/book/backend/domain/book/controller/BookController.java @@ -1,8 +1,11 @@ package com.book.backend.domain.book.controller; +import com.book.backend.domain.book.service.BookRequestValidate; import com.book.backend.domain.book.service.BookService; + import com.book.backend.domain.openapi.service.RequestValidate; import com.book.backend.domain.openapi.dto.request.CustomHotTrendRequestDto; + import com.book.backend.domain.openapi.dto.request.HotTrendRequestDto; import com.book.backend.domain.openapi.dto.request.KeywordRequestDto; import com.book.backend.domain.openapi.dto.response.CustomHotTrendResponseDto; @@ -35,7 +38,7 @@ @Slf4j public class BookController { private final BookService bookService; - private final RequestValidate requestValidate; + private final BookRequestValidate bookRequestValidate; private final ResponseTemplate responseTemplate; // 마니아(4), 다독자(5) 추천 API @@ -46,7 +49,7 @@ public class BookController { @GetMapping("/recommend") public ResponseEntity recommend(@RequestParam String isbn) throws Exception { RequestLogger.param(new String[]{"isbn"}, isbn); - requestValidate.isValidIsbn(isbn); + bookRequestValidate.isValidIsbn(isbn); RecommendRequestDto requestDto = RecommendRequestDto.builder().isbn13(isbn).build(); LinkedList response = bookService.recommend(requestDto); @@ -63,9 +66,11 @@ public ResponseEntity recommend(@RequestParam String isbn) throws Exception { responses = {@ApiResponse(responseCode = "200", content = @Content(schema = @Schema(implementation = HotTrendResponseDto.class)), description = HotTrendResponseDto.description)}) @GetMapping("/hotTrend") + public ResponseEntity hotTrend() throws Exception { LocalDate yesterday = LocalDate.now().minusDays(1); HotTrendRequestDto requestDto = HotTrendRequestDto.builder().searchDt(yesterday.toString()).build(); + LinkedList response = bookService.hotTrend(requestDto); return responseTemplate.success(response, HttpStatus.OK); diff --git a/src/main/java/com/book/backend/domain/book/service/BookRequestValidate.java b/src/main/java/com/book/backend/domain/book/service/BookRequestValidate.java new file mode 100644 index 00000000..1b3fe62c --- /dev/null +++ b/src/main/java/com/book/backend/domain/book/service/BookRequestValidate.java @@ -0,0 +1,27 @@ +package com.book.backend.domain.book.service; + +import com.book.backend.exception.CustomException; +import com.book.backend.exception.ErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class BookRequestValidate { + + public void isValidSearchDt(String searchDt) { + //yyyy-mm-dd 형식인지 확인 + if(!searchDt.matches("^\\d{4}-\\d{2}-\\d{2}$")) { + throw new CustomException(ErrorCode.INVALID_SEARCH_DT_FORMAT); + } + } + + public void isValidIsbn(String isbn) { + // 숫자로 구성된 13자리 ISBN + if(!(isbn.matches("^[0-9]*$") && isbn.length() == 13)) { + throw new CustomException(ErrorCode.INVALID_ISBN); + } + } +} diff --git a/src/main/java/com/book/backend/domain/genre/controller/GenreController.java b/src/main/java/com/book/backend/domain/genre/controller/GenreController.java index b643c4b6..7eef4687 100644 --- a/src/main/java/com/book/backend/domain/genre/controller/GenreController.java +++ b/src/main/java/com/book/backend/domain/genre/controller/GenreController.java @@ -1,15 +1,18 @@ package com.book.backend.domain.genre.controller; -import com.book.backend.domain.book.entity.Book; +import com.book.backend.domain.genre.service.GenreRequestValidate; import com.book.backend.domain.genre.service.GenreService; +import com.book.backend.domain.openapi.dto.request.LoanTrendRequestDto; +import com.book.backend.domain.openapi.dto.response.LoanTrendResponseDto; +import com.book.backend.global.ResponseTemplate; import com.book.backend.global.log.RequestLogger; -import jakarta.validation.constraints.Pattern; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.util.List; +import java.util.LinkedList; @RestController @RequestMapping("/api/genre") @@ -17,27 +20,83 @@ @Slf4j public class GenreController { private final GenreService genreService; + private final GenreRequestValidate genreRequestValidate; + private final ResponseTemplate responseTemplate; /** - * 대주제 KDC 번호(1자리) 입력 시 저장된 책 목록 리턴 + * 일주일 인기순 - 중주제 KDC 번호(2자리) 입력 시 1주일 인기순 도서 목록 리턴 */ - @GetMapping("/main") - public List findBooksByMainKdcNum(@RequestParam @Pattern(regexp = "\\d") Integer kdcNum) { - RequestLogger.param(new String[]{"대주제 KDC 번호"}, kdcNum); + @GetMapping("/aWeekTrend") + public ResponseEntity aWeekTrend(@RequestParam String subKdc, + @RequestParam(required = false) Integer maxSize) throws Exception { + RequestLogger.param(new String[]{"kdcNum"}, subKdc); + genreRequestValidate.isValidSubKdc(subKdc); - List books = genreService.findBooksByMainKdcNum(kdcNum); - return ResponseEntity.ok(books).getBody(); + LoanTrendRequestDto requestDto = LoanTrendRequestDto.builder().dtl_kdc(subKdc).build(); + LinkedList response = genreService.periodToNowTrend(requestDto, 7, maxSize); + + return responseTemplate.success(response, HttpStatus.OK); + } + + /** + * 한달 인기순 - 중주제 KDC 번호(2자리) 입력 시 1개월 인기순 도서 목록 리턴 + */ + @GetMapping("/aMonthTrend") + public ResponseEntity aMonthTrend(@RequestParam String subKdc, + @RequestParam(required = false) Integer maxSize) throws Exception { + RequestLogger.param(new String[]{"kdcNum"}, subKdc); + genreRequestValidate.isValidSubKdc(subKdc); + + LoanTrendRequestDto requestDto = LoanTrendRequestDto.builder().dtl_kdc(subKdc).build(); + LinkedList response = genreService.periodToNowTrend(requestDto, 30, maxSize); + + return responseTemplate.success(response, HttpStatus.OK); + } + + /** + * N월 M주차 - 중주제 KDC 번호(2자리) 입력시 N월 M주차 인기 도서 목록 리턴 + * - (월요일 또는 화요일이면 저번 주로, 아니면 이번 주로 계산) + */ + @GetMapping("/thisWeekTrend") + public ResponseEntity thisWeekTrend(@RequestParam String subKdc, + @RequestParam(required = false) Integer maxSize) throws Exception { + RequestLogger.param(new String[]{"kdcNum"}, subKdc); + genreRequestValidate.isValidSubKdc(subKdc); + + LoanTrendRequestDto requestDto = LoanTrendRequestDto.builder().dtl_kdc(subKdc).build(); + LinkedList response = genreService.thisWeekTrend(requestDto, maxSize); + + return responseTemplate.success(response, HttpStatus.OK); + } + + /** + * 무작위순 - 중주제 KDC 번호(2자리) 입력 시 랜덤한 도서 목록 리턴 + */ + @GetMapping("/random") + public ResponseEntity random(@RequestParam String subKdc, + @RequestParam(required = false) Integer maxSize) throws Exception { + RequestLogger.param(new String[]{"kdcNum"}, subKdc); + genreRequestValidate.isValidSubKdc(subKdc); + + LoanTrendRequestDto requestDto = LoanTrendRequestDto.builder().dtl_kdc(subKdc).build(); + LinkedList response = genreService.random(requestDto, maxSize); + + return responseTemplate.success(response, HttpStatus.OK); } /** - * 중주제 KDC 번호(2자리) 입력 시 저장된 책 목록 리턴 + * 신작 인기순 - 중주제 KDC 번호(2자리) 입력 시 3년 내 출판된 인기 도서 목록 리턴 */ - @GetMapping("/sub") - public List findBooksBySubKdcNum(@RequestParam @Pattern(regexp = "\\d{2}") Integer kdcNum) { - RequestLogger.param(new String[] {"중주제 KDC 번호"}, kdcNum); + @GetMapping("/newTrend") + public ResponseEntity newTrend(@RequestParam String subKdc, + @RequestParam(required = false) Integer maxSize) throws Exception { + RequestLogger.param(new String[]{"kdcNum"}, subKdc); + genreRequestValidate.isValidSubKdc(subKdc); + + LoanTrendRequestDto requestDto = LoanTrendRequestDto.builder().dtl_kdc(subKdc).build(); + LinkedList response = genreService.newTrend(requestDto, maxSize); - List books = genreService.findBooksBySubKdcNum(kdcNum); - return ResponseEntity.ok(books).getBody(); + return responseTemplate.success(response, HttpStatus.OK); } } diff --git a/src/main/java/com/book/backend/domain/genre/service/GenreRequestValidate.java b/src/main/java/com/book/backend/domain/genre/service/GenreRequestValidate.java new file mode 100644 index 00000000..9fb95fc8 --- /dev/null +++ b/src/main/java/com/book/backend/domain/genre/service/GenreRequestValidate.java @@ -0,0 +1,27 @@ +package com.book.backend.domain.genre.service; + +import com.book.backend.exception.CustomException; +import com.book.backend.exception.ErrorCode; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class GenreRequestValidate { + + public void isValidMainKdc(String kdc) { + // 한 자리 숫자로 구성된 KDC 번호 + if(!(kdc.matches("\\d"))) { + throw new CustomException(ErrorCode.INVALID_MAIN_KDC); + } + } + + public void isValidSubKdc(String kdc) { + // 두 자리 숫자로 구성된 KDC 번호 + if(!(kdc.matches("\\d{2}"))) { + throw new CustomException(ErrorCode.INVALID_MAIN_KDC); + } + } +} diff --git a/src/main/java/com/book/backend/domain/genre/service/GenreResponseParser.java b/src/main/java/com/book/backend/domain/genre/service/GenreResponseParser.java new file mode 100644 index 00000000..b3447c08 --- /dev/null +++ b/src/main/java/com/book/backend/domain/genre/service/GenreResponseParser.java @@ -0,0 +1,65 @@ +package com.book.backend.domain.genre.service; + +import com.book.backend.domain.openapi.dto.response.LoanTrendResponseDto; +import com.book.backend.domain.openapi.service.ResponseParser; +import lombok.RequiredArgsConstructor; +import net.minidev.json.JSONObject; +import org.springframework.stereotype.Component; + +import java.util.LinkedList; + +@Component +@RequiredArgsConstructor +public class GenreResponseParser { + private final ResponseParser responseParser; + + public LinkedList periodTrend(JSONObject jsonResponse, Integer maxSize) { + LinkedList loanTrendResponseList = responseParser.loanTrend(jsonResponse); + LinkedList responseList = new LinkedList<>(); + + for (LoanTrendResponseDto response : loanTrendResponseList) { + if (maxSize != null && responseList.size() >= maxSize) { + break; + } + responseList.add(response); + } + return responseList; + } + + public LinkedList random(JSONObject jsonResponse, int resultSize, Integer maxSize) { + LinkedList loanTrendResponseList = responseParser.loanTrend(jsonResponse); + LinkedList responseList = new LinkedList<>(); + + // TODO: #26 PR 병합되면 랜덤 로직 추가 + for (LoanTrendResponseDto response : loanTrendResponseList) { + if (maxSize != null && responseList.size() >= maxSize) { + break; + } + responseList.add(response); + } + return responseList; + } + + public LinkedList newTrend(JSONObject jsonResponse, int currentYear, Integer maxSize) { + LinkedList loanTrendResponseList = responseParser.loanTrend(jsonResponse); + LinkedList responseList = new LinkedList<>(); + + for (LoanTrendResponseDto response : loanTrendResponseList) { + if (maxSize != null && responseList.size() >= maxSize) { + break; + } + + int publication_year; + try { + publication_year = Integer.parseInt(response.getPublication_year()); + } catch (NumberFormatException e) { + continue; + } + + if (publication_year >= currentYear - 2) { + responseList.add(response); + } + } + return responseList; + } +} diff --git a/src/main/java/com/book/backend/domain/genre/service/GenreService.java b/src/main/java/com/book/backend/domain/genre/service/GenreService.java index 904776f5..7c4ce5a8 100644 --- a/src/main/java/com/book/backend/domain/genre/service/GenreService.java +++ b/src/main/java/com/book/backend/domain/genre/service/GenreService.java @@ -1,13 +1,20 @@ package com.book.backend.domain.genre.service; -import com.book.backend.domain.book.entity.Book; import com.book.backend.domain.genre.entity.Genre; import com.book.backend.domain.genre.repository.GenreRepository; +import com.book.backend.domain.openapi.dto.request.LoanTrendRequestDto; +import com.book.backend.domain.openapi.dto.response.LoanTrendResponseDto; +import com.book.backend.domain.openapi.service.OpenAPI; import lombok.RequiredArgsConstructor; +import net.minidev.json.JSONObject; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; +import java.time.DayOfWeek; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAdjusters; +import java.util.LinkedList; import java.util.List; import java.util.Optional; @@ -16,24 +23,14 @@ @Transactional(readOnly = true) public class GenreService { private final GenreRepository genreRepository; + private final OpenAPI openAPI; + private final GenreResponseParser genreResponseParser; public Genre findById(Long id) { return genreRepository.findById(id) .orElseThrow(() -> new IllegalArgumentException("Invalid genre Id:" + id)); } - @Transactional - public void addBook(Genre genre, Book book) { - if (genre.getLevel() == 2) { - genre.getBooks().add(book); - if (book.getGenre() != genre) { - book.setGenre(genre); - } - } else { - throw new UnsupportedOperationException("2단계 장르만 책 리스트를 가질 수 있습니다."); - } - } - public List findSubGenresByKdcNum(String kdcNum) { Optional genre = genreRepository.findByKdcNum(kdcNum); return genre.map(Genre::getSubGenres).orElse(null); @@ -44,29 +41,61 @@ public Genre findByMainKdcNumAndSubKdcNum(String mainKdcNum, String subKdcNum) { .orElseThrow(() -> new IllegalArgumentException("KDC 번호가" + mainKdcNum + subKdcNum + "인 장르를 찾을 수 없습니다.")); } - public List findBooksByMainKdcNum(Integer kdcNum) { - String mainKdcNum = String.valueOf(kdcNum); + public LinkedList periodToNowTrend(LoanTrendRequestDto requestDto, Integer dayPeriod, Integer maxSize) throws Exception { + LocalDate today = LocalDate.now(); + LocalDate startDt = today.minusDays(dayPeriod + 1); + LocalDate endDt = today.minusDays(1); - List allBooks = new ArrayList<>(); - List subGenres = findSubGenresByKdcNum(mainKdcNum); + return periodTrend(requestDto, startDt, endDt, maxSize); + } - if (subGenres != null) { - for (Genre subGenre : subGenres) { - if (subGenre.getBooks() != null) { - allBooks.addAll(subGenre.getBooks()); - } - } + public LinkedList thisWeekTrend(LoanTrendRequestDto requestDto, Integer maxSize) throws Exception { + LocalDate today = LocalDate.now(); + LocalDate startDt, endDt; + // 월요일 또는 화요일이면 저번주로, 아니면 이번주로 계산 + if (today.getDayOfWeek() == DayOfWeek.MONDAY || today.getDayOfWeek() == DayOfWeek.TUESDAY) { + startDt = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusDays(7); + endDt = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY)).minusDays(7); + } else { + startDt = today.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)); + endDt = today.minusDays(1); } - return allBooks; + return periodTrend(requestDto, startDt, endDt, maxSize); } - public List findBooksBySubKdcNum(Integer kdcNum) { - String mainKdcNum = String.valueOf(kdcNum / 10); - String subKdcNum = String.valueOf(kdcNum % 10); + // periodToNowTrend, thisWeekTrend에 의해 호출됨 + public LinkedList periodTrend(LoanTrendRequestDto requestDto, LocalDate startDt, LocalDate endDt, Integer maxSize) throws Exception { + String subUrl = "loanItemSrch"; + + requestDto.setStartDt(startDt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + requestDto.setEndDt(endDt.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))); + + JSONObject JsonResponse = openAPI.connect(subUrl, requestDto, new LoanTrendResponseDto()); + return new LinkedList<>(genreResponseParser.periodTrend(JsonResponse, maxSize)); + } + + public LinkedList random(LoanTrendRequestDto requestDto, Integer maxSize) throws Exception { + String subUrl = "loanItemSrch"; + int resultSize = 200; + + requestDto.setPageSize(500); // 셔플할 리스트의 페이지 크기 설정 + + JSONObject JsonResponse = openAPI.connect(subUrl, requestDto, new LoanTrendResponseDto()); + + return new LinkedList<>(genreResponseParser.random(JsonResponse, resultSize, maxSize)); + } + + public LinkedList newTrend(LoanTrendRequestDto requestDto, Integer maxSize) throws Exception { + String subUrl = "loanItemSrch"; + + requestDto.setPageSize(1500); // 연도로 필터링하기 전 페이지 크기 설정 + LocalDate today = LocalDate.now(); + int currentYear = Integer.parseInt(today.format(DateTimeFormatter.ofPattern("yyyy"))); + + JSONObject JsonResponse = openAPI.connect(subUrl, requestDto, new LoanTrendResponseDto()); - Genre findGenre = findByMainKdcNumAndSubKdcNum(mainKdcNum, subKdcNum); - return findGenre.getBooks(); + return new LinkedList<>(genreResponseParser.newTrend(JsonResponse, currentYear, maxSize)); } } diff --git a/src/main/java/com/book/backend/domain/openapi/dto/request/LoanTrendRequestDto.java b/src/main/java/com/book/backend/domain/openapi/dto/request/LoanTrendRequestDto.java new file mode 100644 index 00000000..e45497d3 --- /dev/null +++ b/src/main/java/com/book/backend/domain/openapi/dto/request/LoanTrendRequestDto.java @@ -0,0 +1,19 @@ +package com.book.backend.domain.openapi.dto.request; + + +import com.book.backend.domain.openapi.dto.request.OpenAPIRequestInterface; +import jakarta.validation.constraints.NotBlank; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@Builder +public class LoanTrendRequestDto implements OpenAPIRequestInterface { + @NotBlank(message = "subKdc는 필수 입력값입니다.") + private String dtl_kdc; + private Integer pageSize; // 페이지 사이즈 + private String startDt; // 검색시작일자 + private String endDt; // 검색종료일자 +} diff --git a/src/main/java/com/book/backend/domain/openapi/dto/response/HotTrendResponseDto.java b/src/main/java/com/book/backend/domain/openapi/dto/response/HotTrendResponseDto.java index 175945dd..d7c3e595 100644 --- a/src/main/java/com/book/backend/domain/openapi/dto/response/HotTrendResponseDto.java +++ b/src/main/java/com/book/backend/domain/openapi/dto/response/HotTrendResponseDto.java @@ -19,7 +19,7 @@ public class HotTrendResponseDto implements OpenAPIResponseInterface { private String publisher; private String publication_year; private String isbn13; - private String additional_symbol; + private String addition_symbol; private String vol; private String class_no; private String class_nm; diff --git a/src/main/java/com/book/backend/domain/openapi/dto/response/LoanTrendResponseDto.java b/src/main/java/com/book/backend/domain/openapi/dto/response/LoanTrendResponseDto.java new file mode 100644 index 00000000..8ce0f4ad --- /dev/null +++ b/src/main/java/com/book/backend/domain/openapi/dto/response/LoanTrendResponseDto.java @@ -0,0 +1,25 @@ +package com.book.backend.domain.openapi.dto.response; + +import com.book.backend.domain.openapi.dto.response.OpenAPIResponseInterface; +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class LoanTrendResponseDto implements OpenAPIResponseInterface { + private String no; + private String ranking; + private String bookname; + private String authors; + private String publisher; + private String publication_year; + private String isbn13; + private String addition_symbol; + private String class_no; + private String class_nm; + private String loan_count; + private String bookImageURL; + private String bookDtlUrl; +} diff --git a/src/main/java/com/book/backend/domain/openapi/dto/response/RecommendResponseDto.java b/src/main/java/com/book/backend/domain/openapi/dto/response/RecommendResponseDto.java index 508d9e02..73ae866f 100644 --- a/src/main/java/com/book/backend/domain/openapi/dto/response/RecommendResponseDto.java +++ b/src/main/java/com/book/backend/domain/openapi/dto/response/RecommendResponseDto.java @@ -15,7 +15,6 @@ public class RecommendResponseDto implements OpenAPIResponseInterface { private String publisher; private String publication_year; private String isbn13; - private String additional_symbol; private String vol; private String class_no; private String class_nm; diff --git a/src/main/java/com/book/backend/domain/openapi/service/ResponseParser.java b/src/main/java/com/book/backend/domain/openapi/service/ResponseParser.java index 8d9617d6..f1358e95 100644 --- a/src/main/java/com/book/backend/domain/openapi/service/ResponseParser.java +++ b/src/main/java/com/book/backend/domain/openapi/service/ResponseParser.java @@ -4,39 +4,49 @@ import com.book.backend.domain.openapi.dto.response.HotTrendResponseDto; import com.book.backend.domain.openapi.dto.response.KeywordResponseDto; import com.book.backend.domain.openapi.dto.response.RecommendResponseDto; + +import java.util.*; + +import com.book.backend.domain.openapi.dto.response.LoanTrendResponseDto; + import java.util.HashSet; import java.util.LinkedList; import lombok.extern.slf4j.Slf4j; + import net.minidev.json.JSONArray; import net.minidev.json.JSONObject; +import org.springframework.stereotype.Component; +@Component @Slf4j public class ResponseParser { public LinkedList recommend(JSONObject jsonResponse) { log.trace("ResponseParser > recommend()"); - JSONArray step0 = (JSONArray) jsonResponse.get("docs"); + + JSONArray docs = (JSONArray) jsonResponse.get("docs"); LinkedList responseList = new LinkedList<>(); HashSet duplicateCheckSet = new HashSet<>(); - for (Object obj : step0) { - JSONObject temp = (JSONObject) obj; - JSONObject step1 = (JSONObject) temp.get("book"); + + for (Object o : docs) { + JSONObject docsElement = (JSONObject) o; + JSONObject book = (JSONObject) docsElement.get("book"); // 중복 추천 체크 (open api 가 중복되는 책을 추천함;;) - String duplicateCheckKey = step1.getAsString("bookname") + step1.getAsString("authors"); + String duplicateCheckKey = book.getAsString("bookname") + book.getAsString("authors"); + if (duplicateCheckSet.add(duplicateCheckKey)) { // 중복 확인 responseList.add(RecommendResponseDto.builder() - .bookname(step1.getAsString("bookname")) - .authors(step1.getAsString("authors")) - .publisher(step1.getAsString("publisher")) - .publication_year(step1.getAsString("publication_year")) - .isbn13(step1.getAsString("isbn13")) - .additional_symbol(step1.getAsString("additional_symbol")) - .vol(step1.getAsString("vol")) - .class_no(step1.getAsString("class_no")) - .class_nm(step1.getAsString("class_nm")) - .bookImageURL(step1.getAsString("bookImageURL")) + .bookname(book.getAsString("bookname")) + .authors(book.getAsString("authors")) + .publisher(book.getAsString("publisher")) + .publication_year(book.getAsString("publication_year")) + .isbn13(book.getAsString("isbn13")) + .vol(book.getAsString("vol")) + .class_no(book.getAsString("class_no")) + .class_nm(book.getAsString("class_nm")) + .bookImageURL(book.getAsString("bookImageURL")) .build()); } } @@ -45,34 +55,67 @@ public LinkedList recommend(JSONObject jsonResponse) { public LinkedList hotTrend(JSONObject jsonResponse) { log.trace("ResponseParser > hotTrend()"); - - JSONArray step0 = (JSONArray) jsonResponse.get("results"); + + JSONArray results = (JSONArray) jsonResponse.get("results"); LinkedList responseList = new LinkedList<>(); - for (int i = 0; i < step0.size(); i++) { - JSONObject temp1 = (JSONObject) step0.get(i); - JSONObject step1 = (JSONObject) temp1.get("result"); - JSONArray step2 = (JSONArray) step1.get("docs"); - for (Object obj : step2) { - JSONObject temp3 = (JSONObject) obj; - JSONObject step3 = (JSONObject) temp3.get("doc"); + for (Object o : results) { + JSONObject resultsElement = (JSONObject) o; + JSONObject result = (JSONObject) resultsElement.get("result"); + JSONArray docs = (JSONArray) result.get("docs"); + for (Object value : docs) { + JSONObject docsElement = (JSONObject) value; + JSONObject doc = (JSONObject) docsElement.get("doc"); responseList.add(HotTrendResponseDto.builder() - .no(step3.getAsString("no")) - .difference(step3.getAsString("difference")) - .baseWeekRank(step3.getAsString("baseWeekRank")) - .pastWeekRank(step3.getAsString("pastWeekRank")) - .bookname(step3.getAsString("bookname")) - .authors(step3.getAsString("authors")) - .publisher(step3.getAsString("publisher")) - .publication_year(step3.getAsString("publication_year")) - .isbn13(step3.getAsString("isbn13")) - .additional_symbol(step3.getAsString("additional_symbol")) - .vol(step3.getAsString("vol")) - .class_no(step3.getAsString("class_no")) - .class_nm(step3.getAsString("class_nm")) - .bookImageURL(step3.getAsString("bookImageURL")) - .bookDtlUrl(step3.getAsString("bookDtlUrl")) + .no(doc.getAsString("no")) + .difference(doc.getAsString("difference")) + .baseWeekRank(doc.getAsString("baseWeekRank")) + .pastWeekRank(doc.getAsString("pastWeekRank")) + .bookname(doc.getAsString("bookname")) + .authors(doc.getAsString("authors")) + .publisher(doc.getAsString("publisher")) + .publication_year(doc.getAsString("publication_year")) + .isbn13(doc.getAsString("isbn13")) + .addition_symbol(doc.getAsString("addition_symbol")) + .vol(doc.getAsString("vol")) + .class_no(doc.getAsString("class_no")) + .class_nm(doc.getAsString("class_nm")) + .bookImageURL(doc.getAsString("bookImageURL")) + .bookDtlUrl(doc.getAsString("bookDtlUrl")) + .build()); + } + } + return responseList; + } + + public LinkedList loanTrend(JSONObject jsonResponse) { + JSONArray docs = (JSONArray) jsonResponse.get("docs"); + + LinkedList responseList = new LinkedList<>(); + HashSet duplicateCheckSet = new HashSet<>(); + + for (Object o : docs) { + + JSONObject docsElement = (JSONObject) o; + JSONObject doc = (JSONObject) docsElement.get("doc"); + + String duplicateCheckKey = doc.getAsString("bookname") + doc.getAsString("authors"); + if (duplicateCheckSet.add(duplicateCheckKey)) { + responseList.add(LoanTrendResponseDto.builder() + .no(doc.getAsString("no")) + .ranking(doc.getAsString("ranking")) + .bookname(doc.getAsString("bookname")) + .authors(doc.getAsString("authors")) + .publisher(doc.getAsString("publisher")) + .publication_year(doc.getAsString("publication_year")) + .isbn13(doc.getAsString("isbn13")) + .addition_symbol(doc.getAsString("addition_symbol")) + .class_no(doc.getAsString("class_no")) + .class_nm(doc.getAsString("class_nm")) + .loan_count(doc.getAsString("loan_count")) + .bookImageURL(doc.getAsString("bookImageURL")) + .bookDtlUrl(doc.getAsString("bookDtlUrl")) .build()); } } diff --git a/src/main/java/com/book/backend/exception/ErrorCode.java b/src/main/java/com/book/backend/exception/ErrorCode.java index 4e8f13a6..842fe17a 100644 --- a/src/main/java/com/book/backend/exception/ErrorCode.java +++ b/src/main/java/com/book/backend/exception/ErrorCode.java @@ -9,6 +9,8 @@ public enum ErrorCode { INVALID_ISBN(HttpStatus.BAD_REQUEST, "400", "숫자로만 구성된 13자리 ISBN 을 입력해주세요."), INVALID_SEARCH_DT_FORMAT(HttpStatus.BAD_REQUEST, "400", "올바르지 않은 검색일자입니다. (yyyy-mm-dd) 형식을 맞춰주세요."), + INVALID_MAIN_KDC(HttpStatus.BAD_REQUEST, "400", "1자리 KDC 번호를 입력해주세요."), + INVALID_SUB_KDC(HttpStatus.BAD_REQUEST, "400", "2자리 KDC 번호를 입력해주세요."), INVALID_SEARCH_DT_DATE(HttpStatus.BAD_REQUEST, "400", "올바르지 않은 검색일자입니다. (어제까지 데이터 조회 가능)"), INVALID_WEEK_MONTH(HttpStatus.BAD_REQUEST, "400", "week 또는 month 로 입력해주세요."), INVALID_AGE(HttpStatus.BAD_REQUEST, "400", "0~100 사이의 숫자로 입력해주세요."), @@ -18,7 +20,6 @@ public enum ErrorCode { INVALID_REGION_CODE(HttpStatus.BAD_REQUEST, "400", "올바르지 않은 지역 코드입니다."), INVALID_LIB_CODE(HttpStatus.BAD_REQUEST, "400", "올바르지 않은 도서관 코드입니다. (6자리 숫자로 입력해주세요)"), - INVALID_CREDENTIALS(HttpStatus.UNAUTHORIZED, "401", "인증 오류가 발생했습니다."), USER_NOT_FOUND(HttpStatus.NOT_FOUND, "404", "해당하는 사용자를 찾을 수 없습니다."), LOGIN_ID_DUPLICATED(HttpStatus.CONFLICT,"409", "사용자의 아이디가 중복됩니다.");