참치코더의 꿈 메모장

Spring / JPA Entity생성 및 Repository 설정 미니 정리(코드 위주) 본문

Spring

Spring / JPA Entity생성 및 Repository 설정 미니 정리(코드 위주)

참치깡 2025. 9. 9. 19:30
728x90

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
 
// 1. JPA Auditing과 공통 엔티티
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import java.time.LocalDateTime;
 
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
@Getter
@NoArgsConstructor
public abstract class BaseEntity {
 
    @CreatedDate
    @Column(name = "regdate", updatable = false)
    private LocalDateTime createdDate;  // 등록일
 
    @LastModifiedDate
    @Column(name = "moddate")
    private LocalDateTime modifiedDate; // 수정일
}
 
// @MappedSuperclass -> 공통 필드를 상속 가능, 테이블 생성 X (그냥 테이블 만드는 거의 가장 상위 부모 클래스 라고 생각하면 편하다 ㅎㅎ)
// @EntityListenres(AuditingEntityListener.class) -> 테이블이 변경될때 생성/수정 날짜 자동 기록 하는 어노테이션 사용가능하게 해주는 설정
// @CreatedDate -> insert 시 시간 자동 기록
// @LastModifiedDate -> 데이터 insert + update 시 자동 갱신
// @Column(updatable=false) -> 수정 시 SQL에서 제외
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
 
@SpringBootApplication
@EnableJpaAuditing // 해당부분 작성해야 위에 시간 자동 기입 사용할 수 있음
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}
 
//////////////////////////////////////////////////////////////////////////////////////////////////////
 
// 2. Board 엔티티와 Lombok
 
import jakarta.persistence.*;
import lombok.*;
 
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class Board extends BaseEntity {
 
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long bno;
 
    private String title;
    private String writer;
    private String content;
}
 
// @Builder -> Builder 패턴 지원
// @NoArgsConstructor -> JPA 필수 기본 생성자
// @AllArgsConstructor -> 전체 필드 생성자
// @Getter -> 모든 필드 getter 자동 생성
 
// Build 사용하는 이유는 테이블에 체이닝 형태로 데이터를 입력할 수 있다.
 
Board board = Board.builder()
                   .title("제목")
                   .writer("user1")
                   .content("내용")
                   .build();
 
 
////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// 3. JpaRepository + 페이징/정렬
 
 
import org.springframework.data.jpa.repository.JpaRepository;
// 첫번째 참조할 테이블명(@Entity 선언 테이블) 두번째 기본키 데이터 타입 넣어야 함(@Id 선언한 것)
public interface BoardRepository extends JpaRepository<Board, Long> {
    // 자동 CRUD 제공
    // 추가로 메서드 이름만으로 쿼리 가능
    List<Board> findByWriter(String writer);
}
J
////////////////////////////////////////////////////////////////////////////////////////////////////////
 
// 4. Pageable & page (페이징 만들때 사용하면 좋은 것)
 
 
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
 
Pageable pageable = PageRequest.of(010, Sort.by("bno").descending());
Page<Board> result = boardRepository.findAll(pageable);
 
List<Board> boards = result.getContent(); // 실제 리스트
boards.forEach(b -> System.out.println(b.getBno() + " : " + b.getTitle()));
 
 
// PageRequest.of(page, size, Sort) -> 0페이지, 10개, bno 내림차순
// result.getContent() -> 이번 페이지 리스트
// result.hasNext() / result.nextPageable() -> 다음 페이지 정보
 



cs

 

- JPA의 사용으로 코드가 많이 생략되고(기술의 발전...) , 실행 흐름 파악이 어려운 만큼 테스트 코드 작성하는게 중요해졌다.

- 보통 코딩시간보다 테스트 코드 짜는 시간이 더 오래 걸림...

 

1. 저장 방법 (C)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import com.example.demo.domain.Board;
import com.example.demo.repository.BoardRepository;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
 
import java.time.LocalDateTime;
 
@Slf4j
@DataJpaTest  // JPA 관련 슬라이스 테스트
class BoardRepositoryTest {
 
    @Autowired
    private BoardRepository boardRepository;
 
    @Test
    void saveBoardTest() {
        // given (저장할 엔티티 생성)
        Board board = Board.builder()
                .title("테스트 제목")
                .content("테스트 내용")
                .writer("tester")
                .createdDate(LocalDateTime.now())
                .build();
 
        // when (저장)
        Board savedBoard = boardRepository.save(board);
 
        // then (확인)
        log.info("저장된 엔티티: {}", savedBoard);
        log.info("저장된 ID: {}", savedBoard.getId());
    }
}
 
cs

 

2. 조회 방법 (R)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Test
void findByIdTest() {
    // given: 저장
    Board board = Board.builder()
            .title("아이디 조회 제목")
            .content("아이디 조회 내용")
            .writer("tester")
            .build();
    Board savedBoard = boardRepository.save(board);
 
    // when: ID로 단건 조회
    Optional<Board> result = boardRepository.findById(savedBoard.getId());
 
    // then
    result.ifPresent(b -> log.info("조회 성공: {}", b));
}
 
cs

 

3. 수정 방법 (U)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
void updateBoardTest() {
    // given: 먼저 저장
    Board board = Board.builder()
            .title("수정 전 제목")
            .content("수정 전 내용")
            .writer("tester")
            .build();
    Board savedBoard = boardRepository.save(board);
 
    // when: 엔티티 수정 후 다시 저장
    savedBoard.changeTitle("수정된 제목");
    savedBoard.changeContent("수정된 내용");
    Board updatedBoard = boardRepository.save(savedBoard);
 
    // then
    log.info("업데이트된 게시글: {}", updatedBoard);
}
 
cs

 

4. 삭제 방법 (D)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Test
void deleteBoardTest() {
    // given: 저장
    Board board = Board.builder()
            .title("삭제 테스트 제목")
            .content("삭제 테스트 내용")
            .writer("tester")
            .build();
    Board savedBoard = boardRepository.save(board);
 
    Long id = savedBoard.getId();
 
    // when: 삭제
    boardRepository.deleteById(id);
 
    // then: 확인
    boolean exists = boardRepository.existsById(id);
    log.info("삭제 후 존재 여부: {}", exists); // false 기대
}
 
cs

 

728x90
Comments