Spring

Spring, Entity와 DTO의 차이점 및 구조 파악 / 변환 방법

greenyellow-s 2025. 3. 13. 14:18
728x90
반응형

 

 

 

Entity와 DTO의 차이점

Entity데이터베이스와 매핑되어 데이터의 상태를 관리하는 객체이며, ORM을 통해 데이터베이스의 CRUD 작업을 처리한다.

즉, Entity는 생성하고 서버를 실행시키면 데이터베이스에 자동으로 테이블이 생성, 수정, 삭제, 읽기가 된다.

 

그에 비해 DTO계층 간 데이터 전송을 위한 객체로 클라이언트에게 필요한 정보만 전송한다.

DTO는 비즈니스 로직을 포함하지 않으며 엔티티의 정보를 전송하는 용도로 사용된다.

 

 

 

데이터를 전송할때 Entity가 아닌 DTO로 변환 후 사용하는 이유는 주로 보안성, 효율성, 유연성, 테스트 용이성 등을 고려하기 때문에 DTO를 사용하면 시스템을 보다 유연하고 안전하게 관리할 수 있게 된다.

 

 

 

쉽게 얘기하면,

Entity데이터베이스와 직접 연결되어 있기 때문에 구조가 고정되어 있으며, 변경이 어렵다.

또한, 데이터베이스와의 연관을 갖고 있어 불필요한 데이터까지 포함될 수 있다.

 

그에 비해 DTO필요한 정보만 담아 데이터를 전송하고 받을 수 있기 때문에 보안성, 효율성, 유연성, 테스트 용이성이 높은 것이다.

 

 


Entity

데이터베이스와 매핑되는 클래스 이다.

 

데이터베이스 테이블의 각 행을 객체로 표현하며, JPA 또는 Hibernate와 같은 ORM 프레임워크를 통해 데이터베이스와 객체 간의 변환이 이루어진다.

 

 

 

✔️ Entity 생성

 

@Entity 어노테이션 사용으로 Entity 클래스를 간단하게 만들 수 있다.

 

 

 

✔️ 기본 설정

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Entity
@EntityListeners(AuditingEntityListener.class)

 

@Builder

빌더 패턴을 자동으로 생성

 

@Getter

getter 메서드 자동 생성

 

@AllArgsConstructor

클래스에 정의된 모든 필드를 매개변수로 받는 생성자를 자동으로 생성

 

@NoArgsConstructor

매개변수가 없는 기본 생성자를 자동으로 생성

 

JPA 엔티티 클래스에서는 기본 생성자가 반드시 필요하다. 내부적으로 객체를 생성할 때 사용되기 때문이다.

따라서, 반드시 기본 생성자가 있어야한다.

 

@EntityListeners(AuditingEntityListener.class)

AuditingEntityListener가 적용되어, 엔디디가 저장되거나 수정될 때 자동으로 생성일과 수정일을 기록할 수 있다.

 

즉, 수정일과 생성일을 자동으로 관리 가능해진다.

@CreateDate @LastModifiedDate 필드에 자동으로 값을 넣을 수 있다.

 

 

 

✔️ 테이블 이름

 

@Table(name="")

@Table(name="테이블이름")

 

 

 

✔️ 인덱스 설정

 

@Table( indexes = { @Index(name = "", columnList = "", unique = true/false )})

@Table(name="테이블이름", indexes = {
        @Index(name = "인덱스이름1", columnList = "id, col1", unique = true),
        @Index(name="인덱스이름2", columnList = "subId", unique = false)
})

 

  name

    인덱스 이름 지정

 

  columnList

    인덱스를 적용할 컬럼 지정

    멀티 인덱스도 가능하다.

 

  unique

    인덱스가 유니크(고유) 한 값을 가지는지 여부 설정

 

 

 

✔️ 기본키

 

@Id

@Id
private String id;

 

 

 

✔️ NOT NULL 설정

 

@NotNull

@NotNull
private String id;

 

 

 

✔️ 컬럼명 설정

 

@Column(name="")

@Column(name = "report_id")
private String id;

 

 

 

✔️ 컬럼의 데이터 타입/제약조건

@NotNull
@Column(name = "col1", precision = 15, scale = 5)
private BigDecimal colOne = BigDecimal.ZERO;

@Size(max=36)
@Column(name = "col2")
private String colTwo;

 

  기본 형식

  private [데이터타입] [컬럼명];

 

 

 

  여기서 [컬럼명]은 데이터베이스의 컬럼명과 다를 수 있다.

 

 

 

  [데이터타입]

 

  VERCHAR() / CHAR()  →  String

  INT  →  int

  DECIMAL()  →  BigDecimal

  DATE  →  LocalDate

  DATETIME  →  LocalDateTime

 

 

 

  [데이터타입] 사이즈 설정

 

  VERCHAR(36) / CHAR(36)  →  @Size(36)

@Size(max=36)
@Column(name = "col1")
private String colOne;

 

  DECIMAL(15, 5)  →  precision = 15, scale = 5 

@NotNull
@Column(name = "col2", precision = 15, scale = 5)
private BigDecimal colTwo;

 

 

 

  [Default] 값 설정

 

  @Column(columnDefinition)

@Column(name = "status", columnDefinition = "VARCHAR(10) DEFAULT 'ACTIVE'")
private String status;

 

  DBMS에 종속적이다.

  기본값이 중요한 경우 사용한다.

 

 

  필드 초기화 (Java 코드)

@Column(name = "status")
private String status = "ACTIVE";

 

  DB 기본값이 아니다. (NULL 허용 시 주의 필요)

 

 

  @PrePersist

@Column(nullable = false)
private String status;

@PrePersist
public void prePersist() {
  if (this.status == null) {
    this.status = "ACTIVE";
  }
}

 

  객체 생성 시만 적용된다.

 

 

  @Builder.Default

@Builder.Default
private String role = "USER";

 

  기본 생성자에는 적용되지 않는다.

 

 

 


DTO

계층 간 데이터 전송을 위한 객체

 

보통 클라이언트와 서버 간에 데이터를 주고 받을 때 사용되며, 엔티티와 다르게 특정 데이터를 포장하여 전달하는 역할을 한다.

 

 

 

✔️ 기본 형태

public class UserDTO {

  @Data
  @NoArgsConstructor
  public UserDTO(Long id, String name, String email) {
    
    @Schema(description = "회원 아이디")
    private Long id;
    
    private String name;
    private String email;
  }
}

 

@Data

  • @Getter (모든 필드의 Getter 메서드 생성)
  • @Setter (모든 필드의 Setter 메서드 생성)
  • @ToString (클래스의 toString() 메서드 자동 생성)
  • @EqualsAndHashCode (객체의 equals() 및 hashCode() 자동 생성)
  • @RequiredArgsConstructor (final 또는 @NonNull 필드를 포함한 생성자 생성)

 

@Schema

  • SpringDoc에서 사용되는 어노테이션
  • API 문서에서 DTO나 모델의 설명을 추가할 때 사용된다.
  • Swagger 문서에서 API의 데이터 구조를 명확히 설명하는 역할

 

 

원하는 형태로 커스텀 가능하다.

 

 

 


Entity와 DTO 변환

 

✔️ Setter / Builder 사용 방식

 

 

Entity  →  DTO

UserEntity entity;

// Setter 사용 방식
UserDTO dto = new UserDTO();
dto.setId(entity.getId());
dto.setName(entity.getName());
dto.setEmail(entity.getEmail());

// @Builder 사용 방식
UserDTO.builder()
          .id(entity.getId())
          .name(entity.getName())
          .email(entity.getEmail())
          .build();

 

 

DTO  →  Entity

UserDTO userDTO;

// Setter 사용 방식
UserEntity entity = new UserEntity();
entity.setId(userDTO.getId());
entity.setName(userDTO.getName());
entity.setEmail(userDTO.getEmail());


// @Builder 사용 방식
UserEntity entity = UserEntity.builder()
    .id(userDTO.getId())
    .name(userDTO.getName())
    .email(userDTO.getEmail())
    .build();

 

 

 

✔️ ModelMapper 라이브러리 사용 방식

 

 

1. 의존성 추가

application.properties

implementation 'org.modelmapper:modelmapper:3.1.1'

 

 

2. Bean 등록

config > ModelMapperConfig.java

@Configuration
public class ModelMapperConfig {
    @Bean
    public ModelMapper modelMapper() {
        return new ModelMapper();
    }
}

 

 

3. 변환

 

Entity  →  DTO

UserDTO userDto = modelMapper.map(userEntity, UserDTO.class);

 

DTO  →  Entity

UserEntity userEntity = modelMapper.map(dto, UserEntity.class);

 

 

리스트 변환

List<UserDTO> userDtoList = userEntityList.stream()
    .map(entity -> modelMapper.map(entity, UserDTO.class))
    .collect(Collectors.toList());

 

728x90
반응형