-
Notifications
You must be signed in to change notification settings - Fork 0
[FEAT] 팔로우 구현 #10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[FEAT] 팔로우 구현 #10
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Walkthrough이번 변경에서는 패키지명 대소문자 일관성 수정과 함께, 팔로우 기능의 전체적인 백엔드 구조가 추가되었습니다. 팔로우/언팔로우 요청 및 응답 DTO, 서비스, 컨트롤러, JPA 레포지토리 등이 새로 생성되었으며, 멤버 테스트 데이터 초기화 컴포넌트도 추가되었습니다. 일부 불필요한 빈 클래스는 삭제되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant FollowController
participant FollowService
participant MemberRepository
participant FollowRepository
Client->>FollowController: POST /follow (FollowRequestDto, requesterEmail)
FollowController->>FollowService: follow(requesterEmail, targetMemberId)
FollowService->>MemberRepository: findByEmail(requesterEmail)
MemberRepository-->>FollowService: Optional<Member>
FollowService->>MemberRepository: findById(targetMemberId)
MemberRepository-->>FollowService: Optional<Member>
FollowService->>FollowRepository: existsByFollowerAndFollowing(follower, following)
FollowRepository-->>FollowService: boolean
FollowService->>FollowRepository: save(new Follow)
FollowRepository-->>FollowService: Follow
FollowService-->>FollowController: FollowResponseDto
FollowController-->>Client: Response<FollowResponseDto>
sequenceDiagram
participant Client
participant FollowController
participant FollowService
participant MemberRepository
participant FollowRepository
Client->>FollowController: POST /follow/unfollow (UnfollowRequestDto, requesterEmail)
FollowController->>FollowService: unfollow(requesterEmail, targetMemberId)
FollowService->>MemberRepository: findByEmail(requesterEmail)
MemberRepository-->>FollowService: Optional<Member>
FollowService->>MemberRepository: findById(targetMemberId)
MemberRepository-->>FollowService: Optional<Member>
FollowService->>FollowRepository: findByFollowerAndFollowing(follower, following)
FollowRepository-->>FollowService: Optional<Follow>
FollowService->>FollowRepository: delete(follow)
FollowRepository-->>FollowService: void
FollowService-->>FollowController: void
FollowController-->>Client: Response<Void>
Poem
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (8)
src/main/java/com/example/fixlog/domain/member/Member.java (1)
11-11: 동일 패키지 내 임포트 구문이 필요한지 검토해주세요.
SocialType은Member클래스와 동일한 패키지(com.example.fixlog.domain.member)에 있으므로 명시적인 임포트가 필요하지 않습니다. 동일 패키지 내 클래스는 자동으로 임포트되기 때문입니다.-import com.example.fixlog.domain.member.SocialType;src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java (1)
20-25: 테스트 데이터 초기화 로직이 잘 구현되었습니다.애플리케이션 실행 시 회원 데이터가 없을 때만 테스트 데이터를 생성하는 로직이 적절합니다. 다만, 민감한 정보(비밀번호)가 하드코딩되어 있으므로 실제 프로덕션 환경에서는 제거하거나 암호화된 값으로 대체하는 것이 좋습니다.
시스템 출력 메시지는 로깅 프레임워크를 사용하는 것이 좋습니다:
- System.out.println("테스트용 멤버 2명 삽입 완료"); + log.info("테스트용 멤버 2명 삽입 완료");클래스에
@Slf4j어노테이션을 추가하거나 로거를 직접 선언하여 사용하세요.src/main/java/com/example/FixLog/dto/follow/request/UnfollowRequestDto.java (2)
7-12: 필드 설명 주석이 누락되었습니다.DTO 구현은 적절하지만,
FollowRequestDto에는 있는 필드 설명 주석이 이 클래스에는 누락되어 있습니다. 코드 일관성을 위해 주석을 추가하는 것이 좋겠습니다.@JsonProperty("target_member_id") -private Long targetMemberId; +private Long targetMemberId; // 언팔로우 대상 ID
1-12: 코드 중복 고려사항
FollowRequestDto와UnfollowRequestDto가 동일한 구조를 가지고 있습니다. 코드 중복을 줄이기 위해 상위 클래스를 만들거나, 하나의 클래스로 통합하는 것을 고려해볼 수 있습니다. 이렇게 하면 향후 필드 변경 시 일관성을 유지하기 쉽습니다.// 예시: 공통 상위 클래스 생성 @Getter @NoArgsConstructor public abstract class MemberTargetRequestDto { @JsonProperty("target_member_id") private Long targetMemberId; // 대상 회원 ID } // 이후 상속 public class FollowRequestDto extends MemberTargetRequestDto { } public class UnfollowRequestDto extends MemberTargetRequestDto { }src/main/java/com/example/FixLog/dto/follow/response/FollowingListResponseDto.java (1)
7-17: 필드 설명 주석 추가 권장DTO 설계가 적절하며 필요한 어노테이션이 잘 적용되어 있습니다. 그러나 각 필드의 의미를 명확히 하기 위해
FollowRequestDto처럼 한글 주석을 추가하는 것이 코드 가독성과 유지보수성을 높일 수 있습니다.@JsonProperty("follow_id") -private Long followId; +private Long followId; // 팔로우 관계 ID @JsonProperty("following_id") -private Long followingId; +private Long followingId; // 팔로잉 대상 ID -private String nickname; +private String nickname; // 팔로잉 대상 닉네임src/main/java/com/example/FixLog/service/follow/FollowService.java (2)
47-65: 언팔로우 로직 개선 가능언팔로우 기능이 적절히 구현되었습니다. 다만, 자기 자신 팔로우 불가 체크 로직은 이미 팔로우 관계가 존재하지 않을 것이므로 불필요할 수 있습니다.
자기 자신 팔로우 불가 체크 로직을 제거하는 것을 고려해보세요:
@Transactional public void unfollow(String requesterEmail, Long targetMemberId) { Member follower = memberRepository.findByEmail(requesterEmail) .orElseThrow(() -> new IllegalArgumentException("요청자 회원 없음")); Member following = memberRepository.findById(targetMemberId) .orElseThrow(() -> new IllegalArgumentException("언팔로우 대상 없음")); - // 자기 자신은 팔로우 불가 - if (follower.getId().equals(following.getId())) { - throw new IllegalArgumentException("자기 자신은 팔로우할 수 없음"); - } Follow follow = followRepository.findByFollowerAndFollowing(follower, following) .orElseThrow(() -> new IllegalArgumentException("팔로우 관계가 존재하지 않음")); followRepository.delete(follow); }
16-22: 에러 메시지 일관성 개선 필요서비스 내 에러 메시지가 일관되지 않습니다. 일부는 "회원 정보가 없음", 다른 곳은 "요청자 회원 없음" 등으로 다르게 표현됩니다.
에러 메시지를 일관되게 수정하는 것을 권장합니다:
@Transactional public FollowResponseDto follow(String requesterEmail, Long targetMemberId){ Member follower = memberRepository.findByEmail(requesterEmail) - .orElseThrow(() -> new IllegalArgumentException("회원 정보가 없음")); + .orElseThrow(() -> new IllegalArgumentException("요청자 회원 없음")); Member following = memberRepository.findById(targetMemberId) .orElseThrow(() -> new IllegalArgumentException("팔로우 대상 없음"));src/main/java/com/example/FixLog/controller/follow/FollowController.java (1)
32-40: 언팔로우 엔드포인트 RESTful 디자인 개선 가능언팔로우 기능이 POST 메소드로 구현되어 있습니다. 보다 RESTful한 접근법은 DELETE 메소드를 사용하는 것입니다.
다음과 같이 변경을 고려해보세요:
- @PostMapping("/unfollow") - public ResponseEntity<Response<Void>> unfollow( - @RequestBody UnfollowRequestDto requestDto, - @RequestParam String requesterEmail) { + @DeleteMapping("/{targetMemberId}") + public ResponseEntity<Response<Void>> unfollow( + @PathVariable Long targetMemberId, + @RequestParam String requesterEmail) { - followService.unfollow(requesterEmail, requestDto.getTargetMemberId()); + followService.unfollow(requesterEmail, targetMemberId); return ResponseEntity.ok(Response.success("언팔로우 완료", null)); }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
📒 Files selected for processing (12)
src/main/java/com/example/FixLog/controller/follow/FollowController.java(1 hunks)src/main/java/com/example/FixLog/dto/follow/request/FollowRequestDto.java(1 hunks)src/main/java/com/example/FixLog/dto/follow/request/UnfollowRequestDto.java(1 hunks)src/main/java/com/example/FixLog/dto/follow/response/FollowResponseDto.java(1 hunks)src/main/java/com/example/FixLog/dto/follow/response/FollowerListResponseDto.java(1 hunks)src/main/java/com/example/FixLog/dto/follow/response/FollowingListResponseDto.java(1 hunks)src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java(1 hunks)src/main/java/com/example/FixLog/repository/MemberRepository.java(1 hunks)src/main/java/com/example/FixLog/repository/follow/FollowRepository.java(1 hunks)src/main/java/com/example/FixLog/service/follow/FollowService.java(1 hunks)src/main/java/com/example/fixlog/domain/follow/Follow.java(1 hunks)src/main/java/com/example/fixlog/domain/member/Member.java(1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/main/java/com/example/FixLog/dto/follow/request/FollowRequestDto.java (1)
src/main/java/com/example/FixLog/dto/follow/response/FollowResponseDto.java (1)
Getter(7-17)
src/main/java/com/example/FixLog/dto/follow/response/FollowResponseDto.java (1)
src/main/java/com/example/FixLog/dto/follow/request/FollowRequestDto.java (1)
Getter(7-12)
🔇 Additional comments (13)
src/main/java/com/example/fixlog/domain/follow/Follow.java (1)
27-30: 생성자 추가가 잘 되었습니다!
follower와following을 초기화하는 생성자가 적절하게 구현되었습니다. 이 생성자는 팔로우 관계를 생성할 때 필요한 필수 관계를 명확하게 설정합니다.src/main/java/com/example/FixLog/dto/follow/request/FollowRequestDto.java (1)
7-12: DTO 구현이 간결하고 명확합니다.DTO 클래스가 적절히 설계되었으며, Lombok 어노테이션(
@Getter,@NoArgsConstructor)과 JSON 매핑을 위한 어노테이션(@JsonProperty)을 올바르게 사용하고 있습니다. 필드에 한글 주석을 추가한 점도 좋습니다.src/main/java/com/example/FixLog/repository/follow/FollowRepository.java (1)
10-15: 리포지토리 메서드 구현이 명확하고 주석이 유용합니다.JpaRepository를 확장하여 필요한 메서드들이 잘 정의되어 있습니다. 각 메서드의 목적을 설명하는 한글 주석이 이해를 돕습니다. 메서드 명명 규칙도 Spring Data JPA 관행을 잘 따르고 있습니다.
src/main/java/com/example/FixLog/dto/follow/response/FollowingListResponseDto.java (1)
7-17: 응답 DTO 구조가 적절합니다.
FollowingListResponseDto클래스는 팔로잉 목록을 조회하는 API의 응답으로 적합한 구조로 설계되었습니다.@Getter와@AllArgsConstructor어노테이션이 적절히 사용되었고, JSON 직렬화를 위한@JsonProperty어노테이션도 잘 적용되었습니다.src/main/java/com/example/FixLog/dto/follow/response/FollowResponseDto.java (1)
1-17: 잘 구현된 응답 DTO응답 DTO가 적절히 구현되었습니다. Lombok 어노테이션을 사용하여 불필요한 보일러플레이트 코드를 줄이고, JSON 직렬화를 위해 @JsonProperty를 적절히 사용했습니다.
src/main/java/com/example/FixLog/dto/follow/response/FollowerListResponseDto.java (1)
1-17: 응답 DTO 구조 적절팔로워 목록 응답 DTO가 적절히 구현되었습니다. 필드명과 JSON 프로퍼티 이름이 일관되게 작성되었습니다.
src/main/java/com/example/FixLog/service/follow/FollowService.java (3)
23-45: 팔로우 기능 로직 검증팔로우 기능이 적절히 구현되었습니다. 자기 자신 팔로우 방지, 중복 팔로우 방지 등의 검증 로직이 포함되어 있습니다.
67-82: 팔로워 목록 조회 기능 적절팔로워 목록 조회 기능이 적절히 구현되었습니다. 읽기 전용 트랜잭션을 사용하여 성능을 최적화했습니다.
84-99: 팔로잉 목록 조회 기능 적절팔로잉 목록 조회 기능이 적절히 구현되었습니다. 스트림 API를 활용하여 코드가 간결하게 작성되었습니다.
src/main/java/com/example/FixLog/controller/follow/FollowController.java (4)
22-30: 팔로우 엔드포인트 적절팔로우 기능 엔드포인트가 적절히 구현되었습니다. 표준화된 응답 형식을 사용하여 일관성 있는 API를 제공합니다.
42-49: 팔로워 목록 조회 엔드포인트 적절팔로워 목록 조회 엔드포인트가 적절히 구현되었습니다. GET 메소드를 사용하여 조회 작업을 처리합니다.
51-58: 팔로잉 목록 조회 엔드포인트 적절팔로잉 목록 조회 엔드포인트가 적절히 구현되었습니다. 응답 메시지가 명확합니다.
25-27: 인증 구현 계획 적절JWT 인증 구현 전까지 임시로 requesterEmail 파라미터를 사용하는 접근은 적절합니다. 주석에서 향후 AuthenticationPrincipal로 대체할 계획을 명시한 것도 좋습니다.
src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java
Outdated
Show resolved
Hide resolved
src/main/java/com/example/FixLog/repository/follow/FollowRepository.java
Outdated
Show resolved
Hide resolved
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
src/main/java/com/example/FixLog/service/follow/FollowService.java (3)
1-1: 패키지명은 소문자를 사용해주세요Java 패키지명은 관례적으로 전부 소문자를 사용합니다. 대문자가 섞이면 IDE 탐색·배포 스크립트에서 의도치 않은 충돌이 발생할 수 있습니다.
예)com.example.fixlog.service.follow
56-60: 자기 자신 체크 로직 중복
follow()·unfollow()모두 동일한 “자기 자신” 검사 로직을 갖고 있습니다. private 메서드로 추출하면 가독성과 유지보수가 향상됩니다.
86-99: 응답 정렬·페이징 없음팔로잉 수가 많을 때 무작위 순서로 전부 반환하면 클라이언트 UX 저하 및 트래픽 과다 유발 가능성이 있습니다.
order by follow.id desc와Page<…>반환을 권장합니다.
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
📒 Files selected for processing (19)
src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java(1 hunks)src/main/java/com/example/FixLog/repository/MemberRepository.java(1 hunks)src/main/java/com/example/FixLog/repository/follow/FollowRepository.java(1 hunks)src/main/java/com/example/FixLog/service/follow/FollowService.java(1 hunks)src/main/java/com/example/fixlog/FixLogApplication.java(1 hunks)src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java(1 hunks)src/main/java/com/example/fixlog/domain/bookmark/BookmarkTag.java(1 hunks)src/main/java/com/example/fixlog/domain/bookmark/BookmarkTagMap.java(1 hunks)src/main/java/com/example/fixlog/domain/follow/Follow.java(2 hunks)src/main/java/com/example/fixlog/domain/fork/Fork.java(1 hunks)src/main/java/com/example/fixlog/domain/like/PostLike.java(1 hunks)src/main/java/com/example/fixlog/domain/member/Member.java(1 hunks)src/main/java/com/example/fixlog/domain/member/SocialType.java(1 hunks)src/main/java/com/example/fixlog/domain/post/Post.java(1 hunks)src/main/java/com/example/fixlog/domain/post/PostImage.java(1 hunks)src/main/java/com/example/fixlog/domain/post/PostTag.java(1 hunks)src/main/java/com/example/fixlog/domain/tag/Tag.java(1 hunks)src/main/java/com/example/fixlog/domain/tag/TagCategory.java(1 hunks)src/test/java/com/example/FixLog/FixLogApplicationTests.java(1 hunks)
✅ Files skipped from review due to trivial changes (13)
- src/main/java/com/example/fixlog/domain/post/PostImage.java
- src/main/java/com/example/fixlog/FixLogApplication.java
- src/main/java/com/example/fixlog/domain/tag/Tag.java
- src/main/java/com/example/fixlog/domain/bookmark/BookmarkTagMap.java
- src/test/java/com/example/FixLog/FixLogApplicationTests.java
- src/main/java/com/example/fixlog/domain/like/PostLike.java
- src/main/java/com/example/fixlog/domain/post/Post.java
- src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java
- src/main/java/com/example/fixlog/domain/member/SocialType.java
- src/main/java/com/example/fixlog/domain/post/PostTag.java
- src/main/java/com/example/fixlog/domain/bookmark/BookmarkTag.java
- src/main/java/com/example/fixlog/domain/fork/Fork.java
- src/main/java/com/example/fixlog/domain/tag/TagCategory.java
🚧 Files skipped from review as they are similar to previous changes (5)
- src/main/java/com/example/fixlog/domain/member/Member.java
- src/main/java/com/example/fixlog/domain/follow/Follow.java
- src/main/java/com/example/FixLog/mock/MemberTestDataInitializer.java
- src/main/java/com/example/FixLog/repository/follow/FollowRepository.java
- src/main/java/com/example/FixLog/repository/MemberRepository.java
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (11)
src/main/java/com/example/fixLog/mock/MemberTestDataInitializer.java (1)
1-27: 코드는 기본 기능을 충실히 수행하지만 몇 가지 개선 사항이 있습니다.테스트 데이터 초기화 로직이 잘 구현되어 있으나, 다음과 같은 개선 사항을 고려해보세요:
- System.out.println 대신 로깅 프레임워크(SLF4J) 사용
- 개발/테스트 환경에서만 활성화되도록 @Profile 어노테이션 추가
- 다양한 SocialType을 가진 테스트 데이터 제공
package com.example.fixLog.mock; import com.example.fixLog.repository.MemberRepository; import lombok.RequiredArgsConstructor; import org.springframework.boot.CommandLineRunner; +import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import com.example.fixLog.domain.member.Member; import com.example.fixLog.domain.member.SocialType; +import lombok.extern.slf4j.Slf4j; import java.util.List; +@Slf4j +@Profile({"dev", "test"}) @Component @RequiredArgsConstructor public class MemberTestDataInitializer implements CommandLineRunner { private final MemberRepository memberRepository; @Override public void run(String... args) { if (memberRepository.count() == 0) { Member member1 = Member.of("[email protected]", "1234", "가나다", SocialType.EMAIL); Member member2 = Member.of("[email protected]", "1234", "라마바", SocialType.EMAIL); + Member member3 = Member.of("[email protected]", "1234", "사아자", SocialType.KAKAO); - memberRepository.saveAll(List.of(member1, member2)); - System.out.println("테스트용 멤버 2명 삽입 완료"); + memberRepository.saveAll(List.of(member1, member2, member3)); + log.info("테스트용 멤버 3명 삽입 완료"); } } }src/main/java/com/example/fixLog/repository/MemberRepository.java (1)
1-10: 기본 구현이 잘 되어 있습니다.Spring Data JPA 규칙에 맞게 잘 구현되어 있습니다. 추가 개선 사항으로 이메일 대소문자 무시 옵션과 중복 이메일 검증 메서드를 고려해볼 수 있습니다.
package com.example.fixLog.repository; import org.springframework.data.jpa.repository.JpaRepository; import com.example.fixLog.domain.member.Member; import java.util.Optional; public interface MemberRepository extends JpaRepository<Member, Long> { Optional<Member> findByEmail(String email); // 이메일로 회원 조회 + Optional<Member> findByEmailIgnoreCase(String email); // 대소문자 구분없이 이메일로 회원 조회 + boolean existsByEmail(String email); // 이메일 중복 확인 }src/main/java/com/example/fixLog/repository/follow/FollowRepository.java (1)
1-15: Repository 인터페이스가 잘 설계되어 있습니다.팔로우 기능에 필요한 핵심 메서드들이 잘 정의되어 있습니다. 다만 데이터가 많아질 경우를 대비한 페이징 처리 메서드 추가를 고려해보세요.
package com.example.fixLog.repository.follow; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import com.example.fixLog.domain.follow.Follow; import com.example.fixLog.domain.member.Member; import java.util.List; import java.util.Optional; public interface FollowRepository extends JpaRepository<Follow, Long> { boolean existsByFollowerAndFollowing(Member follower, Member following); // 중복 방지 - 같은 사람 다시 팔로우 Optional<Follow> findByFollowerAndFollowing(Member follower, Member following); // 팔로우 관계 조회 List<Follow> findByFollowing(Member following); // 나를 팔로우하는 사용자 조회 (팔로워들) List<Follow> findByFollower(Member follower); // 내가 팔로우하는 사용자 조회 (팔로잉들) + Page<Follow> findByFollowing(Member following, Pageable pageable); // 페이징된 팔로워 목록 + Page<Follow> findByFollower(Member follower, Pageable pageable); // 페이징된 팔로잉 목록 }src/main/java/com/example/fixLog/service/follow/FollowService.java (2)
67-82: 팔로워 목록 조회 로직이 잘 구현되어 있습니다.팔로워 목록 조회 로직이 잘 구현되어 있으나, 대용량 데이터 처리를 위한 페이징 적용을 고려해보세요.
// 나를 팔로우하는 목록 조회 (팔로워들) @Transactional(readOnly = true) public List<FollowerListResponseDto> getMyFollowers(String requesterEmail) { Member me = memberRepository.findByEmail(requesterEmail) .orElseThrow(() -> new IllegalArgumentException("요청자 정보를 찾을 수 없음")); List<Follow> follows = followRepository.findByFollowing(me); return follows.stream() .map(follow -> new FollowerListResponseDto( follow.getId(), follow.getFollower().getId(), follow.getFollower().getNickname() )) .toList(); } + + // 페이징을 적용한 팔로워 목록 조회 + @Transactional(readOnly = true) + public Page<FollowerListResponseDto> getMyFollowersWithPaging(String requesterEmail, Pageable pageable) { + Member me = memberRepository.findByEmail(requesterEmail) + .orElseThrow(() -> new IllegalArgumentException("요청자 정보를 찾을 수 없음")); + + Page<Follow> follows = followRepository.findByFollowing(me, pageable); + + return follows.map(follow -> new FollowerListResponseDto( + follow.getId(), + follow.getFollower().getId(), + follow.getFollower().getNickname() + )); + }
84-99: 팔로잉 목록 조회 로직이 잘 구현되어 있습니다.팔로잉 목록 조회 로직이 잘 구현되어 있으나, 팔로워 목록과 마찬가지로 페이징 적용을 고려해보세요.
페이징 처리와 중복 코드 추출을 통한 코드 개선을 권장합니다. 앞서 제안된 리팩토링과 유사한 방식으로 팔로잉 목록에도 페이징 기능을 추가하세요.
src/main/java/com/example/fixLog/controller/follow/FollowController.java (6)
22-30: 팔로우 API 구현이 적절합니다만, 201 상태 코드 사용을 고려해 보세요.팔로우 기능은 새로운 리소스(팔로우 관계)를 생성하는 작업이므로, HTTP 상태 코드 200 보다는 201(Created)이 더 적합할 수 있습니다.
- return ResponseEntity.ok(Response.success("팔로우 완료", result)); + return ResponseEntity.status(201).body(Response.success("팔로우 완료", result));
32-40: 언팔로우 API의 HTTP 메서드를 고려해 보세요.REST 원칙에 따르면 리소스 삭제는 DELETE 메서드를 사용하는 것이 더 적합합니다. 언팔로우는 팔로우 관계를 삭제하는 작업이므로 POST보다 DELETE가 의미적으로 더 맞을 수 있습니다.
- @PostMapping("/unfollow") + @DeleteMapping("/unfollow")
36-38: 불필요한 빈 줄이 있습니다.37번 줄의 빈 줄은 필요하지 않으므로 제거하는 것이 좋겠습니다.
public ResponseEntity<Response<Void>> unfollow( @RequestBody UnfollowRequestDto requestDto, @RequestParam String requesterEmail) { - followService.unfollow(requesterEmail, requestDto.getTargetMemberId()); return ResponseEntity.ok(Response.success("언팔로우 완료", null)); }
42-49: 팔로워 목록 조회 API에 불필요한 빈 줄이 있습니다.46번 줄의 빈 줄은 필요하지 않으므로 제거하는 것이 좋겠습니다.
@GetMapping("/followers") public ResponseEntity<Response<List<FollowerListResponseDto>>> getMyFollowers( @RequestParam String requesterEmail) { - List<FollowerListResponseDto> followers = followService.getMyFollowers(requesterEmail); return ResponseEntity.ok(Response.success("나를 팔로우하는 목록 조회 성공", followers)); }
51-58: 팔로잉 목록 조회 API에 불필요한 빈 줄이 있습니다.55번 줄의 빈 줄은 필요하지 않으므로 제거하는 것이 좋겠습니다.
@GetMapping("/followings") public ResponseEntity<Response<List<FollowingListResponseDto>>> getMyFollowings( @RequestParam String requesterEmail) { - List<FollowingListResponseDto> followings = followService.getMyFollowings(requesterEmail); return ResponseEntity.ok(Response.success("내가 팔로우 중인 목록 조회 성공", followings)); }
1-59: API 문서화를 위한 주석이나 어노테이션이 부족합니다.코드 가독성과 API 문서화를 위해 Swagger/OpenAPI 어노테이션(예: @operation, @apiresponse 등)을 추가하거나, 각 메서드에 javadoc 형식의 주석을 추가하는 것이 좋습니다. 이는 다른 개발자들이 API를 이해하고 사용하는 데 도움이 됩니다.
/** * 사용자를 팔로우합니다. * * @param followRequestDto 팔로우할 대상 사용자 ID를 포함한 요청 DTO * @param requesterEmail 요청자 이메일 (임시, JWT 구현 후 제거 예정) * @return 팔로우 성공 응답 */ @PostMapping public ResponseEntity<Response<FollowResponseDto>> follow(...)
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting
📒 Files selected for processing (33)
src/main/java/com/example/FixLog/controller/MemberController.java(0 hunks)src/main/java/com/example/FixLog/service/MemberService.java(0 hunks)src/main/java/com/example/fixLog/controller/MemberController.java(1 hunks)src/main/java/com/example/fixLog/controller/follow/FollowController.java(1 hunks)src/main/java/com/example/fixLog/dto/Response.java(1 hunks)src/main/java/com/example/fixLog/dto/follow/request/FollowRequestDto.java(1 hunks)src/main/java/com/example/fixLog/dto/follow/request/UnfollowRequestDto.java(1 hunks)src/main/java/com/example/fixLog/dto/follow/response/FollowResponseDto.java(1 hunks)src/main/java/com/example/fixLog/dto/follow/response/FollowerListResponseDto.java(1 hunks)src/main/java/com/example/fixLog/dto/follow/response/FollowingListResponseDto.java(1 hunks)src/main/java/com/example/fixLog/exception/CustomException.java(1 hunks)src/main/java/com/example/fixLog/exception/ErrorCode.java(1 hunks)src/main/java/com/example/fixLog/exception/GlobalExceptionHandler.java(1 hunks)src/main/java/com/example/fixLog/mock/MemberTestDataInitializer.java(1 hunks)src/main/java/com/example/fixLog/repository/MemberRepository.java(1 hunks)src/main/java/com/example/fixLog/repository/follow/FollowRepository.java(1 hunks)src/main/java/com/example/fixLog/service/MemberService.java(1 hunks)src/main/java/com/example/fixLog/service/follow/FollowService.java(1 hunks)src/main/java/com/example/fixlog/FixLogApplication.java(1 hunks)src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java(1 hunks)src/main/java/com/example/fixlog/domain/bookmark/BookmarkTag.java(1 hunks)src/main/java/com/example/fixlog/domain/bookmark/BookmarkTagMap.java(1 hunks)src/main/java/com/example/fixlog/domain/follow/Follow.java(2 hunks)src/main/java/com/example/fixlog/domain/fork/Fork.java(1 hunks)src/main/java/com/example/fixlog/domain/like/PostLike.java(1 hunks)src/main/java/com/example/fixlog/domain/member/Member.java(1 hunks)src/main/java/com/example/fixlog/domain/member/SocialType.java(1 hunks)src/main/java/com/example/fixlog/domain/post/Post.java(1 hunks)src/main/java/com/example/fixlog/domain/post/PostImage.java(1 hunks)src/main/java/com/example/fixlog/domain/post/PostTag.java(1 hunks)src/main/java/com/example/fixlog/domain/tag/Tag.java(1 hunks)src/main/java/com/example/fixlog/domain/tag/TagCategory.java(1 hunks)src/test/java/com/example/fixLog/FixLogApplicationTests.java(1 hunks)
💤 Files with no reviewable changes (2)
- src/main/java/com/example/FixLog/service/MemberService.java
- src/main/java/com/example/FixLog/controller/MemberController.java
✅ Files skipped from review due to trivial changes (13)
- src/test/java/com/example/fixLog/FixLogApplicationTests.java
- src/main/java/com/example/fixLog/exception/ErrorCode.java
- src/main/java/com/example/fixlog/domain/tag/Tag.java
- src/main/java/com/example/fixLog/exception/CustomException.java
- src/main/java/com/example/fixLog/dto/Response.java
- src/main/java/com/example/fixLog/controller/MemberController.java
- src/main/java/com/example/fixLog/service/MemberService.java
- src/main/java/com/example/fixLog/exception/GlobalExceptionHandler.java
- src/main/java/com/example/fixLog/dto/follow/response/FollowingListResponseDto.java
- src/main/java/com/example/fixLog/dto/follow/request/UnfollowRequestDto.java
- src/main/java/com/example/fixLog/dto/follow/response/FollowerListResponseDto.java
- src/main/java/com/example/fixLog/dto/follow/request/FollowRequestDto.java
- src/main/java/com/example/fixLog/dto/follow/response/FollowResponseDto.java
🚧 Files skipped from review as they are similar to previous changes (13)
- src/main/java/com/example/fixlog/domain/member/Member.java
- src/main/java/com/example/fixlog/domain/post/PostTag.java
- src/main/java/com/example/fixlog/domain/member/SocialType.java
- src/main/java/com/example/fixlog/FixLogApplication.java
- src/main/java/com/example/fixlog/domain/post/Post.java
- src/main/java/com/example/fixlog/domain/post/PostImage.java
- src/main/java/com/example/fixlog/domain/bookmark/BookmarkTagMap.java
- src/main/java/com/example/fixlog/domain/like/PostLike.java
- src/main/java/com/example/fixlog/domain/fork/Fork.java
- src/main/java/com/example/fixlog/domain/follow/Follow.java
- src/main/java/com/example/fixlog/domain/bookmark/Bookmark.java
- src/main/java/com/example/fixlog/domain/tag/TagCategory.java
- src/main/java/com/example/fixlog/domain/bookmark/BookmarkTag.java
🔇 Additional comments (3)
src/main/java/com/example/fixLog/service/follow/FollowService.java (1)
24-45: 팔로우 로직이 잘 구현되었습니다.팔로우 로직에 필요한 검증이 잘 구현되어 있습니다. 자기 자신 팔로우 방지와 중복 팔로우 방지 등 적절한 예외 처리가 되어 있습니다.
src/main/java/com/example/fixLog/controller/follow/FollowController.java (2)
1-19: 컨트롤러 선언과 구조가 잘 정의되었습니다.컨트롤러 클래스의 전반적인 구조와 의존성 주입 방식이 Spring 권장 사항을 잘 따르고 있습니다.
@RequiredArgsConstructor를 통한 생성자 주입 패턴이 적절히 사용되었습니다.
26-26: 인증 메커니즘 관련 주석이 명확합니다.JWT 구현 전까지 임시로 이메일 파라미터를 사용한다는 주석은 명확하게 작성되었습니다. 보안을 위해 JWT 구현 후에는 반드시 이 부분을 변경해야 합니다.
…java Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
src/main/java/com/example/fixlog/service/follow/FollowService.java
Outdated
Show resolved
Hide resolved
src/main/java/com/example/fixlog/controller/follow/FollowController.java
Show resolved
Hide resolved
src/main/java/com/example/fixlog/controller/follow/FollowController.java
Show resolved
Hide resolved
sungchaewon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
영서님께서 남기신 부분 작동만 잘 되면 문제 없을 것 같습니다! 고생하셨습니다!!
|
이슈 번호
작업 내용
mock>MemberTestDataInitializer.java)기타
requesterEmail)을Param으로 임시 사용 -> 로그인 구현 후 수정Summary by CodeRabbit
신규 기능
버그 수정
테스트