-
Notifications
You must be signed in to change notification settings - Fork 2
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
[#4] 상품 등록, 조회, 수정, 삭제 #9
Changes from all commits
199dd85
a29c2d1
224e621
0199fa9
834829d
156f094
946b034
c035293
addf71c
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 |
---|---|---|
@@ -0,0 +1,35 @@ | ||
### 아이템 등록 | ||
POST http://localhost:8080/api/v1/items | ||
Content-Type: application/json | ||
|
||
{ | ||
"itemName": "한옥스테이조아당", | ||
"itemPrice": 35000, | ||
"itemStock": 10 | ||
} | ||
|
||
### 아이템 전체 조회 | ||
GET http://localhost:8080/api/v1/items | ||
Content-Type: application/json | ||
|
||
### 아이템 상세 조회 | ||
GET http://localhost:8080/api/v1/items/itm_m01CJuHJ6ogMx7f0 | ||
Content-Type: application/json | ||
|
||
### 아이템 수정 | ||
PUT http://localhost:8080/api/v1/items/itm_m01CJuHJ6ogMx7f0 | ||
Content-Type: application/json | ||
|
||
{ | ||
"itemName": "한옥스테이조아당 업데이트", | ||
"itemPrice": 35000, | ||
"itemStock": 10 | ||
} | ||
|
||
### 아이템 비활성화 | ||
POST http://localhost:8080/api/v1/items/change-end-of-sales | ||
Content-Type: application/json | ||
|
||
{ | ||
"itemToken": "itm_m01CJuHJ6ogMx7f0" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package com.flab.goodchoice.item.application; | ||
|
||
|
||
import com.flab.goodchoice.item.domain.*; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class ItemFacade { | ||
|
||
private final ItemEntryService itemEntryService; | ||
|
||
private final ItemModifyService itemModifyService; | ||
|
||
private final ItemOneService itemOneService; | ||
|
||
private final ItemListService itemListService; | ||
|
||
public String registerItem (ItemCommand.RegisterItemRequest request) { | ||
var itemToken = itemEntryService.registerItem(request); | ||
return itemToken; | ||
} | ||
|
||
public ItemInfo.Main retrieveItemInfo(String itemToken) { | ||
return itemOneService.retrieveItemInfo(itemToken); | ||
} | ||
|
||
public void changeEndOfSaleItem(String itemToken) { | ||
itemModifyService.changeEndOfSale(itemToken); | ||
} | ||
|
||
public void updateItem(String itemToken, ItemCommand.UpdateItemRequest request) { | ||
itemModifyService.updateItem(itemToken, request); | ||
} | ||
|
||
public List<Item> retrieveAllItemInfo() { | ||
return itemListService.retrieveAllItemInfo(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.flab.goodchoice.item.common.util; | ||
|
||
import org.apache.commons.lang3.RandomStringUtils; | ||
|
||
public class TokenGenerator { | ||
private static final int TOKEN_LENGTH = 20; | ||
|
||
public static String randomCharacter(int length) { | ||
return RandomStringUtils.randomAlphanumeric(length); | ||
} | ||
|
||
public static String randomCharacterWithPrefix(String prefix) { | ||
return prefix + randomCharacter(TOKEN_LENGTH - prefix.length()); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
import com.flab.goodchoice.item.common.util.TokenGenerator; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
import org.hibernate.annotations.CreationTimestamp; | ||
import org.hibernate.annotations.UpdateTimestamp; | ||
|
||
import javax.persistence.*; | ||
import java.security.InvalidParameterException; | ||
import java.time.ZonedDateTime; | ||
|
||
@Getter | ||
@Entity | ||
@NoArgsConstructor | ||
@Table(name = "items") | ||
public class Item { | ||
|
||
private static final String ITEM_PREFIX = "itm_"; | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
private String itemToken; | ||
|
||
private String itemName; | ||
|
||
private Long itemPrice; | ||
|
||
private Long itemStock; | ||
|
||
@Enumerated(EnumType.STRING) | ||
private Status status; | ||
|
||
@CreationTimestamp | ||
private ZonedDateTime createdAt; | ||
|
||
@UpdateTimestamp | ||
private ZonedDateTime updatedAt; | ||
|
||
@UpdateTimestamp | ||
private ZonedDateTime deletedAt; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum Status { | ||
PREPARE("판매준비중"), | ||
ON_SALE("판매중"), | ||
END_OF_SALE("판매종료"); | ||
|
||
private final String description; | ||
} | ||
|
||
@Builder | ||
public Item(String itemName, Long itemPrice, Long itemStock) { | ||
if (StringUtils.isBlank(itemName)) throw new InvalidParameterException("Item.itemName"); | ||
if (itemPrice == null) throw new InvalidParameterException("Item.itemPrice"); | ||
if (itemStock == null) throw new InvalidParameterException("Item.itemStock"); | ||
|
||
this.itemToken = TokenGenerator.randomCharacterWithPrefix(ITEM_PREFIX); | ||
this.itemName = itemName; | ||
this.itemPrice = itemPrice; | ||
this.itemStock = itemStock; | ||
this.status = Status.PREPARE; | ||
} | ||
|
||
public void update(String itemName, Long itemPrice, Long itemStock) { | ||
this.itemName = itemName; | ||
this.itemPrice = itemPrice; | ||
this.itemStock = itemStock; | ||
} | ||
|
||
public void changeEndOfSale() { | ||
this.status = Status.END_OF_SALE; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Builder; | ||
import lombok.Getter; | ||
import lombok.ToString; | ||
|
||
public class ItemCommand { | ||
|
||
@Getter | ||
@Builder | ||
@ToString | ||
@AllArgsConstructor | ||
public static class RegisterItemRequest { | ||
private final String itemName; | ||
private final Long itemPrice; | ||
private final Long itemStock; | ||
|
||
public Item toEntity() { | ||
return Item.builder() | ||
.itemName(itemName) | ||
.itemPrice(itemPrice) | ||
.itemStock(itemStock) | ||
.build(); | ||
} | ||
|
||
} | ||
|
||
@Getter | ||
@Builder | ||
@ToString | ||
@AllArgsConstructor | ||
public static class UpdateItemRequest { | ||
private final String itemName; | ||
private final Long itemPrice; | ||
private final Long itemStock; | ||
|
||
public Item toEntity() { | ||
return Item.builder() | ||
.itemName(itemName) | ||
.itemPrice(itemPrice) | ||
.itemStock(itemStock) | ||
.build(); | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class ItemEntryService { | ||
|
||
private final ItemStore itemStore; | ||
|
||
@Transactional | ||
public String registerItem(ItemCommand.RegisterItemRequest command) { | ||
var initItem = command.toEntity(); | ||
var item = itemStore.store(initItem); | ||
return item.getItemToken(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
import lombok.Getter; | ||
import lombok.ToString; | ||
|
||
public class ItemInfo { | ||
|
||
@Getter | ||
@ToString | ||
public static class Main { | ||
private final String itemToken; | ||
private final String itemName; | ||
private final Long itemPrice; | ||
private final Long itemStock; | ||
private final Item.Status status; | ||
|
||
public Main(Item item) { | ||
this.itemToken = item.getItemToken(); | ||
this.itemName = item.getItemName(); | ||
this.itemPrice = item.getItemPrice(); | ||
this.itemStock = item.getItemStock(); | ||
this.status = item.getStatus(); | ||
} | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.util.List; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class ItemListService { | ||
|
||
private final ItemReader itemReader; | ||
|
||
public List<Item> retrieveAllItemInfo() { | ||
return itemReader.getItems(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class ItemModifyService { | ||
|
||
private final ItemReader itemReader; | ||
|
||
@Transactional | ||
public void changeEndOfSale(String itemToken) { | ||
var item = itemReader.getItemBy(itemToken); | ||
item.changeEndOfSale(); | ||
} | ||
|
||
@Transactional | ||
public ItemInfo.Main updateItem(String itemToken, ItemCommand.UpdateItemRequest request) { | ||
var item = itemReader.getItemBy(itemToken); | ||
item.update(request.getItemName(), request.getItemPrice(), request.getItemStock()); | ||
return new ItemInfo.Main(item); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Slf4j | ||
@Service | ||
@RequiredArgsConstructor | ||
public class ItemOneService { | ||
|
||
private final ItemReader itemReader; | ||
|
||
@Transactional(readOnly = true) | ||
public ItemInfo.Main retrieveItemInfo(String itemToken) { | ||
var item = itemReader.getItemBy(itemToken); | ||
return new ItemInfo.Main(item); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
import java.util.List; | ||
|
||
public interface ItemReader { | ||
Item getItemBy(String itemToken); | ||
|
||
List<Item> getItems(); | ||
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. Item 엔티티는 JPA 스펙에 종속된 클래스인데, 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. @f-lab-thor JPA 스펙에 종속된 엔티티 클래스의 사용범위는 어디까지 일까요? 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. @zzangoobrother ItemReader의 구현체에서 itemRepository에 접근해서 item엔티티를 리턴 받도록 구현되어 있는 상태입니다. vo 객체로 어떻게 변환이 가능할까요? 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. itemVO 라고 클래스 만드셔서 dto로 변환 하듯이 하셔도 될 겁니다. 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. 우선 이미 은지님이 그 답을 여기에 말씀해 주셨네요 해당 인터페이스가 존재하는 이유는 ItemReader의 구체적인 방식을 의존하지 않고 내가 jpa를 더이상 안쓰고 다른 구현체를 사용한다고 했을때, 도메인 영역까지 영향이 침범 되지 않을까요? 인터페이스가 도메인 영역에 있고, 인터페이스 구현체가 infrastructure에 있다는 것은 DIP 원칙이 훤히~~ 보이는 구조로 말씀드렸습니다. |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.flab.goodchoice.item.domain; | ||
|
||
public interface ItemStore { | ||
Item store(Item initItem); | ||
} |
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.
👍