이번엔 level 10만 구현하면 되지만 양이 엄청 많다..
Member
<MemberRepository>
package backend.likelion.todos.member;
import java.util.Optional;
import org.springframework.stereotype.Repository;
@Repository
public interface MemberRepository <Member, Long>{
    // TODO [10단계] JpaRepository를 상속받습니다.
    // TODO [10단계] 아래는 기존 코드입니다. 컴파일 오류가 발생하고 있는데, 이를 해결하세요.
    Optional<Member> findByUsername(String username);
}
JpaRepository를 상속받는다. 이 때 제네릭타입을 명시해주어야한다.
또한 인터페이스에는 메서드의 구현을 작성하면 안되니까 선언만 해주었다.
Optional을 하면 null값을 받을 수 있다.
<Member>
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
// TODO [10 단계] : 롬봉을 통해 기본 생성자를 PROTECTED 접근 제한자로 생성하세요.
// TODO [10 단계] : Member 객체를 Entity 로 정의하세요.@NoArgsConstructor은 롬복을 이용하여 기본 생성자를 만드는 것이다. 이는 protected로 선언하였다.
또한 @Entity로 member을 엔티티로 선언하였다.
// TODO [10 단계] : id를 PK, Auto Increment로 설정하세요.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;Id를 @Id 어노테이션을 통해 구현하였다. 또한 @GeneratedValue 어노테이션의 strategy 속성을 GenerationType.IDENTITY로 설정하면, 데이터베이스가 자동으로 id 값을 증가시킨다.
// TODO [10 단계] : 아이디는 unique 제약 조건이 필요합니다.
@Column(unique = true)
private String username;
private String password;
private String nickname;
private String profileImageUrl;username이 아이디이니까 여기다가 @Column을 사용해서 unique제약 조건을 넣었다.
Goal
<GoalRepository>
package backend.likelion.todos.goal;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface GoalRepository extends JpaRepository<String,Long> {
    // TODO [10단계] JpaRepository를 상속받습니다.
    // TODO [10단계] 아래는 기존 코드입니다. 컴파일 오류가 발생하고 있는데, 이를 해결하세요.
    List<Goal> findAllByMemberId(Long memberId) ;
}
위와 마찬가지로 제네릭타입을 명시하고, 메서드 선언한 부분을 제거하였다.
<Goal>
@Getter
// TODO [10 단계] : 롬봉을 통해 기본 생성자를 PROTECTED 접근 제한자로 생성하세요.
@NoArgsConstructor(access =  AccessLevel.PROTECTED)
// TODO [10 단계] : Goal 객체를 Entity 로 정의하세요.
@Entity
public class Goal {
    // TODO [10 단계] : id를 PK, Auto Increment로 설정하세요.
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String color;위에 member과 같이 구현하였다.
// TODO [10 단계] : goal 과 member와의 관계를 설정합니다. (join 하는 컬럼명은 member_id로 설정합니다.), 지연 로딩을 사용합니다.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
goal과 member과의 관계를 설정한다.
지연로딩을 하여 필요한 시기에 데이터를 가져오도록 하였다. 이는 FetchType.LAZY를 사용하여 지연로딩을 구현하였고, 한 member에 여러개의 goal이 들어갈 수 있기 때문에 ManyToOne 어노테이션을 썼다.
또한 JoinColumn으로 join하는 컬럼명을 설정하였다.
Todo
<TodoRepository>
package backend.likelion.todos.todo;
import java.util.List;
import org.antlr.v4.runtime.atn.SemanticContext.AND;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
@Repository
public interface TodoRepository extends JpaRepository<Todo,Long>{
    // TODO [10단계] JpaRepository를 상속받습니다.
    /**
     * TODO [10단계] 아래는 기존 findAllByMemberIdAndDate 코드와 동일한 역할을 합니다.
     * 해당 기능을 완성하세요.
     *
     * 메서드의 이름만으로는 해결할 수 없습니다.
     * 직접 JPQL을 작성해야 합니다.
     * 어떤 어노테이션을 사용해야 할까요?
     *
     * JPQL 수도코드
     * - TODO 와 Goal을 조인합니다.
     * - 조건 : goal의 memberId 가 주어진 인자의 memberId와 동일
     *      AND Todo의 date의 YEAR 부분이 주어진 인자의 year와 동일 (hint: YEAR(date) 시 date의 년도 부분이 나온다.)
     *      AND Todo의 date의 MONTH 부분이 주어진 인자의 month와 동일 (hint: MONTH(date) 시 date의 년도 부분이 나온다.)
     * - 정렬 Todo의 date의 DAY 부분을 오름차순으로. (hint: DAY(date) 시 date의 년도 부분이 나온다.)
     */
    @Query("""
    SELECT t
    FROM Todo t
    JOIN t.goal g
    ON t.goal = g
    WHERE g.member.id = :memberId
    AND YEAR(t.date) = :year
    AND MONTH(t.date) = :month
    ORDER BY DAY(t.date) ASC
    """)
    List<Todo> findAllByMemberIdAndDateOrderByDayAsc(Long memberId, int year, int month);
}
이번엔 단순히 상속받고, 메서드 삭제만 하면 끝나는 것이 아니라 join을 위한 쿼리문도 작성해야한다.
todo와 goal을 조인하고, @Query 어노테이션을 사용한다.
<Todo>
package backend.likelion.todos.todo;
import backend.likelion.todos.common.ForbiddenException;
import backend.likelion.todos.goal.Goal;
import backend.likelion.todos.member.Member;
import jakarta.persistence.*;
import java.time.LocalDate;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
// TODO [10 단계] : 롬봉을 통해 기본 생성자를 PROTECTED 접근 제한자로 생성하세요.
// TODO [10 단계] : Todo 객체를 Entity 로 정의하세요.
@Entity
public class Todo {
    // TODO [10 단계] : id를 PK, Auto Increment로 설정하세요.
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String content;
    private LocalDate date;
    // TODO [10 단계] : todo 와 goal 과의 관계를 설정합니다. (join 하는 컬럼명은 goal_id로 설정합니다.), 지연 로딩을 사용합니다.
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "goal_id")
    private Goal goal;
    private boolean isCompleted;
    public Todo(String content, LocalDate date, Goal goal) {
        this.content = content;
        this.date = date;
        this.goal = goal;
        this.isCompleted = false;
    }
    public void validateMember(Member member) {
        if (!this.goal.getMember().equals(member)) {
            throw new ForbiddenException("해당 투두에 대한 권한이 없습니다.");
        }
    }
    public void update(String content, LocalDate date) {
        this.content = content;
        this.date = date;
    }
    public void check() {
        this.isCompleted = true;
    }
    public void uncheck() {
        this.isCompleted = false;
    }
}
위에 클래스들과 동일한 방식으로 구현하였다. 이번엔 join할 때 @ManyToOne을 사용하였다.

완료!
'Back-end > 멋쟁이사자처럼' 카테고리의 다른 글
| [멋쟁이 사자처럼] level7~9 구현 (0) | 2024.04.30 | 
|---|---|
| [멋쟁이사자처럼] level6 구현 (0) | 2024.04.02 | 
| [멋쟁이사자처럼] 질문 정리 과제 (1) | 2024.03.27 | 
| [멋쟁이사자처럼] 키워드 정리 과제 (0) | 2024.03.27 | 
| [멋쟁이사자처럼] level5 구현 (0) | 2024.03.19 | 
 
										
									 
										
									 
										
									