댓글 엔티티와 리포지토리 + 한글깨짐 해결법

OneTwoThree·2022년 10월 21일
0

유튜브

인텔리제이 한글깨짐 해결법
한글깨지는거 해결함

Article에 달릴 댓글을 위해 엔티티, 리포지토리를 만들어보자

Article과 Comment는 1대 다 관계

댓글은 PK와 FK를 가진다
PK : 나의 id
FK : 대상을 가리키는 id

댓글에서 게시글을 찾아갈 수 있는 구조로 엔티티를 만들어야 한다.

리포지토리는 CrudRepository를 확장한 리포지토리를 확장한 JpaRepository를 사용한다

Comment 엔티티 만들기

package com.example.firstproject.entity;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.*;

@Entity
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
public class Comment {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne // 댓글 엔티티 여러개가 하나의 Article에 연관됨
    @JoinColumn(name = "article_id") // article_id 컬럼에 연결된 Article의 대표값을 저장(필드명 지정)
    private Article article;

    @Column
    private String nickname;

    @Column
    private String  body;




}

Comment 엔티티의 코드다.
article 필드의 @ManyToOne은 Article 엔티티 하나에 Comment 엔티티 여러개가 연관된다는 의미다.
@JoinColumn은 Comment 엔티티의 article_id 필드에 Article의 대표값을 저장한다는 뜻이다.

확인해보면 Comment 테이블이 DB에 생긴 것을 확인할 수 있다.

insert into article(id, title, content) values(1, 'aaaa', '1111');
insert into article(id, title, content) values(2, 'bbbb', '2222');
insert into article(id, title, content) values(3, 'cccc', '3333');

-- article 더미 데이터
insert into article(id,title,content) values(4, '당신의 인생 영화는?', '댓글 ㄱ');
insert into article(id,title,content) values(5, '당신의 소울 푸드는?', '댓글 ㄱ');
insert into article(id,title,content) values(6, '당신의 취미는?', '댓글 ㄱ');

-- comment 더미 데이터
insert into comment(id,article_id,nickname,body) values(1,4,'Park','굳 윌 헌팅');
insert into comment(id,article_id,nickname,body) values(2,4,'Kim','아이 엠 샘');
insert into comment(id,article_id,nickname,body) values(3,4,'Choi','쇼생크 탈출');

insert into comment(id,article_id,nickname,body) values(4,5,'Park','치킨');
insert into comment(id,article_id,nickname,body) values(5,5,'Kim','샤브샤브');
insert into comment(id,article_id,nickname,body) values(6,5,'Choi','초밥');

insert into comment(id,article_id,nickname,body) values(7,6,'Park','조깅');
insert into comment(id,article_id,nickname,body) values(8,6,'Kim','유튜브');
insert into comment(id,article_id,nickname,body) values(9,6,'Choi','독서');

data.sql에 article과 comment의 더미데이터를 만들어준다.



내 id : PK
다른 테이블의 id : FK

Comment 리포지토리 만들기

package com.example.firstproject.repository;

import com.example.firstproject.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

import java.util.List;

public interface CommentRepository extends JpaRepository<Comment, Long> {
    // 특정 게시글의 모든 댓글 조회
    @Query(value = "SELECT * FROM comment WHERE article_id = :articleId",nativeQuery = true)
    List<Comment> findByArticleId(Long articleId);

    // 특정 닉네임의 모든 댓글 조회
    List<Comment> findByNickname(String nickname);

}

CommentRepository는 인터페이스로 만들어준다.
JpaRepository를 상속한다.

findByArticleId는 특정 게시글의 모든 댓글을 조회하는 메소드다
Comment의 List를 반환하고 @Query 어노테이션으로 쿼리문을 넣어줬다
쿼리문의 :articleId 부분이 매개변수 articleId와 매칭된다.

findByNickname 메소드느 특정 닉네임의 모든 댓글을 조회하는 메소드다.
이 메소드는 어노테이션 말고 xml 파일을 만들어서 쿼리를 연결해보자.

resources 에 META-INF > orm.xml을 만들어준다.

<?xml version="1.0" encoding="utf-8" ?>
<entity-mappings xmlns="https://jakarta.ee/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence/orm
                                     https://jakarta.ee/xml/ns/persistence/orm/orm_3_0.xsd"
                 version="3.0">
    <named-native-query
            name="Comment.findByNickname"
            result-class="com.example.firstproject.entity.Comment">
        <query>
            <![CDATA[
                SELECT
                    *
                FROM
                    comment
                WHERE
                    nickname = :nickname
            ]]>
        </query>
    </named-native-query>
</entity-mappings>

orm.xml의 내용은 위와 같이 작성해준다.
바깥의 entitiy-mappings는 구글링 해서 작성하면 됨
name-native-query 태그의 내용을 보면 된다.

name의 메소드가 query의 쿼리문을 실행하고 결과로 result-class 타입을 반환한다는 뜻이다.

쿼리가 단순한 경우엔 어노테이션, 쿼리가 복잡하거나 최적화가 필요한 경우엔 xml을 사용하면 좋다.


CommentRepository 테스트

테스트하기 위해서 CommentRepositoryTest 클래스를 만들어준다.

package com.example.firstproject.repository;

import com.example.firstproject.entity.Article;
import com.example.firstproject.entity.Comment;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

@DataJpaTest // 리포지토리 테스트니까 Jpa와 연동해서 테스트할 수 있다
class CommentRepositoryTest {

    @Autowired CommentRepository commentRepository;


    @Test
    @DisplayName("특정 게시글의 모든 댓글 조회")
    void findByArticleId() {
        {
            // 입력 데이터 준비
            Long articleId = 4L;

            //실제 수행
            List<Comment> comments = commentRepository.findByArticleId(articleId);

            //예상하기
            Article article = new Article(4L, "당신의 인생 영화는?","댓글 ㄱ");

            Comment a = new Comment(1L,article,"Park","굳 윌 헌팅");
            Comment b = new Comment(2L,article,"Kim","아이 엠 샘");
            Comment c = new Comment(3L,article,"Choi","쇼생크 탈출");
            List <Comment> expected = Arrays.asList(a,b,c);

            // 검증
            assertEquals(expected.toString(),comments.toString(),"4번 글의 모든 댓글을 출력");
        }
    }

    @Test
    void findByNickname() {
    }
}

findByArticleId의 테스트는 이렇게 작성했다.
CommentRepositoryTest의 어노테이션을 @DataJpaTest로 Jpa와 연동해 테스트 클래스를 만든다
클래스의 멤버로 commentRepository를 만들어줬다
그리고 전에 테스트 만들 때는 직접 메소드 이름에 내용을 넣어줬는데 그렇게 안하고 @DisplayName으로 작성할 내용을 넣어도 된다.
메소드 내용은 4번 게시글의 모든 댓글을 얻는 findByArticleId와 실제 데이터를 만들어서 비교한다.

참고 ) 계속 테스트에 실패해서 확인해보니 Comment 클래스에 @ToString 어노테이션을 안달았었다..

 void findByArticleId() {
        /* Case 1: 4번 게시글의 모든 댓글 조회 */
        {
            // 준비
            Long articleId = 4L;
            // 수행
            List<Comment> comments = commentRepository.findByArticleId(articleId);
            // 예상
            Article article = new Article(4L, "당신의 인생 영화는?", "댓글 ㄱ");
            Comment a = new Comment(1L, article, "Park", "굳 윌 헌팅");
            Comment b = new Comment(2L, article, "Kim", "아이 엠 샘");
            Comment c = new Comment(3L, article, "Choi", "쇼생크의 탈출");
            List<Comment> expected = Arrays.asList(a, b, c);
            // 검증
            assertEquals(expected.toString(), comments.toString(), "4번 글의 모든 댓글을 출력!");
        }

        /* Case 2: 1번 게시글의 모든 댓글 조회 */
        {
            // 준비
            Long articleId = 1L;
            // 수행
            List<Comment> comments = commentRepository.findByArticleId(articleId);
            // 예상
            Article article = new Article(1L, "가가가가", "1111");
            List<Comment> expected = Arrays.asList();
            // 검증
            assertEquals(expected.toString(), comments.toString(), "1번 글은 댓글이 없음");
        }


    }

추가해서 1번 게시물에 대해 테스트를 진행한다
1번 게시글은 댓글이 없어서 빈 List를 대상으로 비교햔다

 @Test
    @DisplayName("특정 닉네임의 모든 댓글 조회")
    void findByNickname() {
        // Case 1 : Park의 모든 댓글 조회
        {
            // 입력 데이터 준비
            String nickname = "Park";


            //실제 수행
            List<Comment> comments = commentRepository.findByNickname(nickname);

            //예상하기
            Comment a = new Comment(1L, new Article(4L, "당신의 인생 영화는?", "댓글 ㄱ"), nickname, "굳 윌 헌팅");
            Comment b = new Comment(4L, new Article(5L, "당신의 소울 푸드는?", "댓글 ㄱㄱ"), nickname, "치킨");
            Comment c = new Comment(7L, new Article(6L, "당신의 취미는?", "댓글 ㄱㄱㄱ"), nickname, "조깅");
            List<Comment> expected = Arrays.asList(a, b, c);

            //검증
            assertEquals(expected.toString(),comments.toString(),"Park의 모든 댓글을 출력");

        }

    }

닉네임을 통해 댓글을 찾는 findByNickName도 테스트 메소드 만들어준다

package com.example.firstproject.repository;

import com.example.firstproject.entity.Article;
import com.example.firstproject.entity.Comment;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.data.repository.query.Param;

import java.util.Arrays;
import java.util.List;

import static org.junit.jupiter.api.Assertions.*;


@DataJpaTest // 리포지토리 테스트니까 Jpa와 연동해서 테스트할 수 있다
class CommentRepositoryTest {

    @Autowired CommentRepository commentRepository;


    @Test
    @DisplayName("특정 게시글의 모든 댓글 조회")
    void findByArticleId() {
        /* Case 1: 4번 게시글의 모든 댓글 조회 */
        {
            // 준비
            Long articleId = 4L;
            // 수행
            List<Comment> comments = commentRepository.findByArticleId(articleId);
            // 예상
            Article article = new Article(4L, "당신의 인생 영화는?", "댓글 ㄱ");
            Comment a = new Comment(1L, article, "Park", "굳 윌 헌팅");
            Comment b = new Comment(2L, article, "Kim", "아이 엠 샘");
            Comment c = new Comment(3L, article, "Choi", "쇼생크의 탈출");
            List<Comment> expected = Arrays.asList(a, b, c);
            // 검증
            assertEquals(expected.toString(), comments.toString(), "4번 글의 모든 댓글을 출력!");
        }

        /* Case 2: 1번 게시글의 모든 댓글 조회 */
        {
            // 준비
            Long articleId = 1L;
            // 수행
            List<Comment> comments = commentRepository.findByArticleId(articleId);
            // 예상
            Article article = new Article(1L, "가가가가", "1111");
            List<Comment> expected = Arrays.asList();
            // 검증
            assertEquals(expected.toString(), comments.toString(), "1번 글은 댓글이 없음");
        }


    }

    @Test
    @DisplayName("특정 닉네임의 모든 댓글 조회")
    void findByNickname() {
        // Case 1 : Park의 모든 댓글 조회
        {
            // 입력 데이터 준비
            String nickname = "Park";


            //실제 수행
            List<Comment> comments = commentRepository.findByNickname(nickname);

            //예상하기
            Comment a = new Comment(1L, new Article(4L, "당신의 인생 영화는?", "댓글 ㄱ"), nickname, "굳 윌 헌팅");
            Comment b = new Comment(4L, new Article(5L, "당신의 소울 푸드는?", "댓글 ㄱㄱ"), nickname, "치킨");
            Comment c = new Comment(7L, new Article(6L, "당신의 취미는?", "댓글 ㄱㄱㄱ"), nickname, "조깅");
            List<Comment> expected = Arrays.asList(a, b, c);

            //검증
            assertEquals(expected.toString(),comments.toString(),"Park의 모든 댓글을 출력");

        }

    }
}

CommentRepositoryTest.java 전체 코드

테스트가 틀릴 경우

이렇게 어떤 부분이 틀렸는지 확인할 수 있다.

요약

  • 댓글 기능을 만들기 위해 Comment 엔티티 만듬
  • Comment 엔티티는 Article 엔티티와 Many to one 관계
  • FK와 PK
  • CommentRepository에서는 어노테이션을 통해 쿼리 작성, xml을 통해 쿼리 작성하는 두가지 방법
  • 리포지토리 테스트

0개의 댓글