위 사진은 실제 프로젝트 디렉터리의 모습이다.
이번 포스팅에서는 저 model 디렉터리에 대해 탐구해보도록하겠다.
| model
어플리케이션이 무엇을 할 것인지 정의하는 부분
즉, DB와 연동하여 사용자가 입력한 데이터나 사용자에게 출력할 데이터를 다룬다
model 디렉터리에는
config, entity, network, repository
이 4개의 디렉터리가 기본적으로 들어간다고 보면된다
config
Auditable, BaseEntity 같은 설정 클래스를 넣어준다
entity
데이터베이스 테이블에 매핑되는 엔티티 클래스를 넣는다
network
request,response,header 클래스를 넣는다
repository
repostiory 인터페이스들을 넣는다
이제 생성 순서대로 자세히 설명해보겠다
1. entity
데이터베이스(Database, DB) 에 쓰일 필드와 여러 엔티티간 연관관계를 정의한다. 데이터베이스는 엑셀처럼 2차원 테이블이라고 생각하면 되는데, 이 테이블에 서비스에서 필요한 정보를 다 저장하고 활용하게 된다.
아래 그림과 같이 세로의 열 부분이 Column 이고, 가로의 행 부분이 엔티티 객체가 된다. 이 테이블 전체가 엔티티 이고, 각 1개의 행들이 엔티티 객체가 되는 것이라고 생각하면 된다. 이것을 스프링, JPA의 코드로 표현해보자.
필드라는 것은 엔티티의 각 Column을 의미한다. 아래 예시에서 "private Long bno"라고 적은 것처럼 bno라는 필드를 정의하면 하나의 Column을 정의할 수 있는 것이다. @로 시작되는 구문은 어노테이션 이라고 부르는데, 대부분은 엔티티와 데이터베이스를 매핑하는 JPA에서 사용되는 것이다. 여기서는 간단히 의미와 개념만 파악하고 상세한 사용법 및 주의 사항은 다음에 따로 다루자.
@ 어노테이션
대략적인 어노테이션의 개념만 알도록 하고, 일단 따라하면서 만들고 속성, 옵션이나 주의사항은 나중에 익히는 것이 좋다. 너무 많은 정보를 한 번에 이해할 수 없기 때문이다.
@Entity : 클래스 위에 선언하여 이 클래스가 엔티티임을 알려준다. 이렇게 되면 JPA에서 정의된 필드들을 바탕으로 데이터베이스에 테이블을 만들어준다. 만얀 클래스명과 테이블명이 다를경우 @Entity(name="실제 테이블명") 써주면됨
@Builder : 해당 클래스에 해당하는 엔티티 객체를 만들 때 빌더 패턴을 이용해서 만들 수 있도록 지정해주는 어노테이션이다. 이렇게 선언해놓으면 나중에 다른 곳에서 Board.builder(). {여러가지 필드의 초기값 선언 }. build() 형태로 객체를 만들 수 있다.
@AllArgsConstructor : 선언된 모든 필드를 파라미터로 갖는 생성자를 자동으로 만들어준다.
@NoArgsConstructor : 파라미터가 아예없는 기본생성자를 자동으로 만들어준다.
@Getter : 각 필드값을 조회할 수 있는 getter를 자동으로 생성해준다. 예를들어 다른 파일에서 Board 객체의 title값을 얻고 싶다면 getTitle() 메서드를 정의해서 해당 객체의 title값을 얻어오게 되는데, 해당 메서드를 굳이 작성하지 않아도 자동으로 생성해주는 것이다.
변수는 보통 직접 접근 및 변경이 안되도록 private 선언자를 통해 지정한다. title 이라는 변수를 조회하기 위해서 getTitle() 이라는 메서드를 선언하고, title을 리턴하도록 해준다. 이 메서드를 getter라고 부른다.
1
2
3
|
private String title
public String getTitle() { return title }
|
cs |
@ToString : 해당 클래스에 선언된 필드들을 모두 출력할 수 있는 toString 메서드를 자동으로 생성할 수 있도록 해준다.
exclude 속성을 사용하면, 특정 필드를 toString() 결과에서 제외시킬 수도 있다.
@Id, @GeneratedValue : 해당 엔티티의 주요 키(Primary Key, PK)가 될 값을 지정해주는 것이 @Id 이다. @GeneratedValue는 이 PK가 자동으로 1씩 증가하는 형태로 생성될지 등을 결정해주는 어노테이션이다.
@ManyToOne : 해당 엔티티와 다른 엔티티를 관계짓고 싶을 때 쓰는 어노테이션이다. ManyToOne이라고 부르는 이유는 Writer 입장에서 Board는 여러 개가 될 수 있기 때문에 Writer : Board = 1 : N 관계가 되기 때문이다.
Data어노테이션은 위 사진엔 없지만 필요하므로 설명하겠음
@Data : @Getter / @Setter, @ToString, @EqualsAndHashCode와 @RequiredArgsConstructor 를 합쳐놓은 종합 선물 세트라고 할 수 있다. POJO(Plain Old Java Objects)와 bean과 관련된 모든 보일러플레이트(boilerplate =재사용 가능한 코드)를 생성한다. class의 모든 필드에 대한 getter, setter, toString, equals와 같은 함수들 말이다.
MySQL에서 테이블 생성
model 디렉터리안에 config entity network repository 하위 디렉터리를 생성
entity 안에 MoneyMember 이라는 클래스를 생성
클래스안에 created_date,update_date 필드 제외하고 다 작성
클래스 명위에 아래 어노테이션 다 작성
어떤 필드가 기본키인지 지정안해줘서 빨간줄뜸
private Long id; 위에다가
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
이 두 어노테이션을 붙여준다
참고로 @GeneratedValue(strategy - GenerationType.IDENTITY)는
자동생성전략 중 하나로
기본 키 생성을 데이터베이스에 위임하는 역할을 한다
즉, id 값을 null로 하면 DB가 알아서 AUTO_INCREMENT 해준다.
위에서 클래스안에 created_date,update_date 필드 제외하고 다 작성 했다
이제 이 두 필드에대해서는 Spring Data JPA Auditing 기능을 활용해보겠다
JPA Auditing 기능
서비스를 운영할 때 사용자의 기본적인 로그를 DB에 남겨야 할 때가 있다.
이를테면 마지막 로그인 시간이라던지 엔티티 생성 시간, 변경된 시간과 변경한 사람의 이름등등.
만약 엔티티들이 많고 모든 엔티티가 동일하게 로그를 기록해야한다면
일일이 똑같이 다 써줘야하는 번거로움이 생긴다
모든 엔티티가 동일한 연산을 수행해야 한다면 연산을 처리하는 기본 엔티티를 만들고 모든 데이터 요청시에 엔티티가 업데이트된다면 되지 않을까?
이 때 즉, 생성일/수정일/생성자를 자동화할 때 사용하는게 바로 JPA Auditing 이다.
Spring Data JPA 에서는 위의 Auditing 기능을 제공한다.
Auditing은 Spring Data JPA 에서만 사용할 수 있는 개념은 아니다.
JPA 자체적으로도 Auditing 기능을 사용할 수 있지만 Spring Data JPA 에서는 더 깔끔하고 쉽게 제공한다.
@EnableJpaAuditing 사용하기
Spring Data JPA 에서 JPA 를 사용하기 위해서는 SpringBoot 설정 클래스에 @EnableJpaAuditing 을 적어줘야한다.
보통 Springboot 를 실행시키는 클래스 상단에 많이 사용하고는 한다.
Application 파일로 이동해
@EnableJpaAuditing 을 적어준다
그리고 Auditing을 할 필드를 갖는 기본 엔티티를 생성해야한다
config디렉터리에 BaseEntity 클래스를 생성해준다
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
@Getter
public class BaseEntity {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;
@LastModifiedDate
private LocalDateTime updateDate;
}
어노테이션은 접은글로 설명
![](https://blog.kakaocdn.net/dn/bdr9Uj/btsbbrr5YyY/UmyK7yFVecA0U7ZQafs6f1/img.png)
이렇게 작성하면 해당 엔티티 클래스가 JPA 이벤트가 발생한다면 Auditing 을 수행하여 값을 업데이트 한다.
자! 무슨 새로운 어노테이션들이 존재한다. 하나씩 알아보자.
- @EntityListeners(AuditingEntityListener.class)
- @MappedSuperClass
- @Getter
- @CreatedDate
- @Column(updatable = false)
@EntityListeners
@EntityListeners 는 엔티티를 DB에 적용하기 전, 이후에 커스텀 콜백을 요청할 수 있는 어노테이션이다.
@EntityListeners 의 인자로 커스텀 콜백을 요청할 클래스를 지정해주면 되는데, Auditing 을 수행할 때는 JPA 에서 제공하는 AuditingEntityListener.class 를 인자로 넘기면 된다.
![](https://blog.kakaocdn.net/dn/bLJeWu/btsaVhLUgTI/FQY2TZtcNp77Z9AvUUXM70/img.png)
그럼 위에 보는바와 같이@PrePersist 어노테이션으로 JPA 의 Auditing 기능을 Spring Data JPA 가 사용하게 되는 것이다.
@MappedSuperClass
@MappedSuperClass 은 엔티티의 공통 매핑 정보가 필요할 때 주로 사용한다.
즉, 부모 클래스(엔티티)에 필드를 선언하고 단순히 속성만 받아서 사용하고싶을 때 사용하는 방법이다.
우리는 BaseEntity를 생성하고 Auditing 기능이 필요한 엔티티 클래스에서 사용할 것이기 때문에 @MappedSuperClass 어노테이션을 사용하는 것이다.
@CreatedDate
@CreatedDate 어노테이션은 Spring Data JPA의 Auditing 에서 가장 흥미로운 어노테이션이다.
사실 이 어노테이션도 Spring Data JPA 의 고유 기능은 아니고 Spring Data 에 있는 어노테이션으로 Spring Data 에서 추상화 해놓은 것이다.
CreatedDate의 javadoc 에 나온 설명을 참고해보자.
![](https://blog.kakaocdn.net/dn/cc4zXq/btsa6bRAyfG/sF1dfVyRK7R0WWXHlsk270/img.png)
Declares a field as the one representing the date the entity containing the field was created.
번) 필드를 포함하는 엔티티가 작성된 날짜를 나타내는 필드라고 선언한다.
javadoc 에 나온 내용을 보면 우리가 해당 필드를 선언하면 엔티티가 작성된 날짜, created 된 날짜를 사용할 수 있게 된다는 것이다.
이와 비슷한 어노테이션이 몇 개 더 존재한다.
- CreatedDate
- 해당 엔티티가 생성될 때, 생성하는 시각을 자동으로 삽입해준다.
- CreatedBy
- 해당 엔티티가 생성될 때, 생성하는 사람이 누구인지 자동으로 삽입해준다.
- 생성하는 주체를 지정하기 위해서 AuditorAware<T> 를 지정해야 한다.
이는 Spring Security 와 함께 다뤄야 하는 내용이므로 추후 업로드 예정
- LastModifiedDate
- 해당 엔티티가 수정될 때, 수정하는 시각을 자동으로 삽입해준다.
- LastModifiedBy
- 해당 엔티티가 수정될 때, 수정하는 주체가 누구인지 자동으로 삽입해준다.
- 생성하는 주체를 지정하기 위해서 AuditorAware<T> 를 지정해야 한다.
이는 Spring Security 와 함께 다뤄야 하는 내용이므로 추후 업로드 예정
- 생성하는 주체를 지정하기 위해서 AuditorAware<T> 를 지정해야 한다.
- 해당 엔티티가 수정될 때, 수정하는 주체가 누구인지 자동으로 삽입해준다.
위에서 언급하였듯 CreatedBy 와 LastModifiedBy 어노테이션은 추후 Spring Security 시리즈와 함께 이야기 해보려 한다.
만약 궁금하다면 AuditorAware 적용 키워드로 검색해볼 것을 추천한다.
@Column(updatable = false)
이는 JPA의 기본 어노테이션 에서 나온 @Column과 동일하다.
updatable 을 왜 false 로 했을까?
혹시 모를 상황을 대비해서이다.
우리는 해당 BaseEntity를 JPA가 테이블에 접근하는 시점에만 JPA가 사용하도록 하고 싶은데 만약 개발자에 의해 수정되면 안되기 때문에 updatable을 false로 해주는 것을 권장한다.
이후 이 클래스를 상속시켜줘야한다
MoneyMember 로가서 BaseEntity를 상속받자
이제 BaseEntity를 상속만 받으면 굳이 필드를 입력해주지 않아도
알아서 created_date 과 update_date 이 생성되고
또한 생성 및 수정시 jpa가 자동으로 값을 입력해준다
다음은 MoneyBoard클래스를 생성한다
MoneyBoard는 audit을 사용할 필드가 없으므로 필요없다.
여기서는
ManyToOne을 눈여겨 봐야함
MoneyBoard는 사용자가 쓴 글 정보가 들어가고
MoneyMember는 사용자 정보가 들어간다
한명의 사용자는 여러개의 글을 쓸수있다
그래서 이 관계는 1(사용자):N(사용자가 쓴 글) 이된다
N에 해당하는 클래스안에 들어가는 것이 바로
ManyToOne이다
1에 해당하는 클래스에도 OneToMany 같은 어노테이션을 쓴다면
양방향 연관관계라고하고
한쪽에만 ManyToOne같은 연관관계 어노테이션이 있다면
단방향 연관관계라고 한다
여기서는 단방향 연관관계를 사용할것이다
EAGER는 1에 해당하는 엔티티를 한번에 다가져올것인지
LAZY는 필요할때 하나씩 꺼내올것인지
정해주는 설정값이다.
@JoinColumn에 name에는
아래필드명 + _(언더바) + 참조하는 키에 해당하는 필드명
을 적어주면된다
이렇게 하면 엔티티설정은 끝이다
'웹 개발 > 🍃 SpringBoot' 카테고리의 다른 글
SpringBoot | CRUD 준비,Header<T>,service,apicontroller (0) | 2023.04.30 |
---|---|
SpringBoot | model(repository) with JPA Repository (0) | 2023.04.19 |
SpringBoot | ModelAndView에 데이터얹기 + Thymeleaf (0) | 2023.04.15 |
SpringBoot | Controller - PageController (0) | 2023.03.27 |
SpringBoot | REST API, HTTP Method (0) | 2023.03.21 |