Skip to content
This repository was archived by the owner on Jan 11, 2026. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.example.spot.domain.enums.Status;
import com.example.spot.domain.enums.StudySortBy;
import com.example.spot.domain.enums.StudyState;
import com.example.spot.domain.enums.Theme;
import com.example.spot.domain.enums.ThemeType;
import com.example.spot.domain.mapping.MemberStudy;
import com.example.spot.domain.mapping.QMemberStudy;
import com.example.spot.domain.mapping.QRegionStudy;
Expand Down Expand Up @@ -424,6 +426,10 @@ private static void getConditions(Map<String, Object> search, QStudy study,
if (search.get("fee") != null) {
builder.and(study.fee.loe((Integer) search.get("fee")));
}
if (search.get("themeTypes") != null) {
List<ThemeType> themeTypes = (List<ThemeType>) search.get("themeTypes");
builder.and(study.studyThemes.any().theme.studyTheme.in(themeTypes));
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import com.example.spot.domain.enums.StudySortBy;
import com.example.spot.domain.enums.ThemeType;
import com.example.spot.web.dto.search.SearchRequestDTO.SearchRequestStudyDTO;
import com.example.spot.web.dto.search.SearchRequestStudyDTO;
import com.example.spot.web.dto.search.SearchRequestStudyWithThemeDTO;
import com.example.spot.web.dto.search.SearchResponseDTO.HotKeywordDTO;
import com.example.spot.web.dto.search.SearchResponseDTO.MyPageDTO;
import com.example.spot.web.dto.search.SearchResponseDTO.StudyPreviewDTO;
Expand Down Expand Up @@ -41,16 +42,16 @@ StudyPreviewDTO findInterestStudiesByConditionsSpecific(Pageable pageable, Long
SearchRequestStudyDTO request, ThemeType theme, StudySortBy sortBy);

// 내 관심 지역 스터디 페이징 조회
StudyPreviewDTO findInterestRegionStudiesByConditionsAll(Pageable pageable, Long memberId,
SearchRequestStudyDTO request, StudySortBy sortBy);
StudyPreviewDTO findInterestRegionStudiesByConditionsAll(
Pageable pageable, Long memberId, SearchRequestStudyWithThemeDTO request, StudySortBy sortBy);

// 내 특정 관심 지역 스터디 페이징 조회
StudyPreviewDTO findInterestRegionStudiesByConditionsSpecific(Pageable pageable, Long memberId,
SearchRequestStudyDTO request, String regionCode, StudySortBy sortBy);
StudyPreviewDTO findInterestRegionStudiesByConditionsSpecific(
Pageable pageable, Long memberId, SearchRequestStudyWithThemeDTO request, String regionCode, StudySortBy sortBy);

// 모집 중 스터디 조회
StudyPreviewDTO findRecruitingStudiesByConditions(Pageable pageable,
SearchRequestStudyDTO request, StudySortBy sortBy);
StudyPreviewDTO findRecruitingStudiesByConditions(
Pageable pageable, SearchRequestStudyWithThemeDTO request, StudySortBy sortBy);

// 찜한 스터디 조회
StudyPreviewDTO findLikedStudies(Long memberId, Pageable pageable);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
import com.example.spot.repository.StudyThemeRepository;
import com.example.spot.repository.ThemeRepository;
import com.example.spot.security.utils.SecurityUtils;
import com.example.spot.web.dto.search.SearchRequestDTO.SearchRequestStudyDTO;
import com.example.spot.web.dto.search.SearchRequestStudyDTO;
import com.example.spot.web.dto.search.SearchRequestStudyWithThemeDTO;
import com.example.spot.web.dto.search.SearchResponseDTO;
import com.example.spot.web.dto.search.SearchResponseDTO.HotKeywordDTO;
import com.example.spot.web.dto.search.SearchResponseDTO.MyPageDTO;
Expand Down Expand Up @@ -472,8 +473,8 @@ public StudyPreviewDTO findInterestStudiesByConditionsSpecific(Pageable pageable
*
*/
@Override
public StudyPreviewDTO findInterestRegionStudiesByConditionsAll(Pageable pageable,
Long memberId, SearchRequestStudyDTO request, StudySortBy sortBy) {
public StudyPreviewDTO findInterestRegionStudiesByConditionsAll(
Pageable pageable, Long memberId, SearchRequestStudyWithThemeDTO request, StudySortBy sortBy) {

// 회원이 참가하고 있는 스터디 ID 가져오기
List<Long> memberOngoingStudyIds = getOngoingStudyIds(memberId);
Expand All @@ -498,7 +499,7 @@ public StudyPreviewDTO findInterestRegionStudiesByConditionsAll(Pageable pageabl
throw new StudyHandler(ErrorStatus._STUDY_REGION_NOT_EXIST);

// 검색 조건 맵 생성
Map<String, Object> conditions = getSearchConditions(request);
Map<String, Object> conditions = getSearchConditionsWithTheme(request);


// 검색 조건에 맞는 스터디 갯수 조회
Expand Down Expand Up @@ -535,8 +536,8 @@ public StudyPreviewDTO findInterestRegionStudiesByConditionsAll(Pageable pageabl
*
*/
@Override
public StudyPreviewDTO findInterestRegionStudiesByConditionsSpecific(Pageable pageable,
Long memberId, SearchRequestStudyDTO request, String regionCode, StudySortBy sortBy) {
public StudyPreviewDTO findInterestRegionStudiesByConditionsSpecific(
Pageable pageable, Long memberId, SearchRequestStudyWithThemeDTO request, String regionCode, StudySortBy sortBy) {

// 회원이 참가하고 있는 스터디 ID 가져오기
List<Long> memberOngoingStudyIds = getOngoingStudyIds(memberId);
Expand Down Expand Up @@ -568,7 +569,7 @@ public StudyPreviewDTO findInterestRegionStudiesByConditionsSpecific(Pageable pa
throw new StudyHandler(ErrorStatus._STUDY_REGION_NOT_EXIST);

// 검색 조건 맵 생성
Map<String, Object> conditions = getSearchConditions(request);
Map<String, Object> conditions = getSearchConditionsWithTheme(request);

// 검색 조건에 맞는 스터디 갯수 조회
long totalElements = studyRepository.countStudyByConditionsAndRegionStudiesAndNotInIds(
Expand Down Expand Up @@ -598,11 +599,11 @@ public StudyPreviewDTO findInterestRegionStudiesByConditionsSpecific(Pageable pa
*
*/
@Override
public StudyPreviewDTO findRecruitingStudiesByConditions(Pageable pageable,
SearchRequestStudyDTO request, StudySortBy sortBy) {
public StudyPreviewDTO findRecruitingStudiesByConditions(
Pageable pageable, SearchRequestStudyWithThemeDTO request, StudySortBy sortBy) {

// 검색 조건 맵 생성
Map<String, Object> conditions = getSearchConditions(request);
Map<String, Object> conditions = getSearchConditionsWithTheme(request);

// 검색 조건(모집 중)에 맞는 스터디 조회
List<Study> studies = studyRepository.findRecruitingStudyByConditions(conditions,
Expand Down Expand Up @@ -884,6 +885,38 @@ private static Map<String, Object> getSearchConditions(SearchRequestStudyDTO req
return search;
}

/**
* 검색 조건을 입력 받아 검색 조건 맵을 생성하는 메서드입니다.
*
* @param request 검색 조건을 입력 받습니다.
*
* @return 검색 조건 맵을 반환합니다.
*
*/
private static Map<String, Object> getSearchConditionsWithTheme(SearchRequestStudyWithThemeDTO request) {
Map<String, Object> 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.getFee() != null)
search.put("fee", request.getFee());

if (request.getThemeTypes() != null && !request.getThemeTypes().isEmpty()) {
search.put("themeTypes", request.getThemeTypes());
}

return search;
}


/**
* 스터디 목록을 DTO로 변환하는 메서드입니다.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
import com.example.spot.security.utils.SecurityUtils;
import com.example.spot.service.study.StudyCommandService;
import com.example.spot.service.study.StudyQueryService;
import com.example.spot.validation.annotation.ExistMember;
import com.example.spot.web.dto.search.SearchRequestDTO.SearchRequestStudyDTO;
import com.example.spot.web.dto.search.SearchRequestStudyDTO;
import com.example.spot.web.dto.search.SearchRequestStudyWithThemeDTO;
import com.example.spot.web.dto.search.SearchResponseDTO.HotKeywordDTO;
import com.example.spot.web.dto.search.SearchResponseDTO.MyPageDTO;
import com.example.spot.web.dto.search.SearchResponseDTO.StudyPreviewDTO;
Expand Down Expand Up @@ -206,7 +206,7 @@ public ApiResponse<StudyPreviewDTO> interestStudiesByConditionsSpecific(
@Parameter(name = "size", description = "조회할 페이지 크기를 입력 받습니다. 페이지 크기는 1 이상의 정수 입니다. ", required = true)
@Parameter(name = "sortBy", description = "정렬 기준을 입력 받습니다.", required = true)
public ApiResponse<StudyPreviewDTO> interestRegionStudiesByConditionsAll(
@ModelAttribute @Valid SearchRequestStudyDTO searchRequestStudyDTO,
@ModelAttribute @Valid SearchRequestStudyWithThemeDTO searchRequestStudyDTO,
@RequestParam @Min(0) Integer page,
@RequestParam @Min(1) Integer size,
@RequestParam StudySortBy sortBy
Expand Down Expand Up @@ -240,7 +240,7 @@ public ApiResponse<StudyPreviewDTO> interestRegionStudiesByConditionsAll(
@Parameter(name = "sortBy", description = "정렬 기준을 입력 받습니다.", required = true)
public ApiResponse<StudyPreviewDTO> interestRegionStudiesByConditionsSpecific(
@RequestParam String regionCode,
@ModelAttribute @Valid SearchRequestStudyDTO searchRequestStudyDTO,
@ModelAttribute @Valid SearchRequestStudyWithThemeDTO searchRequestStudyDTO,
@RequestParam @Min(0) Integer page,
@RequestParam @Min(1) Integer size,
@RequestParam StudySortBy sortBy
Expand Down Expand Up @@ -274,7 +274,7 @@ public ApiResponse<StudyPreviewDTO> interestRegionStudiesByConditionsSpecific(
@Parameter(name = "size", description = "조회할 페이지 크기를 입력 받습니다. 페이지 크기는 1 이상의 정수 입니다. ", required = true)
@Parameter(name = "sortBy", description = "정렬 기준을 입력 받습니다.", required = true)
public ApiResponse<StudyPreviewDTO> recruitingStudiesByConditions(
@ModelAttribute @Valid SearchRequestStudyDTO searchRequestStudyDTO,
@ModelAttribute @Valid SearchRequestStudyWithThemeDTO searchRequestStudyDTO,
@RequestParam @Min(0) Integer page,
@RequestParam @Min(1) Integer size,
@RequestParam StudySortBy sortBy) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.example.spot.web.dto.search;

import com.example.spot.domain.enums.Gender;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

@Getter
@Setter
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class BaseSearchRequestStudyDTO {

@Schema(description = "성별을 입력 받습니다.", example = "MALE")
private Gender gender;

@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")
private Boolean isOnline;

@Schema(description = "스터디 활동비 유무 (true, false).", example = "false")
private Boolean hasFee;

@Schema(description = "스터디 최대 활동비.", example = "10000")
@Max(value = 1000000, message = "최대 활동비는 1,000,000원 입니다.")
private Integer fee;

// 공통 검증 로직
@AssertTrue(message = "최소 나이는 최대 나이보다 작아야 합니다.")
private boolean isValidAgeRange() {
if (minAge == null || maxAge == null) {
return true;
}
return minAge <= maxAge;
}

@AssertTrue(message = "활동비가 없는 경우에는 활동비 금액을 입력 받지 않습니다.")
private boolean isValidFee() {
if (hasFee == null || hasFee) {
return true;
}
return fee == null;
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.example.spot.web.dto.search;

import com.example.spot.domain.enums.Gender;
import com.example.spot.domain.enums.ThemeType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.AssertTrue;
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;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
public class SearchRequestStudyDTO extends BaseSearchRequestStudyDTO {

}

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.example.spot.web.dto.search;

import com.example.spot.domain.enums.Gender;
import com.example.spot.domain.enums.ThemeType;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.SuperBuilder;

@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
public class SearchRequestStudyWithThemeDTO extends BaseSearchRequestStudyDTO {

@Schema(description = "스터디 테마 리스트입니다. (예: HOBBY, PROJECT, EXAM)", example = "[\"HOBBY\", \"PROJECT\"]")
private List<ThemeType> themeTypes;
}
Loading