Service, controller 클래스 생성 및 메서드 구현
애플리케이션에서 핵심 기능을 제공하는 서비스, 비즈니스 로직과 클라이언트 요청을 연결하는 컨트롤러를 생성해보겠습니다.
서비스 클래스 만들기
- 서비스 레이어에서는 도메인 모델(Domain Model)을 활용해 애플리케이션에서 제공하는 핵심 기능을 제공한다.
- 핵심 기능을 구현하려면 세부 기능을 정의해야한다.
- 아키텍처의 한계를 극복하기 위해 아키텍처를 서비스 로직과 비즈니스 로직으로 분리하기도 한다.
- 도메인을 활용한 세부 기능들은 비즈니스 레이어 로직에 구현하고, 서비스 레이어에서는 기능 등을 종합해서 핵심기능을 전달하도록 구성하는 경우가 대표적이다.
DTO 클래스 생성
ProductDto
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ProductDto {
private String name;
private int price;
private int stock;
}
ProductResponseDto
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ProductResponseDto {
private Long number;
private String name;
private int price;
private int stock;
}
Service 클래스 생성
ProductService
public interface ProductService {
ProductResponseDto getProduct(Long number);
ProductResponseDto saveProduct(ProductDto productDto);
ProductResponseDto changeProductName(Long number, String name) throws Exception;
void deleteProduct(Long number);
}
- DAO에서 구현한 기능을 서비스 인터페이스에서 호출해 결과값을 가져오는 작업을 수행하도록 설계했다.
- 서비스에서는 클라이언트가 요청한 데이터를 적절하게 가공해서 컨트롤러에게 넘기는 역할을 한다.
- 서비스에서는 리턴 타입이 DTO 객체이다. DAO 객체에서는 엔티티 타입을 사용하는 것을 고려하면 서비스 레이어에서 DTO 객체와 엔티티 객체를 각 레이어에 변환해서 전달하는 역할을 수행한다.
- 회사나 개발 그룹 내 규정에 따라 DTO를 사용하기도 한다.
ProductService 인터페이스 구현 클래스
@Service
@RequiredArgsConstructor
public class ProductServiceImpl implements ProductService {
private final ProductDao productDao;
@Override
public ProductResponseDto getProduct(Long number) {
return null;
}
@Override
public ProductResponseDto saveProduct(ProductDto productDto) {
return null;
}
@Override
public ProductResponseDto changeProductName(Long number, String name) throws Exception {
return null;
}
@Override
public void deleteProduct(Long number) {
}
}
getProduct() 메서드 구현
@Override
public ProductResponseDto getProduct(Long number) {
Product product = productDao.selectProduct(number);
ProductResponseDto productResponseDto = ProductResponseDto.builder()
.number(product.getNumber())
.name(product.getName())
.price(product.getPrice())
.stock(product.getStock())
.build();
return productResponseDto;
}
- lombok의 builder()를 이용하여 DTO 객체를 생성하고 엔티티 객체 변환 작업 진행
saveProduct() 메서드 구현
@Override
public ProductResponseDto saveProduct(ProductDto productDto) {
Product product = Product.builder()
.name(productDto.getName())
.price(productDto.getPrice())
.stock(productDto.getStock())
.createdAt(LocalDateTime.now())
.updatedAt(LocalDateTime.now())
.build();
Product savedProduct = this.productDao.insertProduct(product);
ProductResponseDto productResponseDto = ProductResponseDto.builder()
.number(savedProduct.getNumber())
.name(savedProduct.getName())
.price(savedProduct.getPrice())
.stock(savedProduct.getStock())
.build();
return productResponseDto;
}
- 전달받은 DTO 객체를 통해 엔티티 객체를 생성해서 초기화 후 DAO 객체로 전달한다.
- 일반적으로 저장 메서드는 void 타입으로 작성하거나 성공 여부를 나타내는 boolean 타입으로 지정하는 경우가 많다.
- void로 저장 메서드를 구현하는 경우 클라이언트가 저장한 데이터의 인덱스 값을 알 방법이 없기 때문에, 데이터를 저장하면서 가져온 인덱스를 DTO에 담아 결과값으로 클라이언트에 전달한다.
changeProductName() 메서드 구현
@Override
public ProductResponseDto changeProductName(Long number, String name) throws Exception {
Product changedProduct = this.productDao.updateProductName(number, name);
ProductResponseDto productResponseDto = ProductResponseDto.builder()
.number(changedProduct.getNumber())
.name(changedProduct.getName())
.price(changedProduct.getPrice())
.stock(changedProduct.getStock())
.build();
return productResponseDto;
}
- 이름을 변경하기 위해 클라이언트로부터 대상을 식별할 수 있는 인덱스 값과 변경하려는 이름 값을 받아온다.
- 실제 레코드 값을 변경하는 작업은 DAO에서 진행하기 때문에 서비스 레이어에서는 해당 메서드를 호출해서 결과값만 받아온다.
deleteProduct() 메서드 구현
@Override
public void deleteProduct(Long number) throws Exception{
this.productDao.deleteProduct(number);
}
- 삭제하는 메서드는 리포지토리에서 제공하는 delete() 메서드를 사용할 경우 리턴타입이 지정되지 않기에 리턴 타입을 void 로 지정하여 메서드를 구현한다.
컨트롤러 클래스 생성
ProductController 클래스
@RestController
@RequestMapping("/product")
@RequiredArgsConstructor
public class ProductController {
private final ProductService productService;
@GetMapping()
public ResponseEntity<ProductResponseDto> getProduct(Long number) {
ProductResponseDto responseDto = this.productService.getProduct(number);
return ResponseEntity.status(HttpStatus.OK).body(responseDto);
}
@PostMapping()
public ResponseEntity<ProductResponseDto> createProduct(@RequestBody ProductDto productDto) {
ProductResponseDto responseDto = this.productService.saveProduct(productDto);
return ResponseEntity.status(HttpStatus.OK).body(responseDto);
}
@PutMapping()
public ResponseEntity<ProductResponseDto> changeProductName(
@RequestBody ChangeProductNameDto changeProductNameDto) throws Exception {
ProductResponseDto responseDto = this.productService.changeProductName(
changeProductNameDto.getNumber(),
changeProductNameDto.getName());
return ResponseEntity.status(HttpStatus.OK).body(responseDto);
}
}
Summary
📌 일반적으로 DAO의 리턴타입은 Entity, 서비스에서의 리턴타입은 DTO이다.
📌 Service 메서드 구현 방법
- Service 생성
- 엔티티 객체의 값을 받아와서 DTO 객체를 생성하고 변환한다.
- Service 저장
- 일반적으로 저장 메서드는 void 또는 boolean 타입으로 구현된다.
- void 타입인 경우, 데이터의 인덱스 값을 알 수 없기 때문에 DTO 타입으로 변환하여 값을 리턴한다.
- Service 수정
- 실제 변경하는 값은 DAO에서 진행하고 있기 때문에 해당 메서드를 호출하여 결과값만 받아온다.
- Service 삭제
- 리포지토리에서 제공하는 delete() 메서드 사용
- 리턴 타입이 지정되지 않기에 void로 지정하여 구현한다.
반응형
'Book > 스프링부트 핵심가이드' 카테고리의 다른 글
lombok 설정 방법과 주요 어노테이션 (1) | 2023.11.03 |
---|---|
DAO(Data Access Object) 개념과 클래스 구성 (0) | 2023.11.03 |
JPA Repository 인터페이스 생성과 사용 방법 (0) | 2023.11.02 |
댓글