Search
Duplicate

VO, DTO, Entity의 분리

스프링 프레임워크를 사용하여 MVC 구조의 웹 어플리케이션을 개발할 때
보통 아래와 같이 구성한다.
WEB Layer
Filter
Interceptor
Controller
Service Layer
business logic
Repository Layer
Data Access Object
Domain Model
VO
DTO
Entity
그리고, 보통 DB에서 가져온 값을 담고, 각 레이어로 전달하기 위하여
VO라고 부르는 객체를 사용하곤 한다.

흔하게 사용되는 VO (근본이 없는..)

package in.parkjw.jboard.test; public class PersonVO { public PersonVO (String name, int age) { this.name = name; this.age = age; } private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
Java
복사
생성자 혹은 Mybatis 와 같은 자바 퍼시스턴스 프레임워크를
통하여 가져온 값을 그대로 매핑하여 이리 저리 알뜰하게 이거 하나로 사용한다.
PersonVO p1 = new PersonVO(); p1.setName("asd"); p1.setAge(1); PersonVO p2 = new PersonVO("zxc", 2); PersonVO p3 = personRepository.findAllById(1);
Java
복사
물론 이렇게 사용해도 잘 동작하기는 한다.
하지만, 각 객체의 설계 목적을 고려하여 분리한다는 이론적인 이유가 아니라
개발을 하고 서비스를 하다보면 현실적인 문제의 당면하게 된다.
만약 VO와 매핑되는 테이블의 컬럼이 추가 되었을 때,
경우에 따라 해당 VO가 참조되는 소스 모두를 수정을 해야하거나 등
하나의 변화로 인하여 어플리케이션 전체가 영향을 받는 상황이 연출 될 수 있다.
다시 한 번 언급을 하지만 이렇게 써도 저렇게 써도 동작은 한다.
다만 설계 목적에 맞는 객체를 사용한다면 보다 효율적이고,
합리적인 개발을 할 수 있지 않을까 싶다.
이 쯤에서 각 객체들을 구분해보자.

VO

Value Object 값 그 자체를 표현하는 객체
로직을 포함 할 수 있음
객체의 불변성을 보장 (Read Only)
Object Class의 equals(), hashCode()를 오버라이딩 해야함
Intellij 기준에서는 두 메서드에 대하여 자동완성을 지원
값이 같다면 각 VO는 같은 객체로 식별

DTO

Data Transfer Object 계층(Layer)간 데이터 교환을 위해 사용하는 객체
로직을 포함하지 않음
데이터 교환만으로 사용되기 때문에 GetterSetter만 갖음
가변성을 가진다
데이터 캡슐화를 유연하게 대응 가능 (Entity → DTO)
값이 같더라도 각 DTO는 다른 객체로 식별

Entity

DB의 테이블과 링크(매핑)되는 객체
로직을 포함 할 수 있음
단 Presentation 로직이 아닌, Domain 로직만 가져야 한다
Entity를 구성하는 필드Table의 컬럼과 매핑이 된다

DTO와 Entity를 구분하는 이유?

View Layer와 DB Layer의 역활을 철저히 분리하기 위함
테이블의 변화가 생길 때 Entity도 변화가 이뤄짐. 이 때 두 객체를 분리 하지않으면
어플리케이션 전체 영향이 간다
비즈니스 로직의 요구에 따라 DTO는 변화가 생길 수 있는데, 이 때 Entity와 혼용하는 경우
모델링의 순수성을 깨고, Domain Model을 망치게 된다.

VO와 DTO는 어떻게 구분하나요?

목적에 따라서 사용하면 된다.
보통 Repository 레이어에서 가져온 Entity를 DTO로 변환 하여 Service 레이어를 보내고,
비즈니스 로직을 수행하여 DTO에 클라이언트의 반환할 값을 담은 후 Controller로 반환한다.
스프링을 처음 배울 때 DTO 목적으로 사용 하는 객체를 VO라고 배우는 경우가 많다.
그 둘을 구분하는게 웹 개발을할 때 생각보다 필요성을 못 느끼다 보니 간과하고 시간을 보내게 된 것 같다. 역사를 따지자면 원인 제공자(?)는 아래와 같다
⌜Core J2EE Patterns: Best Practices and Design Strategies⌟ 책의 초판에서는 데이터 전송용 객체VO로 정의했다. 그 이후 2판에서는 해당 객체를 DTO로 정정해서 작성했다.

Modelmapper 소개

DTO와 Entity를 구분하는건 이제 이해했다.
하지만, 매번 두 객체를 변환을 하는 것은 상당히 번거로운 작업이 된다.
걱정하지마라. 우리에게는 Modelmapper 가 있다.
다른 Object를 자동으로 Converting을 해주는 라이브러리 http://modelmapper.org/
Sorce가 되는 클래스에는 Getter가 있어야 하고,
Destination이 되는 클래스에는 Setter가 있어야 한다.
매핑 전략은 3가지를 지원한다. ( Standard, Loose, Strict )
Service → Controller 예제
BoardDTO dto = new BoardDTO(); BoardEntity entity = boardRepository.findBoardEntityById(1l); ModelMapper mapper = new ModelMapper(); // 매핑 전략 설정 mapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); // map(Sorce, Destination) mapper.map(entity, dto); return dto;
Java
복사
세부적인 사용 방법은 공식 홈페이지 혹은 구글링을 하면 잘 나와있으므로 여기까지 작성하겠다.