Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Product crud #45

Merged
merged 21 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
000fca6
feat: Product CRUD 기능 추가
wintiger98 Apr 4, 2024
eb53246
Merge branch 'main' of https://github.com/SSapingMall/backend into pr…
wintiger98 Apr 7, 2024
e556ae5
Refactor : Controller와 Service 레이어간 관심사 분리
wintiger98 Apr 7, 2024
ec32a2d
Test : ProductService Test 코드 작성
wintiger98 Apr 7, 2024
3575602
Feat : 사용자 정의 예외 처리(Product Not found exception) 추가
wintiger98 Apr 7, 2024
24db68f
Merge branch 'main' of https://github.com/SSapingMall/backend into pr…
wintiger98 Apr 10, 2024
ab0dc78
🩹 Fix : 컨벤션 규칙 적용 및 어노테이션 사용 추가
wintiger98 Apr 10, 2024
7b2ecc3
:zap: [Refactor] 성능개선을 위해 ModelMapper -> MapStruct 방식으로 변경
wintiger98 Apr 14, 2024
e4494f8
Merge branch 'main' of https://github.com/SSapingMall/backend into pr…
wintiger98 Apr 23, 2024
8bc1cb1
Merge branch 'main' of https://github.com/SSapingMall/backend into pr…
wintiger98 Apr 23, 2024
9a47e92
:sparkles: ddl-auto 수정
wintiger98 Apr 23, 2024
fd09bfa
:sparkles: 날짜 관련 필드 자동 채우기를 위한 어노테이션 추가
wintiger98 Apr 23, 2024
138e9f7
:sparkles: 날짜 관련 필드 자동 채우기를 위한 어노테이션 추가
wintiger98 Apr 23, 2024
b9c540c
:art: 안 쓰는 어노테이션 삭제
wintiger98 Apr 23, 2024
c5b546b
:art: controller 리턴 방식 팀원과 통일
wintiger98 Apr 23, 2024
6e92bf0
:art: int -> Long 형 변환
wintiger98 Apr 23, 2024
fc165be
:art: 안 쓰는 속성 제거
wintiger98 Apr 23, 2024
da6af3f
:sparkles: GlobalHandler에 UserNotFound Exception 추가
wintiger98 Apr 23, 2024
585a845
:sparkles: insert, update 안 되는 이슈 해결
wintiger98 Apr 23, 2024
312d0b9
:sparkles: insert, update 안 되는 이슈 해결로 인한 테스트 수정
wintiger98 Apr 23, 2024
8d6a8e2
:art: 안 쓰는 커밋 제거
wintiger98 Apr 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.ssafy.springbootapi.domain.product.api;

import java.util.List;

import com.ssafy.springbootapi.domain.product.application.ProductService;
import com.ssafy.springbootapi.domain.product.dto.ProductInput;
import com.ssafy.springbootapi.domain.product.dto.ProductListOutput;
import com.ssafy.springbootapi.domain.product.dto.ProductOutput;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@Tag(name = "Product", description = "Product 관련 API 입니다.")
@RestController
@RequiredArgsConstructor
@CrossOrigin
kkho9654 marked this conversation as resolved.
Show resolved Hide resolved
@RequestMapping("/api/v1/products")
public class ProductController {
private final ProductService productService;

@Operation(summary = "모든 제품 조회")
@GetMapping("")
public ResponseEntity<List<ProductListOutput>> getAllProducts() {
List<ProductListOutput> products = productService.getAllProducts();
return new ResponseEntity<>(products, HttpStatus.OK);
}

@Operation(summary = "제품 ID로 조회")
@GetMapping("/{id}")
public ResponseEntity<ProductOutput> getProductById(@PathVariable Long id) {
ProductOutput product = productService.getProductById(id);
return new ResponseEntity<>(product, HttpStatus.OK);
}

@Operation(summary = "새 제품 추가")
@PostMapping("")
public ResponseEntity<ProductOutput> createProduct(@RequestBody ProductInput productInput) {
// 서비스 레이어를 통해 비즈니스 로직 처리
ProductOutput newProduct = productService.insertProduct(productInput);

// 생성된 Product 객체 반환
return new ResponseEntity<>(newProduct, HttpStatus.CREATED);
}

@Operation(summary = "제품 정보 업데이트")
@PutMapping("/{id}")
public ResponseEntity<ProductOutput> updateProduct(@PathVariable Long id, @RequestBody ProductInput productDetails) {
// 서비스 레이어를 통해 비즈니스 로직 처리
ProductOutput updatedProduct = productService.updateProduct(id, productDetails);

// 업데이트된 Product 객체 반환
return new ResponseEntity<>(updatedProduct, HttpStatus.OK);
}
@Operation(summary = "제품 삭제")
@DeleteMapping("/{id}")
public ResponseEntity<ProductOutput> deleteProduct(@PathVariable Long id) {
ProductOutput product = productService.removeProduct(id);
return new ResponseEntity<>(product, HttpStatus.NO_CONTENT);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.ssafy.springbootapi.domain.product.application;

import java.util.List;
import java.util.stream.Collectors;

import com.ssafy.springbootapi.domain.product.dao.ProductRepository;
import com.ssafy.springbootapi.domain.product.domain.Product;
import com.ssafy.springbootapi.domain.product.dto.ProductInput;
import com.ssafy.springbootapi.domain.product.dto.ProductListOutput;
import com.ssafy.springbootapi.domain.product.dto.ProductOutput;
import com.ssafy.springbootapi.domain.product.exception.NotFoundProductException;
import lombok.RequiredArgsConstructor;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class ProductService {
private final ProductRepository productRepository;
private final ModelMapper modelMapper;

public List<ProductListOutput> getAllProducts() {
List<Product> products = productRepository.findAll();
return products.stream()
.map(product -> modelMapper.map(product, ProductListOutput.class))
.collect(Collectors.toList());
}

public ProductOutput getProductById(Long id) {
Product product = findProductByIdOrThrow(id);
return modelMapper.map(product, ProductOutput.class);
}

public ProductOutput insertProduct(ProductInput productInput) {
Product product = modelMapper.map(productInput, Product.class);
return modelMapper.map(productRepository.save(product), ProductOutput.class);
}

public ProductOutput removeProduct(Long id) {
Product toRemove = findProductByIdOrThrow(id);
productRepository.delete(toRemove);
return modelMapper.map(toRemove, ProductOutput.class);
}


public ProductOutput updateProduct(Long id, ProductInput productInput) {
Product productToUpdate = findProductByIdOrThrow(id);

// 업데이트 로직
productToUpdate.setCategory(productInput.getCategory());
productToUpdate.setStock(productInput.getStock());
productToUpdate.setImageUrl(productInput.getImageUrl());
kkho9654 marked this conversation as resolved.
Show resolved Hide resolved

productRepository.save(productToUpdate);

return modelMapper.map(productToUpdate, ProductOutput.class);
}

// ProductService 클래스 내부에 private 메소드 추가
private Product findProductByIdOrThrow(Long id) {
return productRepository.findById(id)
.orElseThrow(() -> new NotFoundProductException("Product not found with id: " + id));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ssafy.springbootapi.domain.product.dao;

import com.ssafy.springbootapi.domain.product.domain.Product;
import org.springframework.data.jpa.repository.JpaRepository;

public interface ProductRepository extends JpaRepository<Product, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.ssafy.springbootapi.domain.product.domain;


import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import jakarta.persistence.*;
import lombok.*;

import java.time.LocalDateTime;

@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@Table(name = "product")
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@Builder
public class Product {
@Id
@GeneratedValue
@Column(name = "id", unique = true)
private Long id;
@Column(name = "image_url")
private String imageUrl;
@Column(name = "created_at")
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "price", nullable = false)
private int price;
private String description;
private int category;
private int stock;
// @ManyToOne
// @JoinColumn(name = "user_id")
// private User user;
@Column(name = "user_id")
private int userId;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.ssafy.springbootapi.domain.product.dto;

import lombok.*;
import lombok.experimental.SuperBuilder;

@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
@SuperBuilder
public class ProductBase {
private String imageUrl;
private String name;
private int price;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.ssafy.springbootapi.domain.product.dto;

import lombok.*;
import lombok.experimental.SuperBuilder;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@SuperBuilder
public class ProductInput extends ProductBase {
private String description;
private int category;
private int stock;
private int user_id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.ssafy.springbootapi.domain.product.dto;

import lombok.*;
import lombok.experimental.SuperBuilder;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@SuperBuilder
public class ProductListOutput extends ProductBase{
private Long id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.ssafy.springbootapi.domain.product.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

@NoArgsConstructor
@AllArgsConstructor
@Getter
@SuperBuilder
public class ProductOutput extends ProductListOutput{
private String description;
private int category;
private int stock;
private int user_id;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.ssafy.springbootapi.domain.product.exception;

public class NotFoundProductException extends RuntimeException{
public NotFoundProductException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.ssafy.springbootapi.global.error;

// import com.ssafy.springbootapi.domain.product.exception.NotFoundProductException;
import com.ssafy.springbootapi.domain.product.exception.NotFoundProductException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
Expand All @@ -9,8 +9,8 @@
@ControllerAdvice
public class GlobalExceptionHandler { // Domain별 Exception 핸들러

// @ExceptionHandler(NotFoundProductException.class)
// public ResponseEntity<?> handleNotFoundProductException(NotFoundProductException ex) {
// return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
// }
@ExceptionHandler(NotFoundProductException.class)
public ResponseEntity<?> handleNotFoundProductException(NotFoundProductException ex) {
return new ResponseEntity<>(ex.getMessage(), HttpStatus.NOT_FOUND);
}
}
Loading