From 943753ea09d1a0f2ff1f79d8d23951804d17121b Mon Sep 17 00:00:00 2001 From: jinwoo22 Date: Thu, 25 Jul 2024 15:42:21 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=B0=A9=EB=B9=84=EA=B5=90=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bang_ggood/category/domain/Category.java | 51 ++++++++++-------- .../controller/ChecklistController.java | 10 +++- .../checklist/domain/Checklist.java | 6 +++ .../dto/CategoryScoreReadResponse.java | 6 +++ .../dto/ChecklistComparisonReadResponse.java | 29 ++++++++++ .../dto/ChecklistsComparisonReadResponse.java | 6 +++ .../repository/ChecklistOptionRepository.java | 3 ++ .../repository/ChecklistRepository.java | 1 + .../checklist/service/ChecklistService.java | 53 ++++++++++++++++++- .../exception/GlobalExceptionHandler.java | 3 +- .../category/domain/CategoryTest.java | 43 +++++++++++++-- 11 files changed, 184 insertions(+), 27 deletions(-) create mode 100644 backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/CategoryScoreReadResponse.java create mode 100644 backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistComparisonReadResponse.java create mode 100644 backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistsComparisonReadResponse.java diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/category/domain/Category.java b/backend/bang-ggood/src/main/java/com/bang_ggood/category/domain/Category.java index 990640370..c9efda915 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/category/domain/Category.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/category/domain/Category.java @@ -34,6 +34,36 @@ public static boolean contains(int id) { .anyMatch(category -> category.id == id); } + // 2. 뱃지 부여 + public static List getBadges(List questions) { + return Arrays.stream(values()) + .filter(category -> category.calculateTotalScore(questions) >= 80) + .map(Category::getBadge) + .toList(); + } + + // 1. 총점 : score * 100 / maxScore + public int calculateTotalScore(List questions) { + List filteredQuestions = filterQuestion(questions); + + if (filteredQuestions.isEmpty()) { + return 0; + } + + int maxScore = Grade.calculateMaxScore(filteredQuestions.size()); + int score = filteredQuestions.stream() + .mapToInt(question -> Grade.getScore(question.getAnswer())) + .sum(); + + return score * 100 / maxScore; + } + + private List filterQuestion(List questions) { + return questions.stream() + .filter(checklistQuestion -> questionIds.contains(checklistQuestion.getQuestionId())) + .toList(); + } + public int getId() { return id; } @@ -47,25 +77,4 @@ public String getDescription() { public Set getQuestionIds() { return questionIds; } - - public static List getBadges(List questions) { - return Arrays.stream(values()) - .filter(category -> { - Set questionIds = category.questionIds; - List categoryQuestions = questions.stream() - .filter(checklistQuestion -> questionIds.contains(checklistQuestion.getQuestionId())) - .toList(); - if (categoryQuestions.isEmpty()) { - return false; - } - int maxScore = Grade.calculateMaxScore(categoryQuestions.size()); - int score = categoryQuestions.stream() - .mapToInt(question -> Grade.getScore(question.getAnswer())) - .sum(); - - return (score * 100 / maxScore) >= 80; - }) - .map(Category::getBadge) - .toList(); - } } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/controller/ChecklistController.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/controller/ChecklistController.java index 4bfe4c61a..7e933e66b 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/controller/ChecklistController.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/controller/ChecklistController.java @@ -1,16 +1,19 @@ package com.bang_ggood.checklist.controller; import com.bang_ggood.checklist.dto.ChecklistCreateRequest; -import com.bang_ggood.checklist.dto.UserChecklistsPreviewResponse; import com.bang_ggood.checklist.dto.ChecklistQuestionsResponse; +import com.bang_ggood.checklist.dto.ChecklistsComparisonReadResponse; +import com.bang_ggood.checklist.dto.UserChecklistsPreviewResponse; import com.bang_ggood.checklist.service.ChecklistService; import jakarta.validation.Valid; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.net.URI; +import java.util.List; @RestController public class ChecklistController { @@ -36,4 +39,9 @@ public ResponseEntity readUserChecklistsPreview() public ResponseEntity readChecklistQuestions() { return ResponseEntity.ok(checklistService.readChecklistQuestions()); } + + @GetMapping("/checklists/comparison") + public ResponseEntity readChecklistsComparison(@RequestParam("id")List checklistIds) { + return ResponseEntity.ok(checklistService.readChecklistsComparison(checklistIds)); + } } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Checklist.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Checklist.java index 6188cd8c5..68120e8e1 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Checklist.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/domain/Checklist.java @@ -71,6 +71,12 @@ public String getRoomAddress() { return room.getAddress(); } + public Integer getRoomFloor() { return room.getFloor(); } + + public String getRoomStation() { return room.getStation(); } + + public Integer getRoomWalkingTime() { return room.getWalkingTime(); } + public Integer getDeposit() { return deposit; } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/CategoryScoreReadResponse.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/CategoryScoreReadResponse.java new file mode 100644 index 000000000..30278b78e --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/CategoryScoreReadResponse.java @@ -0,0 +1,6 @@ +package com.bang_ggood.checklist.dto; + +public record CategoryScoreReadResponse( + Integer categoryId, String categoryName, Integer score +) { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistComparisonReadResponse.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistComparisonReadResponse.java new file mode 100644 index 000000000..b7669d06c --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistComparisonReadResponse.java @@ -0,0 +1,29 @@ +package com.bang_ggood.checklist.dto; + +import com.bang_ggood.checklist.domain.Checklist; +import java.util.List; + +public record ChecklistComparisonReadResponse( + Long checklistId, String roomName, String address, + Integer floor, Integer deposit, Integer rent, + Integer contractTerm, String station, Integer walkingTime, + Integer optionCount, Integer score, + List categories +) { + public static ChecklistComparisonReadResponse of(Checklist checklist, int checklistOptionCount, int checklistScore, List categoryScores) { + return new ChecklistComparisonReadResponse( + checklist.getId(), + checklist.getRoomName(), + checklist.getRoomAddress(), + checklist.getRoomFloor(), + checklist.getDeposit(), + checklist.getRent(), + checklist.getContractTerm(), + checklist.getRoomStation(), + checklist.getRoomWalkingTime(), + checklistOptionCount, + checklistScore, + categoryScores + ); + } +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistsComparisonReadResponse.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistsComparisonReadResponse.java new file mode 100644 index 000000000..f9968c4bb --- /dev/null +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/dto/ChecklistsComparisonReadResponse.java @@ -0,0 +1,6 @@ +package com.bang_ggood.checklist.dto; + +import java.util.List; + +public record ChecklistsComparisonReadResponse(List checklists) { +} diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistOptionRepository.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistOptionRepository.java index 8ed6404d4..cff60ee03 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistOptionRepository.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistOptionRepository.java @@ -1,7 +1,10 @@ package com.bang_ggood.checklist.repository; +import com.bang_ggood.checklist.domain.Checklist; import com.bang_ggood.checklist.domain.ChecklistOption; import org.springframework.data.jpa.repository.JpaRepository; public interface ChecklistOptionRepository extends JpaRepository { + + Integer countByChecklist(Checklist checklist); } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistRepository.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistRepository.java index 1420528d5..97ad12149 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistRepository.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/repository/ChecklistRepository.java @@ -8,4 +8,5 @@ public interface ChecklistRepository extends JpaRepository { List findByUser(User user); + List findByUserAndIdIn(User user, List checklistIds); } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistService.java b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistService.java index 879fa5cec..ca9345620 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistService.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/checklist/service/ChecklistService.java @@ -8,9 +8,12 @@ import com.bang_ggood.checklist.domain.Option; import com.bang_ggood.checklist.domain.Questionlist; import com.bang_ggood.checklist.dto.BadgeResponse; +import com.bang_ggood.checklist.dto.CategoryScoreReadResponse; +import com.bang_ggood.checklist.dto.ChecklistComparisonReadResponse; import com.bang_ggood.checklist.dto.ChecklistCreateRequest; import com.bang_ggood.checklist.dto.ChecklistInfo; import com.bang_ggood.checklist.dto.ChecklistQuestionsResponse; +import com.bang_ggood.checklist.dto.ChecklistsComparisonReadResponse; import com.bang_ggood.checklist.dto.QuestionCreateRequest; import com.bang_ggood.checklist.dto.QuestionResponse; import com.bang_ggood.checklist.dto.UserChecklistPreviewResponse; @@ -26,6 +29,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -147,7 +151,7 @@ private List createBadges(List questions) { .toList(); } - public ChecklistQuestionsResponse readChecklistQuestions () { + public ChecklistQuestionsResponse readChecklistQuestions() { List categoryQuestionsResponses = new ArrayList<>(); for (Category category : Category.values()) { CategoryQuestionsResponse categoryQuestionsResponse = @@ -167,4 +171,51 @@ private List readChecklistQuestion(Category category) { .forEach(questionResponses::add); return questionResponses; } + + @Transactional + public ChecklistsComparisonReadResponse readChecklistsComparison(List checklistIds) { + User user = new User(1L, "방끗"); + + List responses = checklistRepository.findByUserAndIdIn(user, checklistIds) + .stream() + .map(checklist -> { + // 카테고리별 총점 + List categoryScores = calculateCategoryScores(checklist); + + // 체크리스트 총점 + int checklistScore = calculateChecklistScore(categoryScores); + + // 옵션 개수 + int checklistOptionCount = checklistOptionRepository.countByChecklist(checklist); + + return ChecklistComparisonReadResponse.of( + checklist, checklistOptionCount, checklistScore, categoryScores);}) + .sorted(Comparator.comparing(ChecklistComparisonReadResponse::score).reversed()) + .toList(); + + return new ChecklistsComparisonReadResponse(responses); + } + + private List calculateCategoryScores(Checklist checklist) { + List categoryScores = new ArrayList<>(); + + for (Category category : Category.values()) { + int categoryScore = category.calculateTotalScore(checklist.getQuestions()); + if (categoryScore != 0) { + categoryScores.add(new CategoryScoreReadResponse( + category.getId(), + category.getDescription(), + categoryScore + )); + } + } + + return categoryScores; + } + + private int calculateChecklistScore(List categoryScores) { + return categoryScores.stream() + .mapToInt(CategoryScoreReadResponse::score) + .sum() / categoryScores.size(); + } } diff --git a/backend/bang-ggood/src/main/java/com/bang_ggood/exception/GlobalExceptionHandler.java b/backend/bang-ggood/src/main/java/com/bang_ggood/exception/GlobalExceptionHandler.java index 9ebbcc99f..4c62e8e8d 100644 --- a/backend/bang-ggood/src/main/java/com/bang_ggood/exception/GlobalExceptionHandler.java +++ b/backend/bang-ggood/src/main/java/com/bang_ggood/exception/GlobalExceptionHandler.java @@ -22,7 +22,8 @@ public ResponseEntity handleBangggoodException(BangggoodExcep } @ExceptionHandler(RuntimeException.class) - public ResponseEntity handleRuntimeException(HttpServletRequest request) { + public ResponseEntity handleRuntimeException(RuntimeException runtimeException, HttpServletRequest request) { + runtimeException.printStackTrace(); ExceptionResponse response = new ExceptionResponse( request.getMethod(), request.getRequestURI(), diff --git a/backend/bang-ggood/src/test/java/com/bang_ggood/category/domain/CategoryTest.java b/backend/bang-ggood/src/test/java/com/bang_ggood/category/domain/CategoryTest.java index ee99c5e76..689b2b33f 100644 --- a/backend/bang-ggood/src/test/java/com/bang_ggood/category/domain/CategoryTest.java +++ b/backend/bang-ggood/src/test/java/com/bang_ggood/category/domain/CategoryTest.java @@ -1,11 +1,14 @@ package com.bang_ggood.category.domain; import com.bang_ggood.checklist.domain.ChecklistQuestion; -import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import java.util.List; +import static com.bang_ggood.category.domain.Category.CLEAN; +import static com.bang_ggood.category.domain.Category.SECURITY; +import static org.assertj.core.api.Assertions.assertThat; + class CategoryTest { @DisplayName("뱃지 부여 : 카테고리 총점이 80점 이상일 때") @@ -24,7 +27,7 @@ void getBadges() { List badges = Category.getBadges(questions); // then - Assertions.assertThat(badges).containsExactly(Badge.CLEAN); + assertThat(badges).containsExactly(Badge.CLEAN); } @DisplayName("뱃지 미부여 : 카테고리 총점이 80점 미만일 때") @@ -43,6 +46,40 @@ void getBadges_NoBadges() { List badges = Category.getBadges(questions); // then - Assertions.assertThat(badges).isEmpty(); + assertThat(badges).isEmpty(); + } + + @DisplayName("카테고리 총점수 계산 성공") + @Test + void calculateTotalScore() { + // given + List questions = List.of(new ChecklistQuestion(null, 1, "GOOD"), + new ChecklistQuestion(null, 2, "GOOD"), + new ChecklistQuestion(null, 3, "GOOD"), + new ChecklistQuestion(null, 4, "BAD"), + new ChecklistQuestion(null, 5, "BAD")); + + // when + int totalScore = CLEAN.calculateTotalScore(questions); + + // then + assertThat(totalScore).isEqualTo(( 11 * 100 / 15)); + } + + @DisplayName("카테고리 총점수 계산 성공 : 해당 카테고리에 대한 답변이 없을 경우") + @Test + void calculateTotalScore_WhenCategoryDoesNotMatch() { + // given + List questions = List.of(new ChecklistQuestion(null, 1, "GOOD"), + new ChecklistQuestion(null, 2, "GOOD"), + new ChecklistQuestion(null, 3, "GOOD"), + new ChecklistQuestion(null, 4, "BAD"), + new ChecklistQuestion(null, 5, "BAD")); + + // when + int totalScore = SECURITY.calculateTotalScore(questions); + + // then + assertThat(totalScore).isZero(); } }