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

feat : 상품 등록 , 상품 단일 조회 , 상품 옵션 도메인 수정 #10

Merged
merged 1 commit into from
Nov 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -36,8 +36,7 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter {

// 필터 건너뛰는 api url (사용자 인증 미필요 api)
private static final List<String> EXCLUDED_URLS = Arrays.asList(
"/login/oauth2/kakao", // 로그인
"/login/oauth2/**"
"/login/oauth2/kakao" // 로그인
);

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class OrderReadResponseDto {
public static OrderReadResponseDto from(Orders order) {
return new OrderReadResponseDto(
order.getOrderId(),
order.getProductOption().getTitle(),
order.getProductOption().getOptionName(),
order.getOrderState().name(),
order.getOrderStatus().name(),
order.getRequest(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public Orders(String request , User sellerUser , User buyerUser , Product produc
}

public static Orders createOrder(String request, User seller, User buyer, Product product, ProductOption productOption, Long orderCount) {
Long payAmount = (product.getPrice() + productOption.getSubPrice()) * orderCount; // 상품 가격 계산
Long payAmount = (product.getPrice() + productOption.getOptionPrice()) * orderCount; // 상품 가격 계산
return new Orders(request, seller, buyer, product, productOption, orderCount, payAmount);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.ecyce.karma.domain.product.controller;

import com.ecyce.karma.domain.auth.customAnnotation.AuthUser;
import com.ecyce.karma.domain.product.dto.response.ProductDetailResponse;
import com.ecyce.karma.domain.product.dto.request.ProductRequestDto;
import com.ecyce.karma.domain.product.service.ProductService;
import com.ecyce.karma.domain.user.entity.User;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;


@RestController
@RequestMapping("/product")
@RequiredArgsConstructor
public class ProductController {

private final ProductService productService;

/* 상품 등록 , 현재 사진 업로드하는 코드는 포함되어 있지 않음 */
@PostMapping
public ResponseEntity<ProductDetailResponse> registerProduct(@AuthUser User user , @RequestBody ProductRequestDto dto){
ProductDetailResponse response = productService.registerProduct(user , dto);
return ResponseEntity.status(HttpStatus.CREATED)
.body(response);
}

/* 단일 상품 조회 (상세)*/
@GetMapping("/{productId}")
public ResponseEntity<ProductDetailResponse> getProductDetail(@PathVariable("productId") Long productId){
ProductDetailResponse dto = productService.getProductDetail(productId);
return ResponseEntity.status(HttpStatus.OK)
.body(dto);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.ecyce.karma.domain.product.dto.request;

import com.ecyce.karma.domain.product.entity.Product;
import com.ecyce.karma.domain.product.entity.ProductOption;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OptionRequestDto {

private String optionName;
private int optionPrice;

public OptionRequestDto(String optionName , int optionPrice){
this.optionName = optionName;
this.optionPrice = optionPrice;
}

public static ProductOption toEntity(Product product , OptionRequestDto requestDto){
return ProductOption.builder()
.optionName(requestDto.getOptionName())
.optionPrice(requestDto.getOptionPrice())
.product(product)
.build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.ecyce.karma.domain.product.dto.request;

import com.ecyce.karma.domain.product.entity.Product;
import com.ecyce.karma.domain.product.entity.ProductState;
import com.ecyce.karma.domain.user.entity.User;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ProductRequestDto {
private String productName;
private int price ;
private String content;
private int duration;
private ProductState productState;
private List<OptionRequestDto> option;

public ProductRequestDto(String productName , int price , String content , int duration , ProductState productState ,List<OptionRequestDto> optionRequest){
this.productName = productName;
this.price = price;
this.content = content;
this.duration = duration;
this.productState = productState;
this.option = optionRequest;
}

public static Product toEntity(User user , ProductRequestDto requestDto){

return Product.builder()
.user(user)
.productName(requestDto.getProductName())
.content(requestDto.getContent())
.price(requestDto.getPrice())
.duration(requestDto.getDuration())
.rating(0)
.productState(ProductState.ON_SALE) // 처음에는 판매중 상태
.build();
}




}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.ecyce.karma.domain.product.dto.response;

import com.ecyce.karma.domain.product.dto.request.OptionRequestDto;
import com.ecyce.karma.domain.product.entity.ProductOption;
import org.springframework.security.access.method.P;

public record OptionResponseDto(
Long optionId,
String optionName,
int optionPrice
) {
public static OptionResponseDto from(ProductOption productOption){
return new OptionResponseDto(
productOption.getOptionId(),
productOption.getOptionName(),
productOption.getOptionPrice()
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.ecyce.karma.domain.product.dto.response;

import com.ecyce.karma.domain.product.entity.Product;
import com.ecyce.karma.domain.product.entity.ProductOption;
import com.ecyce.karma.domain.product.entity.ProductState;

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

public record ProductDetailResponse(
Long productId, // 상품 Id
Long userId, // 판매자 Id
String productName, // 상품 이름
int price, // 가격
String content, // 제품 소개
int duration, // 소요 기간
Integer rating, // 평점
ProductState productState, // 제품 공개 여부

List<OptionResponseDto> options

) {
public static ProductDetailResponse from(Product product){
return new ProductDetailResponse(
product.getProductId(),
product.getUser().getUserId(),
product.getProductName(),
product.getPrice(),
product.getContent(),
product.getDuration(),
product.getRating(),
product.getProductState(),
product.getOptions().stream()
.map(OptionResponseDto :: from )
.collect(Collectors.toList())
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,16 @@ public class Product {
private String productName;

@Column(nullable = false)
private Long price;
private int price;

@Column(nullable = false)
private String content;

@Column(nullable = false)
private Long duration;
private int duration;

@Column(nullable = false)
private Long rating;
@Column
private Integer rating; // 점수는 아무도 리뷰를 쓰지 않은 경우 , 없을 수 있음

@Enumerated(EnumType.STRING)
@Column(nullable = false)
Expand All @@ -53,7 +53,7 @@ public class Product {


@Builder
public Product(User user , String productName , Long price , String content , Long duration , Long rating , ProductState productState){
public Product(User user , String productName , int price , String content , int duration , int rating , ProductState productState){
this.user = user;
this.productName = productName;
this.price = price;
Expand All @@ -63,4 +63,8 @@ public Product(User user , String productName , Long price , String content , Lo
this.productState = productState;
}





}
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,24 @@ public class ProductOption {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "productOptionId")
private Long id;
private Long optionId;

@Column(nullable = false)
private String title;
private String optionName;

@Column(nullable = false)
private Long subPrice; // 옵션 추가 금액
private int optionPrice; // 옵션 추가 금액

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "productId", nullable = false)
private Product product;

@Builder
public ProductOption(String title, Product product, Long price) {
this.title = title;
this.subPrice = price;
public ProductOption(String optionName, Product product, int optionPrice) {
this.optionName = optionName;
this.optionPrice = optionPrice;
this.product = product;
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.ecyce.karma.domain.product.service;

import com.ecyce.karma.domain.product.dto.request.OptionRequestDto;
import com.ecyce.karma.domain.product.dto.response.ProductDetailResponse;
import com.ecyce.karma.domain.product.dto.request.ProductRequestDto;
import com.ecyce.karma.domain.product.entity.Product;
import com.ecyce.karma.domain.product.entity.ProductOption;
import com.ecyce.karma.domain.product.repository.ProductOptionRepository;
import com.ecyce.karma.domain.product.repository.ProductRepository;
import com.ecyce.karma.domain.user.entity.User;
import com.ecyce.karma.global.exception.CustomException;
import com.ecyce.karma.global.exception.ErrorCode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Slf4j
@Service
@Transactional
@RequiredArgsConstructor
public class ProductService {

private final ProductRepository productRepository;
private final ProductOptionRepository productOptionRepository;

/* 제품 상세 조회 */
public ProductDetailResponse getProductDetail(Long productId) {
Product product = productRepository.findById(productId)
.orElseThrow(() -> new CustomException(ErrorCode.PRODUCT_NOT_FOUND));

return ProductDetailResponse.from(product);
}

/* 제품 등록 */
public ProductDetailResponse registerProduct(User user, ProductRequestDto dto) {
Product product = ProductRequestDto.toEntity(user , dto);
productRepository.save(product);
// 옵션이 있다면
if (dto.getOption() != null) {
for (OptionRequestDto optionDto : dto.getOption()) {
ProductOption productOption = optionDto.toEntity(product , optionDto);
productOptionRepository.save(productOption);
}
}

return ProductDetailResponse.from(product);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ public class SecurityConfig {
// 인증이 필요없는 URL 패턴 목록을 정의
private static final String[] AUTH_WHITELIST = {
"/login/oauth2/kakao", // 로그인
"/login/**",
"/product/{productId}", // 상품 상세 조회
"/product", // 전체 상품 조회
"/product/categorycode/*" // 카테고리별 조회
};

// cors 설정
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ public enum ErrorCode {
FAIL_AUTHENTICATION(HttpStatus.UNAUTHORIZED, "로그인 후 이용 가능합니다."), // 로그인X 유저의 요청 OR 토큰 불일치
TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "토큰이 만료되었습니다."), // 엑세스 토큰 만료
FAIL_AUTHORIZATION(HttpStatus.FORBIDDEN, "권한이 없는 요청입니다."), // 권한 없는 요청
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "INTERNAL SERVER ERROR");// 예상치 못한 에러
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "INTERNAL SERVER ERROR"),// 예상치 못한 에러

// product
PRODUCT_NOT_FOUND(HttpStatus.NOT_FOUND , "해당하는 제품을 찾을 수 없습니다.");

private final HttpStatus status;
private final String message;
Expand Down