Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class MenuCreateRequest {
@NotNull
private String description;
@NotNull
private String price;
private Integer price;

public Menu toEntity() {
return Menu.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public class MenuCreateResponse {
private Long storeId;
private String name;
private String description;
private String price;
private Integer price;
private LocalDateTime createdAt;

public static MenuCreateResponse fromEntity(Menu menu) {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/example/gtable/menu/dto/MenuReadDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class MenuReadDto {
private Long storeId;
private String name;
private String description;
private String price;
private Integer price;
private List<MenuImageUploadResponse> images;

public static MenuReadDto fromEntity(Menu menu, List<MenuImageUploadResponse> images) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/example/gtable/menu/model/Menu.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ public class Menu extends BaseTimeEntity {
private Long storeId;
private String name;
private String description;
private String price;
private Integer price;

public Menu(LocalDateTime createdAt, Long id, Long storeId, String name, String description, String price) {
public Menu(LocalDateTime createdAt, Long id, Long storeId, String name, String description, Integer price) {
super(createdAt);
this.Id = id;
this.storeId = storeId;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.example.gtable.order.controller;

import java.util.List;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -12,10 +15,12 @@
import com.example.gtable.order.dto.OrderCreateRequestDto;
import com.example.gtable.order.dto.OrderCreateResponseDto;
import com.example.gtable.order.service.OrderService;
import com.example.gtable.orderitem.dto.OrderItemListGetResponseDto;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpSession;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;

Expand All @@ -28,19 +33,38 @@ public class OrderController {

@PostMapping("/create/{storeId}/{tableId}")
@Operation(summary = "주문 생성", description = "특정 주점 - 특정 테이블에 대한 주문 생성")
@ApiResponse(responseCode = "201", description = "북마크 생성")
@ApiResponse(responseCode = "201", description = "주문 생성")
public ResponseEntity<?> createOrder(
@PathVariable Long storeId,
@PathVariable Long tableId,
@RequestBody @Valid OrderCreateRequestDto orderCreateRequestDto
@RequestBody @Valid OrderCreateRequestDto orderCreateRequestDto,
HttpSession session
) {
OrderCreateResponseDto response = orderService.createOrder(storeId,tableId,orderCreateRequestDto);
String sessionId = session.getId();
OrderCreateResponseDto response = orderService.createOrder(storeId,tableId,orderCreateRequestDto,sessionId);
return ResponseEntity
.status(HttpStatus.CREATED)
.body(
ApiUtils.success(
response
)
ApiUtils.success(response)
);
}

@GetMapping("/items/{storeId}/{tableId}")
@Operation(summary = "테이블별 주문 아이템 조회", description = "비로그인(세션) 기준으로 테이블의 내 주문 목록만 조회")
@ApiResponse(responseCode = "200", description = "주문 조회")
public ResponseEntity<?> 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.
status(HttpStatus.OK)
.body(
ApiUtils.success(orderItems)
);
}
}
14 changes: 13 additions & 1 deletion src/main/java/com/example/gtable/order/entity/UserOrder.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package com.example.gtable.order.entity;

import java.util.ArrayList;
import java.util.List;

import com.example.gtable.global.entity.BaseTimeEntity;
import com.example.gtable.orderitem.entity.OrderItem;
import com.example.gtable.store.model.Store;

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
Expand All @@ -11,8 +16,10 @@
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;
Expand All @@ -21,7 +28,7 @@
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@SuperBuilder
@Builder
public class UserOrder extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Expand All @@ -37,4 +44,9 @@ public class UserOrder extends BaseTimeEntity {
@JoinColumn(name = "store_id")
private Store store;

@OneToMany(mappedBy = "userOrder", cascade = CascadeType.ALL, orphanRemoval = true)
private List<OrderItem> orderItems = new ArrayList<>();

private String sessionId;

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.gtable.order.repository;

import java.time.LocalDateTime;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
Expand All @@ -11,4 +12,7 @@
public interface OrderRepository extends JpaRepository<UserOrder,Long> {
boolean existsBySignatureAndCreatedAtAfter(String signature, LocalDateTime createdAt);

List<UserOrder> findByStore_StoreIdAndTableIdAndSessionId(Long storeId, Long tableId, String sessionId);


}
18 changes: 16 additions & 2 deletions src/main/java/com/example/gtable/order/service/OrderService.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package com.example.gtable.order.service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -19,6 +18,7 @@
import com.example.gtable.order.dto.OrderCreateResponseDto;
import com.example.gtable.order.entity.UserOrder;
import com.example.gtable.order.repository.OrderRepository;
import com.example.gtable.orderitem.dto.OrderItemListGetResponseDto;
import com.example.gtable.orderitem.entity.OrderItem;
import com.example.gtable.orderitem.repository.OrderItemRepository;
import com.example.gtable.store.model.Store;
Expand All @@ -34,7 +34,8 @@ public class OrderService {
private final MenuRepository menuRepository;
private final OrderItemRepository orderItemRepository;
@Transactional
public OrderCreateResponseDto createOrder(Long storeId, Long tableId, OrderCreateRequestDto orderCreateRequestDto) {
public OrderCreateResponseDto createOrder(Long storeId, Long tableId,
OrderCreateRequestDto orderCreateRequestDto, String sessionId) {
parameterValidation(storeId, tableId, orderCreateRequestDto);

// 💡 [중복 주문 방지] signature 생성 및 체크
Expand All @@ -50,6 +51,7 @@ public OrderCreateResponseDto createOrder(Long storeId, Long tableId, OrderCreat
.tableId(tableId)
.store(store)
.signature(signature) // signature 저장
.sessionId(sessionId) // sessionId 저장
.build();
UserOrder savedOrder = orderRepository.save(order);

Expand Down Expand Up @@ -81,6 +83,18 @@ public OrderCreateResponseDto createOrder(Long storeId, Long tableId, OrderCreat
return OrderCreateResponseDto.fromEntity(savedOrder);
}

@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();
}


private static void parameterValidation(Long storeId, Long tableId, OrderCreateRequestDto orderCreateRequestDto) {
if (storeId == null || tableId == null || orderCreateRequestDto == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.example.gtable.orderitem.dto;

import com.example.gtable.orderitem.entity.OrderItem;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class OrderItemListGetResponseDto {
private Long orderId;
private String menuName;
private Integer quantity;
private Integer price;

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();

}
Comment on lines +20 to +28
Copy link

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.

Suggested change
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.

}