diff --git a/src/main/java/com/hobak/happinessql/domain/record/repository/RecordRepository.java b/src/main/java/com/hobak/happinessql/domain/record/repository/RecordRepository.java index c9b58de..fbf2887 100644 --- a/src/main/java/com/hobak/happinessql/domain/record/repository/RecordRepository.java +++ b/src/main/java/com/hobak/happinessql/domain/record/repository/RecordRepository.java @@ -21,4 +21,7 @@ public interface RecordRepository extends JpaRepository { @Query("SELECT r.activity, COUNT(r) as count FROM Record r WHERE r.createdAt >= :time GROUP BY r.activity ORDER BY count DESC limit 3") List findPopularActivities(@Param("time")LocalDateTime time); + @Query("SELECT r FROM Record r WHERE r.user.userId != :userId") + List findAllExceptUser(@Param("userId") Long userId); + } diff --git a/src/main/java/com/hobak/happinessql/domain/report/api/ReportController.java b/src/main/java/com/hobak/happinessql/domain/report/api/ReportController.java index 688032d..73713a3 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/api/ReportController.java +++ b/src/main/java/com/hobak/happinessql/domain/report/api/ReportController.java @@ -56,49 +56,49 @@ public DataResponseDto getMonthlySummary(@Authenticati @Operation(summary = "[전체] 행복도가 높은 Top 3 활동", description = "전체 기록에서 가장 행복도가 높은 Top 3 활동을 제공합니다.") @GetMapping("/all/top-activities") - public DataResponseDto> getTop3AllHappiestActivities(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getTop3AllHappiestActivities(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportActivityRankingService.getTop3AllHappiestActivities(user); + List responseDto = reportActivityRankingService.getTop3AllHappiestActivities(user); return DataResponseDto.of(responseDto, "행복도가 높은 Top 3 활동(전체)을 성공적으로 조회했습니다."); } @Operation(summary = "[연간] 행복도가 높은 Top 3 활동", description = "이번 해 가장 행복도가 높은 Top 3 활동을 제공합니다.") @GetMapping("/year/top-activities") - public DataResponseDto> getTop3AnnualHappiestActivities(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getTop3AnnualHappiestActivities(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportActivityRankingService.getTop3AnnualHappiestActivities(user); + List responseDto = reportActivityRankingService.getTop3AnnualHappiestActivities(user); return DataResponseDto.of(responseDto, "행복도가 높은 Top 3 활동(연간)을 성공적으로 조회했습니다."); } @Operation(summary = "[월간] 행복도가 높은 Top 3 활동", description = "이번 해 가장 행복도가 높은 Top 3 활동을 제공합니다.") @GetMapping("/month/top-activities") - public DataResponseDto> getTop3MonthlyHappiestActivities(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getTop3MonthlyHappiestActivities(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportActivityRankingService.getTop3MonthlyHappiestActivities(user); + List responseDto = reportActivityRankingService.getTop3MonthlyHappiestActivities(user); return DataResponseDto.of(responseDto, "행복도가 높은 Top 3 활동(월간)을 성공적으로 조회했습니다."); } @Operation(summary = "[전체] 행복도가 높은 Top 3 위치", description = "전체 기록에서 가장 행복도가 높은 Top 3 위치을 제공합니다.") @GetMapping("/all/top-locations") - public DataResponseDto> getTop3AllHappiestLocations(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getTop3AllHappiestLocations(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportLocationRankingService.getTop3AllHappiestLocations(user); + List responseDto = reportLocationRankingService.getTop3AllHappiestLocations(user); return DataResponseDto.of(responseDto, "행복도가 높은 Top 3 위치(전체)를 성공적으로 조회했습니다."); } @Operation(summary = "[연간] 행복도가 높은 Top 3 위치", description = "이번 해 가장 행복도가 높은 Top 3 위치를 제공합니다.") @GetMapping("/year/top-locations") - public DataResponseDto> getTop3AnnualHappiestLocations(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getTop3AnnualHappiestLocations(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportLocationRankingService.getTop3AnnualHappiestLocations(user); + List responseDto = reportLocationRankingService.getTop3AnnualHappiestLocations(user); return DataResponseDto.of(responseDto, "행복도가 높은 Top 3 위치(연간)를 성공적으로 조회했습니다."); } @Operation(summary = "[월간] 행복도가 높은 Top 3 위치", description = "이번 해 가장 행복도가 높은 Top 3 위치를 제공합니다.") @GetMapping("/month/top-locations") - public DataResponseDto> getTop3MonthlyHappiestLocations(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getTop3MonthlyHappiestLocations(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportLocationRankingService.getTop3MonthlyHappiestLocations(user); + List responseDto = reportLocationRankingService.getTop3MonthlyHappiestLocations(user); return DataResponseDto.of(responseDto, "행복도가 높은 Top 3 위치(월간)를 성공적으로 조회했습니다."); } @Operation(summary = "[연간] 행복 그래프", description = "연간 행복지수 그래프를 제공합니다.") @@ -118,73 +118,73 @@ public DataResponseDto getMonthlyGraph(@AuthenticationPr @Operation(summary = "[전체] 모든 활동의 행복도 순위", description = "전체 기록에서 모든 활동의 행복도 순위를 제공합니다.") @GetMapping("/all/ranking/activities") - public DataResponseDto> getAllActivityRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getAllActivityRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportActivityRankingService.getAllActivityRankings(user); + List responseDto = reportActivityRankingService.getAllActivityRankings(user); return DataResponseDto.of(responseDto, "전체 활동 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[연간] 모든 활동의 행복도 순위", description = "이번 해 모든 활동의 행복도 순위를 제공합니다.") @GetMapping("/year/ranking/activities") - public DataResponseDto> getYearlyActivityRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getYearlyActivityRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportActivityRankingService.getYearlyActivityRankings(user); + List responseDto = reportActivityRankingService.getYearlyActivityRankings(user); return DataResponseDto.of(responseDto, "연간 활동 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[월간] 모든 활동의 행복도 순위", description = "이번 달 모든 활동의 행복도 순위를 제공합니다.") @GetMapping("/month/ranking/activities") - public DataResponseDto> getMonthlyActivityRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getMonthlyActivityRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportActivityRankingService.getMonthlyActivityRankings(user); + List responseDto = reportActivityRankingService.getMonthlyActivityRankings(user); return DataResponseDto.of(responseDto, "월간 활동 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[전체] 모든 위치의 행복도 순위", description = "전체 기록에서 모든 위치의 행복도 순위를 제공합니다.") @GetMapping("/all/ranking/locations") - public DataResponseDto> getAllLocationRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getAllLocationRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportLocationRankingService.getAllLocationRankings(user); + List responseDto = reportLocationRankingService.getAllLocationRankings(user); return DataResponseDto.of(responseDto, "전체 위치 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[연간] 모든 위치의 행복도 순위", description = "이번 해 모든 위치의 행복도 순위를 제공합니다.") @GetMapping("/year/ranking/locations") - public DataResponseDto> getYearlyLocationRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getYearlyLocationRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportLocationRankingService.getYearlyLocationRankings(user); + List responseDto = reportLocationRankingService.getYearlyLocationRankings(user); return DataResponseDto.of(responseDto, "연간 위치 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[월간] 모든 위치의 행복도 순위", description = "이번 달 모든 위치의 행복도 순위를 제공합니다.") @GetMapping("/month/ranking/locations") - public DataResponseDto> getMonthlyLocationRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getMonthlyLocationRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportLocationRankingService.getMonthlyLocationRankings(user); + List responseDto = reportLocationRankingService.getMonthlyLocationRankings(user); return DataResponseDto.of(responseDto, "월간 위치 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[전체] 시간대 행복도 순위", description = "전체 기록에서 시간대 행복도 순위를 제공합니다.") @GetMapping("/all/ranking/time") - public DataResponseDto> getAllTimeOfDayRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getAllTimeOfDayRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportTimeOfPeriodRankingService.getAllTimeOfDayRankings(user); + List responseDto = reportTimeOfPeriodRankingService.getAllTimeOfDayRankings(user); return DataResponseDto.of(responseDto, "전체 시간대 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[연간] 시간대 행복도 순위", description = "이번 해 시간대 행복도 순위를 제공합니다.") @GetMapping("/year/ranking/time") - public DataResponseDto> getYearlyTimeOfDayRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getYearlyTimeOfDayRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportTimeOfPeriodRankingService.getYearlyTimeOfDayRankings(user); + List responseDto = reportTimeOfPeriodRankingService.getYearlyTimeOfDayRankings(user); return DataResponseDto.of(responseDto, "연간 시간대 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[월간] 시간대 행복도 순위", description = "이번 달 시간대 행복도 순위를 제공합니다.") @GetMapping("/month/ranking/time") - public DataResponseDto> getMonthlyTimeOfDayRankings(@AuthenticationPrincipal UserDetails userDetails) { + public DataResponseDto> getMonthlyTimeOfDayRankings(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); - List responseDto = reportTimeOfPeriodRankingService.getMonthlyTimeOfDayRankings(user); + List responseDto = reportTimeOfPeriodRankingService.getMonthlyTimeOfDayRankings(user); return DataResponseDto.of(responseDto, "월간 시간대 행복도 순위를 성공적으로 조회했습니다."); } @Operation(summary = "[전체] 평균 행복지수", description = "유저 개인의 전체기간 평균 행복지수와 그에 따른 수준을 판단합니다.") 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 0b7b27b..7b1d61d 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,13 +1,19 @@ package com.hobak.happinessql.domain.report.api; import com.hobak.happinessql.domain.report.application.AverageHappinessService; -import com.hobak.happinessql.domain.report.application.TrendPopularActivitiesService; +import com.hobak.happinessql.domain.report.application.TrendPopularActivityService; +import com.hobak.happinessql.domain.report.application.TrendRecommendService; import com.hobak.happinessql.domain.report.dto.AverageHappinessResponseDto; -import com.hobak.happinessql.domain.report.dto.TrendPopularActivitiesResponseDto; +import com.hobak.happinessql.domain.report.dto.TrendPopularActivitiyResponseDto; +import com.hobak.happinessql.domain.report.dto.TrendRecommendActivityResponseDto; +import com.hobak.happinessql.domain.user.application.UserFindService; +import com.hobak.happinessql.domain.user.domain.User; import com.hobak.happinessql.global.response.DataResponseDto; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.security.core.userdetails.UserDetails; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -19,18 +25,29 @@ @RequiredArgsConstructor @RequestMapping("api/trend") public class TrendController { + private final UserFindService userFindService; private final AverageHappinessService averageHappinessService; - private final TrendPopularActivitiesService trendPopularActivitiesService; + private final TrendPopularActivityService trendPopularActivityService; + private final TrendRecommendService trendRecommendService; + @Operation(summary = "대한민국 평균 행복지수", description = "전체 유저의 평균 행복지수와 그에 따른 수준을 판단합니다.") @GetMapping("/happiness") - public DataResponseDto getHappiness() { + public DataResponseDto getAverageHappiness() { AverageHappinessResponseDto responseDto = averageHappinessService.getTrendHappiness(); return DataResponseDto.of(responseDto, "대한민국 평균 행복지수를 성공적으로 조회했습니다."); } @Operation(summary = "오늘의 인기 활동 top3", description = "오늘 많이 기록된 활동의 이름과 기록 횟수를 조회합니다.") @GetMapping("/popular") - public DataResponseDto> getPopular() { - List responseDto = trendPopularActivitiesService.getPopularActivities(); + public DataResponseDto> getPopularActivities() { + List responseDto = trendPopularActivityService.getPopularActivities(); return DataResponseDto.of(responseDto, "오늘의 인기 활동을 성공적으로 조회했습니다."); } + + @Operation(summary = "추천 활동", description = "추천 활동을 조회합니다. 행복도가 5 이상인 활동 중에서 랜덤으로 하나를 추천받을 수 있습니다.") + @GetMapping("/recommend") + public DataResponseDto> getRecommendedActivities(@AuthenticationPrincipal UserDetails userDetails) { + User user = userFindService.findByUserDetails(userDetails); + List responseDto = trendRecommendService.getRecommendActivities(user); + return DataResponseDto.of(responseDto, "추천 활동을 성공적으로 조회했습니다."); + } } diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/ActivityHappinessAnalyzer.java b/src/main/java/com/hobak/happinessql/domain/report/application/ActivityHappinessAnalyzer.java index c77eec6..e567447 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/application/ActivityHappinessAnalyzer.java +++ b/src/main/java/com/hobak/happinessql/domain/report/application/ActivityHappinessAnalyzer.java @@ -2,7 +2,9 @@ import com.hobak.happinessql.domain.record.domain.Record; import com.hobak.happinessql.domain.report.converter.ReportConverter; -import com.hobak.happinessql.domain.report.dto.ActivityHappinessDto; +import com.hobak.happinessql.domain.report.converter.TrendConverter; +import com.hobak.happinessql.domain.report.dto.ActivityHappinessResponseDto; +import com.hobak.happinessql.domain.report.dto.TrendRecommendActivityResponseDto; import java.util.*; import java.util.stream.Collectors; @@ -38,13 +40,13 @@ public static String getHappiestActivity(List records) { } } - public static List getActivityRankings(List records, int topCount) { - List activityRankings = new ArrayList<>(); + public static List getActivityRankings(List records, int topCount) { + List activityRankings = new ArrayList<>(); if (records == null || records.isEmpty()) { // 데이터가 없는 경우에도 빈 ActivityHappinessDto 객체를 topCount만큼 추가 for (int i = 0; i < topCount; i++) { - activityRankings.add(ReportConverter.toActivityHappinessDto(i + 1, null, null)); + activityRankings.add(ReportConverter.toActivityHappinessResponseDto(i + 1, null, null)); } return activityRankings; } @@ -53,7 +55,7 @@ public static List getActivityRankings(List record // 만약 topCount보다 적게 선정된 경우, 나머지 빈 항목 추가 while (activityRankings.size() < topCount) { - activityRankings.add(ReportConverter.toActivityHappinessDto(activityRankings.size() + 1, null, null)); + activityRankings.add(ReportConverter.toActivityHappinessResponseDto(activityRankings.size() + 1, null, null)); } return activityRankings.stream() @@ -61,8 +63,8 @@ public static List getActivityRankings(List record .collect(Collectors.toList()); } - public static List getActivityRankings(List records) { - List activityRankings = new ArrayList<>(); + public static List getActivityRankings(List records) { + List activityRankings = new ArrayList<>(); // 활동 그룹화 및 이모지 매핑 Map activityEmojiMap = getActivityEmojiMap(records); @@ -79,13 +81,56 @@ public static List getActivityRankings(List record for (int i = 0; i < sortedActivities.size(); i++) { String activity = sortedActivities.get(i); String emoji = activityEmojiMap.get(activity); // 이모지 가져오기 - ActivityHappinessDto activityDto = ReportConverter.toActivityHappinessDto(i + 1, activity, emoji); + ActivityHappinessResponseDto activityDto = ReportConverter.toActivityHappinessResponseDto(i + 1, activity, emoji); activityRankings.add(activityDto); } return activityRankings; } + public static List getRandomHappyActivities(List records, int count) { + + List recommendations = new ArrayList<>(); + + if (records == null || records.isEmpty()) { + // 데이터가 없는 경우에도 빈 TrendRecommendActivityResponseDto 객체를 count 만큼 추가 + for (int i = 0; i < count; i++) { + recommendations.add(TrendConverter.toTrendRecommendActivityResponseDto(null, null)); + } + return recommendations; + } + // 행복도가 5 이상인 활동 필터링 + List happyRecords = records.stream() + .filter(record -> record.getHappiness() >= 5) + .collect(Collectors.toList()); + + // 각 활동별로 그룹화 + Map> activityRecordsMap = groupRecordsByActivity(happyRecords); + + // 랜덤으로 활동 선택 + Random random = new Random(); + List activities = new ArrayList<>(activityRecordsMap.keySet()); + Collections.shuffle(activities); // 랜덤으로 섞기 + + // 활동이 count개 이상인지 확인하고, 최대 count 개 선택 + int limit = Math.min(count, activities.size()); + for (int i = 0; i < limit; i++) { + String activity = activities.get(i); + List recordsForActivity = activityRecordsMap.get(activity); + if (!recordsForActivity.isEmpty()) { + Record record = recordsForActivity.get(random.nextInt(recordsForActivity.size())); + recommendations.add(new TrendRecommendActivityResponseDto(activity, record.getActivity().getEmoji())); + } + } + + // 만약 count보다 적게 선정된 경우, 나머지 빈 항목 추가 + while (recommendations.size() < count) { + recommendations.add(TrendConverter.toTrendRecommendActivityResponseDto(null, null)); + } + + return recommendations; + } + private static Map> groupRecordsByActivity(List records) { return records.stream() .filter(record -> record.getActivity() != null) 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 55a147a..1ec1e10 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 @@ -2,7 +2,7 @@ import com.hobak.happinessql.domain.record.domain.Record; import com.hobak.happinessql.domain.report.converter.ReportConverter; -import com.hobak.happinessql.domain.report.dto.LocationHappinessDto; +import com.hobak.happinessql.domain.report.dto.LocationHappinessResponseDto; import java.util.*; import java.util.stream.Collectors; @@ -38,12 +38,12 @@ public static String getHappiestLocation(List records) { } } - public static List getLocationRankings(List records, int topCount) { - List locationRankings = new ArrayList<>(); + public static List getLocationRankings(List records, int topCount) { + List locationRankings = new ArrayList<>(); if (records == null || records.isEmpty()) { // 데이터가 없는 경우에도 빈 LocationHappinessDto 객체를 topCount만큼 추가 for (int i = 0; i < topCount; i++) { - locationRankings.add(ReportConverter.toLocationHappinessDto(i + 1, null)); + locationRankings.add(ReportConverter.toLocationHappinessResponseDto(i + 1, null)); } return locationRankings; } @@ -51,7 +51,7 @@ public static List getLocationRankings(List record locationRankings = getLocationRankings(records); // 만약 topCount보다 적게 선정된 경우, 나머지 빈 항목 추가 while (locationRankings.size() < topCount) { - locationRankings.add(ReportConverter.toLocationHappinessDto(locationRankings.size() + 1, null)); + locationRankings.add(ReportConverter.toLocationHappinessResponseDto(locationRankings.size() + 1, null)); } return locationRankings.stream() @@ -59,8 +59,8 @@ public static List getLocationRankings(List record .collect(Collectors.toList()); } - public static List getLocationRankings(List records) { - List locationRankings = new ArrayList<>(); + public static List getLocationRankings(List records) { + List locationRankings = new ArrayList<>(); // 도시와 구를 기준으로 Record 그룹화 Map> locationRecordsMap = groupRecordsByLocation(records); @@ -75,7 +75,7 @@ public static List getLocationRankings(List record // 상위 N개의 위치 선정 for (int i = 0; i < sortedLocations.size(); i++) { String location = sortedLocations.get(i); - LocationHappinessDto locationDto = ReportConverter.toLocationHappinessDto(i + 1, location); + LocationHappinessResponseDto locationDto = ReportConverter.toLocationHappinessResponseDto(i + 1, location); locationRankings.add(locationDto); } diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/ReportActivityRankingService.java b/src/main/java/com/hobak/happinessql/domain/report/application/ReportActivityRankingService.java index eee033a..a5b7920 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/application/ReportActivityRankingService.java +++ b/src/main/java/com/hobak/happinessql/domain/report/application/ReportActivityRankingService.java @@ -2,7 +2,7 @@ import com.hobak.happinessql.domain.record.domain.Record; import com.hobak.happinessql.domain.record.repository.RecordRepository; -import com.hobak.happinessql.domain.report.dto.ActivityHappinessDto; +import com.hobak.happinessql.domain.report.dto.ActivityHappinessResponseDto; import com.hobak.happinessql.domain.user.domain.User; import lombok.RequiredArgsConstructor; import java.time.LocalDate; @@ -17,12 +17,12 @@ public class ReportActivityRankingService { private final RecordRepository recordRepository; - public List getTop3AllHappiestActivities(User user) { + public List getTop3AllHappiestActivities(User user) { List records = recordRepository.findAllByUser(user); return ActivityHappinessAnalyzer.getActivityRankings(records, 3); } - public List getTop3AnnualHappiestActivities(User user) { + public List getTop3AnnualHappiestActivities(User user) { int currentYear = LocalDate.now().getYear(); LocalDateTime startOfYear = LocalDateTime.of(currentYear, 1, 1, 0, 0); LocalDateTime endOfYear = LocalDateTime.of(currentYear, 12, 31, 23, 59, 59); @@ -30,7 +30,7 @@ public List getTop3AnnualHappiestActivities(User user) { return ActivityHappinessAnalyzer.getActivityRankings(records, 3); } - public List getTop3MonthlyHappiestActivities(User user) { + public List getTop3MonthlyHappiestActivities(User user) { LocalDate today = LocalDate.now(); LocalDate startOfMonth = today.withDayOfMonth(1); LocalDate endOfMonth = today.withDayOfMonth(today.lengthOfMonth()); @@ -40,12 +40,12 @@ public List getTop3MonthlyHappiestActivities(User user) { return ActivityHappinessAnalyzer.getActivityRankings(records, 3); } - public List getAllActivityRankings(User user) { + public List getAllActivityRankings(User user) { List records = recordRepository.findAllByUser(user); return ActivityHappinessAnalyzer.getActivityRankings(records); } - public List getYearlyActivityRankings(User user) { + public List getYearlyActivityRankings(User user) { int currentYear = LocalDate.now().getYear(); LocalDateTime startOfYear = LocalDateTime.of(currentYear, 1, 1, 0, 0); LocalDateTime endOfYear = LocalDateTime.of(currentYear, 12, 31, 23, 59, 59); @@ -53,7 +53,7 @@ public List getYearlyActivityRankings(User user) { return ActivityHappinessAnalyzer.getActivityRankings(records); } - public List getMonthlyActivityRankings(User user) { + public List getMonthlyActivityRankings(User user) { LocalDate today = LocalDate.now(); LocalDate startOfMonth = LocalDate.now().withDayOfMonth(1); LocalDate endOfMonth = LocalDate.now().withDayOfMonth(today.lengthOfMonth()); diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/ReportLocationRankingService.java b/src/main/java/com/hobak/happinessql/domain/report/application/ReportLocationRankingService.java index 9e23c98..300cbc8 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/application/ReportLocationRankingService.java +++ b/src/main/java/com/hobak/happinessql/domain/report/application/ReportLocationRankingService.java @@ -2,7 +2,7 @@ import com.hobak.happinessql.domain.record.domain.Record; import com.hobak.happinessql.domain.record.repository.RecordRepository; -import com.hobak.happinessql.domain.report.dto.LocationHappinessDto; +import com.hobak.happinessql.domain.report.dto.LocationHappinessResponseDto; import com.hobak.happinessql.domain.user.domain.User; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -16,12 +16,12 @@ public class ReportLocationRankingService { private final RecordRepository recordRepository; - public List getTop3AllHappiestLocations(User user) { + public List getTop3AllHappiestLocations(User user) { List records = recordRepository.findAllByUser(user); return LocationHappinessAnalyzer.getLocationRankings(records, 3); } - public List getTop3AnnualHappiestLocations(User user) { + public List getTop3AnnualHappiestLocations(User user) { int currentYear = LocalDate.now().getYear(); LocalDateTime startOfYear = LocalDateTime.of(currentYear, 1, 1, 0, 0); LocalDateTime endOfYear = LocalDateTime.of(currentYear, 12, 31, 23, 59, 59); @@ -29,7 +29,7 @@ public List getTop3AnnualHappiestLocations(User user) { return LocationHappinessAnalyzer.getLocationRankings(records, 3); } - public List getTop3MonthlyHappiestLocations(User user) { + public List getTop3MonthlyHappiestLocations(User user) { LocalDate today = LocalDate.now(); LocalDate startOfMonth = today.withDayOfMonth(1); LocalDate endOfMonth = today.withDayOfMonth(today.lengthOfMonth()); @@ -39,12 +39,12 @@ public List getTop3MonthlyHappiestLocations(User user) { return LocationHappinessAnalyzer.getLocationRankings(records, 3); } - public List getAllLocationRankings(User user) { + public List getAllLocationRankings(User user) { List records = recordRepository.findAllByUser(user); return LocationHappinessAnalyzer.getLocationRankings(records); } - public List getYearlyLocationRankings(User user) { + public List getYearlyLocationRankings(User user) { int currentYear = LocalDate.now().getYear(); LocalDateTime startOfYear = LocalDateTime.of(currentYear, 1, 1, 0, 0); LocalDateTime endOfYear = LocalDateTime.of(currentYear, 12, 31, 23, 59, 59); @@ -52,7 +52,7 @@ public List getYearlyLocationRankings(User user) { return LocationHappinessAnalyzer.getLocationRankings(records); } - public List getMonthlyLocationRankings(User user) { + public List getMonthlyLocationRankings(User user) { LocalDate today = LocalDate.now(); LocalDate startOfMonth = LocalDate.now().withDayOfMonth(1); LocalDate endOfMonth = LocalDate.now().withDayOfMonth(today.lengthOfMonth()); diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/ReportTimeOfPeriodRankingService.java b/src/main/java/com/hobak/happinessql/domain/report/application/ReportTimeOfPeriodRankingService.java index 49bc1d5..ef3b402 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/application/ReportTimeOfPeriodRankingService.java +++ b/src/main/java/com/hobak/happinessql/domain/report/application/ReportTimeOfPeriodRankingService.java @@ -2,7 +2,7 @@ import com.hobak.happinessql.domain.record.domain.Record; import com.hobak.happinessql.domain.record.repository.RecordRepository; -import com.hobak.happinessql.domain.report.dto.TimeOfDayHappinessDto; +import com.hobak.happinessql.domain.report.dto.TimeOfDayHappinessResponseDto; import com.hobak.happinessql.domain.user.domain.User; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -17,12 +17,12 @@ public class ReportTimeOfPeriodRankingService { private final RecordRepository recordRepository; - public List getAllTimeOfDayRankings(User user) { + public List getAllTimeOfDayRankings(User user) { List records = recordRepository.findAllByUser(user); return TimeOfDayHappinessAnalyzer.getTimeOfDayRankings(records); } - public List getYearlyTimeOfDayRankings(User user) { + public List getYearlyTimeOfDayRankings(User user) { int currentYear = LocalDate.now().getYear(); LocalDateTime startOfYear = LocalDateTime.of(currentYear, 1, 1, 0, 0); LocalDateTime endOfYear = LocalDateTime.of(currentYear, 12, 31, 23, 59, 59); @@ -30,7 +30,7 @@ public List getYearlyTimeOfDayRankings(User user) { return TimeOfDayHappinessAnalyzer.getTimeOfDayRankings(records); } - public List getMonthlyTimeOfDayRankings(User user) { + public List getMonthlyTimeOfDayRankings(User user) { LocalDate today = LocalDate.now(); LocalDate startOfMonth = today.withDayOfMonth(1); LocalDate endOfMonth = today.withDayOfMonth(today.lengthOfMonth()); diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/TimeOfDayHappinessAnalyzer.java b/src/main/java/com/hobak/happinessql/domain/report/application/TimeOfDayHappinessAnalyzer.java index fe31faf..d3149ce 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/application/TimeOfDayHappinessAnalyzer.java +++ b/src/main/java/com/hobak/happinessql/domain/report/application/TimeOfDayHappinessAnalyzer.java @@ -3,7 +3,7 @@ import com.hobak.happinessql.domain.record.domain.Record; import com.hobak.happinessql.domain.report.converter.ReportConverter; import com.hobak.happinessql.domain.report.domain.TimeOfDay; -import com.hobak.happinessql.domain.report.dto.TimeOfDayHappinessDto; +import com.hobak.happinessql.domain.report.dto.TimeOfDayHappinessResponseDto; import java.util.*; import java.util.stream.Collectors; @@ -39,8 +39,8 @@ public static TimeOfDay getHappiestTimeOfDay(List records) { } } - public static List getTimeOfDayRankings(List records) { - List timeOfDayRankings = new ArrayList<>(); + public static List getTimeOfDayRankings(List records) { + List timeOfDayRankings = new ArrayList<>(); // 시간대별 평균 행복도와 빈도 계산 Map> timeOfDayRecordsMap = groupRecordsByTimeOfDay(records); @@ -53,7 +53,7 @@ public static List getTimeOfDayRankings(List reco // 상위 N개의 시간대 선정 for (int i = 0; i < sortedTimesOfDay.size(); i++) { TimeOfDay timeOfDay = sortedTimesOfDay.get(i); - TimeOfDayHappinessDto timeOfDayDto = ReportConverter.toTimeOfDayHappinessDto(i + 1, timeOfDay); + TimeOfDayHappinessResponseDto timeOfDayDto = ReportConverter.toTimeOfDayHappinessResponseDto(i + 1, timeOfDay); timeOfDayRankings.add(timeOfDayDto); } diff --git a/src/main/java/com/hobak/happinessql/domain/report/application/TrendPopularActivitiesService.java b/src/main/java/com/hobak/happinessql/domain/report/application/TrendPopularActivityService.java similarity index 85% rename from src/main/java/com/hobak/happinessql/domain/report/application/TrendPopularActivitiesService.java rename to src/main/java/com/hobak/happinessql/domain/report/application/TrendPopularActivityService.java index 777bd94..c5e12a6 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/application/TrendPopularActivitiesService.java +++ b/src/main/java/com/hobak/happinessql/domain/report/application/TrendPopularActivityService.java @@ -3,7 +3,7 @@ import com.hobak.happinessql.domain.activity.domain.Activity; import com.hobak.happinessql.domain.record.repository.RecordRepository; import com.hobak.happinessql.domain.report.converter.TrendConverter; -import com.hobak.happinessql.domain.report.dto.TrendPopularActivitiesResponseDto; +import com.hobak.happinessql.domain.report.dto.TrendPopularActivitiyResponseDto; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -13,9 +13,9 @@ @Service @RequiredArgsConstructor -public class TrendPopularActivitiesService { +public class TrendPopularActivityService { private final RecordRepository recordRepository; - public List getPopularActivities(){ + public List getPopularActivities(){ LocalDate today = LocalDate.now(); List results = recordRepository.findPopularActivities(today.atStartOfDay()); List popularActivities = results.stream() @@ -25,7 +25,7 @@ public List getPopularActivities(){ .map(result -> ((Number) result[1]).longValue()) .toList(); int ranking = 1; - List responseDtos = new ArrayList<>(); + List responseDtos = new ArrayList<>(); for(int i = 0; i getRecommendActivities(User user) { + List records = recordRepository.findAllExceptUser(user.getUserId()); + return ActivityHappinessAnalyzer.getRandomHappyActivities(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 53a7e5a..9645a3d 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 @@ -15,16 +15,16 @@ public static ReportSummaryResponseDto toReportSummaryResponseDto(TimeOfDay time .build(); } - public static ActivityHappinessDto toActivityHappinessDto(int ranking, String activity, String emoji) { - return ActivityHappinessDto.builder() + public static ActivityHappinessResponseDto toActivityHappinessResponseDto(int ranking, String activity, String emoji) { + return ActivityHappinessResponseDto.builder() .ranking(ranking) .activity(activity) .emoji(emoji) .build(); } - public static LocationHappinessDto toLocationHappinessDto(int ranking, String location) { - return LocationHappinessDto.builder() + public static LocationHappinessResponseDto toLocationHappinessResponseDto(int ranking, String location) { + return LocationHappinessResponseDto.builder() .ranking(ranking) .location(location) .build(); @@ -35,8 +35,8 @@ public static ReportGraphResponseDto toReportGraphResponseDto(ArrayList .happiness(happiness) .build(); } - public static TimeOfDayHappinessDto toTimeOfDayHappinessDto(int ranking, TimeOfDay timeOfDay) { - return TimeOfDayHappinessDto.builder() + public static TimeOfDayHappinessResponseDto toTimeOfDayHappinessResponseDto(int ranking, TimeOfDay timeOfDay) { + return TimeOfDayHappinessResponseDto.builder() .ranking(ranking) .timeOfDay(timeOfDay) .build(); diff --git a/src/main/java/com/hobak/happinessql/domain/report/converter/TrendConverter.java b/src/main/java/com/hobak/happinessql/domain/report/converter/TrendConverter.java index 5ba3128..3b3edc9 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/converter/TrendConverter.java +++ b/src/main/java/com/hobak/happinessql/domain/report/converter/TrendConverter.java @@ -1,9 +1,10 @@ package com.hobak.happinessql.domain.report.converter; -import com.hobak.happinessql.domain.report.dto.TrendPopularActivitiesResponseDto; +import com.hobak.happinessql.domain.report.dto.TrendPopularActivitiyResponseDto; +import com.hobak.happinessql.domain.report.dto.TrendRecommendActivityResponseDto; public class TrendConverter { - public static TrendPopularActivitiesResponseDto toTrendPopularActivitiesResponseDto(int ranking, String name, String emoji, Long times) { - return TrendPopularActivitiesResponseDto + public static TrendPopularActivitiyResponseDto toTrendPopularActivitiesResponseDto(int ranking, String name, String emoji, Long times) { + return TrendPopularActivitiyResponseDto .builder() .ranking(ranking) .times(times) @@ -11,4 +12,12 @@ public static TrendPopularActivitiesResponseDto toTrendPopularActivitiesResponse .emoji(emoji) .build(); } + + public static TrendRecommendActivityResponseDto toTrendRecommendActivityResponseDto(String name, String emoji) { + return TrendRecommendActivityResponseDto + .builder() + .name(name) + .emoji(emoji) + .build(); + } } diff --git a/src/main/java/com/hobak/happinessql/domain/report/dto/ActivityHappinessDto.java b/src/main/java/com/hobak/happinessql/domain/report/dto/ActivityHappinessResponseDto.java similarity index 68% rename from src/main/java/com/hobak/happinessql/domain/report/dto/ActivityHappinessDto.java rename to src/main/java/com/hobak/happinessql/domain/report/dto/ActivityHappinessResponseDto.java index c60f790..cc3e5bc 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/dto/ActivityHappinessDto.java +++ b/src/main/java/com/hobak/happinessql/domain/report/dto/ActivityHappinessResponseDto.java @@ -8,19 +8,16 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class ActivityHappinessDto { +public class ActivityHappinessResponseDto { private int ranking; private String activity; private String emoji; @Builder - public ActivityHappinessDto(int ranking, String activity, String emoji) { + public ActivityHappinessResponseDto(int ranking, String activity, String emoji) { this.ranking = ranking; this.activity = activity; this.emoji = emoji; } - public void setRanking(int ranking) { - this.ranking = ranking; - } } diff --git a/src/main/java/com/hobak/happinessql/domain/report/dto/LocationHappinessDto.java b/src/main/java/com/hobak/happinessql/domain/report/dto/LocationHappinessResponseDto.java similarity index 69% rename from src/main/java/com/hobak/happinessql/domain/report/dto/LocationHappinessDto.java rename to src/main/java/com/hobak/happinessql/domain/report/dto/LocationHappinessResponseDto.java index d46a824..1047c92 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/dto/LocationHappinessDto.java +++ b/src/main/java/com/hobak/happinessql/domain/report/dto/LocationHappinessResponseDto.java @@ -5,12 +5,12 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class LocationHappinessDto { +public class LocationHappinessResponseDto { private int ranking; private String location; @Builder - public LocationHappinessDto(int ranking, String location) { + public LocationHappinessResponseDto(int ranking, String location) { this.ranking = ranking; this.location = location; } diff --git a/src/main/java/com/hobak/happinessql/domain/report/dto/TimeOfDayHappinessDto.java b/src/main/java/com/hobak/happinessql/domain/report/dto/TimeOfDayHappinessResponseDto.java similarity index 80% rename from src/main/java/com/hobak/happinessql/domain/report/dto/TimeOfDayHappinessDto.java rename to src/main/java/com/hobak/happinessql/domain/report/dto/TimeOfDayHappinessResponseDto.java index 5039725..47c730f 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/dto/TimeOfDayHappinessDto.java +++ b/src/main/java/com/hobak/happinessql/domain/report/dto/TimeOfDayHappinessResponseDto.java @@ -10,7 +10,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class TimeOfDayHappinessDto { +public class TimeOfDayHappinessResponseDto { private int ranking; @@ -18,7 +18,7 @@ public class TimeOfDayHappinessDto { private TimeOfDay timeOfDay; @Builder - public TimeOfDayHappinessDto(int ranking, TimeOfDay timeOfDay) { + public TimeOfDayHappinessResponseDto(int ranking, TimeOfDay timeOfDay) { this.ranking = ranking; this.timeOfDay = timeOfDay; } diff --git a/src/main/java/com/hobak/happinessql/domain/report/dto/TrendPopularActivitiesResponseDto.java b/src/main/java/com/hobak/happinessql/domain/report/dto/TrendPopularActivitiyResponseDto.java similarity index 75% rename from src/main/java/com/hobak/happinessql/domain/report/dto/TrendPopularActivitiesResponseDto.java rename to src/main/java/com/hobak/happinessql/domain/report/dto/TrendPopularActivitiyResponseDto.java index 182b54f..3e6c17a 100644 --- a/src/main/java/com/hobak/happinessql/domain/report/dto/TrendPopularActivitiesResponseDto.java +++ b/src/main/java/com/hobak/happinessql/domain/report/dto/TrendPopularActivitiyResponseDto.java @@ -7,13 +7,13 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class TrendPopularActivitiesResponseDto { +public class TrendPopularActivitiyResponseDto { private int ranking; private String name; private String emoji; private Long times; @Builder - public TrendPopularActivitiesResponseDto(int ranking, String name, String emoji, Long times) { + public TrendPopularActivitiyResponseDto(int ranking, String name, String emoji, Long times) { this.ranking = ranking; this.name = name; this.emoji = emoji; diff --git a/src/main/java/com/hobak/happinessql/domain/report/dto/TrendRecommendActivityResponseDto.java b/src/main/java/com/hobak/happinessql/domain/report/dto/TrendRecommendActivityResponseDto.java new file mode 100644 index 0000000..67ca97e --- /dev/null +++ b/src/main/java/com/hobak/happinessql/domain/report/dto/TrendRecommendActivityResponseDto.java @@ -0,0 +1,20 @@ +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 TrendRecommendActivityResponseDto { + private String name; + private String emoji; + + @Builder + public TrendRecommendActivityResponseDto(String name, String emoji) { + this.name = name; + this.emoji = emoji; + } +} diff --git a/src/main/java/com/hobak/happinessql/domain/user/api/UserController.java b/src/main/java/com/hobak/happinessql/domain/user/api/UserController.java index 2e33c03..b399367 100644 --- a/src/main/java/com/hobak/happinessql/domain/user/api/UserController.java +++ b/src/main/java/com/hobak/happinessql/domain/user/api/UserController.java @@ -10,6 +10,8 @@ import com.hobak.happinessql.domain.user.dto.*; import com.hobak.happinessql.global.auth.JwtToken; import com.hobak.happinessql.global.response.DataResponseDto; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.NonNull; import lombok.RequiredArgsConstructor; @@ -18,6 +20,8 @@ import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; + +@Tag(name="User", description = "유저 관련 REST API에 대한 명세를 제공합니다.") @Slf4j @RestController @RequiredArgsConstructor @@ -32,6 +36,8 @@ public class UserController { @NonNull private PasswordEncoder passwordEncoder; + + @Operation(summary = "유저 프로필 조회", description = "유저의 프로필을 조회합니다.") @GetMapping("/profile") public DataResponseDto getUserProfile(@AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); @@ -39,6 +45,7 @@ public DataResponseDto getUserProfile(@AuthenticationPrincipal UserDetai return DataResponseDto.of(userProfileResponseDto, "유저 프로필을 성공적으로 조회했습니다."); } + @Operation(summary = "유저 프로필 수정", description = "유저의 프로필을 수정합니다.") @PutMapping("/profile") public DataResponseDto updateUserProfile(@RequestBody @Valid UserProfileUpdateRequestDto requestDto, @AuthenticationPrincipal UserDetails userDetails) { User user = userFindService.findByUserDetails(userDetails); @@ -47,6 +54,8 @@ public DataResponseDto updateUserProfile(@RequestBody @Valid UserProfile return DataResponseDto.of(responseDto, "유저 프로필을 성공적으로 수정했습니다."); } + + @Operation(summary = "로그인", description = "사용자가 서비스에 로그인하는 데 사용됩니다") @PostMapping("/login") public DataResponseDto signIn(@RequestBody SignInDto signInDto) { UserDetails user = customUserDetailsService.loadUserByUsername(signInDto.getUsername()); @@ -58,6 +67,7 @@ public DataResponseDto signIn(@RequestBody SignInDto signInDto) { } + @Operation(summary = "회원가입", description = "사용자가 서비스에 회원가입하는 데 사용됩니다") @PostMapping("/sign-up") public DataResponseDto signUp(@RequestBody SignUpDto signUpDto){ UserDto savedUserDto = userService.signUp(signUpDto);