From e6d6e238a42a0e0cd16b93acc76cfe50b1a68b42 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 29 Jul 2025 07:16:52 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=ED=8C=8C=EA=B2=AC=EB=8C=80?= =?UTF-8?q?=ED=95=99=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20=ED=8F=AC=ED=95=A8?= =?UTF-8?q?=ED=95=9C=20'=EB=A9=98=ED=86=A0=20=EC=83=81=EC=84=B8=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C'=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mentor/dto/MentorDetailResponse.java | 8 +++++--- .../mentor/service/MentorQueryService.java | 8 +++++++- .../mentor/service/MentorQueryServiceTest.java | 18 +++++++++++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/example/solidconnection/mentor/dto/MentorDetailResponse.java b/src/main/java/com/example/solidconnection/mentor/dto/MentorDetailResponse.java index 3fc042aa7..6b5f04b0c 100644 --- a/src/main/java/com/example/solidconnection/mentor/dto/MentorDetailResponse.java +++ b/src/main/java/com/example/solidconnection/mentor/dto/MentorDetailResponse.java @@ -2,6 +2,7 @@ import com.example.solidconnection.mentor.domain.Mentor; import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.university.domain.University; import java.util.List; public record MentorDetailResponse( @@ -19,13 +20,14 @@ public record MentorDetailResponse( boolean isApplied ) { - public static MentorDetailResponse of(Mentor mentor, SiteUser mentorUser, boolean isApplied) { + public static MentorDetailResponse of(Mentor mentor, SiteUser mentorUser, + University university, boolean isApplied) { return new MentorDetailResponse( mentor.getId(), mentorUser.getNickname(), mentorUser.getProfileImageUrl(), - "국가", // todo: 교환학생 기록이 인증되면 추가 - "대학 이름", // todo: 교환학생 기록이 인증되면 추가 + university.getCountry().getKoreanName(), + university.getKoreanName(), mentor.getTerm(), mentor.getMenteeCount(), mentor.isHasBadge(), diff --git a/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java b/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java index 7d878a1d9..fd4b8e0fd 100644 --- a/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java +++ b/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java @@ -1,6 +1,7 @@ package com.example.solidconnection.mentor.service; import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_NOT_FOUND; +import static com.example.solidconnection.common.exception.ErrorCode.UNIVERSITY_NOT_FOUND; import com.example.solidconnection.common.dto.SliceResponse; import com.example.solidconnection.common.exception.CustomException; @@ -12,6 +13,8 @@ import com.example.solidconnection.mentor.repository.MentoringRepository; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.university.domain.University; +import com.example.solidconnection.university.repository.UniversityRepository; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -29,16 +32,19 @@ public class MentorQueryService { private final MentoringRepository mentoringRepository; private final SiteUserRepository siteUserRepository; private final MentorBatchQueryRepository mentorBatchQueryRepository; + private final UniversityRepository universityRepository; @Transactional(readOnly = true) public MentorDetailResponse getMentorDetails(long mentorId, long currentUserId) { Mentor mentor = mentorRepository.findById(mentorId) .orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND)); + University university = universityRepository.findById(mentor.getUniversityId()) + .orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND)); SiteUser mentorUser = siteUserRepository.findById(mentor.getSiteUserId()) .orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND)); boolean isApplied = mentoringRepository.existsByMentorIdAndMenteeId(mentorId, currentUserId); - return MentorDetailResponse.of(mentor, mentorUser, isApplied); + return MentorDetailResponse.of(mentor, mentorUser, university, isApplied); } @Transactional(readOnly = true) diff --git a/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java b/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java index a7634c7ba..868780557 100644 --- a/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java +++ b/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java @@ -18,6 +18,8 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; +import com.example.solidconnection.university.domain.University; +import com.example.solidconnection.university.fixture.UniversityFixture; import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; @@ -47,9 +49,17 @@ class MentorQueryServiceTest { @Autowired private ChannelFixture channelFixture; - private long universityId = 1L; // todo: 멘토 인증 기능 추가 변경 필요 + @Autowired + private UniversityFixture universityFixture; + + private University university; private String region = "아시아"; + @BeforeEach + void setUp() { + university = universityFixture.그라츠_대학(); + } + @Nested class 멘토_단일_조회_성공 { @@ -58,7 +68,7 @@ class 멘토_단일_조회_성공 { // given SiteUser siteUser = siteUserFixture.사용자(); SiteUser mentorUser = siteUserFixture.사용자(1, "멘토"); - Mentor mentor = mentorFixture.멘토(mentorUser.getId(), universityId); + Mentor mentor = mentorFixture.멘토(mentorUser.getId(), university.getId()); Channel channel1 = channelFixture.채널(1, mentor); Channel channel2 = channelFixture.채널(2, mentor); @@ -69,6 +79,8 @@ class 멘토_단일_조회_성공 { assertAll( () -> assertThat(response.id()).isEqualTo(mentor.getId()), () -> assertThat(response.nickname()).isEqualTo(mentorUser.getNickname()), + () -> assertThat(response.universityName()).isEqualTo(university.getKoreanName()), + () -> assertThat(response.country()).isEqualTo(university.getCountry().getKoreanName()), () -> assertThat(response.channels()).extracting(ChannelResponse::url) .containsExactly(channel1.getUrl(), channel2.getUrl()) ); @@ -78,7 +90,7 @@ class 멘토_단일_조회_성공 { void 멘토에_대한_나의_멘토링_신청_여부를_조회한다() { // given SiteUser mentorUser = siteUserFixture.사용자(1, "멘토"); - Mentor mentor = mentorFixture.멘토(mentorUser.getId(), universityId); + Mentor mentor = mentorFixture.멘토(mentorUser.getId(), university.getId()); SiteUser notAppliedUser = siteUserFixture.사용자(2, "멘토링 지원 안한 사용자"); SiteUser appliedUser = siteUserFixture.사용자(3, "멘토링 지원한 사용자"); From 09cf63028e964a0fb6cb1759381933b183a7ebed Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 29 Jul 2025 07:19:24 +0900 Subject: [PATCH 2/6] =?UTF-8?q?feat:=20=ED=8C=8C=EA=B2=AC=EB=8C=80?= =?UTF-8?q?=ED=95=99=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20=ED=8F=AC=ED=95=A8?= =?UTF-8?q?=ED=95=9C=20'=EB=A9=98=ED=86=A0=20=EB=82=98=EC=9D=98=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=A1=B0=ED=9A=8C'=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mentor/dto/MentorMyPageResponse.java | 7 ++++--- .../mentor/service/MentorMyPageService.java | 8 +++++++- .../mentor/service/MentorMyPageServiceTest.java | 12 ++++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/solidconnection/mentor/dto/MentorMyPageResponse.java b/src/main/java/com/example/solidconnection/mentor/dto/MentorMyPageResponse.java index 95bb26506..50b7f6eab 100644 --- a/src/main/java/com/example/solidconnection/mentor/dto/MentorMyPageResponse.java +++ b/src/main/java/com/example/solidconnection/mentor/dto/MentorMyPageResponse.java @@ -2,6 +2,7 @@ import com.example.solidconnection.mentor.domain.Mentor; import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.university.domain.University; import java.util.List; public record MentorMyPageResponse( @@ -17,13 +18,13 @@ public record MentorMyPageResponse( List channels ) { - public static MentorMyPageResponse of(Mentor mentor, SiteUser siteUser) { + public static MentorMyPageResponse of(Mentor mentor, SiteUser siteUser, University university) { return new MentorMyPageResponse( mentor.getId(), siteUser.getProfileImageUrl(), siteUser.getNickname(), - "국가", // todo: 교환학생 기록이 인증되면 추가 - "대학 이름", + university.getCountry().getKoreanName(), + university.getKoreanName(), mentor.getTerm(), mentor.getMenteeCount(), mentor.isHasBadge(), diff --git a/src/main/java/com/example/solidconnection/mentor/service/MentorMyPageService.java b/src/main/java/com/example/solidconnection/mentor/service/MentorMyPageService.java index 365d10ad4..18e63a6fb 100644 --- a/src/main/java/com/example/solidconnection/mentor/service/MentorMyPageService.java +++ b/src/main/java/com/example/solidconnection/mentor/service/MentorMyPageService.java @@ -2,6 +2,7 @@ import static com.example.solidconnection.common.exception.ErrorCode.CHANNEL_REGISTRATION_LIMIT_EXCEEDED; import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_NOT_FOUND; +import static com.example.solidconnection.common.exception.ErrorCode.UNIVERSITY_NOT_FOUND; import static com.example.solidconnection.common.exception.ErrorCode.USER_NOT_FOUND; import com.example.solidconnection.common.exception.CustomException; @@ -13,6 +14,8 @@ import com.example.solidconnection.mentor.repository.MentorRepository; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.university.domain.University; +import com.example.solidconnection.university.repository.UniversityRepository; import java.util.ArrayList; import java.util.List; import lombok.RequiredArgsConstructor; @@ -28,6 +31,7 @@ public class MentorMyPageService { private final MentorRepository mentorRepository; private final SiteUserRepository siteUserRepository; + private final UniversityRepository universityRepository; @Transactional(readOnly = true) public MentorMyPageResponse getMentorMyPage(long siteUserId) { @@ -35,7 +39,9 @@ public MentorMyPageResponse getMentorMyPage(long siteUserId) { .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); Mentor mentor = mentorRepository.findBySiteUserId(siteUser.getId()) .orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND)); - return MentorMyPageResponse.of(mentor, siteUser); + University university = universityRepository.findById(mentor.getUniversityId()) + .orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND)); + return MentorMyPageResponse.of(mentor, siteUser, university); } @Transactional diff --git a/src/test/java/com/example/solidconnection/mentor/service/MentorMyPageServiceTest.java b/src/test/java/com/example/solidconnection/mentor/service/MentorMyPageServiceTest.java index 85667dffb..5d675e14b 100644 --- a/src/test/java/com/example/solidconnection/mentor/service/MentorMyPageServiceTest.java +++ b/src/test/java/com/example/solidconnection/mentor/service/MentorMyPageServiceTest.java @@ -18,6 +18,8 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; +import com.example.solidconnection.university.domain.University; +import com.example.solidconnection.university.fixture.UniversityFixture; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -44,17 +46,21 @@ class MentorMyPageServiceTest { @Autowired private MentorRepository mentorRepository; + @Autowired + private UniversityFixture universityFixture; + @Autowired private ChannelRepositoryForTest channelRepositoryForTest; private SiteUser mentorUser; private Mentor mentor; - private long universityId = 1L; + private University university; @BeforeEach void setUp() { + university = universityFixture.메이지_대학(); mentorUser = siteUserFixture.멘토(1, "멘토"); - mentor = mentorFixture.멘토(mentorUser.getId(), universityId); + mentor = mentorFixture.멘토(mentorUser.getId(), university.getId()); } @Nested @@ -73,6 +79,8 @@ class 멘토의_마이_페이지를_조회한다 { assertAll( () -> assertThat(response.id()).isEqualTo(mentor.getId()), () -> assertThat(response.nickname()).isEqualTo(mentorUser.getNickname()), + () -> assertThat(response.universityName()).isEqualTo(university.getKoreanName()), + () -> assertThat(response.country()).isEqualTo(university.getCountry().getKoreanName()), () -> assertThat(response.channels()).extracting(ChannelResponse::url) .containsExactly(channel1.getUrl(), channel2.getUrl()) ); From 501ca56e9031eaf92e4d762a404133a762cade92 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 29 Jul 2025 07:35:31 +0900 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=ED=8C=8C=EA=B2=AC=EB=8C=80?= =?UTF-8?q?=ED=95=99=20=EC=A0=95=EB=B3=B4=EB=A5=BC=20=ED=8F=AC=ED=95=A8?= =?UTF-8?q?=ED=95=9C=20'=EB=A9=98=ED=86=A0=20=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C'=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mentor/dto/MentorPreviewResponse.java | 8 ++++-- .../MentorBatchQueryRepository.java | 21 ++++++++++++++ .../mentor/service/MentorQueryService.java | 4 ++- .../MentorBatchQueryRepositoryTest.java | 28 +++++++++++++++++-- .../service/MentorQueryServiceTest.java | 25 +++++++++++------ 5 files changed, 70 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/example/solidconnection/mentor/dto/MentorPreviewResponse.java b/src/main/java/com/example/solidconnection/mentor/dto/MentorPreviewResponse.java index dd590c179..c6678fb53 100644 --- a/src/main/java/com/example/solidconnection/mentor/dto/MentorPreviewResponse.java +++ b/src/main/java/com/example/solidconnection/mentor/dto/MentorPreviewResponse.java @@ -2,6 +2,7 @@ import com.example.solidconnection.mentor.domain.Mentor; import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.university.domain.University; import java.util.List; public record MentorPreviewResponse( @@ -18,13 +19,14 @@ public record MentorPreviewResponse( boolean isApplied ) { - public static MentorPreviewResponse of(Mentor mentor, SiteUser mentorUser, boolean isApplied) { + public static MentorPreviewResponse of(Mentor mentor, SiteUser mentorUser, + University university, boolean isApplied) { return new MentorPreviewResponse( mentor.getId(), mentorUser.getNickname(), mentorUser.getProfileImageUrl(), - "국가", // todo: 교환학생 기록이 인증되면 추가 - "대학 이름", // todo: 교환학생 기록이 인증되면 추가 + university.getCountry().getKoreanName(), + university.getKoreanName(), mentor.getTerm(), mentor.getMenteeCount(), mentor.isHasBadge(), diff --git a/src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java b/src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java index 3e90f944f..ef5999509 100644 --- a/src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java +++ b/src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java @@ -7,6 +7,8 @@ import com.example.solidconnection.mentor.domain.Mentoring; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import com.example.solidconnection.university.domain.University; +import com.example.solidconnection.university.repository.UniversityRepository; import java.util.List; import java.util.Map; import java.util.Set; @@ -21,6 +23,7 @@ public class MentorBatchQueryRepository { // 연관관계가 설정되지 않은 private final SiteUserRepository siteUserRepository; private final MentoringRepository mentoringRepository; + private final UniversityRepository universityRepository; public Map getMentorIdToSiteUserMap(List mentors) { List mentorUserIds = mentors.stream().map(Mentor::getSiteUserId).toList(); @@ -40,6 +43,24 @@ public Map getMentorIdToSiteUserMap(List mentors) { )); } + public Map getMentorIdToUniversityMap(List mentors) { + List universityIds = mentors.stream().map(Mentor::getUniversityId).toList(); + List universities = universityRepository.findAllById(universityIds); + Map universityIdToUniversityMap = universities.stream() + .collect(Collectors.toMap(University::getId, Function.identity())); + + return mentors.stream().collect(Collectors.toMap( + Mentor::getId, + mentor -> { + University university = universityIdToUniversityMap.get(mentor.getUniversityId()); + if (university == null) { // mentor.university_id에 해당하는 대학이 없으면 정합성 문제가 발생한 것 + throw new CustomException(DATA_INTEGRITY_VIOLATION, "mentor.university_id 에 해당하는 university 존재하지 않음"); + } + return university; + } + )); + } + public Map getMentorIdToIsApplied(List mentors, long currentUserId) { List mentorIds = mentors.stream().map(Mentor::getId).toList(); List appliedMentorings = mentoringRepository.findAllByMentorIdInAndMenteeId(mentorIds, currentUserId); diff --git a/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java b/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java index fd4b8e0fd..b9a49708e 100644 --- a/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java +++ b/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java @@ -58,13 +58,15 @@ public SliceResponse getMentorPreviews(String region, lon private List getMentorPreviewResponses(List mentors, long currentUserId) { Map mentorIdToSiteUser = mentorBatchQueryRepository.getMentorIdToSiteUserMap(mentors); + Map mentorIdToUniversity = mentorBatchQueryRepository.getMentorIdToUniversityMap(mentors); Map mentorIdToIsApplied = mentorBatchQueryRepository.getMentorIdToIsApplied(mentors, currentUserId); List mentorPreviews = new ArrayList<>(); for (Mentor mentor : mentors) { SiteUser mentorUser = mentorIdToSiteUser.get(mentor.getId()); + University university = mentorIdToUniversity.get(mentor.getId()); boolean isApplied = mentorIdToIsApplied.get(mentor.getId()); - MentorPreviewResponse response = MentorPreviewResponse.of(mentor, mentorUser, isApplied); + MentorPreviewResponse response = MentorPreviewResponse.of(mentor, mentorUser, university, isApplied); mentorPreviews.add(response); } return mentorPreviews; diff --git a/src/test/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepositoryTest.java b/src/test/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepositoryTest.java index ffa55dd13..347bb684f 100644 --- a/src/test/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepositoryTest.java +++ b/src/test/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepositoryTest.java @@ -9,6 +9,8 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; +import com.example.solidconnection.university.domain.University; +import com.example.solidconnection.university.fixture.UniversityFixture; import java.util.List; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -32,7 +34,10 @@ class MentorBatchQueryRepositoryTest { @Autowired private SiteUserFixture siteUserFixture; - private long universityId = 1L; // todo: 멘토 인증 기능 추가 변경 필요 + @Autowired + private UniversityFixture universityFixture; + + private University university1, university2; private Mentor mentor1, mentor2; private SiteUser mentorUser1, mentorUser2, currentUser; @@ -41,8 +46,10 @@ void setUp() { currentUser = siteUserFixture.사용자(1, "사용자"); mentorUser1 = siteUserFixture.사용자(2, "멘토1"); mentorUser2 = siteUserFixture.사용자(3, "멘토2"); - mentor1 = mentorFixture.멘토(mentorUser1.getId(), universityId); - mentor2 = mentorFixture.멘토(mentorUser2.getId(), universityId); + university1 = universityFixture.코펜하겐IT_대학(); + university2 = universityFixture.메모리얼_대학_세인트존스(); + mentor1 = mentorFixture.멘토(mentorUser1.getId(), university1.getId()); + mentor2 = mentorFixture.멘토(mentorUser2.getId(), university2.getId()); } @Test @@ -60,6 +67,21 @@ void setUp() { ); } + @Test + void 멘토_ID_와_멘토의_파견_대학교를_매핑한다() { + // given + List mentors = List.of(mentor1, mentor2); + + // when + Map mentorIdToUniversity = mentorBatchQueryRepository.getMentorIdToUniversityMap(mentors); + + // then + assertAll( + () -> assertThat(mentorIdToUniversity.get(mentor1.getId()).getId()).isEqualTo(university1.getId()), + () -> assertThat(mentorIdToUniversity.get(mentor2.getId()).getId()).isEqualTo(university2.getId()) + ); + } + @Test void 멘토_ID_와_현재_사용자의_지원_여부를_매핑한다() { // given diff --git a/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java b/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java index 868780557..fb05cf665 100644 --- a/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java +++ b/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java @@ -130,14 +130,17 @@ class 멘토_미리보기_목록_조회 { private Mentor mentor1, mentor2; private SiteUser mentorUser1, mentorUser2, currentUser; + private University university1, university2; @BeforeEach void setUp() { currentUser = siteUserFixture.사용자(1, "사용자1"); mentorUser1 = siteUserFixture.사용자(2, "멘토1"); mentorUser2 = siteUserFixture.사용자(3, "멘토2"); - mentor1 = mentorFixture.멘토(mentorUser1.getId(), universityId); - mentor2 = mentorFixture.멘토(mentorUser2.getId(), universityId); + university1 = universityFixture.괌_대학(); + university2 = universityFixture.린츠_카톨릭_대학(); + mentor1 = mentorFixture.멘토(mentorUser1.getId(), university1.getId()); + mentor2 = mentorFixture.멘토(mentorUser2.getId(), university2.getId()); } @Test @@ -152,15 +155,19 @@ void setUp() { // then Map mentorPreviewMap = response.content().stream() .collect(Collectors.toMap(MentorPreviewResponse::id, Function.identity())); - + MentorPreviewResponse mentor1Response = mentorPreviewMap.get(mentor1.getId()); + MentorPreviewResponse mentor2Response = mentorPreviewMap.get(mentor2.getId()); assertAll( - () -> assertThat(mentorPreviewMap.get(mentor1.getId())).extracting(MentorPreviewResponse::nickname) - .isEqualTo(mentorUser1.getNickname()), - () -> assertThat(mentorPreviewMap.get(mentor1.getId()).channels()).extracting(ChannelResponse::url) + () -> assertThat(mentor1Response.nickname()).isEqualTo(mentorUser1.getNickname()), + () -> assertThat(mentor1Response.universityName()).isEqualTo(university1.getKoreanName()), + () -> assertThat(mentor1Response.country()).isEqualTo(university1.getCountry().getKoreanName()), + () -> assertThat(mentor1Response.channels()).extracting(ChannelResponse::url) .containsOnly(channel1.getUrl()), - () -> assertThat(mentorPreviewMap.get(mentor2.getId())).extracting(MentorPreviewResponse::nickname) - .isEqualTo(mentorUser2.getNickname()), - () -> assertThat(mentorPreviewMap.get(mentor2.getId()).channels()).extracting(ChannelResponse::url) + + () -> assertThat(mentor2Response.nickname()).isEqualTo(mentorUser2.getNickname()), + () -> assertThat(mentor2Response.universityName()).isEqualTo(university2.getKoreanName()), + () -> assertThat(mentor2Response.country()).isEqualTo(university2.getCountry().getKoreanName()), + () -> assertThat(mentor2Response.channels()).extracting(ChannelResponse::url) .containsOnly(channel2.getUrl()) ); } From b05ea66074c87ee4647d64479d819e1f4df3ad0a Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Tue, 29 Jul 2025 09:11:12 +0900 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=EA=B6=8C=EC=97=AD=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=A9=98=ED=86=A0=20=ED=95=84=ED=84=B0=EB=A7=81=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../region/repository/RegionRepository.java | 3 + .../mentor/repository/MentorRepository.java | 10 +++ .../mentor/service/MentorQueryService.java | 19 ++++- .../service/MentorQueryServiceTest.java | 73 +++++++++++++------ 4 files changed, 81 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java b/src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java index eca02bc93..656fc4377 100644 --- a/src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java +++ b/src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java @@ -2,6 +2,7 @@ import com.example.solidconnection.location.region.domain.Region; import java.util.List; +import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -10,4 +11,6 @@ public interface RegionRepository extends JpaRepository { @Query("SELECT r FROM Region r WHERE r.koreanName IN :names") List findByKoreanNames(@Param(value = "names") List names); + + Optional findByKoreanName(String koreanName); } diff --git a/src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java b/src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java index b2332afad..430602f1e 100644 --- a/src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java +++ b/src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java @@ -1,10 +1,13 @@ package com.example.solidconnection.mentor.repository; +import com.example.solidconnection.location.region.domain.Region; import com.example.solidconnection.mentor.domain.Mentor; import java.util.Optional; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface MentorRepository extends JpaRepository { @@ -13,4 +16,11 @@ public interface MentorRepository extends JpaRepository { Optional findBySiteUserId(long siteUserId); Slice findAllBy(Pageable pageable); + + @Query(""" + SELECT m FROM Mentor m + JOIN University u ON m.universityId = u.id + WHERE u.region = :region + """) + Slice findAllByRegion(@Param("region") Region region, Pageable pageable); } diff --git a/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java b/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java index b9a49708e..16c9bdaa5 100644 --- a/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java +++ b/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java @@ -5,6 +5,9 @@ import com.example.solidconnection.common.dto.SliceResponse; import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.common.exception.ErrorCode; +import com.example.solidconnection.location.region.domain.Region; +import com.example.solidconnection.location.region.repository.RegionRepository; import com.example.solidconnection.mentor.domain.Mentor; import com.example.solidconnection.mentor.dto.MentorDetailResponse; import com.example.solidconnection.mentor.dto.MentorPreviewResponse; @@ -33,6 +36,7 @@ public class MentorQueryService { private final SiteUserRepository siteUserRepository; private final MentorBatchQueryRepository mentorBatchQueryRepository; private final UniversityRepository universityRepository; + private final RegionRepository regionRepository; @Transactional(readOnly = true) public MentorDetailResponse getMentorDetails(long mentorId, long currentUserId) { @@ -48,15 +52,24 @@ public MentorDetailResponse getMentorDetails(long mentorId, long currentUserId) } @Transactional(readOnly = true) - public SliceResponse getMentorPreviews(String region, long currentUserId, Pageable pageable) { // todo: 멘토의 '인증' 작업 후 region 필터링 추가 - Slice mentorSlice = mentorRepository.findAllBy(pageable); + public SliceResponse getMentorPreviews(String regionKoreanName, long currentUserId, Pageable pageable) { + Slice mentorSlice = filterMentorsByRegion(regionKoreanName, pageable); List mentors = mentorSlice.toList(); List content = getMentorPreviewResponses(mentors, currentUserId); return SliceResponse.of(content, mentorSlice); } - private List getMentorPreviewResponses(List mentors, long currentUserId) { + private Slice filterMentorsByRegion(String regionKoreanName, Pageable pageable) { + if (regionKoreanName == null || regionKoreanName.isEmpty()) { + return mentorRepository.findAll(pageable); + } + Region region = regionRepository.findByKoreanName(regionKoreanName) + .orElseThrow(() -> new CustomException(ErrorCode.REGION_NOT_FOUND_BY_KOREAN_NAME)); + return mentorRepository.findAllByRegion(region, pageable); + } + + private List getMentorPreviewResponses(List mentors, long currentUserId) { // todo: 이름 변경? Map mentorIdToSiteUser = mentorBatchQueryRepository.getMentorIdToSiteUserMap(mentors); Map mentorIdToUniversity = mentorBatchQueryRepository.getMentorIdToUniversityMap(mentors); Map mentorIdToIsApplied = mentorBatchQueryRepository.getMentorIdToIsApplied(mentors, currentUserId); diff --git a/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java b/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java index fb05cf665..d20bc28d7 100644 --- a/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java +++ b/src/test/java/com/example/solidconnection/mentor/service/MentorQueryServiceTest.java @@ -53,7 +53,6 @@ class MentorQueryServiceTest { private UniversityFixture universityFixture; private University university; - private String region = "아시아"; @BeforeEach void setUp() { @@ -124,7 +123,7 @@ class 멘토_단일_조회_실패 { } @Nested - class 멘토_미리보기_목록_조회 { + class 멘토_미리보기_목록_정보_조회 { private static final int NO_NEXT_PAGE_NUMBER = -1; @@ -150,7 +149,7 @@ void setUp() { Channel channel2 = channelFixture.채널(2, mentor2); // when - SliceResponse response = mentorQueryService.getMentorPreviews(region, currentUser.getId(), PageRequest.of(0, 10)); + SliceResponse response = mentorQueryService.getMentorPreviews("", currentUser.getId(), PageRequest.of(0, 10)); // then Map mentorPreviewMap = response.content().stream() @@ -173,38 +172,70 @@ void setUp() { } @Test - void 멘토들에_대한_나의_멘토링_지원_여부를_조회한다() { + void 다음_페이지_번호를_응답한다() { // given - mentoringFixture.대기중_멘토링(mentor1.getId(), currentUser.getId()); - - // when - SliceResponse response = mentorQueryService.getMentorPreviews(region, currentUser.getId(), PageRequest.of(0, 10)); + SliceResponse response = mentorQueryService.getMentorPreviews("", currentUser.getId(), PageRequest.of(0, 1)); // then - Map mentorPreviewMap = response.content().stream() - .collect(Collectors.toMap(MentorPreviewResponse::id, Function.identity())); - assertAll( - () -> assertThat(mentorPreviewMap.get(mentor1.getId()).isApplied()).isTrue(), - () -> assertThat(mentorPreviewMap.get(mentor2.getId()).isApplied()).isFalse() - ); + assertThat(response.nextPageNumber()).isEqualTo(2); } @Test - void 다음_페이지_번호를_응답한다() { + void 다음_페이지가_없으면_페이지_없음을_의미하는_값을_응답한다() { // given - SliceResponse response = mentorQueryService.getMentorPreviews(region, currentUser.getId(), PageRequest.of(0, 1)); + SliceResponse response = mentorQueryService.getMentorPreviews("", currentUser.getId(), PageRequest.of(0, 10)); // then - assertThat(response.nextPageNumber()).isEqualTo(2); + assertThat(response.nextPageNumber()).isEqualTo(NO_NEXT_PAGE_NUMBER); + } + } + + @Nested + class 멘토_미리보기_목록_필터링 { + + private Mentor asiaMentor, europeMentor; + private SiteUser currentUser; + private University asiaUniversity, europeUniversity; + + @BeforeEach + void setUp() { + currentUser = siteUserFixture.사용자(1, "사용자1"); + SiteUser mentorUser1 = siteUserFixture.사용자(2, "멘토1"); + SiteUser mentorUser2 = siteUserFixture.사용자(3, "멘토2"); + asiaUniversity = universityFixture.메이지_대학(); + europeUniversity = universityFixture.린츠_카톨릭_대학(); + asiaMentor = mentorFixture.멘토(mentorUser1.getId(), asiaUniversity.getId()); + europeMentor = mentorFixture.멘토(mentorUser2.getId(), europeUniversity.getId()); } @Test - void 다음_페이지가_없으면_페이지_없음을_의미하는_값을_응답한다() { - // given - SliceResponse response = mentorQueryService.getMentorPreviews(region, currentUser.getId(), PageRequest.of(0, 10)); + void 권역으로_멘토_목록을_필터링한다() { + // when + SliceResponse asiaFilteredResponse = mentorQueryService.getMentorPreviews( + asiaUniversity.getRegion().getKoreanName(), currentUser.getId(), PageRequest.of(0, 10)); + SliceResponse europeFilteredResponse = mentorQueryService.getMentorPreviews( + europeUniversity.getRegion().getKoreanName(), currentUser.getId(), PageRequest.of(0, 10)); // then - assertThat(response.nextPageNumber()).isEqualTo(NO_NEXT_PAGE_NUMBER); + assertAll( + () -> assertThat(asiaFilteredResponse.content()).hasSize(1) + .extracting(MentorPreviewResponse::id) + .containsExactly(asiaMentor.getId()), + () -> assertThat(europeFilteredResponse.content()).hasSize(1) + .extracting(MentorPreviewResponse::id) + .containsExactly(europeMentor.getId()) + ); + } + + @Test + void 권역을_지정하지_않으면_전체_멘토_목록을_조회한다() { + // when + SliceResponse response = mentorQueryService.getMentorPreviews("", currentUser.getId(), PageRequest.of(0, 10)); + + // then + assertThat(response.content()).hasSize(2) + .extracting(MentorPreviewResponse::id) + .containsExactlyInAnyOrder(asiaMentor.getId(), europeMentor.getId()); } } } From eac65225b3b40780e1072b178e514b59fa6c0445 Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Wed, 30 Jul 2025 16:38:03 +0900 Subject: [PATCH 5/6] =?UTF-8?q?refactor:=20=EC=A4=91=EB=B3=B5=EC=9D=84=20?= =?UTF-8?q?=EC=A4=84=EC=9D=B4=EA=B8=B0=20=EC=9C=84=ED=95=9C=20distinct=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 여러 멘토가 동일한 대학을 나왔을 경우, 동일한 대학을 멘토 수만틈 가지고 있기보다는 distinct를 적용하여 하나씩만 가지고 있게 하는 것이 좋다. --- .../mentor/repository/MentorBatchQueryRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java b/src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java index ef5999509..0b01f3871 100644 --- a/src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java +++ b/src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java @@ -44,7 +44,7 @@ public Map getMentorIdToSiteUserMap(List mentors) { } public Map getMentorIdToUniversityMap(List mentors) { - List universityIds = mentors.stream().map(Mentor::getUniversityId).toList(); + List universityIds = mentors.stream().map(Mentor::getUniversityId).distinct().toList(); List universities = universityRepository.findAllById(universityIds); Map universityIdToUniversityMap = universities.stream() .collect(Collectors.toMap(University::getId, Function.identity())); From ac5fba56c894244628f5e6ebe33a37d4c618383d Mon Sep 17 00:00:00 2001 From: nayonsoso Date: Thu, 31 Jul 2025 10:22:13 +0900 Subject: [PATCH 6/6] =?UTF-8?q?refactor:=20batch=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=ED=9B=84=20=EC=A1=B0=ED=95=A9=ED=95=98=EB=8A=94=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/mentor/service/MentorQueryService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java b/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java index 16c9bdaa5..16b7172d1 100644 --- a/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java +++ b/src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java @@ -55,7 +55,7 @@ public MentorDetailResponse getMentorDetails(long mentorId, long currentUserId) public SliceResponse getMentorPreviews(String regionKoreanName, long currentUserId, Pageable pageable) { Slice mentorSlice = filterMentorsByRegion(regionKoreanName, pageable); List mentors = mentorSlice.toList(); - List content = getMentorPreviewResponses(mentors, currentUserId); + List content = buildMentorPreviewsWithBatchQuery(mentors, currentUserId); return SliceResponse.of(content, mentorSlice); } @@ -69,7 +69,7 @@ private Slice filterMentorsByRegion(String regionKoreanName, Pageable pa return mentorRepository.findAllByRegion(region, pageable); } - private List getMentorPreviewResponses(List mentors, long currentUserId) { // todo: 이름 변경? + private List buildMentorPreviewsWithBatchQuery(List mentors, long currentUserId) { Map mentorIdToSiteUser = mentorBatchQueryRepository.getMentorIdToSiteUserMap(mentors); Map mentorIdToUniversity = mentorBatchQueryRepository.getMentorIdToUniversityMap(mentors); Map mentorIdToIsApplied = mentorBatchQueryRepository.getMentorIdToIsApplied(mentors, currentUserId);