-
Notifications
You must be signed in to change notification settings - Fork 0
feat(order): 사용자별 주문 조회(세션) #50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The head ref may contain hidden characters: "feature/#30-\uC8FC\uBB38CRUD"
Conversation
- 세션 기반 사용자별 주문 조회 로직 구현 - price 타입 Integer로 변경
Walkthrough이번 변경에서는 메뉴 및 주문 관련 DTO와 엔티티의 가격 타입을 Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant OrderController
participant OrderService
participant OrderRepository
participant UserOrder
participant OrderItem
Client->>OrderController: POST /orders/{storeId}/{tableId} (with session)
OrderController->>OrderService: createOrder(storeId, tableId, requestDto, sessionId)
OrderService->>UserOrder: 생성 (sessionId 포함)
OrderService-->>OrderController: OrderCreateResponseDto
OrderController-->>Client: Response
Client->>OrderController: GET /orders/items/{storeId}/{tableId} (with session)
OrderController->>OrderService: getOrderItems(storeId, tableId, sessionId)
OrderService->>OrderRepository: findByStore_StoreIdAndTableIdAndSessionId
OrderRepository-->>OrderService: List<UserOrder>
OrderService->>OrderItem: 주문별 OrderItem 추출
OrderService-->>OrderController: List<OrderItemListGetResponseDto>
OrderController-->>Client: ResponseEntity<List<...>>
Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/main/java/com/example/gtable/order/service/OrderService.java (1)
86-96: 성능 최적화와 빈 결과 처리를 고려해주세요.현재 구현은 기능적으로 올바르지만, 성능과 사용자 경험 측면에서 개선 여지가 있습니다.
다음 개선사항들을 고려해보세요:
- 성능 최적화: Repository에서 직접 OrderItem을 조회하는 방법
- 빈 결과 처리: 빈 목록일 때의 명확한 처리
@Transactional(readOnly = true) public List<OrderItemListGetResponseDto> getOrderItems(Long storeId, Long tableId, String sessionId) { - // 1. UserOrder 목록 조회 (storeId, tableId, sessionId 기준) - List<UserOrder> userOrders = orderRepository.findByStore_StoreIdAndTableIdAndSessionId(storeId, tableId, sessionId); - - // 2. OrderItem으로 변환 - return userOrders.stream() - .flatMap(order -> order.getOrderItems().stream()) - .map(OrderItemListGetResponseDto::fromEntity) - .toList(); + List<UserOrder> userOrders = orderRepository.findByStore_StoreIdAndTableIdAndSessionId(storeId, tableId, sessionId); + + if (userOrders.isEmpty()) { + return Collections.emptyList(); // 빈 목록 명시적 반환 + } + + return userOrders.stream() + .flatMap(order -> order.getOrderItems().stream()) + .map(OrderItemListGetResponseDto::fromEntity) + .collect(Collectors.toList()); }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/main/java/com/example/gtable/menu/dto/MenuCreateRequest.java(1 hunks)src/main/java/com/example/gtable/menu/dto/MenuCreateResponse.java(1 hunks)src/main/java/com/example/gtable/menu/dto/MenuReadDto.java(1 hunks)src/main/java/com/example/gtable/menu/model/Menu.java(1 hunks)src/main/java/com/example/gtable/order/controller/OrderController.java(4 hunks)src/main/java/com/example/gtable/order/entity/UserOrder.java(4 hunks)src/main/java/com/example/gtable/order/repository/OrderRepository.java(2 hunks)src/main/java/com/example/gtable/order/service/OrderService.java(4 hunks)src/main/java/com/example/gtable/orderitem/dto/OrderItemListGetResponseDto.java(1 hunks)
🔇 Additional comments (12)
src/main/java/com/example/gtable/menu/dto/MenuCreateResponse.java (1)
19-19: 가격 필드의 데이터 타입 변경을 승인합니다.String에서 Integer로의 타입 변경은 매우 적절한 개선사항입니다. 가격 데이터는 숫자 타입으로 관리하는 것이 데이터 일관성과 타입 안전성 측면에서 훨씬 좋습니다.
src/main/java/com/example/gtable/menu/dto/MenuCreateRequest.java (1)
22-22: 요청 DTO의 가격 필드 타입 변경이 적절합니다.다른 메뉴 관련 클래스들과 일관성을 유지하면서 Integer 타입으로 변경한 것이 좋습니다. @NotNull 검증도 그대로 유지되어 있어 완벽합니다.
src/main/java/com/example/gtable/menu/dto/MenuReadDto.java (1)
20-20: 읽기 DTO의 가격 필드 타입 변경을 승인합니다.메뉴 관련 모든 DTO에서 일관되게 Integer 타입으로 변경하신 것이 매우 체계적이고 좋습니다. fromEntity 메서드도 올바르게 구현되어 있습니다.
src/main/java/com/example/gtable/menu/model/Menu.java (2)
34-41: 생성자 매개변수 타입 변경이 일관성 있게 처리되었습니다.필드 타입 변경에 맞춰 생성자 매개변수도 Integer로 변경하신 것이 좋습니다. 타입 일관성이 잘 유지되고 있습니다.
32-32: 엔티티의 가격 필드 타입 변경을 승인합니다.엔티티 레벨에서 Integer로 변경하신 것이 매우 적절합니다. 데이터베이스에서 가격을 숫자 타입으로 관리하는 것이 올바른 설계입니다.
데이터베이스 마이그레이션이 필요한지 확인해 주세요. 기존 String 타입 데이터가 있다면 Integer로 안전하게 변환되는지 검증이 필요합니다.
다음 스크립트로 price 필드 사용 현황을 확인할 수 있습니다:
#!/bin/bash # 가격 필드 관련 데이터베이스 스키마 및 마이그레이션 파일 확인 fd -e sql | xargs grep -l "price"src/main/java/com/example/gtable/order/repository/OrderRepository.java (2)
4-4: 필요한 import 추가가 적절합니다.List 타입을 사용하기 위한 import가 정확하게 추가되었습니다.
15-15: UserOrder 엔티티의Store관계 매핑(@ManyToOne+@JoinColumn)이 실제로Store필드를 가리키는지 확인하기 위해, 아래 스크립트를 실행해 주세요. 매핑 선언과 조인 컬럼 정보를 함께 보여주시면 검토를 이어가겠습니다.#!/bin/bash # UserOrder 엔티티의 ManyToOne 매핑 주변 코드(필드명 포함) 확인 rg -n --glob 'UserOrder.java' '@ManyToOne' -A3 -B1 src/main/java/com/example/gtable/order/entity/UserOrder.java # JoinColumn 어노테이션으로 매핑 컬럼 이름 확인 rg -n --glob 'UserOrder.java' '@JoinColumn' -A3 -B1 src/main/java/com/example/gtable/order/entity/UserOrder.javasrc/main/java/com/example/gtable/order/service/OrderService.java (1)
37-38: 메서드 시그니처 변경이 적절합니다.세션 ID 매개변수 추가로 세션 기반 주문 관리가 가능해졌습니다. 변경사항이 PR 목표와 일치합니다.
src/main/java/com/example/gtable/order/entity/UserOrder.java (3)
47-48: 엔티티 관계 설정이 적절합니다.OrderItem과의 OneToMany 관계가 올바르게 설정되었습니다.
CascadeType.ALL과orphanRemoval = true설정으로 데이터 무결성이 잘 관리될 것 같습니다.
50-50: 세션 ID 필드 추가가 적절합니다.세션 기반 주문 관리를 위한 sessionId 필드가 올바르게 추가되었습니다.
31-31: Builder 어노테이션 변경에 대한 검증이 필요합니다.
@SuperBuilder에서@Builder로 변경되었는데,BaseTimeEntity와의 상속 관계에서 문제가 없는지 확인이 필요합니다.다음 스크립트로 BaseTimeEntity의 Builder 패턴 사용을 확인해주세요:
#!/bin/bash # BaseTimeEntity에서 SuperBuilder 사용 여부 확인 ast-grep --pattern 'class BaseTimeEntity { $$$ }' # SuperBuilder 어노테이션 사용 확인 rg -A 3 -B 3 "@SuperBuilder" src/main/java/com/example/gtable/global/entity/BaseTimeEntity.javasrc/main/java/com/example/gtable/order/controller/OrderController.java (1)
40-44: 세션 처리 구현이 올바릅니다.
HttpSession을 통한 세션 ID 추출과 서비스 계층으로의 전달이 적절하게 구현되었습니다.
| public static OrderItemListGetResponseDto fromEntity(OrderItem orderItem) { | ||
| return OrderItemListGetResponseDto.builder() | ||
| .orderId(orderItem.getUserOrder().getId()) | ||
| .menuName(orderItem.getMenu().getName()) | ||
| .quantity(orderItem.getQuantity()) | ||
| .price(orderItem.getMenu().getPrice()) | ||
| .build(); | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
엔티티 접근 시 null 안전성 고려가 필요합니다.
fromEntity 메서드에서 orderItem.getUserOrder()와 orderItem.getMenu() 접근 시 null 체크가 없어 NPE 위험이 있습니다. 안전성을 위해 방어적 프로그래밍을 권장드립니다.
다음과 같이 null 안전성을 추가해보세요:
public static OrderItemListGetResponseDto fromEntity(OrderItem orderItem) {
+ if (orderItem == null || orderItem.getUserOrder() == null || orderItem.getMenu() == null) {
+ throw new IllegalArgumentException("OrderItem과 연관된 엔티티들이 null일 수 없습니다");
+ }
return OrderItemListGetResponseDto.builder()
.orderId(orderItem.getUserOrder().getId())
.menuName(orderItem.getMenu().getName())
.quantity(orderItem.getQuantity())
.price(orderItem.getMenu().getPrice())
.build();
}📝 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.
| public static OrderItemListGetResponseDto fromEntity(OrderItem orderItem) { | |
| return OrderItemListGetResponseDto.builder() | |
| .orderId(orderItem.getUserOrder().getId()) | |
| .menuName(orderItem.getMenu().getName()) | |
| .quantity(orderItem.getQuantity()) | |
| .price(orderItem.getMenu().getPrice()) | |
| .build(); | |
| } | |
| public static OrderItemListGetResponseDto fromEntity(OrderItem orderItem) { | |
| + if (orderItem == null || orderItem.getUserOrder() == null || orderItem.getMenu() == null) { | |
| + throw new IllegalArgumentException("OrderItem과 연관된 엔티티들이 null일 수 없습니다"); | |
| + } | |
| return OrderItemListGetResponseDto.builder() | |
| .orderId(orderItem.getUserOrder().getId()) | |
| .menuName(orderItem.getMenu().getName()) | |
| .quantity(orderItem.getQuantity()) | |
| .price(orderItem.getMenu().getPrice()) | |
| .build(); | |
| } |
🤖 Prompt for AI Agents
In
src/main/java/com/example/gtable/orderitem/dto/OrderItemListGetResponseDto.java
between lines 20 and 28, the fromEntity method accesses orderItem.getUserOrder()
and orderItem.getMenu() without null checks, risking NullPointerException. Add
defensive null checks before accessing these methods, and handle null cases
appropriately, such as returning default values or throwing informative
exceptions, to ensure null safety.
| @GetMapping("/items/{storeId}/{tableId}") | ||
| @Operation(summary = "테이블별 주문 아이템 조회", description = "비로그인(세션) 기준으로 테이블의 내 주문 목록만 조회") | ||
| @ApiResponse(responseCode = "200", description = "주문 조회") | ||
| public ResponseEntity<List<OrderItemListGetResponseDto>> getOrderItems( | ||
| @PathVariable Long storeId, | ||
| @PathVariable Long tableId, | ||
| HttpSession session | ||
| ) { | ||
| // 세션ID 추출 (Spring이 세션 자동 관리) | ||
| String sessionId = session.getId(); | ||
|
|
||
| List<OrderItemListGetResponseDto> orderItems = orderService.getOrderItems(storeId, tableId, sessionId); | ||
| return ResponseEntity.ok(orderItems); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
API 응답 일관성과 세션 보안을 고려해주세요.
새로운 엔드포인트가 잘 구현되었지만, 몇 가지 개선사항을 제안드립니다.
- API 응답 일관성: 다른 엔드포인트와 동일하게
ApiUtils.success()로 래핑 - 세션 상태 검증: 세션 유효성 체크 추가
@GetMapping("/items/{storeId}/{tableId}")
@Operation(summary = "테이블별 주문 아이템 조회", description = "비로그인(세션) 기준으로 테이블의 내 주문 목록만 조회")
@ApiResponse(responseCode = "200", description = "주문 조회")
-public ResponseEntity<List<OrderItemListGetResponseDto>> getOrderItems(
+public ResponseEntity<?> getOrderItems(
@PathVariable Long storeId,
@PathVariable Long tableId,
HttpSession session
) {
+ if (session.isNew()) {
+ throw new IllegalStateException("유효하지 않은 세션입니다");
+ }
+
String sessionId = session.getId();
List<OrderItemListGetResponseDto> orderItems = orderService.getOrderItems(storeId, tableId, sessionId);
- return ResponseEntity.ok(orderItems);
+ return ResponseEntity.ok(ApiUtils.success(orderItems));
}📝 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.
| @GetMapping("/items/{storeId}/{tableId}") | |
| @Operation(summary = "테이블별 주문 아이템 조회", description = "비로그인(세션) 기준으로 테이블의 내 주문 목록만 조회") | |
| @ApiResponse(responseCode = "200", description = "주문 조회") | |
| public ResponseEntity<List<OrderItemListGetResponseDto>> getOrderItems( | |
| @PathVariable Long storeId, | |
| @PathVariable Long tableId, | |
| HttpSession session | |
| ) { | |
| // 세션ID 추출 (Spring이 세션 자동 관리) | |
| String sessionId = session.getId(); | |
| List<OrderItemListGetResponseDto> orderItems = orderService.getOrderItems(storeId, tableId, sessionId); | |
| return ResponseEntity.ok(orderItems); | |
| } | |
| @GetMapping("/items/{storeId}/{tableId}") | |
| @Operation(summary = "테이블별 주문 아이템 조회", description = "비로그인(세션) 기준으로 테이블의 내 주문 목록만 조회") | |
| @ApiResponse(responseCode = "200", description = "주문 조회") | |
| public ResponseEntity<?> getOrderItems( | |
| @PathVariable Long storeId, | |
| @PathVariable Long tableId, | |
| HttpSession session | |
| ) { | |
| if (session.isNew()) { | |
| throw new IllegalStateException("유효하지 않은 세션입니다"); | |
| } | |
| String sessionId = session.getId(); | |
| List<OrderItemListGetResponseDto> orderItems = orderService.getOrderItems(storeId, tableId, sessionId); | |
| return ResponseEntity.ok(ApiUtils.success(orderItems)); | |
| } |
🤖 Prompt for AI Agents
In src/main/java/com/example/gtable/order/controller/OrderController.java around
lines 54 to 67, the getOrderItems method should be updated to ensure API
response consistency and session security. Wrap the returned orderItems list
with ApiUtils.success() to match the response format of other endpoints.
Additionally, add a check to verify the session is valid before proceeding; if
the session is invalid or expired, return an appropriate error response to
prevent unauthorized access.
작업 요약
Issue Link
#30
문제점 및 어려움
해결 방안
Reference
Summary by CodeRabbit
신규 기능
기능 개선
버그 수정