From 5bd7e5f9168e833390887ca32e6a374a0eaacdc7 Mon Sep 17 00:00:00 2001 From: dbfgml20 Date: Mon, 13 Oct 2025 20:30:05 +0900 Subject: [PATCH 1/4] =?UTF-8?q?fix:=20DB=20=EC=99=B8=EB=9E=98=ED=82=A4=20?= =?UTF-8?q?=EB=AC=B8=EC=A0=9C=20=EB=B0=9C=EC=83=9D=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/back/global/initData/RoadmapProdInitData.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java b/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java index 386bf5c8..23c61ad6 100644 --- a/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java +++ b/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java @@ -58,7 +58,7 @@ ApplicationRunner baseInitDataApplicationRunner2() { public void runInitData() { initJobData(); initTaskData(); // 보강된 Task 목록 - initSampleJobRoadmap(); // 직업 로드맵 조회 API 테스트용 샘플 데이터 + //initSampleJobRoadmap(); // 직업 로드맵 조회 API 테스트용 샘플 데이터 // 통합 로직 테스트 //initSampleMentorRoadmaps(); // 샘플 멘토 로드맵 10개 생성 From 30802b526382de6cf7f7b59a500c803aa59c1434 Mon Sep 17 00:00:00 2001 From: dbfgml20 Date: Mon, 13 Oct 2025 20:32:21 +0900 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=EA=B8=B0=EC=A1=B4=EA=B3=BC=20?= =?UTF-8?q?=EB=8F=99=EC=9D=BC=ED=95=98=EA=B2=8C=20=ED=8A=B8=EB=9E=9C?= =?UTF-8?q?=EC=9E=AD=EC=85=98=20=EC=B2=98=EB=A6=AC=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/back/global/initData/RoadmapProdInitData.java | 1 - 1 file changed, 1 deletion(-) diff --git a/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java b/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java index 23c61ad6..257d8cfd 100644 --- a/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java +++ b/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java @@ -143,7 +143,6 @@ public void initJobData() { } // --- Task 초기화 (기존 + 기초 보강) --- - @Transactional public void initTaskData() { if (taskService.count() > 0) return; From 09ce727a92f6af0e76210da0df1d99779082b444 Mon Sep 17 00:00:00 2001 From: dbfgml20 <53211374+dbfgml2000@users.noreply.github.com> Date: Mon, 13 Oct 2025 20:37:46 +0900 Subject: [PATCH 3/4] =?UTF-8?q?Revert=20"[Fix]=20=EC=9A=B4=EC=98=81=20DB?= =?UTF-8?q?=20=EC=99=B8=EB=9E=98=ED=82=A4=20=EB=AC=B8=EC=A0=9C=20=EC=A0=9C?= =?UTF-8?q?"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/back/global/initData/RoadmapProdInitData.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java b/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java index 257d8cfd..386bf5c8 100644 --- a/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java +++ b/back/src/main/java/com/back/global/initData/RoadmapProdInitData.java @@ -58,7 +58,7 @@ ApplicationRunner baseInitDataApplicationRunner2() { public void runInitData() { initJobData(); initTaskData(); // 보강된 Task 목록 - //initSampleJobRoadmap(); // 직업 로드맵 조회 API 테스트용 샘플 데이터 + initSampleJobRoadmap(); // 직업 로드맵 조회 API 테스트용 샘플 데이터 // 통합 로직 테스트 //initSampleMentorRoadmaps(); // 샘플 멘토 로드맵 10개 생성 @@ -143,6 +143,7 @@ public void initJobData() { } // --- Task 초기화 (기존 + 기초 보강) --- + @Transactional public void initTaskData() { if (taskService.count() > 0) return; From 9fe01ba4b12f81aa802c5623a7429109be98535e Mon Sep 17 00:00:00 2001 From: dooongdaeng Date: Tue, 14 Oct 2025 16:46:05 +0900 Subject: [PATCH 4/4] =?UTF-8?q?feat:=EB=AA=A8=EB=93=A0=EB=A9=98=ED=86=A0?= =?UTF-8?q?=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/MemberAuthController.java | 16 ++-- .../member/member/dto/MentorListResponse.java | 25 +++++++ .../member/dto/MentorPagingResponse.java | 30 ++++++++ .../member/member/service/MemberService.java | 18 +++++ .../mentor/repository/MentorRepository.java | 5 ++ .../controller/MemberAuthControllerTest.java | 74 +++++++++++++++++++ 6 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 back/src/main/java/com/back/domain/member/member/dto/MentorListResponse.java create mode 100644 back/src/main/java/com/back/domain/member/member/dto/MentorPagingResponse.java 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()); + } + }