Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
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
Tags
more
Archives
Today
Total
관리 메뉴

wintertreey 님의 블로그

entity와 dto의 분리 본문

Spring

entity와 dto의 분리

wintertreey 2024. 8. 7. 19:47

 

                      dto          toentity     entity

사용자   > Controller  > Service > Jpa >     DB

              <                  <    todto  <        <

 

 

DTO와 Entity

DTO(Data Transfer Object) : 클라이언트와 서버 간 데이터 전송을 위해 설계된 객체

Entity : 데이터베이스에 저장되는 데이터 객체로, 데이터베이스와 직접적으로 연결

 

 

Dto와 Entity를 분리한 이유

entity을 직접 반환하는 코드에서 dto로 변환하여 view한테 반환한 이유는 첫 번째 이유는 Entity의 setter를 없애기 위해서였지만 이와 더불어 내가 찾아본 entity와 dto를 분리해야 하는 이유에 대해 적어보겠다.

 

1. Entity를 보호할 수 있다.

entity를 사용자에게 노출하면 원하지 않는 상황에서 자원의 속성이 변경될 가능성이 있다. 그리고 엔티티를 UI계층에 노출하는 것은 테이블 설계를 화면에 공개하는 것이나 다름없기 때문에 보안상으로도 바람직하지 못한 구조가 된다.
또한 dto는 setter를 허용하지만 entity에서 setter는 무분별하게 사용하면 안된다.

2. 화면에 필요한 데이터를 선별할 수 있다.

예를 들어 회원가입을 할 때는 이메일, 비밀번호, 자동로그인 여부 정보만 작성하면 된다. 하지만 도메인 객체 Member는 그 이상의 속성을 가지고 있을 것이다. 필요 이상으로 사용자가 가지고 있는 다른 속성들까지 항상 데이터 전송에 참여하게 되는 것이다. (보안에도 안좋고 속도도 느려짐)
그리고 자동로그인 여부와 같은 속성은 Member에 없을 수도 있다.
이와 같이 Dto와 Entity의 차이로 인해 Dto와 Entity를 분리하는 것이다.

 

3. Entity를 그대로 view에 넘기면, view의 요구사항 변화가 Model에 영향을 끼치기 쉽다.

유저에게 보여줘야 할 정보가 바뀌면, 엔티티를 수정해야 한다.

4. 순환참조를 예방할 수 있다.

jpa에서 양방향 참조된 엔티티를 controller에서 반환하면, 순환참조가 발생하게 된다. 결국 무한 루프에 빠져 스택오버 플로우가 발생한다.
jpa에서 순환참조를 해결하려면 @JsonManagedReference와 @JsonBackReference을 사용하거나, @JsonIgnore을 쓰거나 하는 방법도 있지만 Dto를 사용하는 것이 안전기도 하고 개발자가 보기에도 좋기 때문에 많이 추천하고 있다.

5. validation 코드와 모델링 코드를 분리할 수 있다.

엔티티 클래스는 DB의 테이블과 매칭되는 필드가 속성으로 선언되어 있고, 복잡한 비즈니스 로직이 작성되어있는 곳이다.
그렇기 때문에, 속성에는 @Column, @JoinColumn , @ManyToOne, @OneToOne 등의 모델링을 위한 코드가 추가된다.

여기에 만약 @NotNull, @NotEmpty, @NotBlank 등과 같은 요청에 대한 값의 validation코드가 들어간다면 엔티티 클래스는 더 복잡해지고 그만큼 가독성이 저하된다.

이때, 각각의 요청에 필요한 validation을 DTO에서 정의한다면, 엔티티 클래스를 좀 더 모델링과, 비즈니스 로직에만 집중되도록 만들 수 있다.

 

 

과정별로 코드로 확인해보자.

 

클라이언트 > DB  : toEntity

1. 클라이언트의 요청 

Controller

@Controller
public class MemberController {
	@Autowired
	private MemberServiceInter mservice;
	
	@GetMapping("/member/mlist")
	public String memlist(Model model) {
		mservice.getList(model); 
		return "member/mlist";
	}

 

model.addattribute(키, 키벨류); 이거없이도 mlist에 담겨 넘어간다.

getlist 내부에서 model.addattribute를 통해 데이터를 모델에 추가하고잇기 때문

 

++ mservice.getList(model); //getlist()는 void인데 이렇게 받을수있나? 

 

2. 엔티티

DTO를 Entity로 변환

`Member` 엔티티 클래스 내, 정적 메소드 `toEntity`를 선언하여 DTO를 Entity로 변환한다. 이 과정에서 빌더 패턴을 사용한다.

 

package pack.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import pack.dto.MemberDto;

@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "MEMBER_TBL")
public class Member {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO) // 자동증가
	private Long num;
	private String name;
	private String addr;

	// dto를 entity로 변환
	public static Member toEntity(MemberDto dto) {
		return Member.builder().num(dto.getNum()).name(dto.getName()).addr(dto.getAddr()).build();
	}
}

 

3. Service 

DTO를 Entity로 변환한 후, DB에 저장하는 로직을 작성한다.

@Service
public class MemberServiceImpl implements MemberServiceInter {
	@Autowired
	private MemberRepository memRepository;
    
@Override
	public void insert(MemberDto dto) {// dto이기에 엔티티로 변환작업요.
		// Jpa 작업영역내로 들어갈때 일반자료전달용객체(dto, FormBean)를 대응 entity로 변환.
		memRepository.save(Member.toEntity(dto));

	}
}

 

 

DB > 클라이언트 : toDto

1. DTO

Entity의 멤버 필드 값을 가져와 DTO에 설정해 반환한다.

 
package pack.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import pack.entity.Member;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class MemberDto {
	private Long num;
	private String name;
	private String addr;
	
	//entity를 dto로 변환
		public static MemberDto toDto(Member entity) {
			return MemberDto.builder()
					.num(entity.getNum())
					.name(entity.getName())
					.addr(entity.getAddr())
					.build();
		}
}

 

 

2. Service 

@Service
public class MemberServiceImpl implements MemberServiceInter {
	@Autowired
	private MemberRepository memRepository;

	@Override
	public void getData(Long num, Model model) { // 모델을 갖고온이유. model은 스프링이관리함. 그래서 void여도 괜찮음.
		Member m = memRepository.findById(num).get(); // 엔티티가져옴

		model.addAttribute("dto", MemberDto.toDto(m));// 엔티티 > 디티오작업

	}

 

 

3. 클라이언트

 

	@Controller
public class MemberController {
	@Autowired
	private MemberServiceInter mservice;
	
    //수정
	@GetMapping("/member/updateform")
	public String updateform(@RequestParam("num") Long num, Model model) {
		mservice.getData(num, model);
		return "member/updateform";
	}
 }

 


 

[Spring] DTO와 Entity를 분리하는 이유

DTO와 Entity DTO(Data Transfer Object) : 클라이언트와 서버 간 데이터 전송을 위해 설계된 객...

blog.naver.com

https://cafe.daum.net/flowlife/HrhB/95

 

Entity와 DTO 분리

* Entity와 DTO 분리 *Entity는 데이터베이스와 연관이 있으며 데이터베이스의 영속성을 관리하기 위한 역할을 한다. DTO는 클라이언트와 서버 간의 데이터 전송을 관리하고, 필요한 데이터를 포함하

cafe.daum.net

https://velog.io/@0sunset0/Dto%EC%99%80-Entity%EB%A5%BC-%EB%B6%84%EB%A6%AC%ED%95%98%EB%8A%94-%EC%9D%B4%EC%9C%A0-%EB%B6%84%EB%A6%AC%ED%95%98%EB%8A%94-%EB%B0%A9%EB%B2%95

 

📚 Dto와 Entity를 분리하는 이유, 분리하는 방법

작년에 프로젝트를 하면서 entity를 view에 그대로 반환했다가 Dto로 변환해야겠다는 생각이 들어서 바꿨었는데, Entity와 dto에 대한 내용을 블로그에 정리하면 좋을 거 같아 글을 쓰게 되었다. (일기

velog.io

 

'Spring' 카테고리의 다른 글

파일 업로드, 다운로드  (0) 2024.08.13
JPA 쿼리 메소드 참고 글  (0) 2024.08.08
JPQL연습_미니게시판  (0) 2024.08.01
wmvc 연습. #{}와 ${}의 차이  (0) 2024.08.01
aspectJ pointcut 표현식  (0) 2024.08.01