Entity
Entity는 실제 데이터베이터베이스의 데이터구조와 1:1로 매핑되는 객체이다. 그렇기에 DB의 테이블내에 존재하는 컬럼만을 위한 필드를 가저야한다.
Entity 클래스는 상속을 받고나 구현되여서는 안되며 테이블내에 존재하지 않는 컬럼을 가져서도 안된다.
Entity와 DTO를 구분한 이유
Entity와 DTO를 살펴보면 사용하는 애너테이션만 조금 다를뿐 구성되는 필드는 거희 비슷하다. 하지만 굳이 이 둘을 분리시킨 가장 큰 이유는 두 객체간의 주 목적이 다르기 때문이다.
- DTO : 클라이언트의 요청 데이터를 하나의 객체로 받기 위해 혹은 응답으로 주기위해 사용하며 API계층에서 사용
- Entity : 비즈니스 로직과 데이터베이스의 작업을 수행하기위해 사용되며 비즈니스계층과 데이터 엑세스계층에서 사용
또한 계층별 관심사를 분리하여 계층간의 데이터 교환을 용이하게 하고 각 계층간에 목적에 맞는 필요한 코드만을 작성하여 코드의 구성을 단순화 시킬 수 있다.
마지막으로 보안을 위해서 이다. 데이터베이스에 저장된 사용자의 개인정보 혹은 패스워드와 같이 높은 보안이 필요한 데이터를 클라이언트 측에 매번 보낼 필요가 없다. Entity를 이용하여 데이터베이스에 접근하고 필요한 정보만을 추출해 DTO로 만들어 클라이언트로 응답하면 보다 높은 보안을 가질 수 있다.
Mapper
DTO와 Entity간의 변환을 위해 Mapper 클래스를 만들어서 사용해준다. 즉 Mapper란 DTO를 Entity로 혹은 Entity를 DTO로 변환해 주기위한 클래스이다.
이러한 작업을 Controller 혹은 비즈니스로직에서 수행하게되면 해당 로직이 복잡해지고 객체지향프로그래밍에 맞지 않는 설계가 될것이다.
Mapper클래스는 개발자가 직접 작성하여 만들어 줄수도 있지만 특정한 Library를 이용하여 만들어 줄수도 있다.
예시 - MapStruct library)
dependencies {
...
implementation 'org.mapstruct:mapstruct:1.4.2.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final'
}
우선 위와 같이 build.gradle에 해당 라이브러리를 입력하여 설치해준다.
@Mapper(componentModel = "spring") //MapStruct에서 제공하는 애너테이션과 Spring의 Bean으로 등록한다는 옵션
public interface CoffeeMapper {
Coffee coffeePostDtoToCoffee(CoffeePostDto coffeePostDto); //coffeePostDto를 Coffee 엔티티로 변환
Coffee coffeePatchDtoToCoffee(CoffeePatchDto coffeePatchDto); // CoffeePatchDto를 Coffee로 변환
CoffeeResponseDto coffeeToCoffeeResponseDto(Coffee coffee); // Coffee 엔티티를 CoffeeResponseDto로 변환
}
위와 같이 인터페이스를 생성하여 @Mapper 애너테이션을 이용하여 간단하게 Mapper를 만들어줄 수 있다.
이때 메서드의 반환타입과 매개변수의 반환타입으로 어떤 변환이 이뤄지는지 알수 있다.
이후 Mapper가 필요한 Controller에 생성자와 DI를 이용해 Mapper객체를 해당 Controller클래스에 의존성 주입을 해주고 사용하면 된다.
@RestController
@RequestMapping("/v5/coffees")
public class CoffeeController {
private final CoffeeService coffeeService;
private final CoffeeMapper mapper;
public CoffeeController(CoffeeService coffeeService, CoffeeMapper mapper) {
this.coffeeService = coffeeService;
this.mapper = mapper;
} // 맵퍼 의존성주입
@PostMapping
public ResponseEntity postCoffee(@Valid @RequestBody CoffeePostDto coffeePostDto) {
Coffee coffee = mapper.coffeePostDtoToCoffee(coffeePostDto);
Coffee response = coffeeService.createCoffee(coffee);
ResponseDto response = mapper.coffeeToCoffeeResponseDto(response)
return new ResponseEntity<>(response, HttpStatus.CREATED);
} //맵퍼를 이용해 DTO를 Entity로 변환하여 비즈니스 계층으로 보낸뒤 받은 Entity를 DTO로 변환하여 응답
}
모든 코드를 작성한 뒤 IntelliJ IDE의 오른쪽 상단의 [Gradle] 탭을 클릭한 후, [프로젝트 명 > Tasks 디렉토리 > build 디렉토리 > build task]를 더블 클릭하면 MapStruct로 정의된 인터페이스의 구현 클래스가 생성된다.
이후 IntelliJ IDE의 좌측에서 [Project 탭 > 프로젝트명 > build] 디렉토리내의 MemberMapper 인터페이스가 위치한 패키지 안에서 확인이 가능하다.
(다른 Mapping library들 간의 성능 차이 결과 : https://www.baeldung.com/java-performance-mapping-frameworks )
'Java > Spring & Spring Boot' 카테고리의 다른 글
JDBC(Java Database Connectivity) (0) | 2023.04.20 |
---|---|
Exception, 예외 처리 (0) | 2023.04.18 |
DTO (Data Transfer Object) 과 Validation (0) | 2023.04.12 |
Servlet과 JSP 그리고 MVC(Model, View, Controller) (0) | 2023.04.11 |
관점 지향 프로그래밍 (Aspect Oriented Programming, AOP) (0) | 2023.04.09 |