[꼼꼼한 개발자] 꼼코더
40. [개발일지] - [쇼핑몰 프로젝트] - 04. 상품 도메인 대폭 수정 (modelMapper) 본문
반응형
😧 이전 상황
이전에 상품 엔티티를 만들고 상품 생성(Create)까지 개발을 마쳤었다.
하지만 이후 진행과정에서 교재를 참고해서 하다 보니 개발 속도에 많은 지연이 있었고
팀원과 회의 끝에 구글링을 통해서 빠르게 진행해보기로 했다
'단 모든 코드를 잘 이해하고 넘어가는 것'을 가장 중요하게 이야기 했었다.
왜냐하면 당연히 그 코드를 이해해야 내 것이 되고 앞으로의 프로젝트에서 응용이 가능하기 때문이다
이 것이 클론코딩, 복+붙 (코드 긁어오기)에 대한 주의점이다.
(코드 수정 시작)
🧑🏻💻 엔티티, DTO (코드 수정)
엔티티와 DTO( + FormDTO)를 수정하였다.
/**
* @version 1.0
* @Author seodong-geun
* @since 2023/04/10
*/
@Entity // JPA 엔티티 클래스임을 나타냄
@Data
@Table(name = "product")
public class Product extends BaseEntity{
@Id
@Column(name = "product_id")
@GeneratedValue(strategy = GenerationType.AUTO) // 기본키 자동 생성
private Long id; // 상품코드
@Column(length = 200, nullable = false)
private String name; // 상품명
@Column(nullable = false)
private int price; // 상품가격
@Column(length = 1500, nullable = false)
private String description; // 상품설명
@Column(nullable = false)
private int stock; // 재고
}
/**
* @version 1.1
* @Author seodong-geun
* @since 2023/05/09
* 상품 정보를 담은 폼(form) 데이터를 담는 DTO 클래스
*/
@Getter
@Setter
public class ProductFormDto {
// modelMapper 객체 생성
// Java Bean을 이용하여 객체간의 매핑을 쉽게 처리할 수 있도록 도와주는 라이브러리
private static ModelMapper modelMapper = new ModelMapper();
private Long id;
@NotBlank(message = "상품명은 필수 입력 값입니다.")
private String name;
@NotNull(message = "상품의 가격은 필수 입력 값입니다.")
private Integer price;
@NotBlank(message = "상품 설명은 필수 입력 값입니다.")
private String description;
@NotNull(message = "상품 재고는 필수 입력 값입니다.")
private Integer stock;
// ProductFormDto 객체를 Product 객체로 변환하여 반환
public Product createProduct(){
return modelMapper.map(this, Product.class);
}
// Product 객체를 ProductFormDto 객체로 변환하여 반환
public static ProductFormDto of(Product product){
return modelMapper.map(product, ProductFormDto.class);
}
}
package com.example.DYmall.product.dto;
import lombok.*;
import java.time.LocalDateTime;
/**
* @version 1.0
* @Author seodong-geun
* @since 2023/05/03
* Product 엔티티와 상응하는 데이터 전송 객체
*/
@Getter // Getter 메소드 자동생성
@Setter // Setter 메소드 자동생성
public class ProductDto {
private Long id;
private String name;
private Integer price;
private String description;
private Integer stock;
private LocalDateTime regDate, modDate;
}
🧑🏻💻 서비스와 테스트(인터페이스와 구현체)
다음은 서비스(인터페이스와 구현체), 와 테스트 코드도 수정하였다
테스트 코드는 기존방식과 다르게 '김영한'님 의 방식(given, when, then)으로 작성해 봤다.
/**
* @version 1.0
* @Author seodong-geun
* @since 2023/05/03
*/
public interface ProductService {
Long saveProduct(ProductFormDto productFormDto);
}
/**
* ProductService 인터페이스의 구현체인 ProductServiceImpl 클래스
* @version 1.0
* @Author seodong-geun
* @since 2023/05/03
*/
@Service // Service 클래스 명시
@Log4j2 // 로깅을 위한 lombok 어노테이션
@Transactional
@RequiredArgsConstructor // @Autowired 어노테이션이 없는 final 필드에 대해서 생성자를 생성
public class ProductServiceImpl implements ProductService {
private final ProductRepository productRepository;
public Long saveProduct(ProductFormDto productFormDto) {
//상품 등록
Product product = productFormDto.createProduct();
productRepository.save(product);
return product.getId();
}
}
package com.example.DYmall.product.service;
import com.example.DYmall.product.domain.Product;
import com.example.DYmall.product.dto.ProductFormDto;
import com.example.DYmall.product.repository.ProductRepository;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.persistence.EntityNotFoundException;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* @version 1.0
* @Author seodong-geun
* @since 2023/05/03
*/
@SpringBootTest
public class ProductServiceTests {
@Autowired
private ProductService productService;
@Autowired
private ProductRepository productRepository;
@Test
@DisplayName("상품 등록 테스트")
void createItem() {
// given
ProductFormDto productFormDto = new ProductFormDto();
productFormDto.setName("테스트 상품 명");
productFormDto.setDescription("테스트 상품 설명");
productFormDto.setPrice(500);
productFormDto.setStock(20);
// when
Long productID = productService.saveProduct(productFormDto);
Product product = productRepository.findById(productID)
.orElseThrow(EntityNotFoundException::new);
// then
assertEquals(productFormDto.getName(), product.getName());
assertEquals(productFormDto.getDescription(), product.getDescription());
assertEquals(productFormDto.getPrice(), product.getPrice());
assertEquals(productFormDto.getStock(), product.getStock());
}
}
😁 느낀 점
초반이라 빠르게 계획을 수정하는 게 좋다고 판단하고 있지만
역시 흐름 잡기가 어려운 건 맞다.. 이러면서 성장하는 게 아닐까 싶으면서도
또 이게 맞는 건지 하는 아이러니한 상황..
그래도 새로운 코드들을 보고 이해하는데 재미도 있고 시야도 넓어지고 좋다!
그중에서도 modelMapper는 처음 경험했는데
이전에 객체 <-> 엔티티 변환 코드들이 매우 간략해져서 편했다.!
'개발일지 > 쇼핑몰 프로젝트' 카테고리의 다른 글
Comments