Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
a5fa74c
2주차 영속성컨텍스트 실습
smartandhandsome Jul 29, 2023
7edb8d9
feat: orders 추가
smartandhandsome Jul 30, 2023
9249721
feat: Item 구현
smartandhandsome Jul 30, 2023
24f01c4
feat: Order 도메인 구현
smartandhandsome Jul 30, 2023
6c34145
feat: merge
smartandhandsome Aug 5, 2023
cadaf52
feat: CustomerUpdateRequest 객체를 Customer로 변환하는 메서드 생성
smartandhandsome Jul 31, 2023
58b3a66
feat: 새로 만든 changeCustomer 메서드 사용
smartandhandsome Jul 31, 2023
e098e33
feat: 400 500 상태코드에 body 추가
smartandhandsome Jul 31, 2023
963a060
test: Customer 테스트 작성
smartandhandsome Jul 31, 2023
1e97000
test: Customer Repository 작성
smartandhandsome Jul 31, 2023
7a7fb07
feat:
smartandhandsome Aug 5, 2023
100445c
test: BeforeEach로 데이터 생성 후 1차 캐시 비움
smartandhandsome Aug 3, 2023
236d1ce
refactor: import 시 asterisk 제거하고 import 항목 명시
smartandhandsome Aug 3, 2023
c3b0976
refactor: class와 import 사이 개행 추가
smartandhandsome Aug 3, 2023
a5e4d55
feat: 추상클래스로 변경
smartandhandsome Aug 3, 2023
0131918
test: 각 field를 반환하여 비교한 것을 usingRecursiveComparison으로 변경
smartandhandsome Aug 3, 2023
f9e5cee
feat: ErrorResponse 생성 및 GlobalExceptionHandler 적용
smartandhandsome Aug 3, 2023
beee729
refactor: import 시 asterisk 제거 및 질문 삭제
smartandhandsome Aug 3, 2023
5c9bd47
feat: ErrorResponse에 Getter 추가, ControllerAdvice -> RestControllerAdv…
smartandhandsome Aug 3, 2023
84fc7b2
feat: message 추가
smartandhandsome Aug 3, 2023
33a3c88
refactor: Error Message 변경, ExceptionHandler 분리, 질문 추가
smartandhandsome Aug 3, 2023
da38737
chore
smartandhandsome Aug 5, 2023
bd8314a
chore: 질문 삭제
smartandhandsome Aug 5, 2023
8264c08
feat: CANCELE 추가
smartandhandsome Aug 5, 2023
6b88225
test: main 코드 변경에 따른 test 수정
smartandhandsome Aug 5, 2023
45c7980
Merge branch 'smart-sangmin' into week3
smartandhandsome Aug 5, 2023
e4853c3
feat: 에러메세지 수정
smartandhandsome Aug 5, 2023
a2660f5
feat: import asterisk 제거
smartandhandsome Aug 6, 2023
8af6a32
chore: conflict 해결
smartandhandsome Aug 6, 2023
6cc2537
chore: 질문 삭제
smartandhandsome Aug 6, 2023
c7d6887
feat: NotBlank 추가
smartandhandsome Aug 6, 2023
9731909
feat: private 접근제어자 설정
smartandhandsome Aug 6, 2023
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 @@ -5,14 +5,17 @@
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.programmers.jpaweeklymission.global.BaseEntity;
import org.programmers.jpaweeklymission.order.domain.Order;
import java.util.ArrayList;
import java.util.List;

@Table(name = "customers")
@Entity
Expand All @@ -21,18 +24,20 @@
public class Customer extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;

@NotBlank
@Size(min = 1, max = 20)
@Column(name = "first_name", length = 20, nullable = false)
private String firstName;

@NotBlank
@Size(min = 1, max = 20)
@Column(name = "last_name", length = 20, nullable = false)
private String lastName;

@OneToMany(mappedBy = "customer")
private List<Order> orders = new ArrayList<>();

@Builder
private Customer(String firstName, String lastName) {
this.firstName = firstName;
Expand All @@ -51,4 +56,8 @@ private void changeFirstName(String firstName) {
private void changeLastName(String lastName) {
this.lastName = lastName;
}

public void removeOrder(Order order) {
this.orders.remove(order);
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.programmers.jpaweeklymission.customer.presentation.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record CustomerCreationRequest(
@NotBlank(message = "First name must not be blank.")

Choose a reason for hiding this comment

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

min 이 지정되어 있는데 not blank도 검증 해주어야 하나요?

Copy link
Author

Choose a reason for hiding this comment

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

생각해보니 " " 같은 부분이 있기 때문에 다시 설정했습니다.

@Size(min = 1, max = 20, message = "First name must be at least 1 character and no more than 20 characters.")
String firstName,
@NotBlank(message = "Last name must not be blank.")
@Size(min = 1, max = 20, message = "Last name must be at least 1 character and no more than 20 characters.")
String lastName
) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package org.programmers.jpaweeklymission.customer.presentation.dto;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;

public record CustomerUpdateRequest(
@NotBlank(message = "First name must not be blank.")
@Size(min = 1, max = 20, message = "First name must be at least 1 character and no more than 20 characters.")
String firstName,
@NotBlank(message = "Last name must not be blank.")
@Size(min = 1, max = 20, message = "Last name must be at least 1 character and no more than 20 characters.")
String lastName
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
public abstract class BaseEntity {
@Column(name = "create_at", nullable = false, updatable = false)
@CreatedDate
LocalDateTime createAt;
private LocalDateTime createAt;
@Column(name = "update_at", nullable = false)
@LastModifiedDate
LocalDateTime updateAt;
private LocalDateTime updateAt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler { // TODO: 혹시 멘토님들은 여기서 어떤 어떤 에러를 잡으시나요?
public class GlobalExceptionHandler {
@ExceptionHandler(EntityNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleEntityNotFoundException(EntityNotFoundException e) {
Expand All @@ -23,7 +23,11 @@ public ErrorResponse handleEntityNotFoundException(EntityNotFoundException e) {
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
log.warn(e.getMessage(), e);
return ErrorResponse.newErrorResponse(e.getMessage());
return ErrorResponse.newErrorResponse(e
.getBindingResult()
.getFieldErrors()
.get(0)

Choose a reason for hiding this comment

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

첫 번째 에러만 반환하는 이유가 있나요?

Copy link
Author

Choose a reason for hiding this comment

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

첫 번째 에러에 제가 validation 규칙에서 적용한 message를 담고 있어서 첫번째 에러만 반환했습니다.

뭔가 코드가 찜찜하긴 한데 혹시 다른 방법이 있나요?

.getDefaultMessage());
}

@ExceptionHandler(HttpMessageNotReadableException.class)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.programmers.jpaweeklymission.item.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.programmers.jpaweeklymission.global.BaseEntity;

@Table(name = "items")
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Item extends BaseEntity {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@Column(name = "price")
private int price;

@Column(name = "stock_quantity")
private int stockQuantity;

@Builder
public Item(int price, int stockQuantity) {
this.price = price;
this.stockQuantity = stockQuantity;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package org.programmers.jpaweeklymission.order.domain;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.programmers.jpaweeklymission.customer.Customer;
import org.programmers.jpaweeklymission.global.BaseEntity;

import java.util.List;
import java.util.Objects;

@Table(name = "orders")
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Order extends BaseEntity {
@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.AUTO)

Choose a reason for hiding this comment

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

따로 id 생성 전략을 지정하지 않는 이유가 있나요?

private Long id;

@Enumerated(EnumType.STRING)
@Column(name = "status", nullable = false)
@NotNull
private OrderStatus status;

@Lob
@Column(name = "memo")
private String memo;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer_id", referencedColumnName = "id")
private Customer customer;

@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems;

@Builder
public Order(OrderStatus status, String memo) {
this.status = status;
this.memo = memo;
}

public void setCustomer(Customer customer) {
if (Objects.nonNull(this.customer)) {
customer.removeOrder(this);
Copy link
Member

Choose a reason for hiding this comment

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

이게 로직이 맞나요?

Copy link
Author

@smartandhandsome smartandhandsome Aug 6, 2023

Choose a reason for hiding this comment

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

아 저부분 여쭤보려고 주석을 달았어야 했는데 깜빡했습니다.

일단 강사님께서 강의중에 저런 로직을 작성하셨습니다.

근데 그 부분에 좀 의문이 들었는데 사실 setCustomer 라는 건 제가 생각하기로는 초기에 주문(Order)에 고객(Customer)라는 걸 등록하는 거라고 생각했습니다.

근데 저걸 적으신 강사님이 의도한 건 아래 두 개라고 생각했습니다.

  1. 초기 주문 작성 시 미리 등록된 Customer가 있는지 한 번 더 체크하고 무시하기 위해서?
  2. 주문에 할당된 Customer를 수정하기 위해서?

다른 부분 Item, OrderItem 부분에도 nonNull 체크를 전부 적용하셨는데 이게 필요한가요?, 좋은 방법인가요? 멘토님들 의견 궁금합니다.

Choose a reason for hiding this comment

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

해당 로직은 상품이 생성될 때 구매자가 중복 등록되는 것을 방지하는 코드가 맞는 것 같습니다.

if(Objects.nonNull(this.customer))는 현재 주문에 구매자가 등록되어 있는지 확인하는 구문이네요. 그런데 customer.removeOrder(this)는 인자로 넘어온 구매자와 주문간 관계를 끊어주는 것 같습니다. 이 부분이 조금 어색한 것 같아요.

아래에서 this.customer = customer로 기존 구매자를 새롭게 인자로 넘어온 구매자로 대체하는데, 그렇다면 기존 구매자와 주문간 관계를 끊어주어야 하는 것이 아닐까요?

양방향 매핑이 조금 복잡하다면 단방향 매핑으로 단순하게 시작하는 것도 좋을 것 같네요

Copy link
Author

Choose a reason for hiding this comment

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

제가 잘 이해한 건지 모르겠는데 "그렇다면 기존 구매자와 주문간 관계를 끊어주어야 하는 것이 아닐까요?" 이 부분을 customer.removeOrder(this)라는 문장으로 처리합니다.

}
this.customer = customer;
customer.getOrders().add(this);
}

public void addOrderItems(OrderItem orderItem) {
orderItem.setOrder(this);
Copy link
Member

Choose a reason for hiding this comment

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

현재 orderItems에는 추가되는 orderItem을 add 해주지 않아도 되나요?

Copy link
Author

Choose a reason for hiding this comment

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

setOrder 메서드가 아래처럼 작성 되어 있습니다.

this.order = order;
order.getOrderItems().add(this);

Copy link
Member

Choose a reason for hiding this comment

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

orderItem이 주도적으로 제어하는 이유가 있나요?

Copy link
Author

@smartandhandsome smartandhandsome Aug 8, 2023

Choose a reason for hiding this comment

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

누가 하던지 상관없다고 생각하는데, 키를 갖고 있고 수정 시 쿼리가 나가는 OrderItem 테이블에서 제어해주는게 좋다고 생각했습니다.

또, 양방향 매핑 시에 저런 메서드가 계속적으로 생겨나는데, 키를 갖고 있는 쪽에 저런 메서드를 정의하자라고 기준을 정헀습니다.

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.programmers.jpaweeklymission.order.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.programmers.jpaweeklymission.global.BaseEntity;
import org.programmers.jpaweeklymission.item.domain.Item;

import java.util.Objects;

@Entity
@Getter
@Table(name = "order_items")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OrderItem extends BaseEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;

@ManyToOne
@JoinColumn(name = "order_id", referencedColumnName = "id")
private Order order;

@ManyToOne
@JoinColumn(name = "item_id", referencedColumnName = "id")
private Item item;

public void setOrder(Order order) {
this.order = order;
order.getOrderItems().add(this);
}

public void setItem(Item item) {
this.item = item;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.programmers.jpaweeklymission.order.domain;


public enum OrderStatus {
CREATED,
SHIPPING,
DELIVERED,
CANCELED
}
Loading