spring.jpa.show_sql=true
spring.h2.console.enabled=true
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.hikari.jdbc-url=jdbc:h2:mem:testdb
spring.datasource.password=
spring.datasource.hikari.username=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
다음과 같은 코드를 추가하며 이번 조회 기능은 실제로 톰캣을 실행하며 확인을 해본다.
앞에서 언급한것처럼 로컬 환경에서는 H2 데이터베이스를 사용하기에 직접 접근하기위하여서 웹 콘솔을 활용을 하게 된다. 그래서 위와 같은 코드를 추가하여 준다.
추가한 뒤 다음 링크로 접속을 하게 된다. http://localhost:8080/h2-console 접속을 하게 된다면 다음과 같은 화면이 뜨게 된다.
그 이후 SELECT문을 사용하여서 테이블의 내용을 확인하여 본다면 다음과 같이 데이터가 현재는 등록이 되어있지 않은 상태로 있다는 것을 알 수 있는데...
그리하여서 insert문을 활용하여서 데이터를 추가하고
insert into posts (author, content, title) values ('author', 'content', 'title');
그 이후 조회가 되는지 확인하여보기위하여서 이전 API에서 작성한것처럼 http://localhost:8080/api/v1/{id}였던것처럼 id자리에 현재 테이블에 등록이 되어있던 하나의 테이블의 id인 1을 넣어준다.
보통 엔티티에서는 해당 데이터의 생성시간과 수정시간을 포함을 한다. 언제 만들어졌는지, 언제 수정되었는지는 나중에 유지보수의 측면에서 상당히 중요한 정보이기 떄문이다. 그래서 기본적으로는 매번 DB에 삽입하기 전, 갱신하기 전 날짜 데이터를 등록/수정하는 코드가 여기저기 들어가게 된다.
//생성일 추가 코드 예제
public void savePosts(){
...
posts.setCreateDate(new LocalDate());
postsRepository.save(posts);
...
}
즉, 이런 코드들이 계속해서 들어가야 한다는 점이다. 그러면 당연히 코드도 복잡해지고 어질어질~~할 것이다.
그래서 이 문제를 해결하기 위하여서 JPA Auditing을 사용한다.
이전에 보게 되면 날짜와 관련된 클래스들이 있다는 것들을 알 수 있는데 예를 들자면은 Calendar, Date와 같은 클래스 말이다.
그런데 Java8부터 LocalDate LocatDateTime이 등장을 했는데 앞서 말하였던 Calendar, Date와 같은 클래스들의 문제점들을 제대로 고친 타입이다.
- 불변(변경이 불가능한) 객체가 아닙니다.
- 멀티스레드 환경에서 언제든 문제가 발생할 수 있습니다.
- Calendar는 월(Month) 값 설계가 잘못되었습니다.
- 10월을 나타내는 Calendar.OCTOBER의 숫자 값은 '9'입니다.
- 당연히 '10'으로 생각했던 개발자들에게는 큰 혼란이 왔습니다.
이후 더 많은 내용들은 Naver D2 - Java의 날짜와 시간 API를 참고하면 좋다.(재밌는 내용들도 되게 많다.)(https://d2.naver.com/helloworld/645609)
이제 본격적으로 한 번 구현을 해보도록 하자.
package com.khyojun.admin.springboot.domain;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import javax.persistence.EntityListeners;
import javax.persistence.MappedSuperclass;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class BaseTimeEntity {
@CreatedDate
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime modifiedDate;
}
🔍 BaseTimeEntity 클래스는 모든 Entity의 상위 클래스가 되어서 Entity들의 createdDate, modifiedDate를 자동으로 관리하는 역할을 한다.
- @MappedSuperclass
- JPA Entity 클래스들이 BaseTimeEntity를 상속할 경우 필드들(createdDate, modifiedDate)도 칼럼으로 인식하도록 한다.
- @EntityListeners(AuditingEntityListener.class)
- BaseTimeEntity 클래스에 Auditing 기능을 포함시킨다.
- @CreatedDate
- Entity가 생성되어 저장될 때 시간이 자동 저장이 된다.
- @LastModifiedDate
- 조회한 Entity의 값을 변경할 때 시간이 자동 저장이 된다.
- Auditing: 엔티티를 생성하거나 변경한 사람과의 발생한 시점을 투명하게 추적 : 변경 시점 추적
- Spring Data Jpa를 보면 정보를 캡처하는데 Entity Listener와 함께 제공이 된다고 한다. 그래서 AuditingEntityListener내부를 등록을 해야한다.
이렇게 한 이후로 Entity클래스에 BaseTimeEntity를 상속받게 한다.
...
public class Posts extends BaseTimeEntity{
...
}
마지막으로 JPA Auditing 어노테이션들을 모두 활성화할 수 있도록 Application클래스에 활성화 어노테이션 하나를 추가한다.
@EnableJpaAuditing
@SpringBootApplication
public class Application{
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
}
자 그러면 위 코드들은 작성이 완료되었고 이제 테스트 코드를 한 번 만들어보도록 하자.
@Test
public void BaseTimeEntity_등록() {
//given
LocalDateTime now= LocalDateTime.of(2022,8,17,22,0,0);
postRepository.save(Posts.builder().title("title").content("content").author("author").build());
//when
List<Posts> postsList = postRepository.findAll();
//then
Posts posts=postsList.get(0);
System.out.println(">>>>>>>>>>>>> createDate=" + posts.getCreatedDate() + ", modifiedDate="+posts.getModifiedDate());
Assertions.assertThat(posts.getCreatedDate()).isAfter(now);
Assertions.assertThat(posts.getModifiedDate()).isAfter(now);
}
위 코드의 내용들을 분석해보자면 우선은 지금 현재의 시간을 기준으로 나중에 assertThat을 사용하여서 지금 등록을 한 시간보다 뒤에 시간이 맞는지 확인하게 된다.