diff --git a/src/main/java/com/example/spot/repository/querydsl/impl/StudyRepositoryCustomImpl.java b/src/main/java/com/example/spot/repository/querydsl/impl/StudyRepositoryCustomImpl.java index c71e5700..1766a367 100644 --- a/src/main/java/com/example/spot/repository/querydsl/impl/StudyRepositoryCustomImpl.java +++ b/src/main/java/com/example/spot/repository/querydsl/impl/StudyRepositoryCustomImpl.java @@ -1,5 +1,6 @@ package com.example.spot.repository.querydsl.impl; +import com.example.spot.domain.Region; import com.example.spot.domain.enums.Gender; import com.example.spot.domain.enums.Status; import com.example.spot.domain.enums.StudySortBy; @@ -433,6 +434,10 @@ private static void getConditions(Map search, QStudy study, List themeTypes = (List) search.get("themeTypes"); builder.and(study.studyThemes.any().theme.studyTheme.in(themeTypes)); } + if (search.get("regions") != null) { + List regionList = (List) search.get("regions"); + builder.and(study.regionStudies.any().region.in(regionList)); + } } } diff --git a/src/main/java/com/example/spot/service/study/StudyQueryServiceImpl.java b/src/main/java/com/example/spot/service/study/StudyQueryServiceImpl.java index 275944b5..ab48d423 100644 --- a/src/main/java/com/example/spot/service/study/StudyQueryServiceImpl.java +++ b/src/main/java/com/example/spot/service/study/StudyQueryServiceImpl.java @@ -8,6 +8,7 @@ import com.example.spot.domain.Region; import com.example.spot.domain.Theme; import com.example.spot.domain.enums.ApplicationStatus; +import com.example.spot.domain.enums.Gender; import com.example.spot.domain.enums.Status; import com.example.spot.domain.enums.StudyLikeStatus; import com.example.spot.domain.enums.StudySortBy; @@ -24,6 +25,7 @@ import com.example.spot.repository.MemberThemeRepository; import com.example.spot.repository.PreferredRegionRepository; import com.example.spot.repository.PreferredStudyRepository; +import com.example.spot.repository.RegionRepository; import com.example.spot.repository.RegionStudyRepository; import com.example.spot.repository.StudyRepository; import com.example.spot.repository.StudyThemeRepository; @@ -86,6 +88,7 @@ public class StudyQueryServiceImpl implements StudyQueryService { // 지역 관련 조회 private final PreferredRegionRepository preferredRegionRepository; private final RegionStudyRepository regionStudyRepository; + private final RegionRepository regionRepository; private final RedisTemplate redisTemplate; @@ -866,25 +869,10 @@ private List getOngoingStudyIds(Long memberId) { * @return 검색 조건 맵을 반환합니다. * */ - private static Map getSearchConditions(SearchRequestStudyDTO request) { - log.info("request: {}", request.getIsOnline()); + private Map getSearchConditions(SearchRequestStudyDTO request) { // 검색 조건 맵 생성 - Map search = new HashMap<>(); - if (request.getGender() != null) - search.put("gender", request.getGender()); - if (request.getMinAge() != null) - search.put("minAge", request.getMinAge()); - if (request.getMaxAge() != null) - search.put("maxAge", request.getMaxAge()); - if (request.getIsOnline() != null) - search.put("isOnline", request.getIsOnline()); - if (request.getHasFee() != null) - search.put("hasFee", request.getHasFee()); - if (request.getMaxFee() != null) - search.put("maxFee", request.getMaxFee()); - if (request.getMinFee() != null) - search.put("minFee", request.getMinFee()); - return search; + return getBasicStudyFilteringConditions(request.getGender(), request.getMinAge(), request.getMaxAge(), + request.getIsOnline(), request.getHasFee(), request.getMaxFee(), request.getMinFee(), request.getRegionCodes()); } /** @@ -895,23 +883,10 @@ private static Map getSearchConditions(SearchRequestStudyDTO req * @return 검색 조건 맵을 반환합니다. * */ - private static Map getSearchConditionsWithTheme(SearchRequestStudyWithThemeDTO request) { - Map search = new HashMap<>(); - - if (request.getGender() != null) - search.put("gender", request.getGender()); - if (request.getMinAge() != null) - search.put("minAge", request.getMinAge()); - if (request.getMaxAge() != null) - search.put("maxAge", request.getMaxAge()); - if (request.getIsOnline() != null) - search.put("isOnline", request.getIsOnline()); - if (request.getHasFee() != null) - search.put("hasFee", request.getHasFee()); - if (request.getMaxFee() != null) - search.put("maxFee", request.getMaxFee()); - if (request.getMinFee() != null) - search.put("minFee", request.getMinFee()); + private Map getSearchConditionsWithTheme(SearchRequestStudyWithThemeDTO request) { + Map search = getBasicStudyFilteringConditions(request.getGender(), request.getMinAge(), + request.getMaxAge(), request.getIsOnline(), + request.getHasFee(), request.getMaxFee(), request.getMinFee(), request.getRegionCodes()); if (request.getThemeTypes() != null && !request.getThemeTypes().isEmpty()) { search.put("themeTypes", request.getThemeTypes()); @@ -920,6 +895,45 @@ private static Map getSearchConditionsWithTheme(SearchRequestStu return search; } + private Map getBasicStudyFilteringConditions(Gender gender, Integer minAge, Integer maxAge, + Boolean isOnline, Boolean hasFee, + Integer maxFee, Integer minFee, List regions) { + Map search = new HashMap<>(); + + if (gender != null) + search.put("gender", gender); + if (minAge != null) + search.put("minAge", minAge); + if (maxAge != null) + search.put("maxAge", maxAge); + if (isOnline != null) + search.put("isOnline", isOnline); + if (hasFee != null) + search.put("hasFee", hasFee); + if (maxFee != null) + search.put("maxFee", maxFee); + if (minFee != null) + search.put("minFee", minFee); + + // 지역 코드가 null 이거나 비어있으면 검색 조건에 추가하지 않음 + if (regions == null || regions.isEmpty()) + return search; + + List regionList = convertCodeToRegion(regions); + + if (regionList != null && !regionList.isEmpty()) + search.put("regions", regionList); + return search; + } + + private List convertCodeToRegion(List regions) { + List regionList = regions.stream() + .map(regionCode -> regionRepository.findByCode(regionCode) + .orElseThrow(() -> new StudyHandler(ErrorStatus._STUDY_REGION_NOT_EXIST))) + .toList(); + return regionList; + } + /** * 스터디 목록을 DTO로 변환하는 메서드입니다. diff --git a/src/main/java/com/example/spot/web/dto/search/BaseSearchRequestStudyDTO.java b/src/main/java/com/example/spot/web/dto/search/BaseSearchRequestStudyDTO.java index 2a2e1556..2b83c240 100644 --- a/src/main/java/com/example/spot/web/dto/search/BaseSearchRequestStudyDTO.java +++ b/src/main/java/com/example/spot/web/dto/search/BaseSearchRequestStudyDTO.java @@ -6,6 +6,7 @@ import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Min; import jakarta.validation.constraints.NotNull; +import java.util.List; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -25,12 +26,10 @@ public class BaseSearchRequestStudyDTO { @Schema(description = "최소 나이 (18 이상).", example = "18") @Min(value = 18, message = "최소 나이는 18세 입니다.") - @NotNull(message = "최소 나이는 필수 입력 값입니다.") private Integer minAge; @Schema(description = "최대 나이 (60 이하).", example = "60") @Max(value = 60, message = "최대 나이는 60세 입니다.") - @NotNull(message = "최대 나이는 필수 입력 값입니다.") private Integer maxAge; @Schema(description = "스터디 온라인 진행 여부 (true, false).", example = "true") @@ -47,6 +46,9 @@ public class BaseSearchRequestStudyDTO { @Min(value = 0, message = "최소 활동비는 0원 입니다.") private Integer minFee; + @Schema(description = "스터디 활동 지역") + private List regionCodes; + // 공통 검증 로직 @AssertTrue(message = "최소 나이는 최대 나이보다 작아야 합니다.") private boolean isValidAgeRange() { @@ -72,4 +74,12 @@ private boolean isValidFeeRange() { return minFee <= maxFee; } + @AssertTrue(message = "온라인 스터디 조회 시, 스터디 지역을 입력받지 않습니다.") + private boolean isValidRegion() { + if (isOnline == null || !isOnline) { + return true; + } + return regionCodes == null || regionCodes.isEmpty(); + } + }