Skip to content

[3주차] Cart App #1#6

Open
moonnahye wants to merge 8 commits intodal-lab:mainfrom
moonnahye:cart-transaction-script
Open

[3주차] Cart App #1#6
moonnahye wants to merge 8 commits intodal-lab:mainfrom
moonnahye:cart-transaction-script

Conversation

@moonnahye
Copy link

@moonnahye moonnahye commented Feb 22, 2025

Summary by CodeRabbit

  • 새로운 기능

    • MongoDB 연동 기능을 도입하여 데이터 관리 신뢰성이 향상되었습니다.
    • 향상된 쇼핑 카트 기능으로 상품 추가 및 상세 카트 정보를 제공하여 사용자가 장바구니 내 항목과 총 가격을 명확하게 확인할 수 있습니다.
    • 입력값 유효성 검증이 강화되어 보다 정확한 데이터 처리가 이루어집니다.
  • 테스트

    • 카트 및 데이터 연동 기능의 안정성을 확보하기 위한 추가 테스트 케이스가 도입되었습니다.

@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2025

Walkthrough

이번 변경사항은 프로젝트에 MongoDB 의존성을 추가하고, MongoDB와 연동되는 Bean과 DAO 클래스를 도입한 것과 함께 장바구니 관련 기능을 구현 및 개선한 내용입니다. 주요 변경 내용으로는 MongoDB 드라이버 의존성 추가, MongoDB 연결을 위한 Bean 메서드 (mongoClient(), mongoDatabase()) 구현, Cart, LineItem, Product 등의 모델 클래스 추가, 장바구니 조회 및 제품 추가 기능을 제공하는 서비스 및 컨트롤러 수정, 그리고 해당 기능들을 검증하는 단위 테스트 추가가 포함됩니다.

Changes

파일 경로 (축약형) 변경 요약
build.gradle.kts MongoDB 드라이버(core & sync) 의존성 추가
src/.../Application.java MongoDB 연결을 위한 Bean 메서드(mongoClient(), mongoDatabase()) 추가
src/.../CartService.java 장바구니 조회(getCart) 및 제품 추가(addProduct) 기능 구현
src/.../CartController.java CartService 의존성 주입, detail() 반환 타입을 CartDto로 수정, DTO 매핑 메서드 추가
src/.../LineItemController.java CartService 주입, create() 메서드 파라미터를 DTO로 수정하여 제품 추가 기능 개선
src/.../dtos/AddProductToCartDto.java AddProductToCartDto 레코드 추가 (유효성 검증 애너테이션 포함)
src/.../dtos/CartDto.java CartDto 레코드 및 중첩 LineItemDto 추가하여 장바구니 데이터 구조 정의
src/.../infrastructure/LineItemDAO.java MongoDB 연동 CRUD 작업 수행을 위한 LineItemDAO 클래스 추가 (findAll, add, update 메서드 포함)
src/.../infrastructure/ProductDAO.java 제품 정보 조회를 위한 ProductDAO 클래스 추가 (find 메서드 포함)
src/.../model/Cart.java, src/.../model/LineItem.java, src/.../model/Product.java Cart, LineItem, Product 모델 클래스 추가
src/test/.../MongoTest.java MongoDB 연결 및 데이터 검증 테스트 추가
src/test/.../CartServiceTest.java CartService 기능 단위 테스트 작성 (총 가격 계산, 제품 추가 등)
src/test/.../CartControllerTest.java, src/test/.../LineItemControllerTest.java 컨트롤러 테스트 수정 및 입력 검증 테스트 추가 (CartService 모킹 포함)

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant LineItemController
    participant CartService
    participant LineItemDAO
    participant ProductDAO
    participant MongoDB

    Client ->> LineItemController: POST /cart/line-items (AddProductToCartDto)
    LineItemController ->> CartService: addProduct(productId, quantity)
    alt LineItem exists in cart
        CartService ->> LineItemDAO: update 기존 LineItem
    else New product
        CartService ->> LineItemDAO: add 새 LineItem
    end
    LineItemDAO ->> MongoDB: CRUD 작업
    CartService ->> LineItemDAO: getCart() 호출
    LineItemDAO ->> MongoDB: line_items 조회
    CartService ->> ProductDAO: find(productId) 호출
    ProductDAO ->> MongoDB: products 조회
    CartService -->> LineItemController: 처리 완료 응답
Loading
sequenceDiagram
    participant Client
    participant CartController
    participant CartService
    participant LineItemDAO
    participant ProductDAO
    participant MongoDB

    Client ->> CartController: GET /cart
    CartController ->> CartService: getCart()
    CartService ->> LineItemDAO: findAll() 호출
    LineItemDAO ->> MongoDB: line_items 조회
    CartService ->> ProductDAO: find(productId) 호출 (각 LineItem별)
    ProductDAO ->> MongoDB: products 조회
    CartService -->> CartController: Cart 객체 반환
    CartController -->> Client: CartDto (lineItems, totalPrice) 응답
Loading

Poem

귀여운 토끼가 뛰어요, 코드 숲을 달리며
MongoDB의 씨앗 심고, 새로운 기능을 피우네요.
장바구니 속 작은 꿈들이, 한 줄 한 줄 채워지고,
컨트롤러와 DAO가 춤을 추며, 데이터 흐름을 이어가요.
🐰 코드 밭에서 행복한 토끼, 오늘도 기분 최고!
작은 오타도 웃음으로, 다 함께 발전하는 우리!
뛰어라, 코드 토끼!

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🧹 Nitpick comments (3)
src/main/java/com/example/demo/model/Cart.java (1)

10-13: 생성자에 유효성 검사 추가 필요

매개변수의 유효성을 검사하여 안정성을 높일 수 있습니다.

다음과 같이 수정하는 것을 제안합니다:

 public Cart(List<LineItem> lineItems, int totalPrice) {
+    if (lineItems == null) {
+        throw new IllegalArgumentException("lineItems는 null일 수 없습니다.");
+    }
+    if (totalPrice < 0) {
+        throw new IllegalArgumentException("totalPrice는 음수일 수 없습니다.");
+    }
     this.lineItems = lineItems;
     this.totalPrice = totalPrice;
 }
src/test/java/com/example/demo/controllers/CartControllerTest.java (1)

29-41: 테스트 케이스 보완이 필요합니다

현재 테스트는 기본적인 성공 케이스만 검증하고 있습니다. 다음과 같은 추가 테스트 케이스가 필요합니다:

  • 장바구니가 비어있지 않은 경우
  • 총액이 0이 아닌 경우
  • JSON 응답 구조 전체 검증

다음과 같이 테스트를 보완해주세요:

     @Test
     @DisplayName("GET /cart")
     void detail() throws Exception {
-        Cart cart = new Cart(List.of(), 0);
+        LineItem item = new LineItem("1", "product-1", 2);
+        Cart cart = new Cart(List.of(item), 10000);
         given(cartService.getCart()).willReturn(cart);
 
         mockMvc.perform(get("/cart"))
-                .andExpect(content().string(
-                        containsString("lineItems")
-                ))
+                .andExpect(content().json("""
+                        {
+                            "lineItems": [{
+                                "productId": "product-1",
+                                "quantity": 2
+                            }],
+                            "totalPrice": 10000
+                        }
+                        """))
                 .andExpect(status().isOk());
     }
src/test/java/com/example/demo/application/CartServiceTest.java (1)

131-135: 테스트 헬퍼 메서드 개선 필요

addProductInCart 메서드의 ID 생성 로직이 단순합니다. 더 견고한 구현이 필요합니다.

다음과 같이 개선하는 것을 제안합니다:

     private void addProductInCart(Product product, int quantity) {
-        String id = "item-"+(lineItems.size() +1);
+        String id = String.format("item-%s-%d", product.getId(), System.currentTimeMillis());
         LineItem lineItem = new LineItem(id, product.getId(), quantity);
         lineItems.add(lineItem);
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9ff8df4 and d8fd264.

📒 Files selected for processing (16)
  • build.gradle.kts (1 hunks)
  • src/main/java/com/example/demo/Application.java (1 hunks)
  • src/main/java/com/example/demo/application/CartService.java (1 hunks)
  • src/main/java/com/example/demo/controllers/CartController.java (1 hunks)
  • src/main/java/com/example/demo/controllers/LineItemController.java (1 hunks)
  • src/main/java/com/example/demo/controllers/dtos/AddProductToCartDto.java (1 hunks)
  • src/main/java/com/example/demo/controllers/dtos/CartDto.java (1 hunks)
  • src/main/java/com/example/demo/infrastructure/LineItemDAO.java (1 hunks)
  • src/main/java/com/example/demo/infrastructure/ProductDAO.java (1 hunks)
  • src/main/java/com/example/demo/model/Cart.java (1 hunks)
  • src/main/java/com/example/demo/model/LineItem.java (1 hunks)
  • src/main/java/com/example/demo/model/Product.java (1 hunks)
  • src/test/java/com/example/demo/MongoTest.java (1 hunks)
  • src/test/java/com/example/demo/application/CartServiceTest.java (1 hunks)
  • src/test/java/com/example/demo/controllers/CartControllerTest.java (1 hunks)
  • src/test/java/com/example/demo/controllers/LineItemControllerTest.java (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/main/java/com/example/demo/model/Product.java
🔇 Additional comments (12)
src/main/java/com/example/demo/controllers/CartController.java (4)

3-6: 주입 대상 서비스를 위한 적절한 import
CartService, CartDto, Cart, LineItem 등 필요한 클래스들을 정확히 import하여 의존 관계를 명시하셨습니다. 레이어별 역할이 분리되어 있고 DTO 패키지 구조와도 잘 어우러집니다.


15-19: 생성자를 통한 의존성 주입
final 키워드를 사용하여 불변성을 유지하고, 생성자를 통해 CartService를 주입하는 패턴이 적절합니다. 추후 테스트와 유지보수 측면에서도 더 편리한 구조입니다.


22-29: detail() 메서드에서 장바구니 정보 반환 로직
Cart 객체를 조회한 뒤, 그 정보를 CartDto로 변환하여 반환하는 로직이 명확하고 직관적입니다. 다만, cart가 null이거나 LineItem 목록이 비어 있을 가능성이 있다면, 예외 처리를 검토해 보시는 걸 권장합니다.


32-39: mapToDto 메서드를 통한 LineItem 매핑
LineItem의 속성을 DTO로 간결하게 변환하고 있습니다. 혹시 null인 LineItem이 전달될 여지가 있다면, 해당 부분에 대한 방어 로직이나 예외 처리를 추가해 보길 권장합니다.

src/main/java/com/example/demo/controllers/dtos/AddProductToCartDto.java (2)

3-4: 유효성 검증을 위한 어노테이션 임포트
@NotBlank, @Positive 어노테이션 적용을 위해 jakarta.validation 패키지를 올바르게 import하셨습니다. Spring Boot 3 환경에서 권장되는 접근 방식입니다.


6-12: AddProductToCartDto 레코드 정의
productIdquantity 필드에 적절한 유효성 검사를 부여하고, 레코드로 선언하여 불변성을 보장하는 구조가 깔끔합니다. 장바구니에 상품을 추가할 때 필요한 정보를 직관적으로 담고 있습니다.

src/main/java/com/example/demo/controllers/dtos/CartDto.java (2)

5-8: CartDto 레코드 구조
lineItemstotalPrice를 하나의 DTO로 묶어 관리함으로써 장바구니 정보를 직관적으로 전달할 수 있습니다. CartController에서 반환하기에 적합한 설계입니다.


9-18: 중첩 LineItemDto 레코드
각 라인 아이템의 식별자, 이름, 가격, 수량 등을 명확하게 캡슐화하고 있습니다. 불변 객체 특성이 잘 적용되어 유지보수가 용이해 보입니다.

src/main/java/com/example/demo/model/Cart.java (1)

15-17: 불변 컬렉션 사용이 적절합니다.

Collections.unmodifiableList를 사용하여 외부에서 리스트를 수정할 수 없도록 보호한 것이 좋습니다.

src/main/java/com/example/demo/controllers/LineItemController.java (2)

16-21: 의존성 주입이 올바르게 구현되었습니다!

생성자를 통한 의존성 주입 방식을 사용하여 CartService를 주입받고 있어 좋습니다.


25-31: 입력 유효성 검증이 잘 구현되었습니다!

@Valid 어노테이션을 사용하여 요청 본문의 유효성을 검증하고 있으며, CartService를 통해 비즈니스 로직을 처리하는 구조가 깔끔합니다.

src/test/java/com/example/demo/controllers/LineItemControllerTest.java (1)

39-69: 테스트 케이스가 잘 구현되었습니다!

입력 값 검증에 대한 테스트 케이스가 잘 작성되었습니다. 빈 productId와 유효하지 않은 수량에 대한 검증이 포함되어 있어 좋습니다.

Comment on lines +16 to +19
@Bean
public MongoClient mongoClient() {
return MongoClients.create("mongodb://localhost:27017");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

MongoDB 연결 설정 개선 필요

MongoDB 연결 문자열이 하드코딩되어 있어 환경에 따른 유연한 설정이 어렵습니다.

다음과 같이 수정하는 것을 제안합니다:

+import org.springframework.beans.factory.annotation.Value;

 @Bean
 public MongoClient mongoClient() {
-    return MongoClients.create("mongodb://localhost:27017");
+    @Value("${spring.data.mongodb.uri:mongodb://localhost:27017}")
+    private String mongoUri;
+    return MongoClients.create(mongoUri);
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +21 to +24
@Bean
public MongoDatabase mongoDatabase(MongoClient mongoClient) {
return mongoClient.getDatabase("demo");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

데이터베이스 이름을 설정 파일로 분리 필요

데이터베이스 이름도 환경에 따라 설정할 수 있도록 외부화가 필요합니다.

다음과 같이 수정하는 것을 제안합니다:

 @Bean
 public MongoDatabase mongoDatabase(MongoClient mongoClient) {
-    return mongoClient.getDatabase("demo");
+    @Value("${spring.data.mongodb.database:demo}")
+    private String databaseName;
+    return mongoClient.getDatabase(databaseName);
 }

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +17 to +29
@Test
void test() {

MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
MongoDatabase database = mongoClient.getDatabase("demo");
MongoCollection<Document> collection = database.getCollection("products");

List<Document> documents = new ArrayList<>();
collection.find().into(documents);

assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠");
assertThat(documents.get(1).getString("name")).isEqualTo("청바지");
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

테스트 코드 개선 필요

현재 테스트 코드에는 다음과 같은 개선이 필요합니다:

  1. 테스트 데이터 설정과 정리가 없습니다
  2. 하드코딩된 테스트 데이터에 의존적입니다
  3. 예외 처리가 없습니다

다음과 같이 수정하는 것을 제안합니다:

+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;

 public class MongoTest {
+    private MongoClient mongoClient;
+    private MongoDatabase database;
+    private MongoCollection<Document> collection;
+
+    @BeforeEach
+    void setUp() {
+        mongoClient = MongoClients.create("mongodb://localhost:27017");
+        database = mongoClient.getDatabase("demo");
+        collection = database.getCollection("products");
+        
+        // 테스트 데이터 설정
+        collection.insertMany(Arrays.asList(
+            new Document("name", "티셔츠").append("price", 10000),
+            new Document("name", "청바지").append("price", 20000)
+        ));
+    }
+
+    @AfterEach
+    void tearDown() {
+        collection.drop();
+        mongoClient.close();
+    }

     @Test
     void test() {
-        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
-        MongoDatabase database = mongoClient.getDatabase("demo");
-        MongoCollection<Document> collection = database.getCollection("products");

         List<Document> documents = new ArrayList<>();
         collection.find().into(documents);

+        assertThat(documents).hasSize(2);
         assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠");
         assertThat(documents.get(1).getString("name")).isEqualTo("청바지");
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Test
void test() {
MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
MongoDatabase database = mongoClient.getDatabase("demo");
MongoCollection<Document> collection = database.getCollection("products");
List<Document> documents = new ArrayList<>();
collection.find().into(documents);
assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠");
assertThat(documents.get(1).getString("name")).isEqualTo("청바지");
}
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoCollection;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
public class MongoTest {
private MongoClient mongoClient;
private MongoDatabase database;
private MongoCollection<Document> collection;
@BeforeEach
void setUp() {
mongoClient = MongoClients.create("mongodb://localhost:27017");
database = mongoClient.getDatabase("demo");
collection = database.getCollection("products");
// 테스트 데이터 설정
collection.insertMany(Arrays.asList(
new Document("name", "티셔츠").append("price", 10000),
new Document("name", "청바지").append("price", 20000)
));
}
@AfterEach
void tearDown() {
collection.drop();
mongoClient.close();
}
@Test
void test() {
List<Document> documents = new ArrayList<>();
collection.find().into(documents);
assertThat(documents).hasSize(2);
assertThat(documents.get(0).getString("name")).isEqualTo("티셔츠");
assertThat(documents.get(1).getString("name")).isEqualTo("청바지");
}
}

Comment on lines +23 to +36
public Product find(String productId) {

MongoCollection<Document> 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")
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

에러 처리 및 유효성 검사 추가 필요

현재 구현에는 다음과 같은 개선이 필요합니다:

  1. 문서를 찾지 못했을 때의 처리가 없습니다
  2. productId의 유효성 검사가 없습니다
  3. ObjectId 변환 시 예외 처리가 없습니다

다음과 같이 수정하는 것을 제안합니다:

 public Product find(String productId) {
+    if (productId == null || productId.trim().isEmpty()) {
+        throw new IllegalArgumentException("productId는 null이거나 비어있을 수 없습니다.");
+    }
+
+    ObjectId objectId;
+    try {
+        objectId = new ObjectId(productId);
+    } catch (IllegalArgumentException e) {
+        throw new IllegalArgumentException("유효하지 않은 productId 형식입니다.", e);
+    }

     MongoCollection<Document> collection = mongoDatabase.getCollection("products");

     Document document = collection.find(
-            Filters.eq("_id", new ObjectId(productId))
+            Filters.eq("_id", objectId)
     ).first();

+    if (document == null) {
+        throw new ProductNotFoundException("ID가 " + productId + "인 상품을 찾을 수 없습니다.");
+    }

     return new Product(
             document.getObjectId("_id").toString(),
             document.getString("name"),
             document.getInteger("price")
     );
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public Product find(String productId) {
MongoCollection<Document> 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")
);
}
public Product find(String productId) {
if (productId == null || productId.trim().isEmpty()) {
throw new IllegalArgumentException("productId는 null이거나 비어있을 수 없습니다.");
}
ObjectId objectId;
try {
objectId = new ObjectId(productId);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("유효하지 않은 productId 형식입니다.", e);
}
MongoCollection<Document> collection = mongoDatabase.getCollection("products");
Document document = collection.find(
Filters.eq("_id", objectId)
).first();
if (document == null) {
throw new ProductNotFoundException("ID가 " + productId + "인 상품을 찾을 수 없습니다.");
}
return new Product(
document.getObjectId("_id").toString(),
document.getString("name"),
document.getInteger("price")
);
}

Comment on lines 60 to 62
public void setQunatity(int qunatity) {
this.quantity = qunatity;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

메서드 이름에 오타가 있습니다

setQunatity 메서드 이름에 오타가 있습니다. setQuantity로 수정해야 합니다.

다음과 같이 수정해주세요:

-    public void setQunatity(int qunatity) {
-        this.quantity = qunatity;
+    public void setQuantity(int quantity) {
+        this.quantity = quantity;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void setQunatity(int qunatity) {
this.quantity = qunatity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}

Comment on lines +3 to +12
public class LineItem {

private String id;
private String productId;
private int quantity;

private String productName;
private int unitPrice;
private int totalPrice;

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

모델 클래스에 유효성 검증이 필요합니다

수량(quantity)과 가격(unitPrice, totalPrice)에 대한 유효성 검증이 없습니다. 음수 값이 들어올 수 있는 위험이 있습니다.

Jakarta Validation 어노테이션을 사용하여 유효성 검증을 추가하는 것을 추천드립니다:

 public class LineItem {
     private String id;
     private String productId;
+    @Min(value = 1, message = "수량은 1 이상이어야 합니다")
     private int quantity;
 
     private String productName;
+    @Min(value = 0, message = "단가는 0 이상이어야 합니다")
     private int unitPrice;
+    @Min(value = 0, message = "총액은 0 이상이어야 합니다")
     private int totalPrice;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public class LineItem {
private String id;
private String productId;
private int quantity;
private String productName;
private int unitPrice;
private int totalPrice;
public class LineItem {
private String id;
private String productId;
@Min(value = 1, message = "수량은 1 이상이어야 합니다")
private int quantity;
private String productName;
@Min(value = 0, message = "단가는 0 이상이어야 합니다")
private int unitPrice;
@Min(value = 0, message = "총액은 0 이상이어야 합니다")
private int totalPrice;
}

Comment on lines 39 to 47
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())
)
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

메서드 이름에 오타가 있습니다

upadate 메서드 이름에 오타가 있습니다. update로 수정해야 합니다.

다음과 같이 수정해주세요:

-    public void upadate(LineItem lineItem) {
+    public void update(LineItem lineItem) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
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())
)
);
}
public void update(LineItem lineItem) {
collection.updateOne(
Filters.eq("_id", new ObjectId(lineItem.getId())),
Updates.combine(
Updates.set("product_id", lineItem.getProductId()),
Updates.set("quantity", lineItem.getQuantity())
)
);
}

Comment on lines 44 to 60
public void addProduct(String productId, int quantity) {

List<LineItem> 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);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

예외 처리 추가 필요

productId가 유효하지 않은 경우에 대한 예외 처리가 누락되어 있습니다. ProductDAO.find()가 null을 반환할 경우 처리가 필요합니다.

다음과 같이 수정하는 것을 제안합니다:

     public void addProduct(String productId, int quantity) {
+        Product product = productDAO.find(productId);
+        if (product == null) {
+            throw new IllegalArgumentException("상품을 찾을 수 없습니다: " + productId);
+        }
 
         List<LineItem> lineItems = lineItemDAO.findAll();
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void addProduct(String productId, int quantity) {
List<LineItem> 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);
}
public void addProduct(String productId, int quantity) {
+ Product product = productDAO.find(productId);
+ if (product == null) {
+ throw new IllegalArgumentException("상품을 찾을 수 없습니다: " + productId);
+ }
List<LineItem> 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);
}

Comment on lines 58 to 59
lineItem.setQunatity(lineItem.getQuantity() + quantity);
lineItemDAO.upadate(lineItem);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

오타 수정이 필요합니다.

setQunatityupadate 메서드 이름에 오타가 있습니다. 올바른 메서드 이름으로 수정해야 합니다.

다음과 같이 수정하세요:

-        lineItem.setQunatity(lineItem.getQuantity() + quantity);
-        lineItemDAO.upadate(lineItem);
+        lineItem.setQuantity(lineItem.getQuantity() + quantity);
+        lineItemDAO.update(lineItem);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
lineItem.setQunatity(lineItem.getQuantity() + quantity);
lineItemDAO.upadate(lineItem);
lineItem.setQuantity(lineItem.getQuantity() + quantity);
lineItemDAO.update(lineItem);

Comment on lines +22 to +23
implementation("org.mongodb:mongodb-driver-core:5.3.1")
implementation("org.mongodb:mongodb-driver-sync:5.3.1")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

MongoDB 드라이버 버전 호환성 확인 필요

Spring Boot 3.3.4와 MongoDB 드라이버 5.3.1의 호환성을 확인해야 합니다.


🌐 Web query:

What is the recommended MongoDB driver version for Spring Boot 3.3.4?

💡 Result:

The recommended MongoDB driver version for Spring Boot 3.3.4 is mongodb-driver-sync 5.0.1[9]. This version is explicitly listed as a direct dependency in the spring-boot-starter-data-mongodb:3.3.4 artifact[9], ensuring compatibility with Spring Data MongoDB 4.x[4][9].

Key compatibility details:

  • Spring Boot 3.x aligns with Spring Data MongoDB 4.x, which requires MongoDB Java Driver ≥5.x[4][7].
  • The mongodb-driver-sync:5.0.x line supports MongoDB server versions from 5.0 to 7.x according to MongoDB's compatibility matrix[3].

Avoid mixing older driver versions (e.g., 3.x or 4.x) with Spring Boot 3.x, as this causes conflicts like NoSuchMethodError or classpath incompatibilities[1][8]. If upgrading from legacy systems, ensure all related dependencies (Spring Data MongoDB and MongoDB Java Driver) are updated simultaneously[8][10].

Citations:


MongoDB 드라이버 버전 불일치 문제: Spring Boot 3.3.4에는 mongodb-driver-sync 5.0.1 버전을 권장합니다

  • 현재 **build.gradle.kts (라인 22-23)**에서 MongoDB 드라이버가 5.3.1 버전으로 지정되어 있습니다.
  • Spring Boot 3.3.4의 spring-boot-starter-data-mongodb에서는 mongodb-driver-sync 5.0.1 버전을 명시하고 있으므로, 권장 버전과 일치시켜 호환성 문제 및 예기치 않은 오류를 방지하는 것이 좋습니다.
  • 아래와 같이 변경을 고려해 주세요:
-    implementation("org.mongodb:mongodb-driver-core:5.3.1")
-    implementation("org.mongodb:mongodb-driver-sync:5.3.1")
+    implementation("org.mongodb:mongodb-driver-core:5.0.1")
+    implementation("org.mongodb:mongodb-driver-sync:5.0.1")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
implementation("org.mongodb:mongodb-driver-core:5.3.1")
implementation("org.mongodb:mongodb-driver-sync:5.3.1")
implementation("org.mongodb:mongodb-driver-core:5.0.1")
implementation("org.mongodb:mongodb-driver-sync:5.0.1")

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (3)
src/main/java/com/example/demo/controllers/CartController.java (2)

7-7: 사용하지 않는 import 문을 제거해주세요

DeleteMapping import가 현재 코드에서 사용되지 않고 있습니다.

-import org.springframework.web.bind.annotation.DeleteMapping;

33-41: null 체크 로직 추가를 고려해주세요

LineItem의 필드들이 null일 경우에 대한 방어 로직이 필요할 수 있습니다.

 private CartDto.LineItemDto mapToDto(LineItem lineItem) {
+    if (lineItem == null) {
+        throw new IllegalArgumentException("LineItem이 null일 수 없습니다");
+    }
     return new CartDto.LineItemDto(
             lineItem.getId(),
             lineItem.getProductId(),
             lineItem.getProductName(),
             lineItem.getUnitPrice(),
             lineItem.getQuantity(),
             lineItem.getTotalPrice());
 }
src/main/java/com/example/demo/infrastructure/LineItemDAO.java (1)

18-22: 컬렉션 이름을 상수로 분리하는 것이 좋겠습니다

컬렉션 이름을 private static final 상수로 분리하면 유지보수성이 향상됩니다.

 public class LineItemDAO {
+    private static final String COLLECTION_NAME = "line_items";
     private final MongoCollection<Document> collection;
 
     public LineItemDAO(MongoDatabase mongoDatabase) {
-        this.collection = mongoDatabase.getCollection("line_items");
+        this.collection = mongoDatabase.getCollection(COLLECTION_NAME);
     }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d8fd264 and 42048e8.

📒 Files selected for processing (5)
  • src/main/java/com/example/demo/application/CartService.java (1 hunks)
  • src/main/java/com/example/demo/controllers/CartController.java (1 hunks)
  • src/main/java/com/example/demo/infrastructure/LineItemDAO.java (1 hunks)
  • src/main/java/com/example/demo/model/LineItem.java (1 hunks)
  • src/test/java/com/example/demo/application/CartServiceTest.java (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/test/java/com/example/demo/application/CartServiceTest.java
  • src/main/java/com/example/demo/application/CartService.java
  • src/main/java/com/example/demo/model/LineItem.java
🔇 Additional comments (3)
src/main/java/com/example/demo/controllers/CartController.java (2)

16-20: 생성자 주입 패턴이 잘 구현되었습니다!

생성자를 통한 의존성 주입과 final 필드 사용으로 불변성이 보장되어 있습니다.


23-31: DTO 변환 로직이 깔끔하게 구현되었습니다!

Cart 엔티티를 CartDto로 변환하는 과정이 stream API를 활용하여 효율적으로 구현되어 있습니다.

src/main/java/com/example/demo/infrastructure/LineItemDAO.java (1)

24-29: MongoDB 예외 처리가 필요합니다

MongoDB 작업 시 발생할 수 있는 예외에 대한 처리가 없습니다.

Comment on lines +24 to +29
public List<LineItem> findAll() {
List<Document> documents = new ArrayList<>();
collection.find().into(documents);

return documents.stream().map(this::mapToModel).toList();
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

페이지네이션 구현이 필요합니다

대량의 데이터를 처리할 때 성능 문제가 발생할 수 있으므로, 페이지네이션을 구현하는 것이 좋습니다.

-    public List<LineItem> findAll() {
+    public List<LineItem> findAll(int skip, int limit) {
         List<Document> documents = new ArrayList<>();
-        collection.find().into(documents);
+        collection.find()
+                 .skip(skip)
+                 .limit(limit)
+                 .into(documents);
 
         return documents.stream().map(this::mapToModel).toList();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public List<LineItem> findAll() {
List<Document> documents = new ArrayList<>();
collection.find().into(documents);
return documents.stream().map(this::mapToModel).toList();
}
public List<LineItem> findAll(int skip, int limit) {
List<Document> documents = new ArrayList<>();
collection.find()
.skip(skip)
.limit(limit)
.into(documents);
return documents.stream().map(this::mapToModel).toList();
}

Comment on lines +49 to +55
private LineItem mapToModel(Document document) {
return new LineItem(
document.getObjectId("_id").toString(),
document.getString("product_id"),
document.getInteger("quantity")
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

모든 필드를 매핑해야 합니다

Document에서 LineItem으로 변환 시 모든 필드가 매핑되어야 합니다.

     private LineItem mapToModel(Document document) {
         return new LineItem(
                 document.getObjectId("_id").toString(),
                 document.getString("product_id"),
-                document.getInteger("quantity")
+                document.getString("product_name"),
+                document.getInteger("quantity"),
+                document.getDouble("unit_price")
         );
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private LineItem mapToModel(Document document) {
return new LineItem(
document.getObjectId("_id").toString(),
document.getString("product_id"),
document.getInteger("quantity")
);
}
private LineItem mapToModel(Document document) {
return new LineItem(
document.getObjectId("_id").toString(),
document.getString("product_id"),
document.getString("product_name"),
document.getInteger("quantity"),
document.getDouble("unit_price")
);
}

Comment on lines +39 to +47
public void update(LineItem lineItem) {
collection.updateOne(
Filters.eq("_id", new ObjectId(lineItem.getId())),
Updates.combine(
Updates.set("product_id", lineItem.getProductId()),
Updates.set("quantity", lineItem.getQuantity())
)
);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

모든 필드에 대한 업데이트가 필요합니다

현재 product_idquantity만 업데이트하고 있습니다. 모든 필드를 업데이트해야 합니다.

     public void update(LineItem lineItem) {
         collection.updateOne(
                 Filters.eq("_id", new ObjectId(lineItem.getId())),
                 Updates.combine(
                         Updates.set("product_id", lineItem.getProductId()),
-                        Updates.set("quantity", lineItem.getQuantity())
+                        Updates.set("quantity", lineItem.getQuantity()),
+                        Updates.set("product_name", lineItem.getProductName()),
+                        Updates.set("unit_price", lineItem.getUnitPrice())
                 )
         );
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void update(LineItem lineItem) {
collection.updateOne(
Filters.eq("_id", new ObjectId(lineItem.getId())),
Updates.combine(
Updates.set("product_id", lineItem.getProductId()),
Updates.set("quantity", lineItem.getQuantity())
)
);
}
public void update(LineItem lineItem) {
collection.updateOne(
Filters.eq("_id", new ObjectId(lineItem.getId())),
Updates.combine(
Updates.set("product_id", lineItem.getProductId()),
Updates.set("quantity", lineItem.getQuantity()),
Updates.set("product_name", lineItem.getProductName()),
Updates.set("unit_price", lineItem.getUnitPrice())
)
);
}

Comment on lines +31 to +37
public void add(LineItem lineItem) {
Document document = new Document()
.append("product_id", lineItem.getProductId())
.append("quantity", lineItem.getQuantity());

collection.insertOne(document);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

LineItem의 모든 필드를 저장해야 합니다

현재 product_idquantity만 저장하고 있습니다. 나머지 필드들도 저장이 필요합니다.

     public void add(LineItem lineItem) {
         Document document = new Document()
                 .append("product_id", lineItem.getProductId())
-                .append("quantity", lineItem.getQuantity());
+                .append("quantity", lineItem.getQuantity())
+                .append("product_name", lineItem.getProductName())
+                .append("unit_price", lineItem.getUnitPrice());
 
         collection.insertOne(document);
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public void add(LineItem lineItem) {
Document document = new Document()
.append("product_id", lineItem.getProductId())
.append("quantity", lineItem.getQuantity());
collection.insertOne(document);
}
public void add(LineItem lineItem) {
Document document = new Document()
.append("product_id", lineItem.getProductId())
.append("quantity", lineItem.getQuantity())
.append("product_name", lineItem.getProductName())
.append("unit_price", lineItem.getUnitPrice());
collection.insertOne(document);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant