diff --git a/back/src/main/java/com/back/domain/member/member/controller/MemberAuthController.java b/back/src/main/java/com/back/domain/member/member/controller/MemberAuthController.java index 49c156f5..c288d241 100644 --- a/back/src/main/java/com/back/domain/member/member/controller/MemberAuthController.java +++ b/back/src/main/java/com/back/domain/member/member/controller/MemberAuthController.java @@ -1,10 +1,6 @@ package com.back.domain.member.member.controller; -import com.back.domain.member.member.dto.MenteeSignupRequest; -import com.back.domain.member.member.dto.MentorSignupVerifyRequest; -import com.back.domain.member.member.dto.MentorVerificationRequest; -import com.back.domain.member.member.dto.LoginRequest; -import com.back.domain.member.member.dto.MemberMeResponse; +import com.back.domain.member.member.dto.*; import com.back.domain.member.member.entity.Member; import com.back.domain.member.member.service.MemberService; import com.back.global.rq.Rq; @@ -119,4 +115,14 @@ public RsData withdrawMember() { return new RsData<>("200-7", "회원 탈퇴가 완료되었습니다."); } + @GetMapping("/mentors") + @Operation(summary = "모든 멘토 조회") + public RsData getAllMentors( + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size + ) { + MentorPagingResponse response = memberService.getAllMentors(page, size); + return new RsData<>("200-8", "멘토 목록 조회 성공", response); + } + } diff --git a/back/src/main/java/com/back/domain/member/member/dto/MentorListResponse.java b/back/src/main/java/com/back/domain/member/member/dto/MentorListResponse.java new file mode 100644 index 00000000..7fae7b6a --- /dev/null +++ b/back/src/main/java/com/back/domain/member/member/dto/MentorListResponse.java @@ -0,0 +1,25 @@ +package com.back.domain.member.member.dto; + +import com.back.domain.member.mentor.entity.Mentor; + +public record MentorListResponse( + Long mentorId, + Long memberId, + String name, + String nickname, + String job, + Integer careerYears, + Double rate +) { + public static MentorListResponse from(Mentor mentor) { + return new MentorListResponse( + mentor.getId(), + mentor.getMember().getId(), + mentor.getMember().getName(), + mentor.getMember().getNickname(), + mentor.getJob() != null ? mentor.getJob().getName() : null, + mentor.getCareerYears(), + mentor.getRate() + ); + } +} diff --git a/back/src/main/java/com/back/domain/member/member/dto/MentorPagingResponse.java b/back/src/main/java/com/back/domain/member/member/dto/MentorPagingResponse.java new file mode 100644 index 00000000..5ecaa7b8 --- /dev/null +++ b/back/src/main/java/com/back/domain/member/member/dto/MentorPagingResponse.java @@ -0,0 +1,30 @@ +package com.back.domain.member.member.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import org.springframework.data.domain.Page; + +import java.util.List; + +public record MentorPagingResponse( + @Schema(description = "멘토 목록") + List mentors, + @Schema(description = "현재 페이지 (0부터 시작)") + int currentPage, + @Schema(description = "총 페이지") + int totalPage, + @Schema(description = "총 개수") + long totalElements, + @Schema(description = "다음 페이지 존재 여부") + boolean hasNext +) { + + public static MentorPagingResponse from(Page page) { + return new MentorPagingResponse( + page.getContent(), + page.getNumber(), + page.getTotalPages(), + page.getTotalElements(), + page.hasNext() + ); + } +} diff --git a/back/src/main/java/com/back/domain/member/member/service/MemberService.java b/back/src/main/java/com/back/domain/member/member/service/MemberService.java index b0875255..e9c8ad2a 100644 --- a/back/src/main/java/com/back/domain/member/member/service/MemberService.java +++ b/back/src/main/java/com/back/domain/member/member/service/MemberService.java @@ -18,6 +18,7 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Map; import java.util.Optional; @@ -389,4 +390,21 @@ private void validateNicknameDuplicate(String nickname, Member currentMember) { } } + public MentorPagingResponse getAllMentors(int page, int size) { + List allMentors = mentorRepository.findAllActiveWithMemberAndJob(); + + int start = page * size; + int end = Math.min(start + size, allMentors.size()); + List pagedMentors = allMentors.subList(start, end); + + Page mentorPage = new org.springframework.data.domain.PageImpl<>( + pagedMentors, + PageRequest.of(page, size), + allMentors.size() + ); + + Page responsePage = mentorPage.map(MentorListResponse::from); + return MentorPagingResponse.from(responsePage); + } + } diff --git a/back/src/main/java/com/back/domain/member/mentor/repository/MentorRepository.java b/back/src/main/java/com/back/domain/member/mentor/repository/MentorRepository.java index 6e7bff6f..f125308b 100644 --- a/back/src/main/java/com/back/domain/member/mentor/repository/MentorRepository.java +++ b/back/src/main/java/com/back/domain/member/mentor/repository/MentorRepository.java @@ -5,6 +5,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.util.List; import java.util.Optional; public interface MentorRepository extends JpaRepository { @@ -21,4 +22,8 @@ public interface MentorRepository extends JpaRepository { // 삭제된 멘토 포함 조회 (관리자용) @Query("SELECT m FROM Mentor m LEFT JOIN FETCH m.job WHERE m.member.id = :memberId") Optional findByMemberIdIncludingDeleted(@Param("memberId") Long memberId); + + // 모든 활성 멘토 조회 (member, job fetch join) + @Query("SELECT m FROM Mentor m JOIN FETCH m.member LEFT JOIN FETCH m.job WHERE m.isDeleted = false ORDER BY m.id DESC") + List findAllActiveWithMemberAndJob(); } \ No newline at end of file diff --git a/back/src/test/java/com/back/domain/member/member/controller/MemberAuthControllerTest.java b/back/src/test/java/com/back/domain/member/member/controller/MemberAuthControllerTest.java index f2d7e80a..f53aecef 100644 --- a/back/src/test/java/com/back/domain/member/member/controller/MemberAuthControllerTest.java +++ b/back/src/test/java/com/back/domain/member/member/controller/MemberAuthControllerTest.java @@ -567,4 +567,78 @@ void t13() throws Exception { // TODO: 마이페이지 관련 테스트들은 MemberMyPageControllerTest로 이동됨 + @Test + @DisplayName("모든 멘토 조회 - 페이징 처리") + void t14() throws Exception { + // 여러 멘토 생성 + memberService.joinMentor("mentor1@example.com", "멘토1", "멘토닉네임1", "password123", "Backend", 5); + memberService.joinMentor("mentor2@example.com", "멘토2", "멘토닉네임2", "password123", "Frontend", 3); + memberService.joinMentor("mentor3@example.com", "멘토3", "멘토닉네임3", "password123", "DevOps", 7); + + // 멘토 목록 조회 + ResultActions result = mvc + .perform( + get("/auth/mentors") + .param("page", "0") + .param("size", "10") + ) + .andDo(print()); + + result + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("$.resultCode").value("200-8")) + .andExpect(jsonPath("$.msg").value("멘토 목록 조회 성공")) + .andExpect(jsonPath("$.data.mentors").isArray()) + .andExpect(jsonPath("$.data.mentors.length()").value(4)) + .andExpect(jsonPath("$.data.currentPage").value(0)) + .andExpect(jsonPath("$.data.totalElements").value(4)) + .andExpect(jsonPath("$.data.hasNext").value(false)); + } + + @Test + @DisplayName("모든 멘토 조회 - 페이지 크기 조정") + void t16() throws Exception { + // 5명의 멘토 생성 + for (int i = 1; i <= 5; i++) { + memberService.joinMentor("mentor" + i + "@example.com", "멘토" + i, "멘토닉네임" + i, "password123", "Backend", i); + } + + // 페이지 크기를 2로 설정하여 첫 페이지 조회 + ResultActions result = mvc + .perform( + get("/auth/mentors") + .param("page", "0") + .param("size", "2") + ) + .andDo(print()); + + result + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("$.data.mentors.length()").value(2)) + .andExpect(jsonPath("$.data.totalElements").value(6)) + .andExpect(jsonPath("$.data.totalPage").value(3)) + .andExpect(jsonPath("$.data.hasNext").value(true)); + } + + @Test + @DisplayName("모든 멘토 조회 - 멘토 정보 확인") + void t17() throws Exception { + // 멘토 생성 + memberService.joinMentor("detailmentor@example.com", "상세멘토", "상세닉네임", "password123", "Backend", 10); + + // 멘토 목록 조회 + ResultActions result = mvc + .perform(get("/auth/mentors")) + .andDo(print()); + + result + .andExpect(status().is2xxSuccessful()) + .andExpect(jsonPath("$.data.mentors[0].name").value("상세멘토")) + .andExpect(jsonPath("$.data.mentors[0].nickname").value("상세닉네임")) + .andExpect(jsonPath("$.data.mentors[0].job").value("Backend")) + .andExpect(jsonPath("$.data.mentors[0].careerYears").value(10)) + .andExpect(jsonPath("$.data.mentors[0].mentorId").isNotEmpty()) + .andExpect(jsonPath("$.data.mentors[0].memberId").isNotEmpty()); + } + }