From 2a932fa093add04a0db6d930970f334d08ce7a48 Mon Sep 17 00:00:00 2001 From: yel-m Date: Sat, 1 Jun 2024 16:22:55 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat=20:=20=EC=A0=84=EC=B2=B4=20=EC=9C=A0?= =?UTF-8?q?=EC=A0=80=EC=9D=98=20=ED=96=89=EB=B3=B5=20=EC=A7=80=EB=8F=84=20?= =?UTF-8?q?API=20=EA=B5=AC=EC=B6=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/report/api/TrendController.java | 19 ++++---- .../LocationHappinessAnalyzer.java | 48 ++++++++++++++++++- .../TrendLocationRankingService.java | 23 +++++++++ .../report/converter/ReportConverter.java | 12 +++++ .../LocationActivityRankingResponseDto.java | 26 ++++++++++ 5 files changed, 119 insertions(+), 9 deletions(-) create mode 100644 src/main/java/com/hobak/happinessql/domain/report/application/TrendLocationRankingService.java create mode 100644 src/main/java/com/hobak/happinessql/domain/report/dto/LocationActivityRankingResponseDto.java diff --git a/src/main/java/com/hobak/happinessql/domain/report/api/TrendController.java b/src/main/java/com/hobak/happinessql/domain/report/api/TrendController.java index 5354e47..2b145c7 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/api/TrendController.java +++ b/src/main/java/com/hobak/happinessql/domain/report/api/TrendController.java @@ -1,14 +1,8 @@ package com.hobak.happinessql.domain.report.api; -import com.hobak.happinessql.domain.report.application.AverageHappinessService; -import com.hobak.happinessql.domain.report.application.TrendPopularActivityService; -import com.hobak.happinessql.domain.report.application.TrendRecommendService; -import com.hobak.happinessql.domain.report.application.TrendSummaryService; +import com.hobak.happinessql.domain.report.application.*; import com.hobak.happinessql.domain.report.domain.AgeGroup; -import com.hobak.happinessql.domain.report.dto.AverageHappinessResponseDto; -import com.hobak.happinessql.domain.report.dto.SummaryResponseDto; -import com.hobak.happinessql.domain.report.dto.TrendPopularActivitiyResponseDto; -import com.hobak.happinessql.domain.report.dto.TrendRecommendActivityResponseDto; +import com.hobak.happinessql.domain.report.dto.*; import com.hobak.happinessql.domain.user.application.UserFindService; import com.hobak.happinessql.domain.user.domain.Gender; import com.hobak.happinessql.domain.user.domain.User; @@ -36,6 +30,7 @@ public class TrendController { private final TrendPopularActivityService trendPopularActivityService; private final TrendRecommendService trendRecommendService; private final TrendSummaryService trendSummaryService; + private final TrendLocationRankingService trendLocationRankingService; @Operation(summary = "대한민국 평균 행복지수", description = "전체 유저의 평균 행복지수와 그에 따른 수준을 판단합니다.") @GetMapping("/happiness") @@ -68,4 +63,12 @@ public DataResponseDto getSummary(@RequestParam(required = false) AgeGro if(responseDto == null) return DataResponseDto.of("아직은 데이터가 없어요.", "행복 트렌드의 행복 종합 리포트를 성공적으로 조회했습니다."); return DataResponseDto.of(responseDto, "행복 트렌드의 행복 종합 리포트를 성공적으로 조회했습니다."); } + + @Operation(summary = "행복도가 높은 장소와 활동 Top3", description = "전체 유저가 행복했던 장소 Top 3의 이름, 위치, 그 장소에서 가장 행복도가 높았던 활동을 조회합니다.") + @GetMapping("/top-locations") + public DataResponseDto> getTop3HappiestLocations(@AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); + List responseDto = trendLocationRankingService.getTop3HappyLocationsWithActivities(user); + return DataResponseDto.of(responseDto, "행복도가 높은 장소와 활동 Top3를 성공적으로 조회했습니다."); + } } diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/LocationHappinessAnalyzer.java b/src/main/java/com/hobak/happinessql/domain/report/application/LocationHappinessAnalyzer.java index 0505f7c..f5f1364 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/application/LocationHappinessAnalyzer.java +++ b/src/main/java/com/hobak/happinessql/domain/report/application/LocationHappinessAnalyzer.java @@ -1,7 +1,9 @@ package com.hobak.happinessql.domain.report.application; +import com.hobak.happinessql.domain.record.domain.Location; import com.hobak.happinessql.domain.record.domain.Record; import com.hobak.happinessql.domain.report.converter.ReportConverter; +import com.hobak.happinessql.domain.report.dto.LocationActivityRankingResponseDto; import com.hobak.happinessql.domain.report.dto.LocationRankingResponseDto; import java.util.*; @@ -82,6 +84,51 @@ public static List getLocationRankings(List return locationRankings; } + public static List getLocationActivityRankings(List records, int topCount) { + List locationActivityRankings = new ArrayList<>(); + if(records == null || records.isEmpty()) { + for(int i = 0; i < topCount; i++) { + locationActivityRankings.add(ReportConverter.toLocationActivityRankingResponseDto(i + 1, null, null)); + } + return locationActivityRankings; + } + + Map> locationRecordsMap = groupRecordsByLocation(records); + + Map locationAverageHappiness = calculateLocationAverageHappiness(locationRecordsMap); + Map locationFrequency = calculateLocationFrequency(locationRecordsMap); + + List sortedLocations = sortLocations(locationAverageHappiness, locationFrequency); + + for(int i = 0; i < sortedLocations.size(); i++) { + String locationStr = sortedLocations.get(i); + List locationRecords = locationRecordsMap.get(locationStr); + + Record happiestRecord = locationRecords.stream() + .max(Comparator.comparingInt(Record::getHappiness)) + .orElse(null); + + Location location = happiestRecord != null ? happiestRecord.getLocation() : null; + String happiesActivity = happiestRecord != null ? happiestRecord.getActivity().getName() : null; + + LocationActivityRankingResponseDto dto = ReportConverter.toLocationActivityRankingResponseDto( + i+1, + location, + happiesActivity + ); + locationActivityRankings.add(dto); + } + + while(locationActivityRankings.size() < topCount) { + locationActivityRankings.add(ReportConverter.toLocationActivityRankingResponseDto(locationActivityRankings.size() + 1, null, null)); + } + + return locationActivityRankings.stream() + .limit(topCount) + .collect(Collectors.toList()); + + } + private static Map> groupRecordsByLocation(List records) { return records.stream() .filter(record -> record.getLocation() != null) @@ -145,5 +192,4 @@ private static List sortLocations(Map locationAverageHap .map(Map.Entry::getKey) .toList(); } - } diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/TrendLocationRankingService.java b/src/main/java/com/hobak/happinessql/domain/report/application/TrendLocationRankingService.java new file mode 100644 index 0000000..8131dcb --- /dev/null +++ b/src/main/java/com/hobak/happinessql/domain/report/application/TrendLocationRankingService.java @@ -0,0 +1,23 @@ +package com.hobak.happinessql.domain.report.application; + +import com.hobak.happinessql.domain.record.domain.Record; +import com.hobak.happinessql.domain.record.repository.RecordRepository; +import com.hobak.happinessql.domain.report.dto.LocationActivityRankingResponseDto; +import com.hobak.happinessql.domain.user.domain.User; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class TrendLocationRankingService { + + private final RecordRepository recordRepository; + + public List getTop3HappyLocationsWithActivities(User user) { + List records = recordRepository.findAllByUser(user); + return LocationHappinessAnalyzer.getLocationActivityRankings(records, 3); + + } +} diff --git a/src/main/java/com/hobak/happinessql/domain/report/converter/ReportConverter.java b/src/main/java/com/hobak/happinessql/domain/report/converter/ReportConverter.java index f33a336..8c27b75 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/converter/ReportConverter.java +++ b/src/main/java/com/hobak/happinessql/domain/report/converter/ReportConverter.java @@ -1,5 +1,6 @@ package com.hobak.happinessql.domain.report.converter; +import com.hobak.happinessql.domain.record.domain.Location; import com.hobak.happinessql.domain.report.domain.HappinessLevel; import com.hobak.happinessql.domain.report.domain.TimeOfDay; import com.hobak.happinessql.domain.report.dto.*; @@ -30,6 +31,17 @@ public static LocationRankingResponseDto toLocationRankingResponseDto(int rankin .build(); } + public static LocationActivityRankingResponseDto toLocationActivityRankingResponseDto(int ranking, Location location, String happinesActivity) { + return LocationActivityRankingResponseDto.builder() + .ranking(ranking) + .location(location != null ? location.getCity() + " " + location.getDistrict() : null) + .latitude(location != null ? location.getLatitude() : null) + .longitude(location != null ? location.getLongitude() : null) + .happiestActivity(happinesActivity) + .build(); + + } + public static ReportGraphResponseDto toReportGraphResponseDto(ArrayList labels, ArrayList happiness){ return ReportGraphResponseDto.builder() .labels(labels) diff --git a/src/main/java/com/hobak/happinessql/domain/report/dto/LocationActivityRankingResponseDto.java b/src/main/java/com/hobak/happinessql/domain/report/dto/LocationActivityRankingResponseDto.java new file mode 100644 index 0000000..9b1a738 --- /dev/null +++ b/src/main/java/com/hobak/happinessql/domain/report/dto/LocationActivityRankingResponseDto.java @@ -0,0 +1,26 @@ +package com.hobak.happinessql.domain.report.dto; + + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class LocationActivityRankingResponseDto { + private int ranking; + private String location; + private Double latitude; + private Double longitude; + private String happiestActivity; + + @Builder + public LocationActivityRankingResponseDto(int ranking, String location, Double latitude, Double longitude, String happiestActivity) { + this.ranking = ranking; + this.location = location; + this.latitude = latitude; + this.longitude = longitude; + this.happiestActivity = happiestActivity; + } +} From c581a4b95cc7b0e7f564078f630ee8715388eeea Mon Sep 17 00:00:00 2001 From: yel-m Date: Sat, 1 Jun 2024 16:26:55 +0900 Subject: [PATCH 2/2] =?UTF-8?q?chore=20:=20TODO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/report/application/LocationHappinessAnalyzer.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/LocationHappinessAnalyzer.java b/src/main/java/com/hobak/happinessql/domain/report/application/LocationHappinessAnalyzer.java index f5f1364..0b8c5c6 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/application/LocationHappinessAnalyzer.java +++ b/src/main/java/com/hobak/happinessql/domain/report/application/LocationHappinessAnalyzer.java @@ -17,6 +17,7 @@ public static String getHappiestLocation(List records) { } // 도시와 구를 기준으로 Record 그룹화 + // TODO : 나중에 주석 삭제 및 랜덤 돌리는 로직 메서드로 추출해서 Ranking 관련 메서드에도 추가 Map> locationRecordsMap = groupRecordsByLocation(records); // 위치별 평균 행복도와 빈도 계산