From c477044dccf6a1d9f59afc2176829f167478196b Mon Sep 17 00:00:00 2001 From: nahye Date: Sat, 22 Feb 2025 22:26:55 +0900 Subject: [PATCH 1/8] =?UTF-8?q?=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=ED=99=95=EC=9D=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle.kts | 3 + .../java/com/example/demo/Application.java | 14 +++++ .../demo/controllers/CartController.java | 60 ++++++++++++++++++- .../demo/controllers/dtos/CartDto.java | 18 ++++++ src/test/java/com/example/demo/MongoTest.java | 30 ++++++++++ .../demo/controllers/CartControllerTest.java | 6 ++ 6 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/demo/controllers/dtos/CartDto.java create mode 100644 src/test/java/com/example/demo/MongoTest.java diff --git a/build.gradle.kts b/build.gradle.kts index 10a77c4..1525c7c 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,6 +19,9 @@ dependencies { implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter-validation") + implementation("org.mongodb:mongodb-driver-core:5.3.1") + implementation("org.mongodb:mongodb-driver-sync:5.3.1") + developmentOnly("org.springframework.boot:spring-boot-devtools") testImplementation("org.springframework.boot:spring-boot-starter-test") diff --git a/src/main/java/com/example/demo/Application.java b/src/main/java/com/example/demo/Application.java index b464ed7..a250406 100644 --- a/src/main/java/com/example/demo/Application.java +++ b/src/main/java/com/example/demo/Application.java @@ -1,11 +1,25 @@ package com.example.demo; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } + + @Bean + public MongoClient mongoClient() { + return MongoClients.create("mongodb://localhost:27017"); + } + + @Bean + public MongoDatabase mongoDatabase(MongoClient mongoClient) { + return mongoClient.getDatabase("demo"); + } } diff --git a/src/main/java/com/example/demo/controllers/CartController.java b/src/main/java/com/example/demo/controllers/CartController.java index 0e1469a..d5f54fe 100644 --- a/src/main/java/com/example/demo/controllers/CartController.java +++ b/src/main/java/com/example/demo/controllers/CartController.java @@ -1,14 +1,70 @@ package com.example.demo.controllers; +import com.example.demo.controllers.dtos.CartDto; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import org.bson.Document; +import org.bson.types.ObjectId; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import java.util.ArrayList; +import java.util.List; + @RestController @RequestMapping("/cart") public class CartController { + + private final MongoDatabase mongoDatabase; + + public CartController(MongoDatabase mongoDatabase) { + this.mongoDatabase = mongoDatabase; + } + @GetMapping - String detail() { - return ""; + CartDto detail() { + + MongoCollection collection = + mongoDatabase.getCollection("line_items"); + + List documents = new ArrayList<>(); + collection.find().into(documents); + + List lineItems = documents.stream() + .map(this::mapToDto) + .toList(); + + int totalPrice = lineItems.stream() + .mapToInt(CartDto.LineItemDto::totalPrice) + .sum(); + + return new CartDto( + lineItems, totalPrice); + } + + private CartDto.LineItemDto mapToDto(Document document) { + String productId = document.getString("product_id"); + Document productDocument = findProduct(productId); + + int unitPrice = productDocument.getInteger("price"); + int quantity = document.getInteger("quantity"); + return new CartDto.LineItemDto( + document.getObjectId("_id").toString(), + document.getString("product_id"), + productDocument.getString("name"), + unitPrice, + quantity, + unitPrice * quantity); + } + + private Document findProduct(String productId) { + MongoCollection productsCollection = + mongoDatabase.getCollection("products"); + + return productsCollection.find( + Filters.eq("_id", new ObjectId(productId)) + ).first(); } } diff --git a/src/main/java/com/example/demo/controllers/dtos/CartDto.java b/src/main/java/com/example/demo/controllers/dtos/CartDto.java new file mode 100644 index 0000000..02a9de5 --- /dev/null +++ b/src/main/java/com/example/demo/controllers/dtos/CartDto.java @@ -0,0 +1,18 @@ +package com.example.demo.controllers.dtos; + +import java.util.List; + +public record CartDto( + List lineItems, + int totalPrice +) { + public record LineItemDto( + String id, + String productId, + String productName, + int unitPrice, + int quantity, + int totalPrice + ) { + } +} diff --git a/src/test/java/com/example/demo/MongoTest.java b/src/test/java/com/example/demo/MongoTest.java new file mode 100644 index 0000000..96d52c6 --- /dev/null +++ b/src/test/java/com/example/demo/MongoTest.java @@ -0,0 +1,30 @@ +package com.example.demo; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class MongoTest { + + @Test + void test() { + + MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017"); + MongoDatabase database = mongoClient.getDatabase("demo"); + MongoCollection collection = database.getCollection("products"); + + List documents = new ArrayList<>(); + collection.find().into(documents); + + assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠"); + assertThat(documents.get(1).getString("name")).isEqualTo("청바지"); + } +} diff --git a/src/test/java/com/example/demo/controllers/CartControllerTest.java b/src/test/java/com/example/demo/controllers/CartControllerTest.java index 619307d..f05783f 100644 --- a/src/test/java/com/example/demo/controllers/CartControllerTest.java +++ b/src/test/java/com/example/demo/controllers/CartControllerTest.java @@ -6,7 +6,10 @@ import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.test.web.servlet.MockMvc; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @WebMvcTest(CartController.class) @@ -18,6 +21,9 @@ class CartControllerTest { @DisplayName("GET /cart") void detail() throws Exception { mockMvc.perform(get("/cart")) + .andExpect(content().string( + containsString("lineItems") + )) .andExpect(status().isOk()); } } From 827015498042ac57e1633b99e88f4adae5c3d043 Mon Sep 17 00:00:00 2001 From: nahye Date: Sat, 22 Feb 2025 23:52:58 +0900 Subject: [PATCH 2/8] =?UTF-8?q?DAO=EC=99=80=20Model(TO)=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=ED=9B=84=20=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/controllers/CartController.java | 71 +++++++++---------- .../demo/infrastructure/LineItemDAO.java | 39 ++++++++++ .../demo/infrastructure/ProductDAO.java | 37 ++++++++++ .../java/com/example/demo/model/LineItem.java | 54 ++++++++++++++ .../java/com/example/demo/model/Product.java | 23 ++++++ 5 files changed, 185 insertions(+), 39 deletions(-) create mode 100644 src/main/java/com/example/demo/infrastructure/LineItemDAO.java create mode 100644 src/main/java/com/example/demo/infrastructure/ProductDAO.java create mode 100644 src/main/java/com/example/demo/model/LineItem.java create mode 100644 src/main/java/com/example/demo/model/Product.java diff --git a/src/main/java/com/example/demo/controllers/CartController.java b/src/main/java/com/example/demo/controllers/CartController.java index d5f54fe..32c1446 100644 --- a/src/main/java/com/example/demo/controllers/CartController.java +++ b/src/main/java/com/example/demo/controllers/CartController.java @@ -1,70 +1,63 @@ package com.example.demo.controllers; import com.example.demo.controllers.dtos.CartDto; -import com.mongodb.client.MongoCollection; -import com.mongodb.client.MongoDatabase; -import com.mongodb.client.model.Filters; -import org.bson.Document; -import org.bson.types.ObjectId; +import com.example.demo.infrastructure.LineItemDAO; +import com.example.demo.infrastructure.ProductDAO; +import com.example.demo.model.LineItem; +import com.example.demo.model.Product; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.ArrayList; import java.util.List; @RestController @RequestMapping("/cart") public class CartController { - private final MongoDatabase mongoDatabase; + private final LineItemDAO lineItemDAO; + private final ProductDAO productDAO; - public CartController(MongoDatabase mongoDatabase) { - this.mongoDatabase = mongoDatabase; + public CartController(LineItemDAO lineItemDAO, ProductDAO productDAO) { + this.lineItemDAO = lineItemDAO; + this.productDAO = productDAO; } @GetMapping CartDto detail() { - MongoCollection collection = - mongoDatabase.getCollection("line_items"); + List lineItems = lineItemDAO.findAll(); - List documents = new ArrayList<>(); - collection.find().into(documents); + lineItems.forEach(lineItem -> { + String productId = lineItem.getProductId(); + Product product = productDAO.find(productId); - List lineItems = documents.stream() - .map(this::mapToDto) - .toList(); + int unitPrice = product.getPrice(); + int quantity = lineItem.getQuantity(); + + lineItem.setProductName(product.getName()); + lineItem.setUnitPrice(product.getPrice()); + lineItem.setTotalPrice(unitPrice * quantity); + }); int totalPrice = lineItems.stream() - .mapToInt(CartDto.LineItemDto::totalPrice) + .mapToInt(LineItem::getTotalPrice) .sum(); return new CartDto( - lineItems, totalPrice); + lineItems.stream() + .map(this::mapToDto) + .toList(), + totalPrice); } - private CartDto.LineItemDto mapToDto(Document document) { - String productId = document.getString("product_id"); - Document productDocument = findProduct(productId); - - int unitPrice = productDocument.getInteger("price"); - int quantity = document.getInteger("quantity"); + private CartDto.LineItemDto mapToDto(LineItem lineItem) { return new CartDto.LineItemDto( - document.getObjectId("_id").toString(), - document.getString("product_id"), - productDocument.getString("name"), - unitPrice, - quantity, - unitPrice * quantity); - } - - private Document findProduct(String productId) { - MongoCollection productsCollection = - mongoDatabase.getCollection("products"); - - return productsCollection.find( - Filters.eq("_id", new ObjectId(productId)) - ).first(); + lineItem.getId(), + lineItem.getProductId(), + lineItem.getProductName(), + lineItem.getUnitPrice(), + lineItem.getQuantity(), + lineItem.getTotalPrice()); } } diff --git a/src/main/java/com/example/demo/infrastructure/LineItemDAO.java b/src/main/java/com/example/demo/infrastructure/LineItemDAO.java new file mode 100644 index 0000000..dd9baf9 --- /dev/null +++ b/src/main/java/com/example/demo/infrastructure/LineItemDAO.java @@ -0,0 +1,39 @@ +package com.example.demo.infrastructure; + +import com.example.demo.model.LineItem; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +public class LineItemDAO { + + private final MongoDatabase mongoDatabase; + + public LineItemDAO(MongoDatabase mongoDatabase) { + this.mongoDatabase = mongoDatabase; + } + + public List findAll() { + + MongoCollection collection = + mongoDatabase.getCollection("line_items"); + + List documents = new ArrayList<>(); + collection.find().into(documents); + + return documents.stream().map(this::mapToModel).toList(); + } + + private LineItem mapToModel(Document document) { + return new LineItem( + document.getObjectId("_id").toString(), + document.getString("product_id"), + document.getInteger("quantity") + ); + } +} diff --git a/src/main/java/com/example/demo/infrastructure/ProductDAO.java b/src/main/java/com/example/demo/infrastructure/ProductDAO.java new file mode 100644 index 0000000..e8e7c5c --- /dev/null +++ b/src/main/java/com/example/demo/infrastructure/ProductDAO.java @@ -0,0 +1,37 @@ +package com.example.demo.infrastructure; + +import com.example.demo.model.LineItem; +import com.example.demo.model.Product; +import com.mongodb.client.MongoCollection; +import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import org.bson.Document; +import org.bson.types.ObjectId; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class ProductDAO { + + private final MongoDatabase mongoDatabase; + + public ProductDAO(MongoDatabase mongoDatabase) { + this.mongoDatabase = mongoDatabase; + } + + public Product find(String productId) { + + MongoCollection collection = mongoDatabase.getCollection("products"); + + Document document = collection.find( + Filters.eq("_id", new ObjectId(productId)) + ).first(); + + return new Product( + document.getObjectId("_id").toString(), + document.getString("name"), + document.getInteger("price") + ); + } +} diff --git a/src/main/java/com/example/demo/model/LineItem.java b/src/main/java/com/example/demo/model/LineItem.java new file mode 100644 index 0000000..9a3065f --- /dev/null +++ b/src/main/java/com/example/demo/model/LineItem.java @@ -0,0 +1,54 @@ +package com.example.demo.model; + +public class LineItem { + + private String id; + private String productId; + private int quantity; + + private String productName; + private int unitPrice; + private int totalPrice; + + public LineItem(String id, String productId, int quantity) { + this.id = id; + this.productId = productId; + this.quantity = quantity; + } + + public String getId() { + return id; + } + + public String getProductId() { + return productId; + } + + public int getQuantity() { + return quantity; + } + + public String getProductName() { + return productName; + } + + public void setProductName(String productName) { + this.productName = productName; + } + + public int getUnitPrice() { + return unitPrice; + } + + public void setUnitPrice(int unitPrice) { + this.unitPrice = unitPrice; + } + + public int getTotalPrice() { + return totalPrice; + } + + public void setTotalPrice(int totalPrice) { + this.totalPrice = totalPrice; + } +} diff --git a/src/main/java/com/example/demo/model/Product.java b/src/main/java/com/example/demo/model/Product.java new file mode 100644 index 0000000..599aad1 --- /dev/null +++ b/src/main/java/com/example/demo/model/Product.java @@ -0,0 +1,23 @@ +package com.example.demo.model; + +public class Product { + + private String id; + private String name; + private int price; + + public Product(String id, String name, int price) { + this.id = id; + this.name = name; + this.price = price; + } + + + public String getName() { + return name; + } + + public int getPrice() { + return price; + } +} From c9df4ad5a5951fb95819b234599d6bd2df52c0c1 Mon Sep 17 00:00:00 2001 From: nahye Date: Sat, 22 Feb 2025 23:58:53 +0900 Subject: [PATCH 3/8] =?UTF-8?q?Cart=20=EC=B6=94=EA=B0=80=ED=9B=84=20getCar?= =?UTF-8?q?t()=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/controllers/CartController.java | 36 +++++++++++-------- .../java/com/example/demo/model/Cart.java | 23 ++++++++++++ 2 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 src/main/java/com/example/demo/model/Cart.java diff --git a/src/main/java/com/example/demo/controllers/CartController.java b/src/main/java/com/example/demo/controllers/CartController.java index 32c1446..77d48a4 100644 --- a/src/main/java/com/example/demo/controllers/CartController.java +++ b/src/main/java/com/example/demo/controllers/CartController.java @@ -3,6 +3,7 @@ import com.example.demo.controllers.dtos.CartDto; import com.example.demo.infrastructure.LineItemDAO; import com.example.demo.infrastructure.ProductDAO; +import com.example.demo.model.Cart; import com.example.demo.model.LineItem; import com.example.demo.model.Product; import org.springframework.web.bind.annotation.GetMapping; @@ -26,6 +27,25 @@ public CartController(LineItemDAO lineItemDAO, ProductDAO productDAO) { @GetMapping CartDto detail() { + Cart cart = getCart(); + return new CartDto( + cart.getLineItems().stream() + .map(this::mapToDto) + .toList(), + cart.getTotalPrice()); + } + + private CartDto.LineItemDto mapToDto(LineItem lineItem) { + return new CartDto.LineItemDto( + lineItem.getId(), + lineItem.getProductId(), + lineItem.getProductName(), + lineItem.getUnitPrice(), + lineItem.getQuantity(), + lineItem.getTotalPrice()); + } + + private Cart getCart() { List lineItems = lineItemDAO.findAll(); lineItems.forEach(lineItem -> { @@ -44,20 +64,6 @@ CartDto detail() { .mapToInt(LineItem::getTotalPrice) .sum(); - return new CartDto( - lineItems.stream() - .map(this::mapToDto) - .toList(), - totalPrice); - } - - private CartDto.LineItemDto mapToDto(LineItem lineItem) { - return new CartDto.LineItemDto( - lineItem.getId(), - lineItem.getProductId(), - lineItem.getProductName(), - lineItem.getUnitPrice(), - lineItem.getQuantity(), - lineItem.getTotalPrice()); + return new Cart(lineItems, totalPrice); } } diff --git a/src/main/java/com/example/demo/model/Cart.java b/src/main/java/com/example/demo/model/Cart.java new file mode 100644 index 0000000..913a979 --- /dev/null +++ b/src/main/java/com/example/demo/model/Cart.java @@ -0,0 +1,23 @@ +package com.example.demo.model; + +import java.util.Collections; +import java.util.List; + +public class Cart { + private List lineItems; + private int totalPrice; + + public Cart(List lineItems, int totalPrice) { + this.lineItems = lineItems; + this.totalPrice = totalPrice; + } + + public List getLineItems() { + return Collections.unmodifiableList(lineItems); + } + + public int getTotalPrice() { + return totalPrice; + } + +} From d5117d23a839bc4d6b95085b13a3988f9f846f2d Mon Sep 17 00:00:00 2001 From: nahye Date: Sun, 23 Feb 2025 00:02:03 +0900 Subject: [PATCH 4/8] =?UTF-8?q?CartService=EB=A1=9C=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/application/CartService.java | 43 +++++++++++++++++++ .../demo/controllers/CartController.java | 38 +++------------- 2 files changed, 48 insertions(+), 33 deletions(-) create mode 100644 src/main/java/com/example/demo/application/CartService.java diff --git a/src/main/java/com/example/demo/application/CartService.java b/src/main/java/com/example/demo/application/CartService.java new file mode 100644 index 0000000..3478e7a --- /dev/null +++ b/src/main/java/com/example/demo/application/CartService.java @@ -0,0 +1,43 @@ +package com.example.demo.application; + +import com.example.demo.infrastructure.LineItemDAO; +import com.example.demo.infrastructure.ProductDAO; +import com.example.demo.model.Cart; +import com.example.demo.model.LineItem; +import com.example.demo.model.Product; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class CartService { + private final LineItemDAO lineItemDAO; + private final ProductDAO productDAO; + + public CartService(LineItemDAO lineItemDAO, ProductDAO productDAO) { + this.lineItemDAO = lineItemDAO; + this.productDAO = productDAO; + } + + public Cart getCart() { + List lineItems = lineItemDAO.findAll(); + + lineItems.forEach(lineItem -> { + String productId = lineItem.getProductId(); + Product product = productDAO.find(productId); + + int unitPrice = product.getPrice(); + int quantity = lineItem.getQuantity(); + + lineItem.setProductName(product.getName()); + lineItem.setUnitPrice(product.getPrice()); + lineItem.setTotalPrice(unitPrice * quantity); + }); + + int totalPrice = lineItems.stream() + .mapToInt(LineItem::getTotalPrice) + .sum(); + + return new Cart(lineItems, totalPrice); + } +} diff --git a/src/main/java/com/example/demo/controllers/CartController.java b/src/main/java/com/example/demo/controllers/CartController.java index 77d48a4..8647003 100644 --- a/src/main/java/com/example/demo/controllers/CartController.java +++ b/src/main/java/com/example/demo/controllers/CartController.java @@ -1,33 +1,27 @@ package com.example.demo.controllers; +import com.example.demo.application.CartService; import com.example.demo.controllers.dtos.CartDto; -import com.example.demo.infrastructure.LineItemDAO; -import com.example.demo.infrastructure.ProductDAO; import com.example.demo.model.Cart; import com.example.demo.model.LineItem; -import com.example.demo.model.Product; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; -import java.util.List; - @RestController @RequestMapping("/cart") public class CartController { - private final LineItemDAO lineItemDAO; - private final ProductDAO productDAO; + private final CartService cartService; - public CartController(LineItemDAO lineItemDAO, ProductDAO productDAO) { - this.lineItemDAO = lineItemDAO; - this.productDAO = productDAO; + public CartController(CartService cartService) { + this.cartService = cartService; } @GetMapping CartDto detail() { - Cart cart = getCart(); + Cart cart = cartService.getCart(); return new CartDto( cart.getLineItems().stream() .map(this::mapToDto) @@ -44,26 +38,4 @@ private CartDto.LineItemDto mapToDto(LineItem lineItem) { lineItem.getQuantity(), lineItem.getTotalPrice()); } - - private Cart getCart() { - List lineItems = lineItemDAO.findAll(); - - lineItems.forEach(lineItem -> { - String productId = lineItem.getProductId(); - Product product = productDAO.find(productId); - - int unitPrice = product.getPrice(); - int quantity = lineItem.getQuantity(); - - lineItem.setProductName(product.getName()); - lineItem.setUnitPrice(product.getPrice()); - lineItem.setTotalPrice(unitPrice * quantity); - }); - - int totalPrice = lineItems.stream() - .mapToInt(LineItem::getTotalPrice) - .sum(); - - return new Cart(lineItems, totalPrice); - } } From c173f22d39a0cfd2b2ce1db0e9feac0c5b8a4702 Mon Sep 17 00:00:00 2001 From: nahye Date: Sun, 23 Feb 2025 00:44:00 +0900 Subject: [PATCH 5/8] =?UTF-8?q?CartServiceTest=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/example/demo/model/Product.java | 3 + .../demo/application/CartServiceTest.java | 88 +++++++++++++++++++ .../demo/controllers/CartControllerTest.java | 13 +++ 3 files changed, 104 insertions(+) create mode 100644 src/test/java/com/example/demo/application/CartServiceTest.java diff --git a/src/main/java/com/example/demo/model/Product.java b/src/main/java/com/example/demo/model/Product.java index 599aad1..45f51e7 100644 --- a/src/main/java/com/example/demo/model/Product.java +++ b/src/main/java/com/example/demo/model/Product.java @@ -12,6 +12,9 @@ public Product(String id, String name, int price) { this.price = price; } + public String getId() { + return id; + } public String getName() { return name; diff --git a/src/test/java/com/example/demo/application/CartServiceTest.java b/src/test/java/com/example/demo/application/CartServiceTest.java new file mode 100644 index 0000000..3f1e9c7 --- /dev/null +++ b/src/test/java/com/example/demo/application/CartServiceTest.java @@ -0,0 +1,88 @@ +package com.example.demo.application; + +import com.example.demo.infrastructure.LineItemDAO; +import com.example.demo.infrastructure.ProductDAO; +import com.example.demo.model.Cart; +import com.example.demo.model.LineItem; +import com.example.demo.model.Product; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + +class CartServiceTest { + + private Product product1; + private Product product2; + + private List lineItems; + + private LineItemDAO lineItemDAO; + private ProductDAO productDAO; + private CartService cartService; + + @BeforeEach + void setUp() { + lineItemDAO = mock(LineItemDAO.class); + productDAO = mock(ProductDAO.class); + cartService = new CartService(lineItemDAO, productDAO); + + lineItems = new ArrayList<>(); + given(lineItemDAO.findAll()).willReturn(lineItems); + + product1 = new Product("product-1", "product #1", 5000); + product2 = new Product("product-2", "product #2", 3000); + given(productDAO.find(product1.getId())).willReturn(product1); + given(productDAO.find(product2.getId())).willReturn(product2); + } + + @Test + @DisplayName("장바구니가 비어있으면 총가격은 0원") + void totalPriceIsZero() { + given(lineItemDAO.findAll()).willReturn(List.of()); + + Cart cart = cartService.getCart(); + + assertThat(cart.getTotalPrice()).isEqualTo(0); + } + + @Test + @DisplayName("장바구니에 있는 하나의 상품의 가격을 모두 더해서 총 가격을 구한다.") + void calculateTotalPriceWithOneLineItem() { + int quantity = 2; + addProductInCart(product1, quantity); + + Cart cart = cartService.getCart(); + + assertThat(cart.getTotalPrice()).isEqualTo(product1.getPrice() * quantity); + } + + @Test + @DisplayName("장바구니에 있는 여러 상품의 가격을 모두 더해서 총 가격을 구한다.") + void calculateTotalPriceWithManyLineItems() { + int quantity1 = 2; + int quantity2 = 3; + addProductInCart(product1, quantity1); + addProductInCart(product2, quantity2); + + Cart cart = cartService.getCart(); + + assertThat(cart.getTotalPrice()).isEqualTo(product1.getPrice() * quantity1 + + product2.getPrice() * quantity2); + } + + + + + private void addProductInCart(Product product, int quantity) { + String id = "item-"+(lineItems.size() +1); + LineItem lineItem = new LineItem(id, product.getId(), quantity); + lineItems.add(lineItem); + } +} diff --git a/src/test/java/com/example/demo/controllers/CartControllerTest.java b/src/test/java/com/example/demo/controllers/CartControllerTest.java index f05783f..03ac0c4 100644 --- a/src/test/java/com/example/demo/controllers/CartControllerTest.java +++ b/src/test/java/com/example/demo/controllers/CartControllerTest.java @@ -1,13 +1,19 @@ package com.example.demo.controllers; +import com.example.demo.application.CartService; +import com.example.demo.model.Cart; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; +import java.util.List; + import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.containsString; +import static org.mockito.BDDMockito.given; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -17,9 +23,16 @@ class CartControllerTest { @Autowired private MockMvc mockMvc; + @MockBean + private CartService cartService; + @Test @DisplayName("GET /cart") void detail() throws Exception { + + Cart cart = new Cart(List.of(), 0); + given(cartService.getCart()).willReturn(cart); + mockMvc.perform(get("/cart")) .andExpect(content().string( containsString("lineItems") From 0819d9168816e7c95cb4c36d79abc1ee725213f2 Mon Sep 17 00:00:00 2001 From: nahye Date: Sun, 23 Feb 2025 01:16:56 +0900 Subject: [PATCH 6/8] =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20?= =?UTF-8?q?=EC=83=81=ED=92=88=20=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=8A=A5?= =?UTF-8?q?=EA=B3=BC=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/application/CartService.java | 18 +++++++ .../demo/infrastructure/LineItemDAO.java | 29 ++++++++--- .../java/com/example/demo/model/LineItem.java | 9 ++++ .../demo/application/CartServiceTest.java | 48 +++++++++++++++++++ 4 files changed, 98 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/demo/application/CartService.java b/src/main/java/com/example/demo/application/CartService.java index 3478e7a..6505ee6 100644 --- a/src/main/java/com/example/demo/application/CartService.java +++ b/src/main/java/com/example/demo/application/CartService.java @@ -40,4 +40,22 @@ public Cart getCart() { return new Cart(lineItems, totalPrice); } + + public void addProduct(String productId, int quantity) { + + List lineItems = lineItemDAO.findAll(); + + LineItem lineItem = lineItems.stream() + .filter(i -> i.getProductId().equals(productId)) + .findFirst() + .orElse(null); + + if (lineItem == null) { + lineItem = new LineItem(productId, quantity); + lineItemDAO.add(lineItem); + return; + } + lineItem.setQunatity(lineItem.getQuantity() + quantity); + lineItemDAO.upadate(lineItem); + } } diff --git a/src/main/java/com/example/demo/infrastructure/LineItemDAO.java b/src/main/java/com/example/demo/infrastructure/LineItemDAO.java index dd9baf9..6654e3e 100644 --- a/src/main/java/com/example/demo/infrastructure/LineItemDAO.java +++ b/src/main/java/com/example/demo/infrastructure/LineItemDAO.java @@ -3,7 +3,10 @@ import com.example.demo.model.LineItem; import com.mongodb.client.MongoCollection; import com.mongodb.client.MongoDatabase; +import com.mongodb.client.model.Filters; +import com.mongodb.client.model.Updates; import org.bson.Document; +import org.bson.types.ObjectId; import org.springframework.stereotype.Component; import java.util.ArrayList; @@ -12,23 +15,37 @@ @Component public class LineItemDAO { - private final MongoDatabase mongoDatabase; + private final MongoCollection collection; public LineItemDAO(MongoDatabase mongoDatabase) { - this.mongoDatabase = mongoDatabase; + this.collection = mongoDatabase.getCollection("line_items"); } public List findAll() { - - MongoCollection collection = - mongoDatabase.getCollection("line_items"); - List documents = new ArrayList<>(); collection.find().into(documents); return documents.stream().map(this::mapToModel).toList(); } + public void add(LineItem lineItem) { + Document document = new Document() + .append("product_id", lineItem.getProductId()) + .append("quantity", lineItem.getQuantity()); + + collection.insertOne(document); + } + + public void upadate(LineItem lineItem) { + collection.updateOne( + Filters.eq("_id", new ObjectId(lineItem.getId())), + Updates.combine( + Updates.set("product_id", lineItem.getProductId()), + Updates.set("quantity", lineItem.getQuantity()) + ) + ); + } + private LineItem mapToModel(Document document) { return new LineItem( document.getObjectId("_id").toString(), diff --git a/src/main/java/com/example/demo/model/LineItem.java b/src/main/java/com/example/demo/model/LineItem.java index 9a3065f..942227b 100644 --- a/src/main/java/com/example/demo/model/LineItem.java +++ b/src/main/java/com/example/demo/model/LineItem.java @@ -16,6 +16,11 @@ public LineItem(String id, String productId, int quantity) { this.quantity = quantity; } + public LineItem(String productId, int quantity) { + this.productId = productId; + this.quantity = quantity; + } + public String getId() { return id; } @@ -51,4 +56,8 @@ public int getTotalPrice() { public void setTotalPrice(int totalPrice) { this.totalPrice = totalPrice; } + + public void setQunatity(int qunatity) { + this.quantity = qunatity; + } } diff --git a/src/test/java/com/example/demo/application/CartServiceTest.java b/src/test/java/com/example/demo/application/CartServiceTest.java index 3f1e9c7..6e9d509 100644 --- a/src/test/java/com/example/demo/application/CartServiceTest.java +++ b/src/test/java/com/example/demo/application/CartServiceTest.java @@ -13,8 +13,11 @@ import java.util.List; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; class CartServiceTest { @@ -77,6 +80,51 @@ void calculateTotalPriceWithManyLineItems() { + product2.getPrice() * quantity2); } + // 상품담기 + + @Test + @DisplayName("비어있는 장바구니에 상품 담기") + void addProduct(){ + String productId = product1.getId(); + int quantity = 1; + + cartService.addProduct(productId, quantity); + + verify(lineItemDAO).add(argThat(lineItem -> + lineItem.getProductId().equals(productId) + && lineItem.getQuantity() == quantity)); + } + + @Test + @DisplayName("장바구니에 없는 상품 담기") + void addNewProduct(){ + String productId = product1.getId(); + int quantity = 1; + + lineItems.add(new LineItem(product2.getId(), 5)); + + cartService.addProduct(productId, quantity); + + verify(lineItemDAO).add(argThat(lineItem -> + lineItem.getProductId().equals(productId) + && lineItem.getQuantity() == quantity)); + } + + @Test + @DisplayName("장바구니에 이미있는 상품 담기") + void addExistingProduct(){ + String productId = product1.getId(); + int oldQuantity = 1; + int newQuantity = 2; + + lineItems.add(new LineItem(product1.getId(), oldQuantity)); + + cartService.addProduct(productId, newQuantity); + + verify(lineItemDAO).upadate(argThat(lineItem -> + lineItem.getProductId().equals(productId) + && lineItem.getQuantity() == oldQuantity + newQuantity)); + } From d8fd2641856ffa3a21b0474c165c729ff56d0360 Mon Sep 17 00:00:00 2001 From: nahye Date: Sun, 23 Feb 2025 01:34:31 +0900 Subject: [PATCH 7/8] =?UTF-8?q?=EC=9E=A5=EB=B0=94=EA=B5=AC=EB=8B=88=20?= =?UTF-8?q?=EC=83=81=ED=92=88=20=EC=B6=94=EA=B0=80=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EB=A6=AC=EC=86=8C=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/controllers/LineItemController.java | 20 +++++++++- .../controllers/dtos/AddProductToCartDto.java | 12 ++++++ .../controllers/LineItemControllerTest.java | 37 +++++++++++++++++++ 3 files changed, 67 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/example/demo/controllers/dtos/AddProductToCartDto.java diff --git a/src/main/java/com/example/demo/controllers/LineItemController.java b/src/main/java/com/example/demo/controllers/LineItemController.java index 20dc170..8540162 100644 --- a/src/main/java/com/example/demo/controllers/LineItemController.java +++ b/src/main/java/com/example/demo/controllers/LineItemController.java @@ -1,7 +1,11 @@ package com.example.demo.controllers; +import com.example.demo.application.CartService; +import com.example.demo.controllers.dtos.AddProductToCartDto; +import jakarta.validation.Valid; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -9,9 +13,21 @@ @RestController @RequestMapping("/cart/line-items") public class LineItemController { + + private final CartService cartService; + + public LineItemController(CartService cartService) { + this.cartService = cartService; + } + @PostMapping @ResponseStatus(HttpStatus.CREATED) - void create() { - // + void create( + @Valid @RequestBody AddProductToCartDto addProductToCartDto + ) { + cartService.addProduct( + addProductToCartDto.productId(), + addProductToCartDto.quantity() + ); } } diff --git a/src/main/java/com/example/demo/controllers/dtos/AddProductToCartDto.java b/src/main/java/com/example/demo/controllers/dtos/AddProductToCartDto.java new file mode 100644 index 0000000..3f8921a --- /dev/null +++ b/src/main/java/com/example/demo/controllers/dtos/AddProductToCartDto.java @@ -0,0 +1,12 @@ +package com.example.demo.controllers.dtos; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Positive; + +public record AddProductToCartDto( + @NotBlank + String productId, + @Positive + int quantity +) { +} diff --git a/src/test/java/com/example/demo/controllers/LineItemControllerTest.java b/src/test/java/com/example/demo/controllers/LineItemControllerTest.java index 41eabbc..7be2ecf 100644 --- a/src/test/java/com/example/demo/controllers/LineItemControllerTest.java +++ b/src/test/java/com/example/demo/controllers/LineItemControllerTest.java @@ -1,9 +1,11 @@ package com.example.demo.controllers; +import com.example.demo.application.CartService; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; @@ -15,6 +17,9 @@ class LineItemControllerTest { @Autowired private MockMvc mockMvc; + @MockBean + private CartService cartService; + @Test @DisplayName("POST /cart/line-items") void addProduct() throws Exception { @@ -30,4 +35,36 @@ void addProduct() throws Exception { .content(json)) .andExpect(status().isCreated()); } + + @Test + @DisplayName("POST /cart/line-items - ProductId가 없을 때") + void addProductWithoutProductId() throws Exception { + String json = """ + { + "productId": "", + "quantity": 2 + } + """; + + mockMvc.perform(post("/cart/line-items") + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andExpect(status().isBadRequest()); + } + + @Test + @DisplayName("POST /cart/line-items - 수량이 양수가 아닐때") + void addProductWithInvalidQuantity() throws Exception { + String json = """ + { + "productId": "product-1", + "quantity": 0 + } + """; + + mockMvc.perform(post("/cart/line-items") + .contentType(MediaType.APPLICATION_JSON) + .content(json)) + .andExpect(status().isBadRequest()); + } } From 42048e8c5f496429574b17f247496069c914648e Mon Sep 17 00:00:00 2001 From: nahye Date: Sun, 23 Feb 2025 10:27:54 +0900 Subject: [PATCH 8/8] =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/demo/application/CartService.java | 4 ++-- .../java/com/example/demo/controllers/CartController.java | 1 + .../java/com/example/demo/infrastructure/LineItemDAO.java | 2 +- src/main/java/com/example/demo/model/LineItem.java | 4 ++-- .../java/com/example/demo/application/CartServiceTest.java | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/example/demo/application/CartService.java b/src/main/java/com/example/demo/application/CartService.java index 6505ee6..121579a 100644 --- a/src/main/java/com/example/demo/application/CartService.java +++ b/src/main/java/com/example/demo/application/CartService.java @@ -55,7 +55,7 @@ public void addProduct(String productId, int quantity) { lineItemDAO.add(lineItem); return; } - lineItem.setQunatity(lineItem.getQuantity() + quantity); - lineItemDAO.upadate(lineItem); + lineItem.setQuantity(lineItem.getQuantity() + quantity); + lineItemDAO.update(lineItem); } } diff --git a/src/main/java/com/example/demo/controllers/CartController.java b/src/main/java/com/example/demo/controllers/CartController.java index 8647003..0c0d5b3 100644 --- a/src/main/java/com/example/demo/controllers/CartController.java +++ b/src/main/java/com/example/demo/controllers/CartController.java @@ -4,6 +4,7 @@ import com.example.demo.controllers.dtos.CartDto; import com.example.demo.model.Cart; import com.example.demo.model.LineItem; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; diff --git a/src/main/java/com/example/demo/infrastructure/LineItemDAO.java b/src/main/java/com/example/demo/infrastructure/LineItemDAO.java index 6654e3e..3598d2d 100644 --- a/src/main/java/com/example/demo/infrastructure/LineItemDAO.java +++ b/src/main/java/com/example/demo/infrastructure/LineItemDAO.java @@ -36,7 +36,7 @@ public void add(LineItem lineItem) { collection.insertOne(document); } - public void upadate(LineItem lineItem) { + public void update(LineItem lineItem) { collection.updateOne( Filters.eq("_id", new ObjectId(lineItem.getId())), Updates.combine( diff --git a/src/main/java/com/example/demo/model/LineItem.java b/src/main/java/com/example/demo/model/LineItem.java index 942227b..087ea1b 100644 --- a/src/main/java/com/example/demo/model/LineItem.java +++ b/src/main/java/com/example/demo/model/LineItem.java @@ -57,7 +57,7 @@ public void setTotalPrice(int totalPrice) { this.totalPrice = totalPrice; } - public void setQunatity(int qunatity) { - this.quantity = qunatity; + public void setQuantity(int quantity) { + this.quantity = quantity; } } diff --git a/src/test/java/com/example/demo/application/CartServiceTest.java b/src/test/java/com/example/demo/application/CartServiceTest.java index 6e9d509..a5061d4 100644 --- a/src/test/java/com/example/demo/application/CartServiceTest.java +++ b/src/test/java/com/example/demo/application/CartServiceTest.java @@ -121,7 +121,7 @@ void addExistingProduct(){ cartService.addProduct(productId, newQuantity); - verify(lineItemDAO).upadate(argThat(lineItem -> + verify(lineItemDAO).update(argThat(lineItem -> lineItem.getProductId().equals(productId) && lineItem.getQuantity() == oldQuantity + newQuantity)); }