Skip to content

Commit a30a234

Browse files
authored
[레거시 코드 리팩터링 - 2단계] 현구막(최현구) 미션 제출합니다. (#170)
* docs: 컨트롤러 메서드를 통한 요구사항 정리 * docs: 서비스 메서드를 통한 요구사항 정리 * chore: gitignore에 bin 디렉토리 추가 * test: JdbcTemplateProductDao 테스트 작성 * refactor: JdbcTemplateDao 테스트 중복설정 추상화 * test: JdbcTemplateTableGroup 테스트 작성 * refactor: 엔티티 저장 테스트 검증 변경 * test: JdbcTemplateOrderTableDao 테스트 작성 * test: JdbcTemplateOrderDao 테스트 작성 * test: JdbcTemplateMenuGroupDao 테스트 작성 * test: JdbcTemplateMenuDao 테스트 작성 * test: JdbcTemplateMenuProductDao 테스트 작성 * test: JdbcTemplateOrderLineItemDao 테스트 작성 * refactor: Order가 생성될 때 필요한 orderTableId 값을 임의의 값이 아닌 실제 값을 사용하도록 변경 * test: MenuGroupService 테스트 작성 * test: ProductService 테스트 작성 * test: MenuGroupService DisplayName 추가 * test: TableService 테스트 작성 * test: TableGroupService 테스트 작성 * test: MenuService 테스트 작성 * refactor: ProductService 전체 조회 테스트 수정 * test: OrderService 테스트 작성 * chore: rest-assured 의존성 추가 * test: MenuGroup 인수 테스트 작성 * test: Menu 인수 테스트 작성 * refactor: Menu 인수 테스트가 Dao가 아닌 Http 요청에 의존하도록 변경 OrderService 테스트 오타 수정 * test: Order 인수 테스트 작성 * refactor: HttpPost, HttpPut 요청 메서드 추상화 * refactor: OrderService 테스트 예시값 수정 * test: Product 인수 테스트 작성 * refactor: HTTP 요청을 이용한 데이터생성 메서드의 이름 변경 * test: TableGroup 인수 테스트 작성 * test: Table 인수 테스트 작성 * docs: README.md 완료사항 반영 * refactor: Product 관련 기능 JPA 도입, 비즈니스 로직 도메인으로 이동 * feat: Exception 핸들러 추가 * refactor: MenuGroup 관련 기능 JPA 도입, 비즈니스 검증 로직 도메인으로 이동 * refactor: Menu, MenuProduct 관련 기능 JPA 도입, 비즈니스 검증 로직 도메인 이동 * refactor: 개행 추가, 불필요한 import 제거 * refactor: 엔티티 단위 테스트 보완 Menu MenuGroup MenuProduct MenuProducts Product Price * refactor: 추가 엔티티 단위 테스트 보완 Order Orders OrderLineItem OrderLineItems OrderTable OrderTables * refactor: 불필요한 Dao, DaoTest 제거 * refactor: MenuGroup 테스트 수정, 컨트롤러 Valid 어노테이션 추가 * refactor: Menu 테스트 수정, 메서드명 변경, 컨트롤러 Valid 어노테이션 추가 * refactor: Order, OrderLineItem 서비스계층 리팩토링, 테스트코드 수정 * refactor: Product 인수테스트명 변경, 컨트롤러 Valid 어노테이션 추가 * refactor: OrderTable, TableGroup 인수 테스트명 변경, 컨트롤러 Valid 어노테이션 추가, 서비스 계층 리팩토링 * refactor: 불필요한 생성자, 사용되지 않는 setter 제거 * refactor: 순환참조를 방지하기 위해 Service계층간 Repository를 의존하도록 변경 * refactor: 스프링 프로필 파일 변경 * refactor: 브랜치 병합 이후 불필요하게 추가된 테스트, 클래스 제거 * refactor: 메뉴상품 총 금액 메서드 추상화 * refactor: 불필요한 import, 사용되지 않는 메서드 제거 * refactor: 이름(Name) 관련 값 객체로 포장 * refactor: 가격(Price) 관련 값 객체로 포장 * refactor: 수량(Quantity) 관련 값 객체로 포장 * refactor: 손님수(NumberOfGuests) 관련 값 객체로 포장
1 parent 135a4bc commit a30a234

File tree

152 files changed

+4952
-4457
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

152 files changed

+4952
-4457
lines changed

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### MenuGroups
66
- [x] `POST /api/menu-groups` 요청을 통해 MenuGroup을 추가할 수 있다.
77
- [x] MenuGroup을 DB에 저장한다.
8+
- [x] MenuGroup의 이름은 Null 이어서는 안된다.
89

910
- [x] `GET /api/menu-groups` 요청을 통해 MenuGroup 목록을 조회할 수 있다.
1011
- [x] MenuGroup 리스트를 DB에서 찾아 반환한다.
@@ -106,3 +107,61 @@
106107
| 단체 지정 | table group | 통합 계산을 위해 개별 주문 테이블을 그룹화하는 기능 |
107108
| 주문 항목 | order line item | 주문에 속하는 수량이 있는 메뉴 |
108109
| 매장 식사 | eat in | 포장하지 않고 매장에서 식사하는 것 |
110+
111+
<br>
112+
113+
## 엔티티 단위 테스트
114+
- [x] Menu
115+
- [x] name null, blank
116+
- [x] price null, negative
117+
- [x] MenuGroup null
118+
- [x] MenuGroup
119+
- [x] name null, blank
120+
- [x] MenuProduct
121+
- [x] menu null
122+
- [x] product null
123+
- [x] quantity null, negative
124+
- [x] MenuProducts
125+
- [x] menu.price > all(product.price * quantity)
126+
- [x] Product
127+
- [x] name null, blank
128+
- [x] price null, negative
129+
- [x] Price
130+
- [x] value null, negative
131+
- [x] Order
132+
- [x] orderTable null
133+
- [x] already completion
134+
- [x] Orders
135+
- [x] completed status
136+
- [x] OrderLineItem
137+
- [x] order null
138+
- [x] menu null
139+
- [x] quantity null, negative
140+
- [x] OrderLineItems
141+
- [x] empty
142+
- [x] menu duplicate
143+
- [x] OrderTable
144+
- [x] numberOfGuests negative
145+
- [x] groupBy status
146+
- [x] ungroup status
147+
- [x] changeNumberOfGuests
148+
- [x] negative
149+
- [x] orderTable status empty
150+
- [x] changeEmpty nonNull tableGroup
151+
- [x] OrderTables
152+
- [x] orderTable count < 2
153+
- [x] orderTable already not empty or grouped
154+
- [x] groupBy
155+
- [x] TableGroup
156+
157+
## 추가 리팩토링
158+
- [x] 커스텀 Exception 추가
159+
- [x] 인수테스트 DisplayName 변경하기
160+
- [x] 엔티티 원시값 포장
161+
- [x] quantity
162+
- [x] price
163+
- [x] name
164+
- [x] numberOfGuests
165+
- [x] DTO getter 디미터 법칙
166+
- [ ] OrderTable에서 TableGroup 값에 따라 empty 설정을 해야하는가 고민
167+
- [x] 서비스 계층 의존 -> 최초의 순환참조 경험 -> Repository 계층 의존하도록 변경

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ dependencies {
1616
implementation 'org.springframework.boot:spring-boot-starter-actuator'
1717
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
1818
implementation 'org.springframework.boot:spring-boot-starter-web'
19+
1920
implementation 'org.flywaydb:flyway-core'
2021
runtimeOnly 'com.h2database:h2'
22+
23+
implementation 'org.springframework.boot:spring-boot-starter-validation'
24+
2125
testImplementation 'io.rest-assured:rest-assured'
2226
testImplementation('org.springframework.boot:spring-boot-starter-test') {
2327
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,33 @@
11
package kitchenpos.application;
22

3-
import kitchenpos.dao.MenuGroupDao;
3+
import java.util.List;
44
import kitchenpos.domain.MenuGroup;
5+
import kitchenpos.repository.MenuGroupRepository;
6+
import kitchenpos.ui.request.MenuGroupRequest;
7+
import kitchenpos.ui.response.MenuGroupResponse;
58
import org.springframework.stereotype.Service;
69
import org.springframework.transaction.annotation.Transactional;
710

8-
import java.util.List;
9-
11+
@Transactional(readOnly = true)
1012
@Service
1113
public class MenuGroupService {
12-
private final MenuGroupDao menuGroupDao;
1314

14-
public MenuGroupService(final MenuGroupDao menuGroupDao) {
15-
this.menuGroupDao = menuGroupDao;
15+
private final MenuGroupRepository menuGroupRepository;
16+
17+
public MenuGroupService(MenuGroupRepository menuGroupRepository) {
18+
this.menuGroupRepository = menuGroupRepository;
1619
}
1720

1821
@Transactional
19-
public MenuGroup create(final MenuGroup menuGroup) {
20-
return menuGroupDao.save(menuGroup);
22+
public MenuGroupResponse create(final MenuGroupRequest request) {
23+
MenuGroup menuGroup = menuGroupRepository.save(request.toEntity());
24+
25+
return MenuGroupResponse.from(menuGroup);
2126
}
2227

23-
public List<MenuGroup> list() {
24-
return menuGroupDao.findAll();
28+
public List<MenuGroupResponse> list() {
29+
List<MenuGroup> menuGroups = menuGroupRepository.findAll();
30+
31+
return MenuGroupResponse.of(menuGroups);
2532
}
2633
}
Lines changed: 60 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,90 @@
11
package kitchenpos.application;
22

3-
import kitchenpos.dao.MenuDao;
4-
import kitchenpos.dao.MenuGroupDao;
5-
import kitchenpos.dao.MenuProductDao;
6-
import kitchenpos.dao.ProductDao;
3+
import java.util.ArrayList;
4+
import java.util.List;
75
import kitchenpos.domain.Menu;
6+
import kitchenpos.domain.MenuGroup;
87
import kitchenpos.domain.MenuProduct;
8+
import kitchenpos.domain.MenuProducts;
9+
import kitchenpos.domain.Price;
910
import kitchenpos.domain.Product;
11+
import kitchenpos.exception.MenuGroupNotFoundException;
12+
import kitchenpos.exception.ProductNotFoundException;
13+
import kitchenpos.repository.MenuGroupRepository;
14+
import kitchenpos.repository.MenuProductRepository;
15+
import kitchenpos.repository.MenuRepository;
16+
import kitchenpos.repository.ProductRepository;
17+
import kitchenpos.ui.request.MenuProductRequest;
18+
import kitchenpos.ui.request.MenuRequest;
19+
import kitchenpos.ui.response.MenuResponse;
1020
import org.springframework.stereotype.Service;
1121
import org.springframework.transaction.annotation.Transactional;
1222

13-
import java.math.BigDecimal;
14-
import java.util.ArrayList;
15-
import java.util.List;
16-
import java.util.Objects;
17-
23+
@Transactional(readOnly = true)
1824
@Service
1925
public class MenuService {
20-
private final MenuDao menuDao;
21-
private final MenuGroupDao menuGroupDao;
22-
private final MenuProductDao menuProductDao;
23-
private final ProductDao productDao;
26+
27+
private final MenuRepository menuRepository;
28+
private final MenuProductRepository menuProductRepository;
29+
private final MenuGroupRepository menuGroupRepository;
30+
private final ProductRepository productRepository;
2431

2532
public MenuService(
26-
final MenuDao menuDao,
27-
final MenuGroupDao menuGroupDao,
28-
final MenuProductDao menuProductDao,
29-
final ProductDao productDao
33+
MenuRepository menuRepository,
34+
MenuProductRepository menuProductRepository,
35+
MenuGroupRepository menuGroupRepository,
36+
ProductRepository productRepository
3037
) {
31-
this.menuDao = menuDao;
32-
this.menuGroupDao = menuGroupDao;
33-
this.menuProductDao = menuProductDao;
34-
this.productDao = productDao;
38+
this.menuRepository = menuRepository;
39+
this.menuProductRepository = menuProductRepository;
40+
this.menuGroupRepository = menuGroupRepository;
41+
this.productRepository = productRepository;
3542
}
3643

3744
@Transactional
38-
public Menu create(final Menu menu) {
39-
final BigDecimal price = menu.getPrice();
40-
41-
if (Objects.isNull(price) || price.compareTo(BigDecimal.ZERO) < 0) {
42-
throw new IllegalArgumentException();
43-
}
45+
public MenuResponse create(final MenuRequest request) {
46+
MenuGroup menuGroup = findMenuGroupById(request.getMenuGroup());
47+
Menu menu = menuRepository.save(new Menu(request.getName(), request.getPrice(), menuGroup));
48+
MenuProducts menuProducts = generateMenuProducts(menu, request.getMenuProducts());
49+
menuProducts.validateMenuPrice(new Price(request.getPrice()));
4450

45-
if (!menuGroupDao.existsById(menu.getMenuGroupId())) {
46-
throw new IllegalArgumentException();
47-
}
51+
return MenuResponse.from(menu, menuProducts.toList());
52+
}
4853

49-
final List<MenuProduct> menuProducts = menu.getMenuProducts();
54+
private MenuProducts generateMenuProducts(Menu menu, List<MenuProductRequest> menuProductRequests) {
55+
List<MenuProduct> menuProducts = new ArrayList<>();
5056

51-
BigDecimal sum = BigDecimal.ZERO;
52-
for (final MenuProduct menuProduct : menuProducts) {
53-
final Product product = productDao.findById(menuProduct.getProductId())
54-
.orElseThrow(IllegalArgumentException::new);
55-
sum = sum.add(product.getPrice().multiply(BigDecimal.valueOf(menuProduct.getQuantity())));
57+
for (MenuProductRequest request : menuProductRequests) {
58+
Product product = findProductById(request.getProductId());
59+
MenuProduct menuProduct = new MenuProduct(menu, product, request.getQuantity());
60+
menuProducts.add(menuProductRepository.save(menuProduct));
5661
}
5762

58-
if (price.compareTo(sum) > 0) {
59-
throw new IllegalArgumentException();
60-
}
63+
return new MenuProducts(menuProducts);
64+
}
6165

62-
final Menu savedMenu = menuDao.save(menu);
66+
public List<MenuResponse> list() {
67+
List<MenuResponse> menuResponses = new ArrayList<>();
6368

64-
final Long menuId = savedMenu.getId();
65-
final List<MenuProduct> savedMenuProducts = new ArrayList<>();
66-
for (final MenuProduct menuProduct : menuProducts) {
67-
menuProduct.setMenuId(menuId);
68-
savedMenuProducts.add(menuProductDao.save(menuProduct));
69+
for (Menu menu : menuRepository.findAll()) {
70+
List<MenuProduct> menuProducts = menuProductRepository.findAllByMenu(menu);
71+
menuResponses.add(MenuResponse.from(menu, menuProducts));
6972
}
70-
savedMenu.setMenuProducts(savedMenuProducts);
7173

72-
return savedMenu;
74+
return menuResponses;
7375
}
7476

75-
public List<Menu> list() {
76-
final List<Menu> menus = menuDao.findAll();
77-
78-
for (final Menu menu : menus) {
79-
menu.setMenuProducts(menuProductDao.findAllByMenuId(menu.getId()));
80-
}
77+
private MenuGroup findMenuGroupById(Long menuGroupId) {
78+
return menuGroupRepository.findById(menuGroupId)
79+
.orElseThrow(() -> new MenuGroupNotFoundException(
80+
String.format("%d ID를 가진 MenuGroup이 존재하지 않습니다.", menuGroupId)
81+
));
82+
}
8183

82-
return menus;
84+
private Product findProductById(Long productId) {
85+
return productRepository.findById(productId)
86+
.orElseThrow(() -> new ProductNotFoundException(
87+
String.format("%d ID를 가진 Product가 존재하지 않습니다.", productId))
88+
);
8389
}
8490
}

0 commit comments

Comments
 (0)