- 
                Notifications
    You must be signed in to change notification settings 
- Fork 151
[4기 윤영운, 김별 ] Springboot-jpa weekly 미션 제출합니다. #324
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
base: 별,영운-misson
Are you sure you want to change the base?
Changes from 1 commit
2c1e0c0
              84b8d45
              569a540
              014cfe1
              ad133cd
              4e34981
              419f904
              9b92e86
              0e0da7a
              f9a0e9f
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -16,13 +16,18 @@ | |
| @Configuration | ||
| public class DataSourceConfig { | ||
|  | ||
| private static final String DRIVER = "org.h2.Driver"; | ||
| private static final String DB_URL = "jdbc:h2:tcp://localhost/~/test"; | ||
| private static final String USER = "sa"; | ||
| private static final String PASSWORD= ""; | ||
|  | ||
| @Bean | ||
| public DataSource dataSource() { | ||
| DriverManagerDataSource dataSource = new DriverManagerDataSource(); | ||
| dataSource.setDriverClassName("org.h2.Driver"); | ||
| dataSource.setUrl("jdbc:h2:tcp://localhost/~/test"); | ||
| dataSource.setUsername("sa"); | ||
| dataSource.setPassword(""); | ||
| dataSource.setDriverClassName(DRIVER); | ||
| dataSource.setUrl(DB_URL); | ||
| dataSource.setUsername(USER); | ||
| dataSource.setPassword(PASSWORD); | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이렇게 필드로 정보를 관리하고 DataSource를 직접 생성하는 의도가 궁금해요. 설정 정보를 읽어다 Spring AutoConfiguration이 Datasource를 만들어 줍니다. | ||
|  | ||
| return dataSource; | ||
| } | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,27 +1,31 @@ | ||
| package com.example.springjpamission.customer.domain; | ||
|  | ||
| import com.example.springjpamission.gobal.BaseEntity; | ||
| import jakarta.persistence.Embedded; | ||
| import jakarta.persistence.Entity; | ||
| import jakarta.persistence.GeneratedValue; | ||
| import jakarta.persistence.GenerationType; | ||
| import jakarta.persistence.Id; | ||
| import lombok.AccessLevel; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
| import com.example.springjpamission.order.domain.Order; | ||
| import jakarta.persistence.*; | ||
| import jakarta.validation.Valid; | ||
|  | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|  | ||
| @Table(name = "customers") | ||
| @Entity | ||
| @Getter | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| public class Customer extends BaseEntity { | ||
|  | ||
| @Id | ||
| @GeneratedValue(strategy = GenerationType.IDENTITY) | ||
| private Long id; | ||
|  | ||
| @Valid | ||
| @Embedded | ||
| @Column(nullable = false) | ||
| private Name name; | ||
|  | ||
| @OneToMany(mappedBy = "customer") | ||
| private List<Order> orders = new ArrayList<>(); | ||
|  | ||
| protected Customer() { } | ||
|  | ||
| 
      Comment on lines
    
      +24
     to 
      +28
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. fetch가 default로 LAZY긴 하지만 명시해두는것이 의도가 보여 좋을때도 있어요 | ||
| public Customer(Name name) { | ||
| this.name = name; | ||
| } | ||
|  | @@ -30,4 +34,16 @@ public void changeName(Name name) { | |
| this.name = name; | ||
| } | ||
|  | ||
| public Long getId() { | ||
| return id; | ||
| } | ||
|  | ||
| public Name getName() { | ||
| return name; | ||
| } | ||
|  | ||
| public List<Order> getOrders() { | ||
| return orders; | ||
| } | ||
|  | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,26 +1,55 @@ | ||
| package com.example.springjpamission.customer.domain; | ||
|  | ||
| import jakarta.persistence.Column; | ||
| import jakarta.persistence.Embeddable; | ||
| import jakarta.validation.constraints.NotBlank; | ||
| import jakarta.validation.constraints.Size; | ||
| import lombok.EqualsAndHashCode; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|  | ||
| @NoArgsConstructor | ||
| @EqualsAndHashCode | ||
| @Getter | ||
| import java.util.Objects; | ||
|  | ||
| @Embeddable | ||
| public class Name { | ||
|  | ||
| @Size(min = 1, max = 50) | ||
| private String firstName; | ||
|  | ||
| @Size(min = 1, max = 50) | ||
| private String lastName; | ||
|  | ||
| protected Name() { } | ||
|  | ||
| public Name(String firstName, String lastName) { | ||
| validateName(firstName,lastName ); | ||
| this.firstName = firstName; | ||
| this.lastName = lastName; | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 코드 정리해서 깔끔하게 유지하도록 노력해봐요. 공백한칸 띄우고 빈칸 지워도 될것같네요 validate 하는 행위랑 초기화 하는 행위랑 문맥이 다르니 한칸 띄워서 가독성을 높여보는것은 어떻게 생각하세요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 문맥을 고려해서 개행하도록 하겠습니다. 🐣 | ||
| } | ||
|  | ||
| private void validateName(String firstName, String lastName) { | ||
| if (firstName == null || firstName.isBlank()) { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| if (lastName == null || lastName.isBlank()) { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| } | ||
|  | ||
| public String getFirstName() { | ||
| return firstName; | ||
| } | ||
|  | ||
| public String getLastName() { | ||
| return lastName; | ||
| } | ||
|  | ||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) return true; | ||
| if (o == null || getClass() != o.getClass()) return false; | ||
| Name name = (Name) o; | ||
| return Objects.equals(firstName, name.firstName) && Objects.equals(lastName, name.lastName); | ||
| } | ||
|  | ||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(firstName, lastName); | ||
| } | ||
|  | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -7,9 +7,12 @@ | |
| import com.example.springjpamission.customer.service.dto.SaveCustomerRequest; | ||
| import com.example.springjpamission.customer.service.dto.CustomerResponse; | ||
| import com.example.springjpamission.customer.service.dto.UpdateCustomerRequest; | ||
| import jakarta.persistence.EntityNotFoundException; | ||
| import org.springframework.data.domain.Pageable; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|  | ||
| @Transactional | ||
| @Service | ||
| public class CustomerService { | ||
|  | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클래스 레벨로 트랜잭셔널 어노테이션을 사용해도 될것같습니다. 다른 의도가 있나요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 클래스 레벨로 설정하면 모든 public method에  | ||
|  | @@ -19,30 +22,30 @@ public CustomerService(CustomerRepository customerRepository) { | |
| this.customerRepository = customerRepository; | ||
| } | ||
|  | ||
| @Transactional | ||
| public CustomerResponse saveCustomer(SaveCustomerRequest saveCustomerRequest) { | ||
| Customer customer = new Customer( | ||
| new Name(saveCustomerRequest.firstName(), saveCustomerRequest.lastName())); | ||
| return new CustomerResponse(customerRepository.save(customer)); | ||
| return CustomerResponse.of(customerRepository.save(customer)); | ||
| } | ||
|  | ||
| @Transactional | ||
| public CustomerResponse updateCustomer(UpdateCustomerRequest updateCustomerRequest) { | ||
| Customer findCustomer = customerRepository.findById(updateCustomerRequest.id()) | ||
| .orElseThrow(() -> new RuntimeException("해당 customer는 존재하지 않습니다.")); | ||
| .orElseThrow(() -> new EntityNotFoundException("해당 customer는 존재하지 않습니다.")); | ||
|  | ||
| findCustomer.changeName( | ||
| new Name(updateCustomerRequest.firstName(), updateCustomerRequest.lastName())); | ||
| return new CustomerResponse(findCustomer); | ||
| return CustomerResponse.of(findCustomer); | ||
| } | ||
|  | ||
| @Transactional | ||
| public CustomerResponses findAll() { | ||
| return CustomerResponses.of(customerRepository.findAll()); | ||
| @Transactional(readOnly = true) | ||
| public CustomerResponses findAll(Pageable pageable) { | ||
| return CustomerResponses.of(customerRepository.findAll(pageable)); | ||
| } | ||
|  | ||
| @Transactional | ||
| public void deleteById(Long id) { | ||
| customerRepository.findById(id) | ||
| .orElseThrow(()->new EntityNotFoundException("해당 customer는 존재하지 않습니다.")); | ||
|  | ||
| customerRepository.deleteById(id); | ||
| } | ||
|  | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -4,8 +4,10 @@ | |
|  | ||
| public record CustomerResponse(Long id, String firstName, String lastName) { | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 개행할것인지 말것인지 통일성을 맞춰주면 좋겠습니다. | ||
|  | ||
| public CustomerResponse(Customer customer) { | ||
| this(customer.getId(), customer.getName().getFirstName(), customer.getName().getLastName()); | ||
| public static CustomerResponse of(Customer customer) { | ||
| return new CustomerResponse(customer.getId(), | ||
| customer.getName().getFirstName(), | ||
| customer.getName().getLastName()); | ||
| 
      Comment on lines
    
      +9
     to 
      +10
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 가르 get get get get get 객체A 를 조작하는 객체 B 는 객체 A가 어떠한 자료를 갖고 어떤 속사정을 갖고있는지 몰라도 됩니다. 디미터의 법칙에 대해 알아보세요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 디미터의 법칙은 준수하도록 코드를 수정하도록 하겠습니다. 🐣 | ||
| } | ||
|  | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,15 +1,17 @@ | ||
| package com.example.springjpamission.customer.service.dto; | ||
|  | ||
| import com.example.springjpamission.customer.domain.Customer; | ||
| import org.springframework.data.domain.Slice; | ||
|  | ||
| import java.util.List; | ||
| import java.util.stream.Collectors; | ||
|  | ||
| public record CustomerResponses(List<CustomerResponse> customerResponses) { | ||
|  | ||
| public static CustomerResponses of(List<Customer> customers) { | ||
| List<CustomerResponse> responses = customers.stream().map(CustomerResponse::new) | ||
| .collect(Collectors.toList()); | ||
| public static CustomerResponses of(Slice<Customer> customers) { | ||
| List<CustomerResponse> responses = customers.stream() | ||
| .map(CustomerResponse::of) | ||
| .collect(Collectors.toList()); | ||
| 
      Comment on lines
    
      +11
     to 
      +14
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 좋네요 ㅎㅎ 정적팩토리 메소드에 바로 넣어서 생성 할까? 말까? 도 생각해보면 좋을거같아요 | ||
| return new CustomerResponses(responses); | ||
| } | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 여기는 정적 팩토리 메소드를 사용하셨네요. 각 케이스에 대해 고민해보고 컨벤션을 통일하는것은 어떨까요? | ||
|  | ||
|  | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -6,29 +6,31 @@ | |
| import jakarta.persistence.PreUpdate; | ||
| import java.time.LocalDateTime; | ||
| import java.time.format.DateTimeFormatter; | ||
| import lombok.Getter; | ||
|  | ||
| @Getter | ||
| @MappedSuperclass | ||
| public class BaseEntity { | ||
| public abstract class BaseEntity { | ||
|  | ||
| @Column(name = "created_at", updatable = false, nullable = false) | ||
| private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DATE_FORMAT은 뭔가 엄청 범용적인거 같기도 해요. public하게 열어 시간 관련 모듈이 있는곳에 두거나, | ||
|  | ||
| @Column(updatable = false, nullable = false) | ||
| private String createAt; | ||
|  | ||
| @Column(name = "last_updated_at", nullable = false) | ||
| @Column(nullable = false) | ||
| private String lastUpdatedAt; | ||
|  | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. timestamp나 datetime을 사용할 수 있습니다. 둘의 차이는 무엇이 있을까요? createdAt updatedAt 둘의 DB 자료형은 어떤것이 유리할까요? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. timestamp :   따라서 createdAt과 updatedAt은 비교적 지금의 날짜를 나타내어 공간을 덜 차지하는 timestamp를 사용하는 것이 더 유리할 것이라고 생각합니다. | ||
| protected BaseEntity() { } | ||
|  | ||
| @PrePersist | ||
| public void prePersist() { | ||
| LocalDateTime now = LocalDateTime.now(); | ||
| createAt = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); | ||
| lastUpdatedAt = now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); | ||
| createAt = now.format(DateTimeFormatter.ofPattern(DATE_FORMAT)); | ||
| lastUpdatedAt = now.format(DateTimeFormatter.ofPattern(DATE_FORMAT)); | ||
| } | ||
|  | ||
| @PreUpdate | ||
| public void preUpdate() { | ||
| lastUpdatedAt = LocalDateTime.now() | ||
| .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")); | ||
| .format(DateTimeFormatter.ofPattern(DATE_FORMAT)); | ||
| } | ||
|  | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,26 +1,34 @@ | ||
| package com.example.springjpamission.order.domain; | ||
|  | ||
| import jakarta.persistence.Column; | ||
| import jakarta.persistence.DiscriminatorValue; | ||
| import jakarta.persistence.Entity; | ||
| import lombok.AccessLevel; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|  | ||
| @Getter | ||
| @Entity | ||
| @DiscriminatorValue("CAR") | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| @Entity | ||
| public class Car extends Item { | ||
|  | ||
| private static final int ZERO = 0; | ||
|  | ||
| @Column | ||
| 
      Comment on lines
    
      +11
     to 
      +13
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ZERO = 0 딸랑 이렇게 두면 0이구나만 알지 우리의 중요한 도메인에서 어떤 역할을 하는지 파악하기 어려울 수 있어요 자동차의 POWER가 ZERO 미만이면 안된다는 비즈니스 규칙을 명확하게 하기 위해 | ||
| private int power; | ||
|  | ||
| public Car(int power) { | ||
| this.power = power; | ||
| } | ||
| protected Car() { } | ||
|  | ||
| public Car(int price, int stockQuantity, int power) { | ||
| public Car(Price price, int stockQuantity, int power) { | ||
| super(price, stockQuantity); | ||
| validatePower(power); | ||
| this.power = power; | ||
| } | ||
|  | ||
| private void validatePower(int power) { | ||
| if(power < ZERO) { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| } | ||
|  | ||
| public int getPower() { | ||
| return power; | ||
| } | ||
|  | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,26 +1,28 @@ | ||
| package com.example.springjpamission.order.domain; | ||
|  | ||
| import jakarta.persistence.Column; | ||
| import jakarta.persistence.DiscriminatorValue; | ||
| import jakarta.persistence.Entity; | ||
| import lombok.AccessLevel; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|  | ||
| @Getter | ||
| @Entity | ||
| @DiscriminatorValue("FOOD") | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
| @Entity | ||
| public class Food extends Item { | ||
|  | ||
| @Column | ||
| private String chef; | ||
|  | ||
| public Food(String chef) { | ||
| this.chef = chef; | ||
| } | ||
| protected Food() { } | ||
|  | ||
| public Food(int price, int stockQuantity, String chef) { | ||
| public Food(Price price, int stockQuantity, String chef) { | ||
| super(price, stockQuantity); | ||
| validateChef(chef); | ||
| this.chef = chef; | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 값객체가 null로 들어올수는 없을까요? | ||
| } | ||
|  | ||
| private void validateChef(String chef) { | ||
| if (chef == null || chef.isBlank()) { | ||
| throw new IllegalArgumentException(); | ||
| } | ||
| } | ||
|  | ||
| } | ||
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.
SpringBoot AutoConfiguration이 제공해주는 Bean들을 사용하지 않고
직접 등록하신 의도가 궁금합니다
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.
저도 궁금
Uh oh!
There was an error while loading. Please reload this page.
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.
SpringBoot AutoConfiguration이 제공하는 Bean을 사용해도 되나
transactionManager가 만들어지려면 EntityManagerFactory가 필요하고 Factory가 만들어지려면 DataSource, JpaVendorAdapter가 필요한 이런 개념들을 파악해 두고 싶어
학습에 목적을 두고 빈을 직접 등록했었던 것 같습니다.
말씀하신대로 SpringBoot가 제공하는 Bean을 사용하는 방식으로 바꿔보겠습니다!!