일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 집합_SET
- 생성자오버로드
- 컬렉션 타입
- 대덕인재개발원
- oracle
- 자바
- 오라클
- 제네릭
- 어윈 사용법
- 객체 비교
- 환경설정
- 다형성
- cursor문
- 한국건설관리시스템
- 추상메서드
- GRANT VIEW
- abstract
- Java
- 인터페이스
- 사용자예외클래스생성
- 예외미루기
- 메소드오버로딩
- exception
- EnhancedFor
- 예외처리
- 참조형변수
- 정수형타입
- 컬렉션프레임워크
- 자동차수리시스템
- NestedFor
- Today
- Total
거니의 velog
(19) 상품 API 서버 구성하기 4 본문
(2) 등록 기능의 처리
* 서비스 계층에 대한 테스트 코드를 작성해 보자. 테스트용 데이터는 실제 이미지가 아니기 때문에 화면에서 이미지 파일들이 제대로 보이지 않는 단점이 있기는 하지만, 서비스 계층이 정상적으로 동작하는지 확인할 수 있고 컨트롤러와 연동이 완료되면 정상적으로 이미지 파일들의 업로드를 확인할 수 있게 된다.
[서비스 등록 기능의 처리]
* ProductService는 등록 처리를 위해서 ProductDTO를 Product와 ProductImage 타입의 객체들로 만들어서 처리해야 한다. 이전 예제와 달리 직접 코드를 통해서 DTO를 엔티티 객체로 변환한다.
* ProductService 인터페이스에 register() 메서드를 추가한다.
package com.unlimited.mallapi.service;
import org.springframework.transaction.annotation.Transactional;
import com.unlimited.mallapi.dto.PageRequestDTO;
import com.unlimited.mallapi.dto.PageResponseDTO;
import com.unlimited.mallapi.dto.ProductDTO;
/**
*
* @Transactional 어노테이션을 서비스 계층의 인터페이스 레벨에 추가하는 것은 특정 메서드가 아닌 해당 인터페이스에 대해 트랜잭션을
* 적용하려는 의도를 나타냅니다. 이는 일반적으로 특별한 상황에서만 사용되며, 보통은 메서드
* 레벨에서 @Transactional 어노테이션을 사용하는 것이 일반적입니다.
*
* 일반적으로 서비스 인터페이스 레벨에 @Transactional 어노테이션을 추가하는 것은 다음과 같은 상황에서
* 고려될 수 있습니다.
*
* 인터페이스의 모든 메서드가 트랜잭션에 참여하는 경우: 인터페이스 내의 모든 메서드가 트랜잭션 내에서 실행되어야
* 할 경우에 사용될 수 있습니다. 이는 특히 서비스 인터페이스가 여러 메서드를 정의하고 이를 구현하는 클래스에서
* 트랜잭션을 관리하기 어려운 경우에 유용할 수 있습니다.
*
* 모든 메서드가 동일한 트랜잭션 속성을 가져야 하는 경우: 인터페이스 내의 모든 메서드가 동일한 트랜잭션 속성을
* 가져야 하는 경우에 해당됩니다. 이는 특별한 경우에만 적용되어야 하며, 대부분의 경우 메서드 레벨에서 트랜잭션
* 속성을 명시하는 것이 더 유연하고 명시적입니다.
*
* 서비스 레이어는 일반적으로 비즈니스 로직을 처리하고 트랜잭션 경계를 설정하는 역할을 합니다. 메서드
* 레벨에서 @Transactional 어노테이션을 사용하는 것이 더 흔하며, 메서드마다 다른 트랜잭션 속성을
* 지정할 수 있어서 더 유연한 구현이 가능합니다. 인터페이스 레벨에서 @Transactional 어노테이션을
* 사용하는 것은 특별한 경우에만 필요하며, 주의해서 사용해야 합니다.
*/
@Transactional(rollbackFor = Exception.class)
public interface ProductService {
PageResponseDTO<ProductDTO> getList(PageRequestDTO pageRequestDTO);
Long register(ProductDTO productDTO);
}
* ProductServiceImpl에서는 DTO를 엔티티로 변환하는 코드를 구현하고 이를 이용해서 register()를 구현한다.
// ProductDTO를 전달받아 상품을 등록하고 등록된 상품의 고유번호(PNO)를 반환하는 메서드입니다.
@Override
public Long register(ProductDTO productDTO) {
// ProductDTO를 엔티티로 변환합니다.
Product product = dtoToEntity(productDTO);
// 상품을 저장하고 저장된 결과를 반환합니다.
Product result = productRepository.save(product);
// 등록된 상품의 고유번호(PNO)를 반환합니다.
return result.getPno();
}
// ProductDTO를 받아서 그에 맞는 Product 엔티티로 변환하는 메서드입니다.
private Product dtoToEntity(ProductDTO productDTO) {
// ProductDTO에서 필요한 정보를 사용하여 Product 엔티티를 생성합니다.
Product product = Product.builder()
.pno(productDTO.getPno())
.pname(productDTO.getPname())
.pdesc(productDTO.getPdesc())
.price(productDTO.getPrice())
.build();
// 업로드된 파일들의 이름 리스트를 가져옵니다.
List<String> uploadFileNames = productDTO.getUploadFileNames();
// 업로드된 파일이 있는 경우 각 파일의 이름을 엔티티에 추가합니다.
if (uploadFileNames == null) {
return product;
}
// 업로드된 파일의 이름을 하나씩 엔티티에 추가합니다.
uploadFileNames.stream().forEach(uploadName -> {
product.addImageString(uploadName);
});
// 생성된 엔티티를 반환합니다.
return product;
}
* test 폴더에서는 ProductServiceTests 내 테스트 코드를 작성해서 register()의 동작을 확인한다.
package com.unlimited.mallapi.service;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.unlimited.mallapi.dto.PageRequestDTO;
import com.unlimited.mallapi.dto.PageResponseDTO;
import com.unlimited.mallapi.dto.ProductDTO;
import lombok.extern.log4j.Log4j2;
@SpringBootTest
@Log4j2
public class ProductServiceTests {
// ProductService를 주입받습니다.
@Autowired
ProductService productService;
(...)
// 상품 등록을 테스트하는 메서드입니다.
@Test
public void testRegister() {
// 새로운 상품을 나타내는 ProductDTO 객체를 생성합니다.
ProductDTO productDTO = ProductDTO.builder()
.pname("새로운 상품")
.pdesc("신규 추가 상품입니다.")
.price(1000)
.build();
// 상품에 대한 업로드된 파일의 이름(UUID를 포함) 리스트를 설정합니다.
productDTO.setUploadFileNames(
java.util.List.of(
UUID.randomUUID() + "_" + "Test1.jpg",
UUID.randomUUID() + "_" + "Test2.jpg"));
// 상품 서비스를 통해 상품을 등록합니다.
productService.register(productDTO);
}
}
* 테스트 실행 시에는 상품 테이블에 1건, 상품 이미지 테이블에 2건의 insert가 실행된다.
* 데이터베이스에 최종 결과를 확인한다.
[컨트롤러와 연동 확인]
* ProductController에서 기존에 구현된 register() 기능을 ProductService를 호출하도록 수정해서 등록 처리한 후 결과를 반환하도록 작성한다(리턴 값은 새로 등록된 상품 번호를 전송하도록 수정한다).
// 상품을 등록하는 메서드입니다.
@PostMapping("/")
public Map<String, Long> register(ProductDTO productDTO) {
// 요청된 상품 정보를 로그에 출력합니다.
log.info("register : " + productDTO);
// 상품 DTO에서 업로드된 파일 목록을 가져옵니다.
List<MultipartFile> files = productDTO.getFiles();
// 파일 유틸을 사용하여 파일을 저장하고, 저장된 파일 이름 리스트를 가져옵니다.
List<String> uploadFileNames = fileUtil.saveFiles(files);
// 상품 DTO에 업로드된 파일 이름 리스트를 설정합니다.
productDTO.setUploadFileNames(uploadFileNames);
// 상품 서비스를 호출하여 상품을 등록하고, 상품 번호를 받아옵니다.
Long pno = productService.register(productDTO);
// 결과를 Map 형태로 반환합니다.
return Map.of("result", pno);
}
* Postman에서는 첨부파일을 추가해서 테스트한다(테스트할 때 'form-data' 방식으로 전송하도록 설정하는 것을 주의).
* Postman에서는 새롭게 생성된 번호가 결과로 전송된다.
* 최종적으로 데이터베이스를 통해서 등록된 상품을 조회한다.
'SpringBoot_React 풀스택 프로젝트' 카테고리의 다른 글
(21) 상품 API 서버 구성하기 6 (0) | 2024.03.04 |
---|---|
(20) 상품 API 서버 구성하기 5 (0) | 2024.03.04 |
(18) 상품 API 서버 구성하기 3 (0) | 2024.03.04 |
(17) 상품 API 서버 구성하기 2 (0) | 2024.02.29 |
(16) 상품 API 서버 구성하기 1 (0) | 2024.02.29 |