Skip to content

Commit dac2759

Browse files
committed
chore(#197/recruit): 멤버 전체 조회 api 구현
1 parent dd74a7e commit dac2759

File tree

6 files changed

+137
-4
lines changed

6 files changed

+137
-4
lines changed

src/main/java/inha/gdgoc/domain/recruit/controller/RecruitMemberController.java

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package inha.gdgoc.domain.recruit.controller;
22

3+
import static inha.gdgoc.domain.recruit.controller.message.RecruitMemberMessage.MEMBER_LIST_RETRIEVED_SUCCESS;
34
import static inha.gdgoc.domain.recruit.controller.message.RecruitMemberMessage.MEMBER_RETRIEVED_SUCCESS;
45
import static inha.gdgoc.domain.recruit.controller.message.RecruitMemberMessage.MEMBER_SAVE_SUCCESS;
56
import static inha.gdgoc.domain.recruit.controller.message.RecruitMemberMessage.PAYMENT_MARKED_COMPLETE_SUCCESS;
@@ -11,15 +12,25 @@
1112
import inha.gdgoc.domain.recruit.dto.request.PaymentUpdateRequest;
1213
import inha.gdgoc.domain.recruit.dto.response.CheckPhoneNumberResponse;
1314
import inha.gdgoc.domain.recruit.dto.response.CheckStudentIdResponse;
15+
import inha.gdgoc.domain.recruit.dto.response.RecruitMemberSummaryResponse;
1416
import inha.gdgoc.domain.recruit.dto.response.SpecifiedMemberResponse;
17+
import inha.gdgoc.domain.recruit.entity.RecruitMember;
1518
import inha.gdgoc.domain.recruit.service.RecruitMemberService;
1619
import inha.gdgoc.global.dto.response.ApiResponse;
20+
import inha.gdgoc.global.dto.response.PageMeta;
1721
import io.swagger.v3.oas.annotations.Operation;
22+
import io.swagger.v3.oas.annotations.Parameter;
1823
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
1924
import io.swagger.v3.oas.annotations.tags.Tag;
2025
import jakarta.validation.constraints.NotBlank;
2126
import jakarta.validation.constraints.Pattern;
27+
import java.util.List;
2228
import lombok.RequiredArgsConstructor;
29+
import org.springframework.data.domain.Page;
30+
import org.springframework.data.domain.PageRequest;
31+
import org.springframework.data.domain.Pageable;
32+
import org.springframework.data.domain.Sort;
33+
import org.springframework.data.domain.Sort.Direction;
2334
import org.springframework.http.ResponseEntity;
2435
import org.springframework.security.access.prepost.PreAuthorize;
2536
import org.springframework.web.bind.annotation.GetMapping;
@@ -84,9 +95,6 @@ public ResponseEntity<ApiResponse<SpecifiedMemberResponse, Void>> getSpecifiedMe
8495
return ResponseEntity.ok(ApiResponse.ok(MEMBER_RETRIEVED_SUCCESS, response));
8596
}
8697

87-
// TODO 전체 응답 조회 및 검색
88-
89-
9098
@Operation(
9199
summary = "입금 상태 변경",
92100
description = "설정하려는 상태(NOT 현재 상태)를 body에 보내주세요. true=입금 완료, false=입금 미완료",
@@ -109,4 +117,42 @@ public ResponseEntity<ApiResponse<Void, Void>> updatePayment(
109117
);
110118
}
111119

120+
@Operation(
121+
summary = "지원자 목록 조회",
122+
description = "전체 목록 또는 이름 검색 결과를 반환합니다. 검색어(question)를 주면 이름 포함 검색, 없으면 전체 조회. sort랑 dir은 example 값 그대로 코딩하는 것 추천...",
123+
security = { @SecurityRequirement(name = "BearerAuth") }
124+
)
125+
@PreAuthorize("hasRole('ADMIN')")
126+
@GetMapping("/recruit/members")
127+
public ResponseEntity<ApiResponse<List<RecruitMemberSummaryResponse>, PageMeta>> getMembers(
128+
@Parameter(description = "검색어(이름 부분 일치). 없으면 전체 조회", example = "소연")
129+
@RequestParam(required = false) String question,
130+
131+
@Parameter(description = "페이지(0부터 시작)", example = "0")
132+
@RequestParam(defaultValue = "0") int page,
133+
134+
@Parameter(description = "페이지 크기", example = "20")
135+
@RequestParam(defaultValue = "20") int size,
136+
137+
@Parameter(description = "정렬 필드", example = "createdAt")
138+
@RequestParam(defaultValue = "createdAt") String sort,
139+
140+
@Parameter(description = "정렬 방향 ASC/DESC", example = "DESC")
141+
@RequestParam(defaultValue = "DESC") String dir
142+
) {
143+
Direction direction = "ASC".equalsIgnoreCase(dir) ? Direction.ASC : Direction.DESC;
144+
Pageable pageable = PageRequest.of(page, size, Sort.by(direction, sort));
145+
146+
Page<RecruitMember> memberPage = (question == null || question.isBlank())
147+
? recruitMemberService.findAllMembersPage(pageable)
148+
: recruitMemberService.searchMembersByNamePage(question, pageable);
149+
150+
List<RecruitMemberSummaryResponse> list = memberPage
151+
.map(RecruitMemberSummaryResponse::from)
152+
.getContent();
153+
PageMeta meta = PageMeta.of(memberPage);
154+
155+
return ResponseEntity.ok(ApiResponse.ok(MEMBER_LIST_RETRIEVED_SUCCESS, list, meta));
156+
}
157+
112158
}

src/main/java/inha/gdgoc/domain/recruit/controller/message/RecruitMemberMessage.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@ public class RecruitMemberMessage {
77
public static final String MEMBER_RETRIEVED_SUCCESS = "성공적으로 특정 멤버의 지원서를 조회했습니다.";
88
public static final String PAYMENT_MARKED_COMPLETE_SUCCESS = "성공적으로 입금 완료로 변경했습니다.";
99
public static final String PAYMENT_MARKED_INCOMPLETE_SUCCESS = "성공적으로 입금 미완료로 변경했습니다.";
10+
public static final String MEMBER_LIST_RETRIEVED_SUCCESS = "성공적으로 멤버 목록을 조회했습니다.";
1011
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package inha.gdgoc.domain.recruit.dto.response;
2+
3+
import inha.gdgoc.domain.recruit.entity.RecruitMember;
4+
5+
public record RecruitMemberSummaryResponse(
6+
Long id,
7+
String name,
8+
String phoneNumber,
9+
String major,
10+
String studentId,
11+
String admissionSemester,
12+
Boolean isPayed
13+
) {
14+
15+
public static RecruitMemberSummaryResponse from(RecruitMember recruitMember) {
16+
String semester = null;
17+
if (recruitMember.getAdmissionSemester() != null) {
18+
String enumName = recruitMember.getAdmissionSemester().name();
19+
semester = enumName.substring(1).replace('_', '-');
20+
}
21+
22+
return new RecruitMemberSummaryResponse(
23+
recruitMember.getId(),
24+
recruitMember.getName(),
25+
recruitMember.getPhoneNumber(),
26+
recruitMember.getMajor(),
27+
recruitMember.getStudentId(),
28+
semester,
29+
recruitMember.getIsPayed()
30+
);
31+
}
32+
}

src/main/java/inha/gdgoc/domain/recruit/repository/RecruitMemberRepository.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import inha.gdgoc.domain.recruit.entity.RecruitMember;
44
import org.springframework.data.jpa.repository.JpaRepository;
5+
import org.springframework.data.domain.Page;
6+
import org.springframework.data.domain.Pageable;
57

68
public interface RecruitMemberRepository extends JpaRepository<RecruitMember, Long> {
79
boolean existsByStudentId(String studentId);
810
boolean existsByPhoneNumber(String phoneNumber);
11+
Page<RecruitMember> findByNameContainingIgnoreCase(String name, Pageable pageable);
912
}

src/main/java/inha/gdgoc/domain/recruit/service/RecruitMemberService.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@
1414
import inha.gdgoc.domain.recruit.exception.RecruitMemberException;
1515
import inha.gdgoc.domain.recruit.repository.AnswerRepository;
1616
import inha.gdgoc.domain.recruit.repository.RecruitMemberRepository;
17-
import jakarta.transaction.Transactional;
1817
import java.util.List;
1918
import lombok.RequiredArgsConstructor;
19+
import org.springframework.data.domain.Page;
20+
import org.springframework.data.domain.Pageable;
2021
import org.springframework.stereotype.Service;
22+
import org.springframework.transaction.annotation.Transactional;
2123

2224
@RequiredArgsConstructor
2325
@Service
@@ -80,4 +82,14 @@ public void updatePayment(Long memberId, boolean isPayed) {
8082
else m.markUnpaid();
8183
}
8284

85+
@Transactional(readOnly = true)
86+
public Page<RecruitMember> findAllMembersPage(Pageable pageable) {
87+
return recruitMemberRepository.findAll(pageable);
88+
}
89+
90+
@Transactional(readOnly = true)
91+
public Page<RecruitMember> searchMembersByNamePage(String name, Pageable pageable) {
92+
return recruitMemberRepository.findByNameContainingIgnoreCase(name, pageable);
93+
}
94+
8395
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package inha.gdgoc.global.dto.response;
2+
3+
import org.springframework.data.domain.Page;
4+
import org.springframework.data.domain.Sort;
5+
6+
public record PageMeta(
7+
int page,
8+
int size,
9+
long totalElements,
10+
int totalPages,
11+
boolean hasNext,
12+
boolean hasPrevious,
13+
String sort,
14+
String direction
15+
) {
16+
17+
public static PageMeta of(Page<?> page) {
18+
String sortProps = page.getSort().stream()
19+
.map(Sort.Order::getProperty)
20+
.reduce((a, b) -> a + "," + b)
21+
.orElse("createdAt");
22+
23+
String dir = page.getSort().stream()
24+
.findFirst()
25+
.map(o -> o.getDirection().name())
26+
.orElse("DESC");
27+
28+
return new PageMeta(
29+
page.getNumber(),
30+
page.getSize(),
31+
page.getTotalElements(),
32+
page.getTotalPages(),
33+
page.hasNext(),
34+
page.hasPrevious(),
35+
sortProps,
36+
dir
37+
);
38+
}
39+
}

0 commit comments

Comments
 (0)