Skip to content

Commit ae9babf

Browse files
authored
feat: 멘토 조회 시 파견대학정보 포함하는 기능, 권역 필터링 기능 구현 (#415)
* feat: 파견대학 정보를 포함한 '멘토 상세 조회' 구현 * feat: 파견대학 정보를 포함한 '멘토 나의 페이지 조회' 구현 * feat: 파견대학 정보를 포함한 '멘토 목록 조회' 구현 * feat: 권역으로 멘토 필터링 구현 * refactor: 중복을 줄이기 위한 distinct 적용 - 여러 멘토가 동일한 대학을 나왔을 경우, 동일한 대학을 멘토 수만틈 가지고 있기보다는 distinct를 적용하여 하나씩만 가지고 있게 하는 것이 좋다. * refactor: batch 조회 후 조합하는 함수 이름 변경
1 parent d8710a0 commit ae9babf

File tree

11 files changed

+200
-54
lines changed

11 files changed

+200
-54
lines changed

src/main/java/com/example/solidconnection/location/region/repository/RegionRepository.java

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

33
import com.example.solidconnection.location.region.domain.Region;
44
import java.util.List;
5+
import java.util.Optional;
56
import org.springframework.data.jpa.repository.JpaRepository;
67
import org.springframework.data.jpa.repository.Query;
78
import org.springframework.data.repository.query.Param;
@@ -10,4 +11,6 @@ public interface RegionRepository extends JpaRepository<Region, Long> {
1011

1112
@Query("SELECT r FROM Region r WHERE r.koreanName IN :names")
1213
List<Region> findByKoreanNames(@Param(value = "names") List<String> names);
14+
15+
Optional<Region> findByKoreanName(String koreanName);
1316
}

src/main/java/com/example/solidconnection/mentor/dto/MentorDetailResponse.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.example.solidconnection.mentor.domain.Mentor;
44
import com.example.solidconnection.siteuser.domain.SiteUser;
5+
import com.example.solidconnection.university.domain.University;
56
import java.util.List;
67

78
public record MentorDetailResponse(
@@ -19,13 +20,14 @@ public record MentorDetailResponse(
1920
boolean isApplied
2021
) {
2122

22-
public static MentorDetailResponse of(Mentor mentor, SiteUser mentorUser, boolean isApplied) {
23+
public static MentorDetailResponse of(Mentor mentor, SiteUser mentorUser,
24+
University university, boolean isApplied) {
2325
return new MentorDetailResponse(
2426
mentor.getId(),
2527
mentorUser.getNickname(),
2628
mentorUser.getProfileImageUrl(),
27-
"국가", // todo: 교환학생 기록이 인증되면 추가
28-
"대학 이름", // todo: 교환학생 기록이 인증되면 추가
29+
university.getCountry().getKoreanName(),
30+
university.getKoreanName(),
2931
mentor.getTerm(),
3032
mentor.getMenteeCount(),
3133
mentor.isHasBadge(),

src/main/java/com/example/solidconnection/mentor/dto/MentorMyPageResponse.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.example.solidconnection.mentor.domain.Mentor;
44
import com.example.solidconnection.siteuser.domain.SiteUser;
5+
import com.example.solidconnection.university.domain.University;
56
import java.util.List;
67

78
public record MentorMyPageResponse(
@@ -17,13 +18,13 @@ public record MentorMyPageResponse(
1718
List<ChannelResponse> channels
1819
) {
1920

20-
public static MentorMyPageResponse of(Mentor mentor, SiteUser siteUser) {
21+
public static MentorMyPageResponse of(Mentor mentor, SiteUser siteUser, University university) {
2122
return new MentorMyPageResponse(
2223
mentor.getId(),
2324
siteUser.getProfileImageUrl(),
2425
siteUser.getNickname(),
25-
"국가", // todo: 교환학생 기록이 인증되면 추가
26-
"대학 이름",
26+
university.getCountry().getKoreanName(),
27+
university.getKoreanName(),
2728
mentor.getTerm(),
2829
mentor.getMenteeCount(),
2930
mentor.isHasBadge(),

src/main/java/com/example/solidconnection/mentor/dto/MentorPreviewResponse.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.example.solidconnection.mentor.domain.Mentor;
44
import com.example.solidconnection.siteuser.domain.SiteUser;
5+
import com.example.solidconnection.university.domain.University;
56
import java.util.List;
67

78
public record MentorPreviewResponse(
@@ -18,13 +19,14 @@ public record MentorPreviewResponse(
1819
boolean isApplied
1920
) {
2021

21-
public static MentorPreviewResponse of(Mentor mentor, SiteUser mentorUser, boolean isApplied) {
22+
public static MentorPreviewResponse of(Mentor mentor, SiteUser mentorUser,
23+
University university, boolean isApplied) {
2224
return new MentorPreviewResponse(
2325
mentor.getId(),
2426
mentorUser.getNickname(),
2527
mentorUser.getProfileImageUrl(),
26-
"국가", // todo: 교환학생 기록이 인증되면 추가
27-
"대학 이름", // todo: 교환학생 기록이 인증되면 추가
28+
university.getCountry().getKoreanName(),
29+
university.getKoreanName(),
2830
mentor.getTerm(),
2931
mentor.getMenteeCount(),
3032
mentor.isHasBadge(),

src/main/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepository.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import com.example.solidconnection.mentor.domain.Mentoring;
88
import com.example.solidconnection.siteuser.domain.SiteUser;
99
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
10+
import com.example.solidconnection.university.domain.University;
11+
import com.example.solidconnection.university.repository.UniversityRepository;
1012
import java.util.List;
1113
import java.util.Map;
1214
import java.util.Set;
@@ -21,6 +23,7 @@ public class MentorBatchQueryRepository { // 연관관계가 설정되지 않은
2123

2224
private final SiteUserRepository siteUserRepository;
2325
private final MentoringRepository mentoringRepository;
26+
private final UniversityRepository universityRepository;
2427

2528
public Map<Long, SiteUser> getMentorIdToSiteUserMap(List<Mentor> mentors) {
2629
List<Long> mentorUserIds = mentors.stream().map(Mentor::getSiteUserId).toList();
@@ -40,6 +43,24 @@ public Map<Long, SiteUser> getMentorIdToSiteUserMap(List<Mentor> mentors) {
4043
));
4144
}
4245

46+
public Map<Long, University> getMentorIdToUniversityMap(List<Mentor> mentors) {
47+
List<Long> universityIds = mentors.stream().map(Mentor::getUniversityId).distinct().toList();
48+
List<University> universities = universityRepository.findAllById(universityIds);
49+
Map<Long, University> universityIdToUniversityMap = universities.stream()
50+
.collect(Collectors.toMap(University::getId, Function.identity()));
51+
52+
return mentors.stream().collect(Collectors.toMap(
53+
Mentor::getId,
54+
mentor -> {
55+
University university = universityIdToUniversityMap.get(mentor.getUniversityId());
56+
if (university == null) { // mentor.university_id에 해당하는 대학이 없으면 정합성 문제가 발생한 것
57+
throw new CustomException(DATA_INTEGRITY_VIOLATION, "mentor.university_id 에 해당하는 university 존재하지 않음");
58+
}
59+
return university;
60+
}
61+
));
62+
}
63+
4364
public Map<Long, Boolean> getMentorIdToIsApplied(List<Mentor> mentors, long currentUserId) {
4465
List<Long> mentorIds = mentors.stream().map(Mentor::getId).toList();
4566
List<Mentoring> appliedMentorings = mentoringRepository.findAllByMentorIdInAndMenteeId(mentorIds, currentUserId);

src/main/java/com/example/solidconnection/mentor/repository/MentorRepository.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.example.solidconnection.mentor.repository;
22

3+
import com.example.solidconnection.location.region.domain.Region;
34
import com.example.solidconnection.mentor.domain.Mentor;
45
import java.util.Optional;
56
import org.springframework.data.domain.Pageable;
67
import org.springframework.data.domain.Slice;
78
import org.springframework.data.jpa.repository.JpaRepository;
9+
import org.springframework.data.jpa.repository.Query;
10+
import org.springframework.data.repository.query.Param;
811

912
public interface MentorRepository extends JpaRepository<Mentor, Long> {
1013

@@ -13,4 +16,11 @@ public interface MentorRepository extends JpaRepository<Mentor, Long> {
1316
Optional<Mentor> findBySiteUserId(long siteUserId);
1417

1518
Slice<Mentor> findAllBy(Pageable pageable);
19+
20+
@Query("""
21+
SELECT m FROM Mentor m
22+
JOIN University u ON m.universityId = u.id
23+
WHERE u.region = :region
24+
""")
25+
Slice<Mentor> findAllByRegion(@Param("region") Region region, Pageable pageable);
1626
}

src/main/java/com/example/solidconnection/mentor/service/MentorMyPageService.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static com.example.solidconnection.common.exception.ErrorCode.CHANNEL_REGISTRATION_LIMIT_EXCEEDED;
44
import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_NOT_FOUND;
5+
import static com.example.solidconnection.common.exception.ErrorCode.UNIVERSITY_NOT_FOUND;
56
import static com.example.solidconnection.common.exception.ErrorCode.USER_NOT_FOUND;
67

78
import com.example.solidconnection.common.exception.CustomException;
@@ -13,6 +14,8 @@
1314
import com.example.solidconnection.mentor.repository.MentorRepository;
1415
import com.example.solidconnection.siteuser.domain.SiteUser;
1516
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
17+
import com.example.solidconnection.university.domain.University;
18+
import com.example.solidconnection.university.repository.UniversityRepository;
1619
import java.util.ArrayList;
1720
import java.util.List;
1821
import lombok.RequiredArgsConstructor;
@@ -28,14 +31,17 @@ public class MentorMyPageService {
2831

2932
private final MentorRepository mentorRepository;
3033
private final SiteUserRepository siteUserRepository;
34+
private final UniversityRepository universityRepository;
3135

3236
@Transactional(readOnly = true)
3337
public MentorMyPageResponse getMentorMyPage(long siteUserId) {
3438
SiteUser siteUser = siteUserRepository.findById(siteUserId)
3539
.orElseThrow(() -> new CustomException(USER_NOT_FOUND));
3640
Mentor mentor = mentorRepository.findBySiteUserId(siteUser.getId())
3741
.orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND));
38-
return MentorMyPageResponse.of(mentor, siteUser);
42+
University university = universityRepository.findById(mentor.getUniversityId())
43+
.orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND));
44+
return MentorMyPageResponse.of(mentor, siteUser, university);
3945
}
4046

4147
@Transactional

src/main/java/com/example/solidconnection/mentor/service/MentorQueryService.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.example.solidconnection.mentor.service;
22

33
import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_NOT_FOUND;
4+
import static com.example.solidconnection.common.exception.ErrorCode.UNIVERSITY_NOT_FOUND;
45

56
import com.example.solidconnection.common.dto.SliceResponse;
67
import com.example.solidconnection.common.exception.CustomException;
8+
import com.example.solidconnection.common.exception.ErrorCode;
9+
import com.example.solidconnection.location.region.domain.Region;
10+
import com.example.solidconnection.location.region.repository.RegionRepository;
711
import com.example.solidconnection.mentor.domain.Mentor;
812
import com.example.solidconnection.mentor.dto.MentorDetailResponse;
913
import com.example.solidconnection.mentor.dto.MentorPreviewResponse;
@@ -12,6 +16,8 @@
1216
import com.example.solidconnection.mentor.repository.MentoringRepository;
1317
import com.example.solidconnection.siteuser.domain.SiteUser;
1418
import com.example.solidconnection.siteuser.repository.SiteUserRepository;
19+
import com.example.solidconnection.university.domain.University;
20+
import com.example.solidconnection.university.repository.UniversityRepository;
1521
import java.util.ArrayList;
1622
import java.util.List;
1723
import java.util.Map;
@@ -29,36 +35,51 @@ public class MentorQueryService {
2935
private final MentoringRepository mentoringRepository;
3036
private final SiteUserRepository siteUserRepository;
3137
private final MentorBatchQueryRepository mentorBatchQueryRepository;
38+
private final UniversityRepository universityRepository;
39+
private final RegionRepository regionRepository;
3240

3341
@Transactional(readOnly = true)
3442
public MentorDetailResponse getMentorDetails(long mentorId, long currentUserId) {
3543
Mentor mentor = mentorRepository.findById(mentorId)
3644
.orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND));
45+
University university = universityRepository.findById(mentor.getUniversityId())
46+
.orElseThrow(() -> new CustomException(UNIVERSITY_NOT_FOUND));
3747
SiteUser mentorUser = siteUserRepository.findById(mentor.getSiteUserId())
3848
.orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND));
3949
boolean isApplied = mentoringRepository.existsByMentorIdAndMenteeId(mentorId, currentUserId);
4050

41-
return MentorDetailResponse.of(mentor, mentorUser, isApplied);
51+
return MentorDetailResponse.of(mentor, mentorUser, university, isApplied);
4252
}
4353

4454
@Transactional(readOnly = true)
45-
public SliceResponse<MentorPreviewResponse> getMentorPreviews(String region, long currentUserId, Pageable pageable) { // todo: 멘토의 '인증' 작업 후 region 필터링 추가
46-
Slice<Mentor> mentorSlice = mentorRepository.findAllBy(pageable);
55+
public SliceResponse<MentorPreviewResponse> getMentorPreviews(String regionKoreanName, long currentUserId, Pageable pageable) {
56+
Slice<Mentor> mentorSlice = filterMentorsByRegion(regionKoreanName, pageable);
4757
List<Mentor> mentors = mentorSlice.toList();
48-
List<MentorPreviewResponse> content = getMentorPreviewResponses(mentors, currentUserId);
58+
List<MentorPreviewResponse> content = buildMentorPreviewsWithBatchQuery(mentors, currentUserId);
4959

5060
return SliceResponse.of(content, mentorSlice);
5161
}
5262

53-
private List<MentorPreviewResponse> getMentorPreviewResponses(List<Mentor> mentors, long currentUserId) {
63+
private Slice<Mentor> filterMentorsByRegion(String regionKoreanName, Pageable pageable) {
64+
if (regionKoreanName == null || regionKoreanName.isEmpty()) {
65+
return mentorRepository.findAll(pageable);
66+
}
67+
Region region = regionRepository.findByKoreanName(regionKoreanName)
68+
.orElseThrow(() -> new CustomException(ErrorCode.REGION_NOT_FOUND_BY_KOREAN_NAME));
69+
return mentorRepository.findAllByRegion(region, pageable);
70+
}
71+
72+
private List<MentorPreviewResponse> buildMentorPreviewsWithBatchQuery(List<Mentor> mentors, long currentUserId) {
5473
Map<Long, SiteUser> mentorIdToSiteUser = mentorBatchQueryRepository.getMentorIdToSiteUserMap(mentors);
74+
Map<Long, University> mentorIdToUniversity = mentorBatchQueryRepository.getMentorIdToUniversityMap(mentors);
5575
Map<Long, Boolean> mentorIdToIsApplied = mentorBatchQueryRepository.getMentorIdToIsApplied(mentors, currentUserId);
5676

5777
List<MentorPreviewResponse> mentorPreviews = new ArrayList<>();
5878
for (Mentor mentor : mentors) {
5979
SiteUser mentorUser = mentorIdToSiteUser.get(mentor.getId());
80+
University university = mentorIdToUniversity.get(mentor.getId());
6081
boolean isApplied = mentorIdToIsApplied.get(mentor.getId());
61-
MentorPreviewResponse response = MentorPreviewResponse.of(mentor, mentorUser, isApplied);
82+
MentorPreviewResponse response = MentorPreviewResponse.of(mentor, mentorUser, university, isApplied);
6283
mentorPreviews.add(response);
6384
}
6485
return mentorPreviews;

src/test/java/com/example/solidconnection/mentor/repository/MentorBatchQueryRepositoryTest.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
import com.example.solidconnection.siteuser.domain.SiteUser;
1010
import com.example.solidconnection.siteuser.fixture.SiteUserFixture;
1111
import com.example.solidconnection.support.TestContainerSpringBootTest;
12+
import com.example.solidconnection.university.domain.University;
13+
import com.example.solidconnection.university.fixture.UniversityFixture;
1214
import java.util.List;
1315
import java.util.Map;
1416
import org.junit.jupiter.api.BeforeEach;
@@ -32,7 +34,10 @@ class MentorBatchQueryRepositoryTest {
3234
@Autowired
3335
private SiteUserFixture siteUserFixture;
3436

35-
private long universityId = 1L; // todo: 멘토 인증 기능 추가 변경 필요
37+
@Autowired
38+
private UniversityFixture universityFixture;
39+
40+
private University university1, university2;
3641
private Mentor mentor1, mentor2;
3742
private SiteUser mentorUser1, mentorUser2, currentUser;
3843

@@ -41,8 +46,10 @@ void setUp() {
4146
currentUser = siteUserFixture.사용자(1, "사용자");
4247
mentorUser1 = siteUserFixture.사용자(2, "멘토1");
4348
mentorUser2 = siteUserFixture.사용자(3, "멘토2");
44-
mentor1 = mentorFixture.멘토(mentorUser1.getId(), universityId);
45-
mentor2 = mentorFixture.멘토(mentorUser2.getId(), universityId);
49+
university1 = universityFixture.코펜하겐IT_대학();
50+
university2 = universityFixture.메모리얼_대학_세인트존스();
51+
mentor1 = mentorFixture.멘토(mentorUser1.getId(), university1.getId());
52+
mentor2 = mentorFixture.멘토(mentorUser2.getId(), university2.getId());
4653
}
4754

4855
@Test
@@ -60,6 +67,21 @@ void setUp() {
6067
);
6168
}
6269

70+
@Test
71+
void 멘토_ID_와_멘토의_파견_대학교를_매핑한다() {
72+
// given
73+
List<Mentor> mentors = List.of(mentor1, mentor2);
74+
75+
// when
76+
Map<Long, University> mentorIdToUniversity = mentorBatchQueryRepository.getMentorIdToUniversityMap(mentors);
77+
78+
// then
79+
assertAll(
80+
() -> assertThat(mentorIdToUniversity.get(mentor1.getId()).getId()).isEqualTo(university1.getId()),
81+
() -> assertThat(mentorIdToUniversity.get(mentor2.getId()).getId()).isEqualTo(university2.getId())
82+
);
83+
}
84+
6385
@Test
6486
void 멘토_ID_와_현재_사용자의_지원_여부를_매핑한다() {
6587
// given

src/test/java/com/example/solidconnection/mentor/service/MentorMyPageServiceTest.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
import com.example.solidconnection.siteuser.domain.SiteUser;
1919
import com.example.solidconnection.siteuser.fixture.SiteUserFixture;
2020
import com.example.solidconnection.support.TestContainerSpringBootTest;
21+
import com.example.solidconnection.university.domain.University;
22+
import com.example.solidconnection.university.fixture.UniversityFixture;
2123
import java.util.List;
2224
import org.junit.jupiter.api.BeforeEach;
2325
import org.junit.jupiter.api.DisplayName;
@@ -44,17 +46,21 @@ class MentorMyPageServiceTest {
4446
@Autowired
4547
private MentorRepository mentorRepository;
4648

49+
@Autowired
50+
private UniversityFixture universityFixture;
51+
4752
@Autowired
4853
private ChannelRepositoryForTest channelRepositoryForTest;
4954

5055
private SiteUser mentorUser;
5156
private Mentor mentor;
52-
private long universityId = 1L;
57+
private University university;
5358

5459
@BeforeEach
5560
void setUp() {
61+
university = universityFixture.메이지_대학();
5662
mentorUser = siteUserFixture.멘토(1, "멘토");
57-
mentor = mentorFixture.멘토(mentorUser.getId(), universityId);
63+
mentor = mentorFixture.멘토(mentorUser.getId(), university.getId());
5864
}
5965

6066
@Nested
@@ -73,6 +79,8 @@ class 멘토의_마이_페이지를_조회한다 {
7379
assertAll(
7480
() -> assertThat(response.id()).isEqualTo(mentor.getId()),
7581
() -> assertThat(response.nickname()).isEqualTo(mentorUser.getNickname()),
82+
() -> assertThat(response.universityName()).isEqualTo(university.getKoreanName()),
83+
() -> assertThat(response.country()).isEqualTo(university.getCountry().getKoreanName()),
7684
() -> assertThat(response.channels()).extracting(ChannelResponse::url)
7785
.containsExactly(channel1.getUrl(), channel2.getUrl())
7886
);

0 commit comments

Comments
 (0)