Projects/[Spring] Code Refactoring Project

일정 관리 프로젝트 개발일지(2025.12~2026.1)

montmer27 2026. 1. 2. 13:50

1️⃣ 경로 패턴 충돌 문제

문제: String 형태의 owner로 일정 조회 시 GET 요청 실행 안 됨
원인:

  • /planners/{plannerId}와 /planners/{plannerOwner} 충돌
  • 해결: 쿼리 파라미터 사용 (/planners?owner=홍길동)
//READ-GET (전체조회 또는 작성자명으로 조회)
    @GetMapping("/planners")
    public ResponseEntity<List<GetPlannerResponse>> getPlanners(
            @RequestParam(required=false) String owner
    ) {
        //작성자명으로 조회
        if(owner != null) {
            return ResponseEntity.status(HttpStatus.OK).body(plannerService.findByOwner(owner));
        }
        //전체조회(RequestParameter 없는 경우)
        return ResponseEntity.status(HttpStatus.OK).body(plannerService.findAll());
    }

2️⃣ 빈 리스트 반환 문제

문제: 쿼리 파라미터 owner로 조회해도 빈 리스트만 나옴
원인:

  • filter(p -> p.equals(owner)) 잘못됨
  • 수정: filter(p -> p.getOwner().equals(owner))
@Transactional
    public List<GetPlannerResponse> findByOwner(String owner){
        List<Planner> planners = plannerRepository.findAll();
        //READ 작성자명으로 조회
        //방법2 -> Stream()으로 가져오기
        return planners.stream()
                .filter(p -> owner.equals(p.getOwner())) //getOwner() 결과가 owner와 같은 planer만 필터링
                .map(GetPlannerResponse::new).toList();
    }

3️⃣ Spring Data JPA 메서드

문제: Repository가 interface인데 메서드를 어디에 정의?
원인:

  • Spring Data JPA는 인터페이스에 메서드 시그니처만 선언하면 자동으로 구현
    • 작동 원리 :Spring Data JPA가 메서드 이름을 분석해서 자동으로 쿼리를 생성함.
      findBy + Owner → SELECT * FROM planner WHERE owner = ?
  • 예: List<Planner> findByOwner(String owner);
public interface CommentRepository extends JpaRepository<Comment, Long> {
    List<Comment> findByPlannerId(Long plannerId);
    long countByPlannerId(Long plannerId); //이렇게만 해도 JPA에서 자동으로 
}

4️⃣ JPA 연관관계 학습

문제: @ManyToOne, @OneToMany, 연관관계 주인 등 개념 이해 부족
원인:

  • @ManyToOne: Comment → Planner (외래키 있는 쪽)
    Comment 입장에서:
    • "나는(Comment) 하나의 Planner에 속해있다"
    • "여러 개의 Comment가 하나의 Planner를 참조한다"
    • = Many(Comment) To One(Planner)
  • @OneToMany: Planner → Comment (mappedBy)
    Planner 입장에서:
    • "나는(Planner) 여러 개의 Comment를 가질 수 있다"
    • = One(Planner) To Many(Comment)
  • LAZY vs EAGER Fetch 전략
// EAGER (즉시 로딩) - 기본값이지만 비추천
@ManyToOne(fetch = FetchType.EAGER)  
// Comment 조회 시 Planner도 무조건 함께 조회 (JOIN 쿼리 발생)

// LAZY (지연 로딩) - 권장! ⭐
@ManyToOne(fetch = FetchType.LAZY)   
// Comment 조회 시 Planner는 안 가져옴
// planner.getTitle() 같이 실제 사용할 때만 조회
  • @JoinColumn 역할
    • DB에서 외래키 컬럼 이름을 planner_id로 만들겠다는 의미
    • 생략하면 자동으로 planner_id 만들어지긴 하지만, 명시적으로 쓰는 게 좋음
@ManyToOne
@JoinColumn(name = "planner_id")  // ⭐ DB 컬럼명 지정
private Planner planner;

5️⃣ Database vs Table 개념

문제: comments database를 만들어야 하나?
원인:

  • Database는 하나 (planner)
  • Table만 추가됨 (comment)
  • JPA가 자동으로 테이블 생성

6️⃣ Postman 에러

문제: 415 Unsupported Media Type
원인:

  • Body 탭에서 Text → JSON으로 변경
  • Content-Type 헤더 자동 설정됨

7️⃣ 양방향 연관관계

문제: Planner 조회 시 Comment도 함께 가져오기
원인:

  • Planner에 @OneToMany 추가
  • GetPlannerResponse에 List<CommentResponse> 추가
  • Fetch Join으로 N+1 문제 방지 가능
### Planner.java
...
@OneToMany(mappedBy = "planner", fetch = FetchType.LAZY)
    private List<Comment> comments = new ArrayList<>();
...

8️⃣  JSON 필드 순서

문제: JSON 출력 순서 변경
원인:

  • @JsonPropertyOrder 어노테이션 사용
  • 예: @JsonPropertyOrder({"id", "title", "owner", ...})
### GetCommentResponse.java
...
@Getter
@JsonPropertyOrder({"id", "owner", "contents", "createdAt", "modifiedAt"})
public class GetCommentResponse {
    private final Long id;
    private final String contents;
    private final String owner;
    private final LocalDateTime createdAt;
    private final LocalDateTime modifiedAt;
...
### GetPlannerResponse.java
...
@JsonPropertyOrder({"id", "title", "owner", "contents", "createdAt", "modifiedAt", "comments"})
public class GetPlannerResponse {
    private final Long id;
    private final String title;
    private final String contents;
    private final String owner;
    private final LocalDateTime createdAt;
    private final LocalDateTime modifiedAt;
    private final List<GetCommentResponse> comments;
...

9️⃣  DTO 구조 개선

문제: Planner와 Comment DTO 분리가 나을까?
원인:

  • 분리가 맞음!
  • dto/planner/, dto/comment/ 구조 추천
  • 확장성과 관리성 향상