domain 패키지 내부 Class 혹은 Enum 파일들은 DB 처리용으로 DB Table과 Mapping되어 DB와 직접적으로 데이터를 교환할 때 사용된다.
domian 패키지 안에는 Board, Time 2개의 파일이 존재하는데
Board : 게시판 글에 대한 정보를 담고 있는 테이블
Time : 데이터 조작 시 자동으로 날짜를 수정해주는 JPA의 Auditing 기능을 사용한다. 이 Time Class를 다른 Entity들이 상속받아 사용하여 자동으로 일시를 부여해준다.
게시글 Entity인 Board가 필요로 하는 속성은 게시글을 구분할 {id, 제목, 내용, 작성자, 작성일시, 수정일시}로 그 중 작성일시와 수정일시는 클라이언트가 직접 입력하는 것이 아니라, JPA Auditing 기능을 사용해 글이 생성될 때 자동으로 부여되도록 하였다.
com.board.domain.Time
package com.board.domain;
import java.time.LocalDateTime;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import jakarta.persistence.Column;
import jakarta.persistence.EntityListeners;
import jakarta.persistence.MappedSuperclass;
import lombok.*;
@Getter
@MappedSuperclass // 클래스가 만들어지지 않는 기초 클래스
@EntityListeners(value = {AuditingEntityListener.class}) // Entity의 변화를 감지하는 리스너
public abstract class Time {
@CreatedDate
@Column(updatable = false)
private LocalDateTime createdDate;
@LastModifiedDate
@Column
private LocalDateTime modifiedDate;
}
이를 위한 Time Class를 구현해보았다.
- @MappedSuperClass
공통으로 사용하는 맵핑 정보만 상속하는 부모 클래스에 선언 - JPA가 시간에 대해 자동으로 값을 넣어주는 Auditing 기능을 사용해서 생성일시, 수정일시를 구현할 수 있다.
- Auditing 기능을 사용하는 해당 클래스에는 @EntityListeners(AuditingEntityListener.class) 를,
- @SpringBootApplication 이 있는 class 에 @EnableJpaAuditing 을 추가해야 한다.
package com.board; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.data.jpa.repository.config.EnableJpaAuditing; @EnableJpaAuditing //JPA Auditing 사용 @SpringBootApplication(exclude = SecurityAutoConfiguration.class) public class BoardApplication { public static void main(String[] args) { SpringApplication.run(BoardApplication.class, args); } }
- @CraetedDate
엔티티가 생성되어 저장될 때 시간을 자동 저장 - @LastModifiedDate
엔티티가 수정된 시간을 자동 저장
com.board.domain.Board
package com.board.domain;
import org.springframework.util.Assert;
import jakarta.persistence.*;
import lombok.*;
//Board : 실제 DB와 매핑될 클래스 (Entity Class)
// JPA에서는 프록시 생성을 위해 기본 생성자를 반드시 하나 생성해야 한다.
// 생성자 자동 생성 : NoArgsConstructor, AllArgsConstructor
// NoArgsConstructor : 객체 생성 시 초기 인자 없이 객체를 생성할 수 있다.
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
@Table(name= "board")
public class Board extends Time{
@Id //PK Field
@GeneratedValue(strategy = GenerationType.IDENTITY) // PK 생성규칙
private Long id;
@Column(length = 10, nullable = false)
private String writer;
@Column(length = 100, nullable = false)
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
@Builder
public Board(Long id, String writer, String title, String content) {
//Assert 구문으로 예외사항 체크
Assert.hasText(writer, "작성자는 필수 입력사항입니다");
Assert.hasText(title, "제목은 필수 입력사항입니다");
Assert.hasText(content, "내용은 필수 입력사항입니다");
this.id = id;
this.writer = writer;
this.title = title;
this.content = content;
}
}
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
@Table(name= "board")
public class Board extends Time{
- @NoArgsConstructor(access = AccessLevel.PROTECTED)
외부에서의 생성을 열어둘 필요가 없기 때문에 생성자의 접근 제한을 PROTECTED로 설정해 무분별한 객체 생성에 대해 한번 더 체크 - @Getter
Getter 메서드를 생성 - @Entity
해당 Annotation을 선언하면 JPA가 관리하게 되며 이를 통해 JPA가 DB의 Table과 상호작용하게 된다. 이를 통해 개발자는 객체 지향적으로 DB Table 및 Query문을 수행할 수 있게 된다. - @Table(name= "board")
name 속성을 통해 Mapping할 Table을 지정 - public class Board extends Time{
앞서 구현한 Time Class를 상속받아 createdDate, modifiedDate 속성을 사용할 수 있게 함
@Id // PK Field
@GeneratedValue(strategy= GenerationType.IDENTITY) // PK의 생성 규칙
private Long id;
- @Id
해당 Property가 Primary Key의 역할을 한다는 것을 나타냄 - @GeneratedValue
Primary Key의 값을 위한 자동 생성 전략을 명시하는 데 사용
@Builder
public Board(Long id, String writer, String title, String content) {
//Assert 구문으로 예외사항 체크
Assert.hasText(writer, "작성자는 필수 입력사항입니다");
Assert.hasText(title, "제목은 필수 입력사항입니다");
Assert.hasText(content, "내용은 필수 입력사항입니다");
this.id = id;
this.writer = writer;
this.title = title;
this.content = content;
}
해당 Board Entity가 Builder 패턴을 사용함을 @Builder 애노테이션을 통해 나타낸다.
@Builder 애노테이션을 사용하면, 추후 객체를 생성할 때 아래의 형태로 간단하게 객체를 생성할 수 있다.
=> builder 메서드가 제공됨
{Class} {obj} {Class}.builder()
.id(id)
.name(name)
. ...
. ...
.build();
Assert.hasText(writer, "writer must not be empty");
Assert.hasText(title, "title must not be empty");
Assert.hasText(content, "content must not be empty");
Assert 구문으로 안전한 객체 생성 패턴을 구현
writer, title, content 객체가 전달되지 않을 경우 Exception을 발생시킨다.
util 패키지는 MVC에 속하지 않는 범용적인 기능들을 제공하는 클래스들을 모아놓은 패키지로 프로젝트 내에서 반복적으로 사용될 수 있는 기능들이 여기에 포함된다.
com.board.util.Header.java
package com.board.util;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
import java.util.List;
import com.board.dto.BoardDto;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Header<T> {
private LocalDateTime transactionTime; //응답이 생성된 시간
private String resultCode; //결과 상태 코드
private String description; //결과에 대한 설명
private T data; //응답 데이터
private Pagination pagination; //페이지네이션 정보를 담은 필드
public static <T> Header<T> OK() {
return (Header<T>) Header.builder()
.transactionTime(LocalDateTime.now())
.resultCode("OK")
.description("OK")
.build();
}
//DATA OK
public static <T> Header<T> OK(T data) {
return (Header<T>) Header.builder()
.transactionTime(LocalDateTime.now())
.resultCode("OK")
.description("OK")
.data(data)
.build();
}
public static <T> Header<T> OK(List<BoardDto> boardDtoList, Pagination pagination) {
return (Header<T>) Header.builder()
.transactionTime(LocalDateTime.now())
.resultCode("OK")
.description("OK")
.data(boardDtoList)
.pagination(pagination)
.build();
}
public static <T> Header<T> ERROR(String description) {
return (Header<T>) Header.builder()
.transactionTime(LocalDateTime.now())
.resultCode("ERROR")
.description(description)
.build();
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data : Lombok 어노테이션으로 getter, setter, toStrig, equals, hashCode 메서드를 자동 생성
com.board.util.Search.java
package com.board.util;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Search {
private String type; //search key
private String keyword; //search value
private Integer page;
private Integer size;
}
com.board.util.Pagination.java
package com.board.util;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Pagination {
private int totalListCnt;
private int pageSize;
}
'Develop > Java & Spring' 카테고리의 다른 글
[Spring Boot] 게시판 프로젝트 외전 #1 JUnit과 Mockito를 이용한 테스트 - 이론 (0) | 2025.03.25 |
---|---|
[Spring Boot] 게시판 프로젝트 #4 Service, Controller 구현 (0) | 2025.03.25 |
[Spring Boot] 게시판 프로젝트 #3 DTO, Repository 구현 (0) | 2025.03.25 |
[Spring Boot] 게시판 프로젝트 #1 세팅 (0) | 2025.03.25 |
BufferedReader, BufferedWriter,StringTokenizer, StringBuilder 빠른 입출력을 위한 함수들 (0) | 2025.03.21 |