-
Spring Boot - JPA를 사용한 데이터 조작Framework & Library 2022. 2. 4. 00:00
JPA를 사용한 데이터 조작
✔️ Entity 생성
@Entity @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder @Table(name = "product") public class ProductEntity { @Id private String productId; private String productName; private int productPrice; private int productStock; }
ㆍ DB의 테이블과 직접적으로 매핑되는 클래스이다.
애너테이션 설명 @Entity 해당 애너테이션을 클래스에 붙이면 JPA가 해당 클래스를 관리하게 된다. @Builder 해당 애너테이션을 사용하게 되면 객체를 생성할 때 생성자를 통해서 객체를 생성하는 것이 아니라 Entity이름.builder( ).필드(값).필드(값).build( );를 통해 필드에 대한 값을 좀 더 명시적으로 지정할 수 있다. @Table 매핑할 테이블을 지정하기 위한 애너테이션이다. @Id Primary Key를 지정하기 위한 애너테이션이다. ㆍ JPA 사용 시 위와 같은 여러 가지 애너테이션을 사용하여 테이블, 필드, 필드 옵션 등을 설정할 수 있다.
✔️ DTO 생성
@Data @NoArgsConstructor @AllArgsConstructor @ToString @Builder public class ProductDTO { private String productId; private String productName; private int productPrice; private int productStock; }
ㆍ Service나 Controller에서 DB에 접근할 때 사용하는 클래스이다.
ㆍ 위에서 설명한 Entity와 다른 점은 Entity는 DB 테이블에 대한 정보를 가지고 있는 클래스이고, DTO는 해당 테이블에서 실제로 CRUD를 할 필드를 정의해둔 것이라고 보면 된다.
ㆍ 이렇게 Entity와 DTO를 분리해서 사용하는 이유는 소스코드 작성 중 DB에 접근할 필드의 변경이 생겼을 경우 Entity를 변경하여 DB에 접근하면 DB 테이블의 내용이 변경되어 큰 문제를 일으킬 수 있기 때문이다. 따라서, 테이블에 대한 정보를 작성하는 Entity 클래스와 DB에 접근하는 필드에 대한 DTO 클래스를 분리해서 사용하는 것이다.
✔️ Repository 생성
public interface ProductRepository extends JpaRepository<ProductEntity, String> { }
ㆍ JPA를 사용하게 되면 JpaRepository 인터페이스를 상속받아 제네릭을 통해 관리하고 하는 클래스, Id의 타입을 <ProductEntity, String>와 같이 작성하면 자동으로 DB와 CRUD 연결을 할 수 있는 메서드를 사용할 수 있다.
✔️ DAO 생성
public interface ProductDAO { ProductEntity saveProduct(ProductEntity productEntity); ProductEntity getProduct(String productId); }
ㆍ Service가 DB에 연결할 수 있게 도와주는 역할을 수행하는 DAO 인터페이스를 생성한다.
ㆍ 해당 인터페이스는 상품을 저장하기 위한 saveProduct( ) 메서드와 상품을 조회하는 getProduct( ) 메서드가 정의되어
@Service public class ProductDAOImpl implements ProductDAO { ProductRepository productRepository; @Autowired public ProductDAOImpl(ProductRepository productRepository) { this.productRepository = productRepository; } @Override public ProductEntity saveProduct(ProductEntity productEntity) { productRepository.save(productEntity); return productEntity; } @Override public ProductEntity getProduct(String productId) { ProductEntity productEntity = productRepository.getById(productId); return productEntity; } }
ㆍ ProductDAO 인터페이스의 구현체인 ProductDAOImpl 클래스이다.
ㆍ ProductRepository 객체에 대한 의존성을 주입받고 해당 객체를 통해 DB에 접근하는 방식으로 동작한다.
✔️ Handler 생성
public interface ProductDataHandler { ProductEntity saveProductEntity(String productId, String productName, int productPrice, int productStock); ProductEntity getProductEntity(String prodyctId); }
ㆍ Handler는 필수적으로 구현하는 것이 아닌, 필요에 따라 구현을 하는 영역이다. 데이터를 핸들링할 필요가 있을 때 해당 영역을 구현한다.
ㆍ Handler 영역 역시 인터페이스와 클래스로 분리되어 있다.
ㆍ 해당 인터페이스는 상품을 저장하기 위한 saveProductEntity( ) 메서드와 상품을 조회하는 getProductEntity( ) 메서드가 정의되어 있다.
@Service @Transactional public class ProductDataHandlerImpl implements ProductDataHandler { ProductDAO productDAO; @Autowired public ProductDataHandlerImpl(ProductDAO productDAO) { this.productDAO = productDAO; } @Override public ProductEntity saveProductEntity(String productId, String productName, int productPrice, int productStock) { ProductEntity productEntity = new ProductEntity(productId, productName, productPrice, productStock); return productDAO.saveProduct(productEntity); } @Override public ProductEntity getProductEntity(String productId) { return productDAO.getProduct(productId); } }
ㆍ ProductDataHandler 인터페이스의 구현체인 ProductDataHandlerImpl 클래스이다.
ㆍ ProductDAO 객체에 대한 의존성을 주입받고 해당 객체를 통해 DB에 접근하는 방식으로 동작한다.
✔️ Service 생성
public interface ProductService { ProductDTO saveProduct(String productId, String productName, int productPrice, int productStock); ProductDTO getProduct(String productId); }
ㆍ Service 영역 역시 인터페이스와 클래스로 분리되어 있다.
ㆍ 해당 인터페이스는 상품을 저장하기 위한 saveProduct( ) 메서드와 상품을 조회하는 getProduct( ) 메서드가 정의되어 있다.
@Service public class ProductServiceImpl implements ProductService { ProductDataHandler productDataHandler; @Autowired public ProductServiceImpl(ProductDataHandler productDataHandler) { this.productDataHandler = productDataHandler; } @Override public ProductDTO saveProduct(String productId, String productName, int productPrice, int productStock) { ProductEntity productEntity = productDataHandler.saveProductEntity(productId, productName, productPrice, productStock); ProductDTO productDTO = new ProductDTO(productEntity.getProductId(), productEntity.getProductName(), productEntity.getProductPrice(), productEntity.getProductStock()); return productDTO; } @Override public ProductDTO getProduct(String productId) { ProductEntity productEntity = productDataHandler.getProductEntity(productId); ProductDTO productDTO = new ProductDTO(productEntity.getProductId(), productEntity.getProductName(), productEntity.getProductPrice(), productEntity.getProductStock()); return productDTO; } }
ㆍ ProductService 인터페이스의 구현체인 ProductServiceImpl 클래스이다.
ㆍ 인터페이스에서 정의된 두 메서드의 실질적인 로직을 구현한 클래스이다.
ㆍ ProductDataHandler 객체에 대한 의존성을 주입받고 해당 객체를 통해 데이터를 조작하는 방식으로 동작한다.
✔️ Controller 생성
@RestController @RequestMapping("/api/v1/product-api") public class ProductController { private ProductService productService; @Autowired ProductController(ProductService productService) { this.productService = productService; } @GetMapping(value = "/product/{productId}") public ProductDTO getProduct(@PathVariable String productId) { return productService.getProduct(productId); } @PostMapping(value = "/product") public ProductDTO createProduct(@RequestBody ProductDTO productDTO) { String productId = productDTO.getProductId(); String productName = productDTO.getProductName(); int productPrice = productDTO.getProductPrice(); int productStock = productDTO.getProductStock(); return productService.saveProduct(productId, productName, productPrice, productStock); } }
ㆍ 사용자로부터 요청을 받고 그에 대한 응답을 해주는 클래스이다.
ㆍ ProductService 객체에 대한 의존성을 주입받게 된다.
ㆍ Controller 클래스로 요청이 들어오게 되면, 각 요청에 매핑된 메서드들이 호출되고 해당 메서드 내의 Service 객체의 비즈니스 로직들이 동작하는 방식이다.
테스트
✔️ 상품 저장 테스트
ㆍ 컨트롤러와 매핑된 URL로 상품 정보를 http body에 담아 상품 저장 요청을 수행한다.
ㆍ 요청에 대한 응답이 정확하게 출력되는 것을 확인할 수 있다.
ㆍ DB 확인 결과 요청한 정보가 정확하게 저장된 것을 확인할 수 있다.
✔️ 상품 조회 테스트
ㆍ 기존에 저장된 상품을 조회하기 위해 서버로 요청을 보낸다.
ㆍ 요청한 상품정보가 정확하게 출력되는 것을 확인할 수 있다.
GitHub - qlsdud0604/spring-boot-study
Contribute to qlsdud0604/spring-boot-study development by creating an account on GitHub.
github.com
728x90