Skip to content

Commit

Permalink
Merge pull request #25 from taco-official/KL-68/상품-정보-수정-api-구현
Browse files Browse the repository at this point in the history
feat(KL-68): update Product API
  • Loading branch information
ohhamma authored Aug 1, 2024
2 parents ed6e70f + 89a1950 commit 05b6ece
Show file tree
Hide file tree
Showing 19 changed files with 796 additions and 190 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -11,8 +12,10 @@

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import taco.klkl.domain.product.dto.request.ProductCreateRequestDto;
import taco.klkl.domain.product.dto.request.ProductUpdateRequestDto;
import taco.klkl.domain.product.dto.response.ProductDetailResponseDto;
import taco.klkl.domain.product.service.ProductService;

Expand All @@ -33,8 +36,20 @@ public ResponseEntity<ProductDetailResponseDto> getProductInfoById(@PathVariable

@PostMapping
@Operation(summary = "상품 등록", description = "상품을 등록합니다.")
public ResponseEntity<ProductDetailResponseDto> createProduct(@RequestBody ProductCreateRequestDto createRequest) {
public ResponseEntity<ProductDetailResponseDto> createProduct(
@Valid @RequestBody ProductCreateRequestDto createRequest
) {
ProductDetailResponseDto productDto = productService.createProduct(createRequest);
return ResponseEntity.status(HttpStatus.CREATED).body(productDto);
}

@PatchMapping("/{id}")
@Operation(summary = "상품 정보 수정", description = "상품 정보를 수정합니다.")
public ResponseEntity<ProductDetailResponseDto> updateProduct(
@PathVariable Long id,
@Valid @RequestBody ProductUpdateRequestDto updateRequest
) {
ProductDetailResponseDto productDto = productService.updateProduct(id, updateRequest);
return ResponseEntity.ok().body(productDto);
}
}
69 changes: 61 additions & 8 deletions src/main/java/taco/klkl/domain/product/domain/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import taco.klkl.domain.product.dto.request.ProductUpdateRequestDto;
import taco.klkl.domain.user.domain.User;
import taco.klkl.global.common.constants.DefaultConstants;
import taco.klkl.global.common.constants.ProductConstants;
Expand All @@ -35,34 +36,62 @@ public class Product {
@JoinColumn(name = "user_id")
private User user;

@Column(name = "name", length = 100, nullable = false)
@Column(
name = "name",
length = ProductConstants.NAME_MAX_LENGTH,
nullable = false
)
private String name;

@Column(name = "description", length = 2000, nullable = false)
@Column(
name = "description",
length = ProductConstants.DESCRIPTION_MAX_LENGTH,
nullable = false
)
private String description;

@Column(name = "address", length = 100)
@Column(
name = "address",
length = ProductConstants.ADDRESS_MAX_LENGTH,
nullable = false
)
@ColumnDefault(DefaultConstants.DEFAULT_STRING)
private String address;

@Column(name = "like_count", nullable = false)
@Column(
name = "like_count",
nullable = false
)
@ColumnDefault(DefaultConstants.DEFAULT_INT_STRING)
private Integer likeCount;

@Column(name = "created_at", nullable = false, updatable = false)
@Column(
name = "created_at",
nullable = false,
updatable = false
)
private LocalDateTime createdAt;

@Column(name = "price")
@ColumnDefault(DefaultConstants.DEFAULT_INT_STRING)
private Integer price;

@Column(name = "city_id", nullable = false)
@Column(
name = "city_id",
nullable = false
)
private Long cityId;

@Column(name = "subcategory_id", nullable = false)
@Column(
name = "subcategory_id",
nullable = false
)
private Long subcategoryId;

@Column(name = "currency_id", nullable = false)
@Column(
name = "currency_id",
nullable = false
)
private Long currencyId;

@PrePersist
Expand Down Expand Up @@ -109,4 +138,28 @@ public static Product of(
) {
return new Product(user, name, description, address, price, cityId, subcategoryId, currencyId);
}

public void update(ProductUpdateRequestDto updateDto) {
if (updateDto.name() != null) {
this.name = updateDto.name();
}
if (updateDto.description() != null) {
this.description = updateDto.description();
}
if (updateDto.address() != null) {
this.address = updateDto.address();
}
if (updateDto.price() != null) {
this.price = updateDto.price();
}
if (updateDto.cityId() != null) {
this.cityId = updateDto.cityId();
}
if (updateDto.subcategoryId() != null) {
this.subcategoryId = updateDto.subcategoryId();
}
if (updateDto.currencyId() != null) {
this.currencyId = updateDto.currencyId();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,47 @@
package taco.klkl.domain.product.dto.request;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
import taco.klkl.global.common.constants.ProductConstants;
import taco.klkl.global.common.constants.ProductValidationMessages;

/**
* TODO: 상품필터속성 추가 해야함 (상품필터속성 테이블 개발 후)
* TODO: 상품 컨트롤러에서 필터 서비스를 이용해서 조합 하는게 괜찮아 보입니다.
* @param name
* @param description
* @param address
* @param price
* @param cityId
* @param subcategoryId
* @param currencyId
* @param address
* @param price
*/
public record ProductCreateRequestDto(
@NotNull(message = "상품명은 필수 항목입니다.") String name,
@NotNull(message = "상품 설명은 필수 항목입니다.") String description,
@NotNull(message = "도시 ID는 필수 항목입니다.") Long cityId,
@NotNull(message = "상품 소분류 ID은 필수 항목입니다.") Long subcategoryId,
@NotNull(message = "통화 ID는 필수 항목입니다.") Long currencyId,
@NotNull(message = ProductValidationMessages.NAME_NOT_NULL)
@NotBlank(message = ProductValidationMessages.NAME_NOT_BLANK)
@Size(max = ProductConstants.NAME_MAX_LENGTH, message = ProductValidationMessages.NAME_SIZE)
String name,

@NotNull(message = ProductValidationMessages.DESCRIPTION_NOT_NULL)
@NotBlank(message = ProductValidationMessages.DESCRIPTION_NOT_BLANK)
@Size(max = ProductConstants.DESCRIPTION_MAX_LENGTH, message = ProductValidationMessages.DESCRIPTION_SIZE)
String description,

@Size(max = ProductConstants.ADDRESS_MAX_LENGTH, message = ProductValidationMessages.ADDRESS_SIZE)
String address,
Integer price

@PositiveOrZero(message = ProductValidationMessages.PRICE_POSITIVE_OR_ZERO)
Integer price,

@NotNull(message = ProductValidationMessages.CITY_ID_NOT_NULL)
Long cityId,

@NotNull(message = ProductValidationMessages.SUBCATEGORY_ID_NOT_NULL)
Long subcategoryId,

@NotNull(message = ProductValidationMessages.CURRENCY_ID_NOT_NULL)
Long currencyId
) {
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,28 @@
package taco.klkl.domain.product.dto.request;

import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
import taco.klkl.global.common.constants.ProductConstants;
import taco.klkl.global.common.constants.ProductValidationMessages;

public record ProductUpdateRequestDto(
@Size(max = ProductConstants.NAME_MAX_LENGTH, message = ProductValidationMessages.NAME_SIZE)
String name,

@Size(max = ProductConstants.DESCRIPTION_MAX_LENGTH, message = ProductValidationMessages.DESCRIPTION_SIZE)
String description,

@Size(max = ProductConstants.ADDRESS_MAX_LENGTH, message = ProductValidationMessages.ADDRESS_SIZE)
String address,

@PositiveOrZero(message = ProductValidationMessages.PRICE_POSITIVE_OR_ZERO)
Integer price,

Long cityId,

Long subcategoryId,
Long currencyId,
String address,
Integer price

Long currencyId

) {
}
18 changes: 14 additions & 4 deletions src/main/java/taco/klkl/domain/product/service/ProductService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,31 +7,42 @@
import taco.klkl.domain.product.dao.ProductRepository;
import taco.klkl.domain.product.domain.Product;
import taco.klkl.domain.product.dto.request.ProductCreateRequestDto;
import taco.klkl.domain.product.dto.request.ProductUpdateRequestDto;
import taco.klkl.domain.product.dto.response.ProductDetailResponseDto;
import taco.klkl.domain.product.exception.ProductNotFoundException;
import taco.klkl.domain.user.domain.User;
import taco.klkl.global.common.constants.ProductConstants;
import taco.klkl.global.util.UserUtil;

@Service
@Transactional
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ProductService {

private final ProductRepository productRepository;
private final UserUtil userUtil;

public ProductDetailResponseDto getProductInfoById(Long id) {
Product product = productRepository.findById(id)
public ProductDetailResponseDto getProductInfoById(final Long id) {
final Product product = productRepository.findById(id)
.orElseThrow(ProductNotFoundException::new);
return ProductDetailResponseDto.from(product);
}

@Transactional
public ProductDetailResponseDto createProduct(final ProductCreateRequestDto productDto) {
final Product product = createProductEntity(productDto);
productRepository.save(product);
return ProductDetailResponseDto.from(product);
}

@Transactional
public ProductDetailResponseDto updateProduct(final Long id, final ProductUpdateRequestDto productDto) {
final Product product = productRepository.findById(id)
.orElseThrow(ProductNotFoundException::new);
product.update(productDto);
return ProductDetailResponseDto.from(product);
}

private Product createProductEntity(final ProductCreateRequestDto productDto) {
final User user = userUtil.findTestUser();
return Product.of(
Expand All @@ -45,5 +56,4 @@ private Product createProductEntity(final ProductCreateRequestDto productDto) {
productDto.currencyId()
);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package taco.klkl.global.common.constants;

public class DefaultConstants {
public final class DefaultConstants {

public static final String DEFAULT_STRING = "'N/A'";
public static final String DEFAULT_INT_STRING = "0";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package taco.klkl.global.common.constants;

public class ProductConstants {
public final class ProductConstants {

public static final int DEFAULT_PRICE = 0;
public static final int DEFAULT_LIKE_COUNT = 0;
public static final String DEFAULT_ADDRESS = "N/A";

public static final int NAME_MAX_LENGTH = 100;
public static final int DESCRIPTION_MAX_LENGTH = 2000;
public static final int ADDRESS_MAX_LENGTH = 100;

private ProductConstants() {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package taco.klkl.global.common.constants;

public final class ProductValidationMessages {

public static final String NAME_NOT_NULL = "상품명은 필수 항목입니다.";
public static final String NAME_NOT_BLANK = "상품명은 비어있을 수 없습니다.";
public static final String NAME_SIZE = "상품명은 100자 이하여야 합니다.";

public static final String DESCRIPTION_NOT_NULL = "상품 설명은 필수 항목입니다.";
public static final String DESCRIPTION_NOT_BLANK = "상품 설명은 비어있을 수 없습니다.";
public static final String DESCRIPTION_SIZE = "상품 설명은 2000자 이하여야 합니다.";

public static final String ADDRESS_SIZE = "주소는 100자 이하여야 합니다.";

public static final String PRICE_POSITIVE_OR_ZERO = "가격은 0 이상이어야 합니다.";

public static final String CITY_ID_NOT_NULL = "도시 ID는 필수 항목입니다.";
public static final String SUBCATEGORY_ID_NOT_NULL = "상품 소분류 ID는 필수 항목입니다.";
public static final String CURRENCY_ID_NOT_NULL = "통화 ID는 필수 항목입니다.";

private ProductValidationMessages() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import taco.klkl.domain.user.domain.User;
import taco.klkl.global.common.enums.Gender;

public class UserConstants {
public final class UserConstants {

public static final String TEST_USER_NAME = "testUser";
public static final User TEST_USER = User.of(
Expand Down
Loading

0 comments on commit 05b6ece

Please sign in to comment.