[Spring Boot/JPA] #1 게시판 만들기 시작

뀨뀨찬찬·2021년 2월 5일
2

spring

목록 보기
1/4
post-custom-banner

개인적으로 시작한 개발이며, 틀린 점이나 부족한 부분이 많을 수 있으니 보완할 사항이나 질문은 댓글로 남겨주세요!

개발 환경

Database : mysql community Server 8.0.23
language : Java 11
Framework : Spring
IDE : IntelliJ ultimate ver.
OS : MS Win10 64bit

분업

도메인을 회원(Member), 게시글(Post), 카테고리(Category), 댓글(Comment)로 나누었고 필자는 그 중 게시글(Post)과 카테고리(Category)를 맡았다.

이 포스트에서는 먼저 게시글과 카테고리에 한해서 포스팅하도록 하고, 후에 분업을 merge한 이후 다른 파트에 대해서도 다루겠다.

도메인 개발

class Post

@Entity
@Getter @Setter
@Table(name = "post")
public class Post {

    @Id @GeneratedValue
    @Column(name = "post_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "category_id") 
    private Category category;

    @OneToMany(mappedBy = "post", cascade = CascadeType.ALL)
    private List<Comment> comments = new ArrayList<>();

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    @Lob
    private String contents;

    @ColumnDefault("0")
    private int likes;
    @ColumnDefault("0")
    private int dislikes;
    @ColumnDefault("0")
    private int scrap;
    @ColumnDefault("0")
    private int visit;

    private LocalDateTime createDate;
    private LocalDateTime updateDate;
  • Member와 Category와는 ManyToOne
  • Comment와는 OneToManty의 연관관계를 매핑.
  • 또 OneToMany의 경우 게시글이 삭제될 경우 관련된 댓글이 함께 삭제될 수 있도록 cascade 옵션을 ALL로 설정.

필수로 들어가야 하는 필드에 nullable = false 옵션을 주어 해당 필드에 null이 들어오는 경우 객체 생성이 되지 않도록 했다.

이후 서비스나 리포지토리에서 가독성을 증가시키기 위해 클래스 안에 여러 코드가 필요한 생성 메서드를 추가했다.

    // == 생성 메서드 == //

    public void createPost(Member member, Category category, String title, String contents) {
        this.member = member;
        this.category = category;
        this.title = title;
        this.contents = contents;
        this.createDate = LocalDateTime.now();
        this.updateDate = LocalDateTime.now();
        this.member.getPosts().add(this);
        this.category.getPosts().add(this);
    }

class Category

@Entity
@Getter @Setter
public class Category {

    @Id @GeneratedValue
    @Column(name = "category_id")
    private Long id;

    private String name;

    @OneToMany(mappedBy = "category")
    private List<Post> posts = new ArrayList<>();

}

Post 클래스에서 Category를 ManyToOne으로 매핑하였기 때문에, Category 클래스에서는 OneToMany로 매핑하고, Post 클래스의 Category category 필드에 의해 매핑된다는 옵션을 명시한다.

리포지토리 개발

PostRepository

@Repository
public interface PostRepository extends JpaRepository<Post, Long>{

    public List<Post> findByMember(Member member);
    public List<Post> findByCategory(Category category);

}

스프링부트에서 기본적인 CRUD가 가능하도록 JpaRepository를 제공하기 때문에, 이를 상속하였다.

interface JpaRepository<T,ID>

Spring Data JPA에서 제공하는 JpaRepository를 상속하기만 해도 기본적인 CRUD 기능을 사용할 수 있다.

  • 상속받을 때엔, T에 Entity 클래스와 ID에 해당 클래스의 PK 타입을 넣는다.
  • JpaRepository가 기본적으로 제공하는 메서드 이외에도 custom 메서드를 추가할 수 있는데, 이를 위해선 규칙에 맞는 메서드를 생성해야 한다 .
  • @Repository 애노테이션을 추가하지 않아도 된다.

규칙에 대해서는 아래의 Spring Data JPA 공식 Document에서 확인할 수 있다.

Spring Data JPA Method Name 규칙

PostRepository에서는 findByMember와 findByCategory 메서드를 추가했다.

CategoryRepository

@Repository
public interface CategoryRepository extends JpaRepository<Category, Long> {

    public Category findByName(String categoryName);

}

CategoryRepository도 JpaRepository를 상속하고, findByName 메서드를 추가했다.

테이블 확인

두 개의 테이블이 잘 생성된 것을 확인할 수 있다. (JetBrains의 DataGrip 사용)

profile
공부하고 있어요!
post-custom-banner

1개의 댓글

comment-user-thumbnail
2022년 6월 28일

안녕하세요 포스팅 잘 봤습니다! 혹시 전체 코드를 볼 수 있는 주소가 있을까요?

답글 달기