[ASAC 3기 개발 과제 일지] 상품 CRUD API 구현하기

배규리·2023년 11월 7일
0
post-thumbnail

처음 써보는 과제 일지,,,
일단 과제 내용이 무엇이냐면!
간단하게는

Spring Coupang REST API 어플리케이션 만들기

구체적으로는
다음 4개의 API 를 직접 개발 (JDBC Template 만을 활용하여)

  • 상품 디테일 CRUD
    • 상품 디테일 정보 조회 API 1개
    • (어드민) 상품 디테일 추가 API 1개
    • (어드민) 상품 디테일 삭제 API 1개
    • (어드민) 상품 디테일 수정 API 1개

음...?
뭐지 지금 이거 적다가 발견한 것
"JDBC Template"만을 사용하여...?
ㅋㅋㅋㅋㅋ황당하는 중........ 😐🫥
ㅎㅎ난 JPA를 써서 구현했다...JDBC Template이 모지...낼부터 공부해봐야겠다 ^^;

API 명세

어쨋든 난 이걸 구현하기 위해서 API는 아래와 같이 명세했다.

  • 상품 추가 API - POST /product/add/{sellerId}

  • 상품 디테일 정보 조회 API - GET /product/{id}/detail

  • 상품 삭제 API - DELETE /product/{id}/delete

  • 상품 디테일 수정 API - UPDATE /product/{id}/update

  • 판매자 추가 API - POST /seller/add

Entity

그리고 아래와 같이 3개의 Entity만을 사용했다.

  • Customer(소비자)
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long customerId;
    private String customerName;
    private String address;
}
  • Seller(판매자)
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Seller {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long sellerId;
    private String sellerName;
    private String sellerNumber; //사업자 등록 번호

    @JsonIgnore
    @OneToMany(mappedBy = "seller")
    private List<Product> productList = new ArrayList<>();
}
  • Product(상품)
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long productId;

    private String productName; //상품 이름
    private String productDetail; // 상품 상세 설명
    private Long productPrice; // 상품 가격
    private Category category; //카테고리
    private Long amount; // 상품 재고

    @ManyToOne
    @JoinColumn(name = "seller_id")
    private Seller seller;
}

근데 생각해보니까 소비자 Entity는 안사용했다...왜 구현했을까 기억이 안남 그냥 했다..ㅋㅋ

Repository

JpaRepository도 상품 CRUD와 판매자 C를 위해 각각 1개씩 총 2개 생성해주었다.

  • SellerRepository
public interface SellerRepository extends JpaRepository<Seller, Long> {
}
  • ProductRepository
public interface ProductRepository extends JpaRepository<Product, Long> {
}

Controller

Controller단은 아래와 같이 선언을 하였는데,,음 아직도 헷갈리는건 PUT이랑 PATCH,,,PUT이면 전체 다 바꾸는거 PATCH면 일부만 바꾸는 거라고 하는데 왜 나누는건지 아직 잘 이해가 안된다,,,이따 다시 정리해봐야지╰(°▽°)╯

  • SellerController
@RestController
@RequiredArgsConstructor
public class SellerController {
    private final SellerService sellerService;
    @PostMapping("/seller/add")
    public ResponseEntity<Seller> addSeller(@RequestBody SellerDto sellerDto){
        return sellerService.addSeller(sellerDto);
    }

}
  • ProductController
@RestController
@RequiredArgsConstructor
public class ProductController {

    private final ProductService productService;

    // 상품 ID에 해당하는 상품의 디테일 정보 조회
    @GetMapping("/product/{id}/detail")
    public ResponseEntity<ProductDetailDto> getProductDetail(@PathVariable String id) {
        return productService.getProductDetail(id);
    }

    // 상품 등록
    @PostMapping("/product/add/{sellerId}")
    public ResponseEntity<String> addProduct(@PathVariable String sellerId,
                                             @RequestBody ProductDto dto) {
        return productService.addProduct(sellerId, dto);
    }

    //상품 삭제
    @DeleteMapping("/product/{id}/delete")
    public ResponseEntity<String> deleteProduct(@PathVariable String id) {
        return productService.deleteProduct(id);
    }

    //상품 수정
    @PutMapping("/product/{id}/update")
    public ResponseEntity<Product> updateProduct(@PathVariable String id,
                                                 @RequestBody ProductUpdateDto dto){
        Product updateProduct = productService.updateProduct(id, dto);
        return ResponseEntity.ok(updateProduct);
    }
}

Service

구체적인 로직을 구현한 Service단은 아래와 같다.
이 부분은 크게도 보고 하나하나 살펴보겠다!

  • ProductService
@Service
@RequiredArgsConstructor
@Slf4j
public class ProductService {
    private final SellerRepository sellerRepository;
    private final ProductRepository productrepository;
    // 상품 ID에 해당하는 상품의 디테일 정보 조회
    public ResponseEntity<ProductDetailDto> getProductDetail(String id){
        Optional<Product> product = productrepository.findById(Long.valueOf(id));
        if(product.isPresent()){
            log.info("Product 발견!");
            ProductDetailDto dto = new ProductDetailDto();
            dto.setDetail(product.get().getProductDetail());
            return ResponseEntity.ok(dto);
        }
        else{
            log.info("Product 못찾음 ㅜㅜ");
            return null;
        }
    }
    // 상품 등록
    public ResponseEntity<String> addProduct(String sellerId,
                                              ProductDto dto){
        Optional<Seller> seller = sellerRepository.findById(Long.valueOf(sellerId));
        if(seller.isPresent()){
            Product product = new Product();
            product.setProductDetail(dto.getProductDetail());
            product.setProductName(dto.getProductName());
            product.setProductPrice(dto.getProductPrice());
            product.setCategory(Category.valueOf(dto.getCategory()));
            product.setAmount(dto.getAmount());
            product.setSeller(seller.get());
            productrepository.save(product);
            return ResponseEntity.ok("Success Add Product!");
        }
        else{
            return ResponseEntity.ofNullable("No seller");
        }

    }

    // 상품 ID에 해당하는 상품 삭제
    public ResponseEntity<String> deleteProduct(String id){
        productrepository.deleteById(Long.valueOf(id));
        return ResponseEntity.ok("Success Delete Product!");
    }

    // 상품 ID에 해당하는 상품 수정
    public Product updateProduct(String id, ProductUpdateDto dto) {
        Product product = productrepository.findById(Long.valueOf(id))
                .orElseThrow(() -> new EntityNotFoundException("Product Not Found"));
        if (dto.getProductName()!=null){
            product.setProductName(dto.getProductName());
        }
        if(dto.getProductDetail()!=null){
            product.setProductDetail(dto.getProductDetail());
        }
        if(dto.getProductPrice()!=null){
            product.setProductPrice(dto.getProductPrice());
        }
        if(dto.getCategory()!=null){
            product.setCategory(Category.valueOf(dto.getCategory()));
        }
        if(dto.getAmount()!=null){
            product.setAmount(dto.getAmount());
        }
        return productrepository.save(product);
    }

}
  • SellerService
@Service
@RequiredArgsConstructor
public class SellerService {
    private final SellerRepository sellerRepository;

    // 판매자 계정 추가
    public ResponseEntity<Seller> addSeller(SellerDto sellerDto) {
        Seller seller = new Seller();
        seller.setSellerName(sellerDto.getSellerName());
        seller.setSellerNumber(sellerDto.getSellerNumber());
        sellerRepository.save(seller);
        return ResponseEntity.ok(seller);
    }
}

getProductDetail

상품 Entity의 productDetail 값을 읽어온다.
productId를 입력받아 productRepository로부터 Product를 찾아오고, 해당 product의 멤버 변수를 Getter로 가져와서 반환해준다.

addProduct

ProductDto로 Product에 입력해줄 값들과 해당 Product를 판매하는 Seller의 id를 입력받고,
Setter로 Product의 멤버 변수값들을 다 넣어준 후에 productRepository로 객체를 저장하였다.

deleteProduct

productId를 입력받아 해당 ID에 해당되는 Product를 삭제한다..
근데 여기서 id에 해당되는 값이 없는 경우에 대한 예외처리를 해야됐던거같은데 못했다...이거 또한 지금 쓰면서 생각남!
다음엔 반영해보자^^;

updateProduct

ProductUpdateDto로 업데이트할 Product의 멤버 변수값들과 해당 Product의 id를 입력받는다.
후에 각각의 멤버 변수 값이 존재하는 경우를 각각 확인하여 하나하나 새로 바꿔넣어주었다.

근데 뭔가 비효율적이라는 생각이 들었다,, 전부 똑같이 NULL인지 여부를 확인하는 과정이 뭔가 반복적인데 흠 반복문으로 처리할 수 있지 않았을까? 아직 Java를 너무 못다루는 것같다 다음 개발 수업 일지에 Java가 나올텐데 그 때 다시 돌아와서 확인해보면 좋을 것같다!

화이팅화이팅!!

profile
백엔드 개발은 취미인 AI 개발자🥹

0개의 댓글