Skip to content

Commit aaf0656

Browse files
committed
[250403] Product : 상품기능 최초 커밋
1 parent 676c608 commit aaf0656

File tree

17 files changed

+707
-0
lines changed

17 files changed

+707
-0
lines changed

build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,17 @@ dependencies {
2626
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
2727
implementation 'org.springframework.boot:spring-boot-starter-jdbc'
2828
implementation 'org.springframework.boot:spring-boot-starter-web'
29+
implementation 'io.jsonwebtoken:jjwt-api:0.12.6'
30+
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.6'
31+
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.6' // JSON 처리를 위한 의존성
2932
compileOnly 'org.projectlombok:lombok'
33+
testCompileOnly 'org.projectlombok:lombok'
3034
developmentOnly 'org.springframework.boot:spring-boot-devtools'
3135
runtimeOnly 'com.mysql:mysql-connector-j'
3236
annotationProcessor 'org.projectlombok:lombok'
3337
testImplementation 'org.springframework.boot:spring-boot-starter-test'
3438
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
39+
implementation 'com.google.code.gson:gson'
3540
}
3641

3742
tasks.named('test') {
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.ecommerce.product.dto.request;
2+
3+
import lombok.Getter;
4+
5+
@Getter
6+
public class ProductDeleteRequest {
7+
8+
private Long productId;
9+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.ecommerce.product.dto.request;
2+
3+
import lombok.Getter;
4+
5+
import java.math.BigDecimal;
6+
import java.util.List;
7+
8+
@Getter
9+
public class ProductModifyRequest {
10+
11+
private String name;
12+
13+
private String description;
14+
15+
private BigDecimal price;
16+
17+
private int stockQuantity;
18+
19+
private List<String> imageUrls;
20+
21+
private String status;
22+
23+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.ecommerce.product.dto.request;
2+
3+
import lombok.Getter;
4+
5+
import java.math.BigDecimal;
6+
import java.util.List;
7+
8+
@Getter
9+
public class ProductRegisterRequest {
10+
11+
private String name;
12+
13+
private String category;
14+
15+
private String description;
16+
17+
private BigDecimal price;
18+
19+
private int stockQuantity;
20+
21+
private List<String> imageUrls;
22+
23+
private String status;
24+
25+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.ecommerce.product.dto.response;
2+
3+
import com.ecommerce.product.productEntity.Product;
4+
import com.ecommerce.product.productEntity.ProductImage;
5+
import lombok.Builder;
6+
7+
import java.math.BigDecimal;
8+
import java.util.List;
9+
import java.util.stream.Collectors;
10+
11+
@Builder
12+
public class ProductResponse {
13+
14+
private Long id;
15+
16+
private String name;
17+
18+
private BigDecimal price;
19+
20+
private String description;
21+
22+
private List<String> imageUrls;
23+
24+
public static ProductResponse from(Product product) {
25+
return new ProductResponse(
26+
product.getId()
27+
, product.getName()
28+
, product.getPrice()
29+
, product.getDescription()
30+
, product.getImageList().stream().map(ProductImage::getImageUrl).collect(Collectors.toList())
31+
);
32+
}
33+
34+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.ecommerce.product.dto.search;
2+
3+
import lombok.Builder;
4+
import lombok.Getter;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.data.domain.Pageable;
7+
8+
import java.math.BigDecimal;
9+
10+
@Getter
11+
@Builder
12+
@RequiredArgsConstructor
13+
public class DetailedSearchCondition {
14+
15+
private String name;
16+
17+
private Long categoryId;
18+
19+
private BigDecimal minPrice;
20+
21+
private BigDecimal maxPrice;
22+
23+
private Pageable pageable;
24+
25+
public static DetailedSearchCondition of(String name, Long categoryId, BigDecimal minPrice, BigDecimal maxPrice, Pageable pageable) {
26+
return DetailedSearchCondition.builder()
27+
.name(name)
28+
.categoryId(categoryId)
29+
.minPrice(minPrice)
30+
.maxPrice(maxPrice)
31+
.pageable(pageable)
32+
.build();
33+
34+
}
35+
36+
}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
package com.ecommerce.product.productController;
2+
3+
import com.ecommerce.product.dto.request.ProductDeleteRequest;
4+
import com.ecommerce.product.dto.request.ProductModifyRequest;
5+
import com.ecommerce.product.dto.request.ProductRegisterRequest;
6+
import com.ecommerce.product.dto.response.ProductResponse;
7+
import com.ecommerce.product.dto.search.DetailedSearchCondition;
8+
import com.ecommerce.product.productEntity.Product;
9+
import com.ecommerce.product.productService.ProductService;
10+
import lombok.RequiredArgsConstructor;
11+
import org.springframework.data.domain.Page;
12+
import org.springframework.data.domain.Pageable;
13+
import org.springframework.data.web.PageableDefault;
14+
import org.springframework.http.ResponseEntity;
15+
import org.springframework.validation.annotation.Validated;
16+
import org.springframework.web.bind.annotation.*;
17+
18+
import java.math.BigDecimal;
19+
import java.nio.file.AccessDeniedException;
20+
import java.util.List;
21+
22+
@RestController
23+
@RequiredArgsConstructor
24+
@RequestMapping("/product")
25+
public class productController {
26+
27+
private final ProductService productService;
28+
29+
30+
/**
31+
* 판매자: 전체 상품 조회
32+
* @params
33+
* auth : jwt 토큰
34+
**/
35+
@GetMapping("/seller/getProducts")
36+
public ResponseEntity<List<ProductResponse>> getSellerProducts(@RequestHeader("Authorization") String auth) {
37+
String token = auth.replace("Bearer ", "");
38+
String email = "";
39+
Long sellerId = Long.valueOf("");
40+
List<ProductResponse> products = productService.getSellerProducts(sellerId);
41+
return ResponseEntity.ok(products);
42+
}
43+
44+
45+
/**
46+
* 판매자: 상품목록 조회
47+
* @params
48+
* auth : jwt 토큰
49+
**/
50+
@GetMapping("/seller/getProducts")
51+
public ResponseEntity<List<ProductResponse>> getSellerProductsByStatus(@RequestHeader("Authorization") String auth, String status) {
52+
String token = auth.replace("Bearer ", "");
53+
String email = "";
54+
Long sellerId = Long.valueOf("");
55+
List<ProductResponse> products = productService.getSellerProducts(sellerId, status);
56+
return ResponseEntity.ok(products);
57+
}
58+
59+
60+
/**
61+
* 판매자: 상품 등록
62+
* @params
63+
* auth : jwt 토큰
64+
* request : 상품 등록
65+
**/
66+
@PostMapping("/register")
67+
public ResponseEntity<?> registerProduct(@RequestHeader("Authorization") String auth, @RequestBody @Validated ProductRegisterRequest request) {
68+
String token = auth.replace("Bearer ", "");
69+
Long sellerId = Long.valueOf("");
70+
Product product = productService.registerProduct(sellerId, request);
71+
return ResponseEntity.ok(product);
72+
}
73+
74+
75+
/**
76+
* 판매자: 상품 정보 변경
77+
* @params
78+
* auth : jwt 토큰
79+
* request : 상품 변경 사항
80+
**/
81+
@PostMapping("/modify/{productId}")
82+
public Product modifyProduct(@RequestHeader("Authorization") String auth, @Validated ProductModifyRequest request) throws AccessDeniedException {
83+
String token = auth.replace("Bearer ", "");
84+
Long sellerId = Long.valueOf("");
85+
Long productId = Long.valueOf("");
86+
return productService.modifyProduct(sellerId, productId, request);
87+
}
88+
89+
90+
/**
91+
* 판매자: 등록된 상품 삭제
92+
* @params
93+
* auth : jwt 토큰
94+
* request : 상품 삭제 대상
95+
**/
96+
@DeleteMapping("/delete/{productId}")
97+
public void deleteProduct(@RequestHeader("Authorization") String auth, @Validated ProductDeleteRequest request) throws AccessDeniedException {
98+
String token = auth.replace("Bearer ", "");
99+
Long sellerId = Long.valueOf("");
100+
productService.deleteProduct(sellerId, request.getProductId());
101+
}
102+
103+
104+
/**
105+
* 구매자: 상품 검색 : 상세정보
106+
* @params
107+
* auth : jwt 토큰
108+
* productId : 상품 id
109+
**/
110+
@GetMapping("/detail/{productId}")
111+
public ResponseEntity<ProductResponse> getProductDetail(@PathVariable Long productId) {
112+
ProductResponse detailedProduct = productService.getProductDetail(productId);
113+
return ResponseEntity.ok(detailedProduct);
114+
}
115+
116+
/**
117+
* 구매자: 상품 검색 : 상세 파라미터
118+
* @params
119+
* auth : jwt 토큰
120+
* name : 상품 이름
121+
* categoryId : 카테고리 id
122+
* minPrice: 최소값
123+
* maxPrice: 최대값
124+
* pageable: 페이징 처리 단위
125+
**/
126+
@GetMapping("/search")
127+
public ResponseEntity<Page<ProductResponse>> searchProducts(
128+
@RequestParam(required = false) String name
129+
, @RequestParam(required = false) Long categoryId
130+
, @RequestParam(required = false) BigDecimal minPrice
131+
, @RequestParam(required = false) BigDecimal maxPrice
132+
, @PageableDefault(size = 20) Pageable pageable
133+
) {
134+
135+
DetailedSearchCondition searchCondition = DetailedSearchCondition.of(name, categoryId, minPrice, maxPrice, pageable);
136+
137+
Page<ProductResponse> searchedProducts = productService.detailSearchProduct(searchCondition);
138+
return ResponseEntity.ok(searchedProducts);
139+
}
140+
141+
142+
}
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package com.ecommerce.product.productEntity;
2+
3+
import com.ecommerce.product.dto.request.ProductRegisterRequest;
4+
import jakarta.persistence.*;
5+
import lombok.*;
6+
7+
import java.math.BigDecimal;
8+
import java.time.LocalDateTime;
9+
import java.util.ArrayList;
10+
import java.util.List;
11+
12+
@Entity
13+
@Table(name = "products")
14+
@Getter
15+
@Setter
16+
@NoArgsConstructor
17+
@RequiredArgsConstructor
18+
@AllArgsConstructor
19+
@Builder
20+
public class Product {
21+
22+
@Id
23+
@GeneratedValue(strategy = GenerationType.IDENTITY)
24+
private long id;
25+
26+
@Column(name = "seller_id", nullable = false)
27+
private Long sellerId;
28+
29+
@Column(nullable = false)
30+
private String name;
31+
32+
@Column(nullable = false)
33+
private BigDecimal price;
34+
35+
@Column(name = "stock_quantity", nullable = false)
36+
private Integer stockQuantity;
37+
38+
@Enumerated(EnumType.STRING)
39+
@Column(nullable = false)
40+
@Builder.Default
41+
private ProductStatus status = ProductStatus.ACTIVE;
42+
43+
private String description;
44+
45+
@OneToMany(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true)
46+
private List<ProductImage> imageList = new ArrayList<>();
47+
48+
@ManyToOne(fetch = FetchType.LAZY)
49+
@JoinColumn(name = "category_id")
50+
private ProductCategory categoryId;
51+
52+
53+
@Column(name = "crea_dt")
54+
private LocalDateTime creaDt;
55+
56+
@Column(name = "updt_dt")
57+
private LocalDateTime updtDt;
58+
59+
public static Product of(Long sellerId, ProductRegisterRequest dto, ProductCategory category) {
60+
return Product.builder()
61+
.sellerId(sellerId)
62+
.name(dto.getName())
63+
.description(dto.getDescription())
64+
.price(dto.getPrice())
65+
.stockQuantity(dto.getStockQuantity())
66+
.categoryId(category)
67+
.status(ProductStatus.ACTIVE)
68+
.build();
69+
70+
71+
}
72+
73+
public static Product of(Product savedProduct, List<ProductImage> imageList) {
74+
return Product.builder()
75+
.sellerId(savedProduct.sellerId)
76+
.name(savedProduct.getName())
77+
.description(savedProduct.getDescription())
78+
.price(savedProduct.getPrice())
79+
.stockQuantity(savedProduct.getStockQuantity())
80+
.status(savedProduct.getStatus())
81+
.imageList(imageList)
82+
.build();
83+
}
84+
85+
@PrePersist
86+
protected void onCreate() {
87+
this.creaDt = LocalDateTime.now();
88+
this.updtDt = LocalDateTime.now();
89+
}
90+
91+
@PreUpdate
92+
protected void onUpdate() {
93+
this.updtDt = LocalDateTime.now();
94+
}
95+
96+
}

0 commit comments

Comments
 (0)