[Fix] 사용자 이미지 Signed URL 조회 방식 전환#204
Conversation
- Post, Profile, UserService 등에서 고정 url로 조회하던 방식을 SignedUrl방식으로 변경하였다. - 그에 따른 테스트 코드도 수정하였다.
|
Caution Review failedThe pull request is closed. Walkthrough여러 서비스에서 사용자 프로필 이미지 조회를 엔티티 직접 접근에서 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Service as 서비스 (Post/Profile/Follow/Comment)
participant UIS as UserImageService
participant UIR as UserImageEntityRepository
participant URLP as URL Provider
Service->>UIS: createImageGetUrlOptional(userId)
UIS->>UIR: findByUserId(userId) / findAllByUserIdIn(ids)
alt 이미지 존재
UIR-->>UIS: UserImageEntity(path,name,ext)
UIS->>URLP: convert to signed URL
URLP-->>UIS: signedUrl
UIS-->>Service: Optional.of(signedUrl)
else 이미지 없음
UIR-->>UIS: empty / []
UIS-->>Service: Optional.empty()
end
note right of Service: hasUserImage = optional.isPresent()\nimageUrl = optional.orElse(null)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (1)
62-73: 사용자 이미지 URL 조회 로직의 중복 제거를 고려하세요.6개의 메서드에서 동일한 패턴이 반복됩니다:
final Optional<String> userImageUrl = userImageService.createImageGetUrlOptional(u.getId()); final boolean hasUserImage = userImageUrl.isPresent();헬퍼 메서드를 추출하여 유지보수성을 개선할 수 있습니다.
다음과 같이 리팩터링할 수 있습니다:
+private record UserImageInfo(boolean hasImage, String imageUrl) { + static UserImageInfo from(Optional<String> imageUrl) { + return new UserImageInfo(imageUrl.isPresent(), imageUrl.orElse(null)); + } +} + return followRepository.findFollowersOrderByCreatedAt(userId, PageRequest.of(page, size)) .map(u -> { - final Optional<String> userImageUrl = userImageService.createImageGetUrlOptional(u.getId()); - final boolean hasUserImage = userImageUrl.isPresent(); + final UserImageInfo imageInfo = UserImageInfo.from( + userImageService.createImageGetUrlOptional(u.getId())); return new GetFollowersResponse( u.getId(), - hasUserImage, - userImageUrl.orElse(null), + imageInfo.hasImage(), + imageInfo.imageUrl(), u.getName(), u.getEmail() ); });Also applies to: 84-95, 112-123, 134-144, 155-166, 183-194
src/test/java/hanium/modic/backend/web/profile/controller/ProfileControllerIntegrationTest.java (1)
54-67: 테스트 데이터 설정이 올바릅니다.사용자 이미지 엔티티 생성 및 저장이 적절하게 구현되어 Signed URL 기반 응답 테스트를 지원합니다.
경로 문자열을 상수나 팩토리 메서드로 추출하면 유지보수성이 향상됩니다:
private static final String IMAGE_PATH_FORMAT = "profiles/%d/image.png"; UserImageEntity image = UserImageEntity.builder() .user(target) .imagePath(String.format(IMAGE_PATH_FORMAT, target.getId())) // ... 나머지 필드 .build();
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java(8 hunks)src/main/java/hanium/modic/backend/domain/post/service/PostService.java(8 hunks)src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewService.java(6 hunks)src/main/java/hanium/modic/backend/domain/profile/service/ProfileService.java(4 hunks)src/main/java/hanium/modic/backend/domain/user/entity/UserEntity.java(0 hunks)src/main/java/hanium/modic/backend/domain/user/service/UserImageService.java(2 hunks)src/main/java/hanium/modic/backend/domain/user/service/UserService.java(3 hunks)src/main/java/hanium/modic/backend/web/user/dto/response/UserInfoResponse.java(1 hunks)src/test/java/hanium/modic/backend/domain/follow/service/FollowMockingServiceTest.java(2 hunks)src/test/java/hanium/modic/backend/domain/post/service/PostServiceTest.java(4 hunks)src/test/java/hanium/modic/backend/domain/postReview/service/PostReviewServiceTest.java(6 hunks)src/test/java/hanium/modic/backend/domain/profile/ProfileServiceTest.java(2 hunks)src/test/java/hanium/modic/backend/domain/user/service/UserServiceTest.java(1 hunks)src/test/java/hanium/modic/backend/web/profile/controller/ProfileControllerIntegrationTest.java(2 hunks)src/test/java/hanium/modic/backend/web/user/controller/UserControllerTest.java(1 hunks)
💤 Files with no reviewable changes (1)
- src/main/java/hanium/modic/backend/domain/user/entity/UserEntity.java
🧰 Additional context used
🧬 Code graph analysis (2)
src/test/java/hanium/modic/backend/web/profile/controller/ProfileControllerIntegrationTest.java (1)
src/test/java/hanium/modic/backend/domain/user/factory/UserFactory.java (1)
UserFactory(9-29)
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (1)
src/test/java/hanium/modic/backend/domain/follow/service/FollowServiceTest.java (1)
Transactional(26-136)
🔇 Additional comments (20)
src/main/java/hanium/modic/backend/domain/user/service/UserService.java (1)
62-65: LGTM! Signed URL 통합이 올바르게 구현되었습니다.
UserImageService를 통한 Optional 기반 이미지 URL 조회와 null 처리가 적절합니다.src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (1)
57-57: 읽기 전용 트랜잭션 애너테이션 추가 승인조회 메서드에
@Transactional(readOnly = true)추가가 적절합니다. 읽기 전용 최적화를 활성화하여 성능을 향상시킵니다.Also applies to: 78-78, 100-100, 128-128, 149-149, 171-171
src/main/java/hanium/modic/backend/domain/user/service/UserImageService.java (1)
35-50: LGTM! Optional 기반 API 설계가 우수합니다.두 가지 조회 메서드 제공:
createImageGetUrlOptional: 이미지가 없을 수 있는 경우를 위한 Optional 반환createImageGetUrl: 이미지가 반드시 존재해야 하는 경우를 위한 예외 발생읽기 전용 트랜잭션 애너테이션과 Optional 체인 사용이 적절합니다.
src/test/java/hanium/modic/backend/domain/user/service/UserServiceTest.java (1)
43-44: Mock 추가가 적절하지만 테스트 검증을 확인하세요.
UserImageServicemock이 추가되었습니다.getUserInfoTest테스트(라인 110-123)가 이미지 URL 조회를 검증하도록 스텁 동작을 추가하는 것이 좋습니다.다음과 같이 테스트를 개선할 수 있습니다:
@Test @DisplayName("유저 정보 조회 테스트") void getUserInfoTest() { // given final Long userId = 1L; UserEntity user = UserFactory.createMockUser(userId); when(userImageService.createImageGetUrlOptional(userId)) .thenReturn(Optional.of("https://signed-url.com/image.jpg")); // when UserInfoResponse response = userService.getUserInfo(user); // then assertThat(response.id()).isEqualTo(userId); assertThat(response.userEmail()).isEqualTo(user.getEmail()); assertThat(response.userName()).isEqualTo(user.getName()); assertThat(response.userImageUrl()).isEqualTo("https://signed-url.com/image.jpg"); verify(userImageService).createImageGetUrlOptional(userId); }src/test/java/hanium/modic/backend/domain/profile/ProfileServiceTest.java (1)
43-44: Mock 추가 확인
UserImageServicemock이 추가되었습니다. 프로필 조회 테스트가 이미지 URL 처리를 검증하도록 스텁 동작 추가를 고려하세요.src/test/java/hanium/modic/backend/domain/post/service/PostServiceTest.java (2)
68-69: LGTM! Mock 추가가 적절합니다.
UserImageServicemock이 올바르게 추가되었습니다.
184-184: 이미지 부재 시나리오 테스트가 우수합니다.
Optional.empty()반환을 명시적으로 스텁하여 사용자 이미지가 없는 경우를 테스트합니다. 엣지 케이스 처리가 적절합니다.Also applies to: 697-697
src/test/java/hanium/modic/backend/web/user/controller/UserControllerTest.java (1)
140-140: LGTM! UserInfoResponse API 변경 반영
UserInfoResponse.from(mockUser)에서UserInfoResponse.of(mockUser, "URL")로 변경하여 명시적 이미지 URL 매개변수를 받는 새로운 팩토리 메서드를 올바르게 사용합니다.src/test/java/hanium/modic/backend/domain/postReview/service/PostReviewServiceTest.java (2)
27-27: LGTM!UserImageService 의존성이 올바르게 추가되었으며, 모킹 설정이 적절합니다.
Also applies to: 41-42
78-78: LGTM!각 테스트 시나리오에서 UserImageService의 stubbing이 정확합니다:
- Line 78: 사용자 이미지가 있는 경우
Optional.of(url)반환- Line 153: 리뷰 이미지는 없지만 사용자 이미지는 있는 경우
Optional.of(url)반환- Line 189: 사용자 이미지가 없는 경우
Optional.empty()반환테스트 단언문들도 Optional 결과에 따라
hasUserImage와userImageUrl을 올바르게 검증하고 있습니다.Also applies to: 153-153, 189-189
src/main/java/hanium/modic/backend/web/user/dto/response/UserInfoResponse.java (1)
17-25: LGTM!팩토리 메서드 시그니처 변경이 적절합니다:
userImageUrl을 외부에서 명시적으로 전달받도록 변경hasUserImage는 전달받은userImageUrl의 null 여부로 올바르게 결정- 서비스 레이어의 Optional 기반 조회 패턴과 일관성 있게 통합됨
src/main/java/hanium/modic/backend/domain/post/service/PostService.java (3)
10-10: LGTM!UserImageService 의존성이 올바르게 추가되었습니다.
Also applies to: 32-32, 57-57
110-111: LGTM!
getPost메서드에서 Optional 기반 이미지 URL 조회가 올바르게 구현되었습니다:
- Line 110:
userImageService.createImageGetUrlOptional()로 Optional 조회- Line 111:
isPresent()로 hasUserImage 결정- Lines 143:
orElse(null)로 null-safe하게 URL 전달Also applies to: 140-150
161-162: LGTM!
getPostForPublic메서드에서도 동일한 Optional 기반 패턴이 일관성 있게 적용되었습니다.Also applies to: 191-201
src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewService.java (3)
8-8: LGTM!UserImageService 의존성이 올바르게 추가되었습니다.
Also applies to: 26-26, 40-40
126-127: LGTM!
getPostReviewDetail메서드에서 Optional 기반 이미지 URL 조회가 올바르게 구현되었습니다:
- Line 126:
createImageGetUrlOptional()로 Optional 조회- Line 127:
isPresent()로 hasUserImage 결정- Line 132:
orElse(null)로 null-safe하게 URL 전달Also applies to: 132-132
166-167: LGTM!
getPostReviews메서드의 페이지 매핑 로직에서도 동일한 Optional 기반 패턴이 일관성 있게 적용되었습니다.Also applies to: 176-176
src/main/java/hanium/modic/backend/domain/profile/service/ProfileService.java (3)
3-3: LGTM!UserImageService 의존성이 올바르게 추가되었습니다.
Also applies to: 13-13, 24-24
31-32: LGTM!
getMyProfile메서드에서 Optional 기반 이미지 URL 조회가 올바르게 구현되었습니다:
- Line 31:
createImageGetUrlOptional()로 Optional 조회- Line 32:
isPresent()로 hasUserImage 결정- Line 39:
orElse(null)로 null-safe하게 URL 전달Also applies to: 38-39
55-56: LGTM!
getProfile메서드에서도 동일한 Optional 기반 패턴이 일관성 있게 적용되었습니다.Also applies to: 62-63
src/test/java/hanium/modic/backend/domain/follow/service/FollowMockingServiceTest.java
Show resolved
Hide resolved
- FollowService에서 고정 url로 조회하던 방식을 SignedUrl방식으로 변경하였다. - 그에 따른 테스트 코드도 수정하였다.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (7)
src/main/java/hanium/modic/backend/domain/follow/repository/FollowEntityRepository.java (1)
53-58: 타입 일관성 개선 권장JPQL의
CASE WHEN표현식은 항상true또는false를 반환하므로 null이 될 수 없습니다. 하지만FollowerWithStatus레코드는Boolean(nullable wrapper)을 사용하고 있습니다. 타입 일관성과 null-safety를 위해 레코드 정의에서booleanprimitive 타입 사용을 고려해보세요.동일한 제안이
FollowingWithStatus(lines 73-78)에도 적용됩니다.src/main/java/hanium/modic/backend/domain/follow/dto/FollowingWithStatus.java (1)
3-8: primitive boolean 타입 사용 권장
isFollowing이Booleanwrapper 타입으로 선언되어 있지만, 리포지토리의 JPQL 쿼리는 항상 non-null 값(true또는false)을 생성합니다. null 처리 부담을 제거하고 타입 안정성을 높이기 위해booleanprimitive 타입 사용을 권장합니다.다음과 같이 수정:
public record FollowingWithStatus( Long id, String name, String email, - Boolean isFollowing + boolean isFollowing ) { }src/main/java/hanium/modic/backend/domain/follow/dto/FollowerWithStatus.java (1)
3-8: primitive boolean 타입 사용 권장
isFollowing이Booleanwrapper 타입으로 선언되어 있지만, 리포지토리의 JPQL 쿼리는 항상 non-null 값을 생성합니다. null 처리 오버헤드를 제거하고 의도를 명확히 하기 위해booleanprimitive 타입 사용을 권장합니다.다음과 같이 수정:
public record FollowerWithStatus( Long id, String name, String email, - Boolean isFollowing + boolean isFollowing ) { }src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (2)
109-110: 코드 포맷팅 개선 권장메서드 호출이 두 줄에 걸쳐 분리되어 있어 가독성이 떨어집니다. 한 줄로 작성하거나 메서드 체이닝 스타일로 정리하는 것을 권장합니다.
예시:
- return followRepository.findFollowersWithStatusOrderByCreatedAt(targetUserId, currentUserId, - PageRequest.of(page, size)) + return followRepository.findFollowersWithStatusOrderByCreatedAt( + targetUserId, currentUserId, PageRequest.of(page, size)) .map(u -> {Also applies to: 180-181
63-73: createImageGetUrlOptional은 외부 네트워크 호출이 아닌 로컬 서명 생성만 수행합니다
userImageRepository.findByUserId()가 호출되는 만큼 DB 조회가 사용자 수만큼 발생하므로, JPA fetch join 또는 IN절 기반 배치 조회 전략 도입해 N+1 문제 완화 고려src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java (1)
58-59: 테스트 커버리지 개선이 필요합니다.테스트에서
mockUser를 생성하지만, 사용자 이미지 관련 필드는 하드코딩된false와null로 설정되어 실제 동작을 검증하지 못하고 있습니다. PR의 목적이 Signed URL 방식으로 전환하는 것인 만큼, 다양한 시나리오(이미지 있음/없음)를 테스트하는 것이 좋습니다.다음과 같이 개선할 수 있습니다:
- GetPostResponse mockResponse = new GetPostResponse( - mockUser.getName(), - false, - null, + // 이미지가 없는 사용자 케이스 + GetPostResponse mockResponseNoImage = new GetPostResponse( + mockUser.getName(), + false, + null,또한 이미지가 있는 케이스를 위한 별도 테스트 추가를 권장합니다:
@Test @DisplayName("공개 게시글 조회 성공 - 사용자 이미지 포함") void getPost_Success_WithUserImage() throws Exception { // 이미지 있는 케이스 테스트 }src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java (1)
42-55: N+1 쿼리 잠재성 검토
- getComments API는 기본 size=10, 최대 30까지 페이징 처리합니다.
- UserImageService.createImageGetUrlOptional()를 댓글마다 개별 호출해 최대 30회 호출됩니다.
- 빈번한 호출이 성능 이슈로 이어질 수 있으니, 필요 시
Map<Long, Optional<String>> createImageGetUrlsForUsers(Set<Long> userIds)같은 배치 조회 메서드 도입을 검토하세요.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
src/main/java/hanium/modic/backend/domain/follow/dto/FollowerWithStatus.java(1 hunks)src/main/java/hanium/modic/backend/domain/follow/dto/FollowingWithStatus.java(1 hunks)src/main/java/hanium/modic/backend/domain/follow/repository/FollowEntityRepository.java(2 hunks)src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java(6 hunks)src/main/java/hanium/modic/backend/domain/postReview/dto/PostReviewCommentDto.java(1 hunks)src/main/java/hanium/modic/backend/domain/postReview/repository/PostReviewCommentRepository.java(1 hunks)src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java(2 hunks)src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java (1)
src/main/java/hanium/modic/backend/domain/user/service/UserImageService.java (1)
Service(22-106)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (9)
src/main/java/hanium/modic/backend/domain/postReview/dto/PostReviewCommentDto.java (2)
1-12: LGTM!도메인 레이어 DTO로서 적절하게 구현되었습니다. Record 타입을 사용하여 간결하고 명확한 데이터 구조를 제공합니다.
1-12: LGTM!레포지토리 레이어의 프로젝션 DTO로 적절하게 구현되었습니다. Record 사용으로 간결하고 불변성이 보장됩니다.
src/main/java/hanium/modic/backend/domain/postReview/repository/PostReviewCommentRepository.java (2)
8-8: 좋은 아키텍처 개선입니다!리포지토리가 웹 레이어의
PostReviewCommentResponse대신 도메인 레이어의PostReviewCommentDto를 반환하도록 변경되었습니다. 이는 계층 간 책임 분리를 명확히 하는 좋은 개선입니다.
- 리포지토리는 도메인 데이터를 반환
- 서비스 레이어에서 웹 응답으로 변환
- 이미지 URL 등 추가 데이터 조합은 서비스에서 처리
Also applies to: 14-26
13-26: LGTM!레포지토리가 응답 DTO 대신 도메인 DTO를 반환하도록 변경되어 계층 분리가 개선되었습니다. 서비스 레이어에서 UserImageService를 통해 추가 데이터를 보강하는 구조가 적절합니다.
src/test/java/hanium/modic/backend/web/post/controller/PublicPostControllerTest.java (1)
58-59: 사용자 이미지 하드코딩 검증 필요
hasUserImage를false,userImageUrl를null로 고정한 것이 “이미지 없는 사용자” 시나리오 의도인지 확인하세요. 다른 테스트에서 사용자 이미지 처리 방식을 찾을 수 없어 누락 가능성이 있으니, 프로필 이미지가 있는 경우와 없는 경우를 모두 다루는 테스트 추가를 검토하세요.src/main/java/hanium/modic/backend/domain/follow/repository/FollowEntityRepository.java (1)
53-78: LGTM!JPQL 생성자 프로젝션 패턴이 올바르게 적용되었습니다. 레코드 정의와 생성자 인자가 정확히 일치하며, LEFT JOIN을 통한 팔로우 상태 확인 로직도 정확합니다.
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (3)
30-30: LGTM!
UserImageService의존성 주입이 올바르게 추가되었습니다. Signed URL 기반 이미지 조회를 위한 필수 변경사항입니다.
57-57: LGTM!읽기 전용 메서드에
@Transactional(readOnly = true)어노테이션이 적절하게 추가되었습니다. 이는 데이터베이스 최적화와 의도 명확화에 도움이 됩니다.Also applies to: 78-78, 100-100, 128-128, 149-149, 171-171
63-73: LGTM!Optional 처리 패턴이 일관되게 적용되었습니다:
Optional<String>로 이미지 URL 조회.isPresent()로 이미지 존재 여부 확인.orElse(null)로 안전한 null 처리Signed URL 마이그레이션 목표에 부합하는 올바른 구현입니다.
Also applies to: 84-95
src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java
Outdated
Show resolved
Hide resolved
src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java
Show resolved
Hide resolved
src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (1)
191-218: 불필요한 중복 쿼리를 제거하세요.
getMyFollowings메서드에서 동일한 쿼리가 두 번 실행됩니다:
- Line 196:
followRepository.findFollowingOrderByCreatedAt(...)- Line 204: 동일한 쿼리 재실행
Line 196에서 조회한
followings변수를 재사용해야 합니다.다음 diff를 적용하여 중복 쿼리를 제거하세요:
// 3. 응답 생성 - return followRepository.findFollowingOrderByCreatedAt(userId, PageRequest.of(page, size)) + return followings .map(u -> { final Optional<String> userImageUrl = userImageService.createImageGetUrlOptional(u.getId()); final boolean hasUserImage = userImageUrl.isPresent();
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java(6 hunks)src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java(4 hunks)src/main/java/hanium/modic/backend/domain/user/repository/UserImageEntityRepository.java(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (3)
src/main/java/hanium/modic/backend/domain/user/repository/UserImageEntityRepository.java (1)
3-3: LGTM! N+1 문제 해결을 위한 배치 조회 메서드가 잘 추가되었습니다.
findAllByUserIdIn메서드는 여러 사용자의 이미지를 한 번에 조회하여 N+1 문제를 효과적으로 해결합니다. Spring Data JPA 네이밍 컨벤션을 올바르게 따르고 있습니다.Also applies to: 14-15
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (2)
62-89: 배치 조회 및 Optional 기반 URL 처리가 잘 구현되었습니다.각 메서드에서 다음 패턴을 올바르게 적용했습니다:
- 사용자 목록 조회
- N+1 문제 방지를 위한 배치 이미지 조회
- Optional 기반 Signed URL 생성
이 접근 방식은 성능을 개선하고 권한 문제를 해결합니다.
Also applies to: 93-120, 124-156, 160-187, 222-258
62-89: @transactional(readOnly = true) 어노테이션 추가가 적절합니다.읽기 전용 트랜잭션 설정은 데이터베이스 성능 최적화에 도움이 됩니다. 모든 조회 메서드에 일관되게 적용되었습니다.
Also applies to: 93-120, 124-156, 160-187, 191-218, 222-258
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (1)
196-217: 중복 쿼리를 제거하세요.Line 196에서 이미 조회한
followings결과를 사용하지 않고, Line 204에서 동일한 쿼리를 다시 실행하고 있습니다.다음 diff를 적용하여 중복 쿼리를 제거하세요:
// 3. 응답 생성 - return followRepository.findFollowingOrderByCreatedAt(userId, PageRequest.of(page, size)) + return followings .map(u -> {
♻️ Duplicate comments (1)
src/test/java/hanium/modic/backend/domain/follow/service/FollowMockingServiceTest.java (1)
43-47: UserImageService 스터빙 및 검증 로직이 여전히 누락되어 있습니다.이전 리뷰에서 지적된 문제가 해결되지 않았습니다.
userImageService.createImageGetUrlOptional()호출에 대한 스터빙과 응답 DTO의hasUserImage,userImageUrl필드 검증이 필요합니다.다음을 추가하세요:
- 각 테스트에서
userImageService.createImageGetUrlOptional()스터빙:when(userImageService.createImageGetUrlOptional(2L)).thenReturn(Optional.of("http://image-url-2")); when(userImageService.createImageGetUrlOptional(3L)).thenReturn(Optional.empty());
- 응답 DTO 필드 검증 추가:
assertThat(result.getContent().get(0).hasUserImage()).isTrue(); assertThat(result.getContent().get(0).userImageUrl()).isEqualTo("http://image-url-2"); assertThat(result.getContent().get(1).hasUserImage()).isFalse(); assertThat(result.getContent().get(1).userImageUrl()).isNull();
🧹 Nitpick comments (1)
src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java (1)
42-61: 배치 조회 패턴이 추가되었으나 개선 여지가 있습니다.N+1 문제를 해결하기 위해 배치 조회를 추가한 것은 좋습니다 (lines 43-45). JPA 영속성 컨텍스트에 미리 로드하여 후속 서비스 호출(line 49)이 캐시를 사용하도록 하는 패턴입니다.
향후 개선 시 고려사항:
UserImageService에 배치 조회 메서드를 추가하면 의도가 더 명확해집니다.예시:
// UserImageService에 추가 public Map<Long, String> createImageGetUrlsForUsers(List<Long> userIds) { List<UserImageEntity> images = userImageEntityRepository.findAllByUserIdIn(userIds); return images.stream() .collect(Collectors.toMap( UserImageEntity::getUserId, img -> imageUtil.createImageGetUrl(img.getImagePath()) )); }서비스 코드:
List<Long> userIds = prcs.getContent().stream() .map(PostReviewCommentDto::userId) .distinct() .toList(); Map<Long, String> userImageUrls = userImageService.createImageGetUrlsForUsers(userIds); return prcs.map(prc -> { final String userImageUrl = userImageUrls.get(prc.userId()); final boolean hasUserImage = userImageUrl != null; // ... });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java(6 hunks)src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java(4 hunks)src/main/java/hanium/modic/backend/domain/user/repository/UserImageEntityRepository.java(2 hunks)src/test/java/hanium/modic/backend/domain/follow/service/FollowMockingServiceTest.java(4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/main/java/hanium/modic/backend/domain/postReview/service/PostReviewCommentService.java (2)
src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (1)
Service(28-279)src/main/java/hanium/modic/backend/domain/user/service/UserImageService.java (1)
Service(22-106)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (2)
src/main/java/hanium/modic/backend/domain/user/repository/UserImageEntityRepository.java (1)
15-15: 배치 조회 메서드 추가가 적절합니다.N+1 문제 해결을 위한 배치 조회 메서드가 올바르게 추가되었습니다. Spring Data JPA의
In키워드를 사용한 메서드 네이밍 규칙을 정확히 따르고 있습니다.src/main/java/hanium/modic/backend/domain/follow/service/FollowService.java (1)
66-88: 배치 조회 패턴이 올바르게 적용되었습니다.N+1 문제 해결을 위한 배치 조회 로직과 Optional 기반 이미지 URL 처리가 적절하게 구현되었습니다. JPA 영속성 컨텍스트를 활용하여 후속 조회 시 캐시된 데이터를 사용하는 패턴입니다.
🧩 작업 내용 요약
———
🔍 관련 이슈
———
🧠 변경 이유 및 주요 포인트
———
🧪 테스트 및 검증
Summary by CodeRabbit