Skip to content
Open
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
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok-mapstruct-binding:0.2.0'

// Querydsl
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
implementation 'com.querydsl:querydsl-jpa:5.1.0:jakarta'
annotationProcessor 'com.querydsl:querydsl-apt:5.1.0:jakarta'
annotationProcessor 'jakarta.persistence:jakarta.persistence-api:'
annotationProcessor 'jakarta.annotation:jakarta.annotation-api'

Expand Down
100 changes: 86 additions & 14 deletions src/asciidoc/api/group.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@

== ✨ API 문서

=== 1. 그룹 생성/탈퇴/관리 API
=== 1. 그룹 가입/탈퇴/관리 API
''''

==== 1-1. 그룹 태그 불러오기
Expand Down Expand Up @@ -150,8 +150,8 @@ include::{snippets}/group-entry-controller-rest-docs-test/increase-code-expire_s




==== 2-3. 유저가 속한 그룹 조회
=== 3. 그룹 조회 API
==== 3-1. 유저가 속한 그룹 조회

*Description* +

Expand All @@ -172,7 +172,7 @@ include::{snippets}/group-controller-rest-docs-test/get-groups_success/http-requ
include::{snippets}/group-controller-rest-docs-test/get-groups_success/http-response.adoc[]
include::{snippets}/group-controller-rest-docs-test/get-groups_success/response-fields.adoc[]

==== 2-4. 그룹 상세 조회
==== 3-2. 그룹 상세 조회

*Description* +

Expand All @@ -192,7 +192,7 @@ include::{snippets}/group-controller-rest-docs-test/get-group-detail_success/htt
include::{snippets}/group-controller-rest-docs-test/get-group-detail_success/http-response.adoc[]
include::{snippets}/group-controller-rest-docs-test/get-group-detail_success/response-fields.adoc[]

==== 2-5. 그룹 대표 정보 조회
==== 3-3. 그룹 대표 정보 조회

*Description* +

Expand All @@ -217,7 +217,79 @@ include::{snippets}/group-entry-controller-rest-docs-test/get-group-summary_succ
include::{snippets}/group-entry-controller-rest-docs-test/get-group-summary_success/http-response.adoc[]
include::{snippets}/group-entry-controller-rest-docs-test/get-group-summary_success/response-fields.adoc[]

==== 2-6. 그룹 가입
==== 3-4. 그룹 검색

*Description* +

'''

각 그룹을 검색합니다. tag, hashTag, name 에 기반하여 검색을 수행할 수 있습니다. 검색 시 기타 필터링 및 정렬 기준을
선택할 수 있습니다.


approval::
* `null` -> 전체
* `true` -> 승인 필요만
* `false` -> 승인 불필요만

open::
* `null` -> 전체
* `true` -> 공개 + 정원 미달 (`isOpen = true` AND `totalMember < maxMember`)
* `false` -> 비공개 또는 정원 꽉 참 (`isOpen = false` OR `totalMember >= maxMember`)

[NOTE]
tag/name/hashTag 중 하나로만 검색이 가능합니다.

[NOTE]
request param 의 cursor 데이터는 이전 응답의 "data.next" 필드로 주어집니다. (이전 데이터의 가장 마지막 ID)

[NOTE]
request param 의 value 데이터는 이전 응답의 "data.next" 필드에서 주어진 식별자를 보고, 해당 데이터의 정렬 기준 값을
문자열로 주어야 합니다. (주어진 resposne 의 경우 "next" 가 205 이므로 groupId = 205 인 필드에 대해 정렬 기준 (POPULAR) 과
대응되는 memberCount 값을 줘야 함)



*Request* +

'''

include::{snippets}/group-controller-rest-docs-test/search-groups_success/http-request.adoc[]
include::{snippets}/group-controller-rest-docs-test/search-groups_success/query-parameters.adoc[]

*Response* +

'''

include::{snippets}/group-controller-rest-docs-test/search-groups_success/http-response.adoc[]
include::{snippets}/group-controller-rest-docs-test/search-groups_success/response-fields.adoc[]

=== 4. 그룹 가입 관련 API

==== 4-1. 초대 코드 생성

*Description* +

'''

그룹 초대 코드 생성을 위해 사용합니다.

*Request* +

'''

include::{snippets}/group-entry-controller-rest-docs-test/generate-entry-code_success/http-request.adoc[]

*Response* +

'''

include::{snippets}/group-entry-controller-rest-docs-test/generate-entry-code_success/response-headers.adoc[]
include::{snippets}/group-entry-controller-rest-docs-test/generate-entry-code_success/response-fields.adoc[]
include::{snippets}/group-entry-controller-rest-docs-test/generate-entry-code_success/http-response.adoc[]


==== 4-2. 그룹 가입

*Description* +

Expand All @@ -240,7 +312,7 @@ include::{snippets}/group-entry-controller-rest-docs-test/join-group_success/req
include::{snippets}/group-entry-controller-rest-docs-test/join-group_success/http-response.adoc[]
include::{snippets}/group-entry-controller-rest-docs-test/join-group_success/response-headers.adoc[]

==== 2-7. 그룹 가입 요청
==== 4-3. 그룹 가입 요청

*Description* +

Expand All @@ -263,7 +335,7 @@ include::{snippets}/group-entry-controller-rest-docs-test/request-participant_su
include::{snippets}/group-entry-controller-rest-docs-test/request-participant_success/http-response.adoc[]
include::{snippets}/group-entry-controller-rest-docs-test/request-participant_success/response-headers.adoc[]

==== 2-8. 그룹 가입 요청 조회
==== 4-4. 그룹 가입 요청 조회

*Description* +

Expand All @@ -286,7 +358,7 @@ include::{snippets}/group-entry-controller-rest-docs-test/get-entry-requests_suc
include::{snippets}/group-entry-controller-rest-docs-test/get-entry-requests_success/http-response.adoc[]
include::{snippets}/group-entry-controller-rest-docs-test/get-entry-requests_success/response-fields.adoc[]

==== 2-9. 그룹 가입 요청 승인
==== 4-5. 그룹 가입 요청 승인

*Description*

Expand All @@ -307,7 +379,7 @@ include::{snippets}/group-entry-controller-rest-docs-test/accept-entry-request_s
include::{snippets}/group-entry-controller-rest-docs-test/accept-entry-request_success/http-response.adoc[]
include::{snippets}/group-entry-controller-rest-docs-test/accept-entry-request_success/response-headers.adoc[]

==== 2-10. 그룹 가입 요청 거절
==== 4-6. 그룹 가입 요청 거절

*Description*

Expand All @@ -327,10 +399,10 @@ include::{snippets}/group-entry-controller-rest-docs-test/refuse-entry-request_s
'''
include::{snippets}/group-entry-controller-rest-docs-test/refuse-entry-request_success/http-response.adoc[]

=== 3. 그룹 스터디 조회/생성/관리 API
=== 5. 그룹 스터디 조회/생성/관리 API
''''

==== 3-1.그룹 카테고리 생성
==== 5-1. 그룹 카테고리 생성

*Description*

Expand All @@ -350,10 +422,10 @@ include::{snippets}/group-category-controller-rest-docs-test/create_success/requ
include::{snippets}/group-category-controller-rest-docs-test/create_success/http-response.adoc[]
include::{snippets}/group-category-controller-rest-docs-test/create_success/response-headers.adoc[]

=== 그룹 랭킹 조회 API
=== 6. 그룹 랭킹 조회 API
'''

==== 일간/주간/월간 랭킹 조회
==== 6-1. 일간/주간/월간 랭킹 조회

*Description*

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* {@link AbstractImageManager}
*
* @author sleepyhoon
* @See AbstractImageManager
* @see AbstractImageManager
* @since 2026-01-13
*/
@Component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,17 @@

import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;

import lombok.RequiredArgsConstructor;

import com.studypals.domain.groupManage.dto.CreateGroupReq;
import com.studypals.domain.groupManage.dto.GetGroupDetailRes;
import com.studypals.domain.groupManage.dto.GetGroupTagRes;
import com.studypals.domain.groupManage.dto.GetGroupsRes;
import com.studypals.domain.groupManage.dao.groupRepository.GroupSortType;
import com.studypals.domain.groupManage.dto.*;
import com.studypals.domain.groupManage.service.GroupService;
import com.studypals.global.annotations.CursorDefault;
import com.studypals.global.request.Cursor;
import com.studypals.global.responses.CommonResponse;
import com.studypals.global.responses.CursorResponse;
import com.studypals.global.responses.Response;
import com.studypals.global.responses.ResponseCode;

Expand Down Expand Up @@ -71,4 +67,24 @@ public ResponseEntity<Response<GetGroupDetailRes>> getGroupDetail(
GetGroupDetailRes response = groupService.getGroupDetails(userId, groupId);
return ResponseEntity.ok(CommonResponse.success(ResponseCode.GROUP_DETAIL, response));
}

@GetMapping("/search")
public ResponseEntity<CursorResponse<GetGroupsRes>> searchGroups(
@CursorDefault(sortType = GroupSortType.class, cursor = 0, size = 5, sort = "POPULAR") Cursor cursor,
@RequestParam(required = false, name = "hashTag") String hashTag,
@RequestParam(required = false, name = "tag") String tag,
@RequestParam(required = false, name = "name") String name,
@RequestParam(required = false, name = "open") Boolean open,
@RequestParam(required = false, name = "approval") Boolean approval) {
Comment on lines +71 to +78
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P3]
필드수가 많은데 hashTag, tag, name, open, approval 5개 필드를 포함한 dto로 필드를 받는 것은 어떤가요?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

적용해보겠습니다.

GroupSearchDto dto = GroupSearchDto.builder()
.hashTag(hashTag)
.tag(tag)
.name(name)
.isOpen(open)
.isApprovalRequired(approval)
.build();
CursorResponse.Content<GetGroupsRes> response = groupService.search(dto, cursor);

return ResponseEntity.ok(CursorResponse.success(ResponseCode.GROUP_SEARCH, response));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import com.studypals.domain.groupManage.service.GroupEntryService;
import com.studypals.global.annotations.CursorDefault;
import com.studypals.global.request.Cursor;
import com.studypals.global.request.DateSortType;
import com.studypals.global.responses.CommonResponse;
import com.studypals.global.responses.CursorResponse;
import com.studypals.global.responses.Response;
Expand Down Expand Up @@ -93,7 +94,9 @@ public ResponseEntity<Void> requestGroupParticipant(

@GetMapping("/{groupId}/entry-requests")
public ResponseEntity<CursorResponse<GroupEntryRequestDto>> getEntryRequests(
@AuthenticationPrincipal Long userId, @PathVariable Long groupId, @CursorDefault Cursor cursor) {
@AuthenticationPrincipal Long userId,
@PathVariable Long groupId,
@CursorDefault(sortType = DateSortType.class) Cursor cursor) {
CursorResponse.Content<GroupEntryRequestDto> response =
groupEntryService.getEntryRequests(userId, groupId, cursor);
return ResponseEntity.ok(CursorResponse.success(ResponseCode.GROUP_ENTRY_REQUEST_LIST, response));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,14 @@ public interface GroupHashTagRepository extends JpaRepository<GroupHashTag, Long
WHERE gt.group.id = :groupId
""")
List<GroupHashTag> findAllByGroupIdWithTag(@Param("groupId") Long groupId);

List<GroupHashTag> findAllByGroupId(Long groupId);

/**
* GroupHashTag 에서 Group 에 대해, id 를 제외한 다른 데이터를 조회 시 N + 1 문제를 야기할 수 있습니다. 따라서 해당 메서드를
* 사용하기 앞서 group 에 대해 ID 외 다른 칼럼을 조회하는지에 대한 확인이 필요합니다.
* @param groupIds 검색하고자 하는 그룹 ID 리스트
* @return groupHashTag 리스트(단 group 은 lazy loading)
*/
List<GroupHashTag> findAllByGroupIdIn(List<Long> groupIds);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.studypals.domain.groupManage.dao;
package com.studypals.domain.groupManage.dao.groupEntryRepository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import com.studypals.domain.groupManage.dao.GroupEntryCodeRedisRepositoryCustom;
import com.studypals.domain.groupManage.entity.GroupEntryCode;

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.studypals.domain.groupManage.dao;
package com.studypals.domain.groupManage.dao.groupEntryRepository;

import org.springframework.data.domain.Slice;
import org.springframework.stereotype.Repository;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package com.studypals.domain.groupManage.dao;
package com.studypals.domain.groupManage.dao.groupEntryRepository;

// import static com.studypals.domain.groupManage.entity.QGroupEntryRequest.groupEntryRequest;

import static com.studypals.domain.groupManage.entity.QGroupEntryRequest.groupEntryRequest;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.studypals.domain.groupManage.dao;
package com.studypals.domain.groupManage.dao.groupEntryRepository;

import java.time.LocalDate;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.studypals.domain.groupManage.dao;
package com.studypals.domain.groupManage.dao.groupMemberRepository;

import java.util.List;

Expand Down Expand Up @@ -33,8 +33,9 @@ public interface GroupMemberCustomRepository {

/**
* 여러 그룹에 속한 모든 멤버의 정보(id,nickname,imageUrl,role)를 한번에 조회합니다.
* @param groupIds
* @return
* @param groupIds 검색할 groupId 리스트
* @param limit 가져올 사용자의 개수 제한
* @return 입력된 groupIds 에 대해, 각 그룹당 소속된 상위 limit 명을 포함한 데이터.
*/
List<GroupMemberProfileMappingDto> findTopNMemberInGroupIds(List<Long> groupIds, int limit);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.studypals.domain.groupManage.dao;
package com.studypals.domain.groupManage.dao.groupMemberRepository;

import static com.studypals.domain.groupManage.entity.QGroupMember.groupMember;
import static com.studypals.domain.memberManage.entity.QMember.member;
Expand All @@ -17,7 +17,7 @@

/**
* group member custom repository 의 구현 클래스입니다.
*
*./
* <p>group member 관련 커스텀 쿼리를 구현합니다.
*
* <p><b>상속 정보:</b><br>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.studypals.domain.groupManage.dao;
package com.studypals.domain.groupManage.dao.groupMemberRepository;

import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -34,7 +34,7 @@ public interface GroupMemberRepository extends JpaRepository<GroupMember, Long>,
@Query(
"""
SELECT new com.studypals.domain.groupManage.dto.GroupSummaryDto(
g.id, g.name, g.tag, g.totalMember, g.chatRoom.id, g.isOpen, g.isApprovalRequired, g.createdDate
g.id, g.name, g.tag, g.totalMember, g.chatRoom.id, g.isOpen, g.isApprovalRequired, g.createdDate
)
FROM GroupMember gm
JOIN gm.group g
Expand Down
Loading