From 30df46b5e951cb30171bf365084b60742ed0c7e8 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Tue, 8 Mar 2022 14:45:07 +0900 Subject: [PATCH 01/13] =?UTF-8?q?refactor(store):=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=ED=85=9C=20=EC=83=9D=EC=84=B1=20=EB=B6=80=EB=B6=84=20Casecade?= =?UTF-8?q?=20=EB=A6=AC=ED=8C=A9=ED=84=B0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/category/entity/Category.java | 7 +++++ .../storeservice/domain/item/entity/Item.java | 28 ++++++++----------- .../domain/item/service/ItemServiceImpl.java | 15 ++++++---- .../item/web/ItemOwnerApiController.java | 4 --- .../domain/itemoption/dto/ItemOptionDto.java | 7 +---- .../domain/itemoption/entity/ItemOption.java | 12 +++++--- 6 files changed, 36 insertions(+), 37 deletions(-) diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/category/entity/Category.java b/store-service/src/main/java/com/justpickup/storeservice/domain/category/entity/Category.java index 7fd7607..d78dd7c 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/category/entity/Category.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/category/entity/Category.java @@ -60,4 +60,11 @@ public class Category extends BaseEntity { return new Category(id,name,order,store); } + public static Category of(String name, Integer order, Store store) { + Category category = new Category(); + category.name = name; + category.order = order; + category.store = store; + return category; + } } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/item/entity/Item.java b/store-service/src/main/java/com/justpickup/storeservice/domain/item/entity/Item.java index 3747090..4d2f177 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/item/entity/Item.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/item/entity/Item.java @@ -11,11 +11,9 @@ import lombok.Getter; import lombok.NoArgsConstructor; import javax.persistence.*; - +import java.util.ArrayList; import java.util.List; -import static javax.persistence.CascadeType.PERSIST; -import static javax.persistence.CascadeType.REMOVE; import static javax.persistence.FetchType.LAZY; @Entity @@ -45,8 +43,8 @@ public class Item extends BaseEntity { @JoinColumn(name = "store_id") private Store store; - @OneToMany(mappedBy = "item" ,cascade = {REMOVE,PERSIST} ) - private List itemOptions; + @OneToMany(mappedBy = "item", cascade = CascadeType.ALL) + private List itemOptions = new ArrayList<>(); // == 연관관계 편의 메소드 ==// public void addItemOption(ItemOption itemOption) { @@ -71,19 +69,15 @@ public class Item extends BaseEntity { } // == 생성 메소드 == // - public static Item createdItem(Category category, Store store, List itemOptions) { + public static Item of(String name, Long price, Category category, Store store, List itemOptions) { Item item = new Item(); - item.setCategory(category); - item.setStore(store); - itemOptions.forEach(item::addItemOption); - return item; - } - - public static Item createdFullItem(Category category, Store store, List itemOptions, String name , Long price) { - Item item = new Item(); - item.setItemNameAndPriceAndCategory( name, price ,category); - item.setStore(store); - itemOptions.forEach(item::addItemOption); + item.name = name; + item.price = price; + item.category = category; + item.store = store; + for (ItemOption itemOption : itemOptions) { + item.addItemOption(itemOption); + } return item; } } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/item/service/ItemServiceImpl.java b/store-service/src/main/java/com/justpickup/storeservice/domain/item/service/ItemServiceImpl.java index f0e71c5..21a50e6 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/item/service/ItemServiceImpl.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/item/service/ItemServiceImpl.java @@ -96,7 +96,6 @@ public class ItemServiceImpl implements ItemService { Long itemPrice, Long categoryId, List itemOptionDtos) { - //find Store Store store = storeRepository.findById(storeId) .orElseThrow(() -> new NotExistItemException("존재하지 않는 매장 입니다.")); @@ -105,11 +104,15 @@ public class ItemServiceImpl implements ItemService { Category category = categoryRepository.findById(categoryId) .orElseThrow(() -> new NotExistItemException("존재하지 않는 카테고리 입니다.")); - //create Item - Item item = Item.createdFullItem(category,store,new ArrayList<>() ,itemName, itemPrice); + List itemOptions = itemOptionDtos + .stream() + .map(itemOptionDto -> { + return ItemOption.of(itemOptionDto.getOptionType(), itemOptionDto.getName()); + }) + .collect(Collectors.toList()); - //add ItemOption - itemOptionDtos.forEach((itemOptionDto -> - itemOptionRepository.save(ItemOptionDto.createItemOption(itemOptionDto, item)))); + Item createdItem = Item.of(itemName, itemPrice, category, store, itemOptions); + + itemRepository.save(createdItem); } } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/item/web/ItemOwnerApiController.java b/store-service/src/main/java/com/justpickup/storeservice/domain/item/web/ItemOwnerApiController.java index 8da50a4..69ba828 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/item/web/ItemOwnerApiController.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/item/web/ItemOwnerApiController.java @@ -129,10 +129,8 @@ public class ItemOwnerApiController { private String name; public ItemOptionResponse(ItemOptionDto itemOptionDto) { - this.id = itemOptionDto.getId(); this.optionType = itemOptionDto.getOptionType(); - this.price = itemOptionDto.getPrice(); this.name = itemOptionDto.getName(); } } @@ -182,13 +180,11 @@ public class ItemOwnerApiController { private Long id; private String name; private OptionType optionType; - private Long price; public static ItemOptionDto createItemOptionDto(ItemOptionRequest itemOptionRequest){ return ItemOptionDto.builder() .id(itemOptionRequest.getId()) .name(itemOptionRequest.getName()) - .price(itemOptionRequest.getPrice()) .optionType(itemOptionRequest.getOptionType()) .build(); diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/dto/ItemOptionDto.java b/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/dto/ItemOptionDto.java index 0ec7b5b..5231920 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/dto/ItemOptionDto.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/dto/ItemOptionDto.java @@ -20,20 +20,15 @@ public class ItemOptionDto { private OptionType optionType; - private Long price; - private String name; public ItemOptionDto (ItemOption itemOption){ this.id = itemOption.getId(); this.optionType = itemOption.getOptionType(); - this.price = itemOption.getPrice(); this.name = itemOption.getName(); } public static ItemOption createItemOption (ItemOptionDto itemOptionDto, Item item){ - - return new ItemOption(itemOptionDto.getOptionType(),itemOptionDto.getPrice(),itemOptionDto.getName(),item); - + return new ItemOption(itemOptionDto.getOptionType(), itemOptionDto.getName(),item); } } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/entity/ItemOption.java b/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/entity/ItemOption.java index d3bb75a..d674b96 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/entity/ItemOption.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/entity/ItemOption.java @@ -22,8 +22,6 @@ public class ItemOption extends BaseEntity { @Enumerated(EnumType.STRING) private OptionType optionType; - private Long price; - private String name; @ManyToOne(fetch = LAZY , cascade = CascadeType.ALL) @@ -36,10 +34,16 @@ public class ItemOption extends BaseEntity { item.getItemOptions().add(this); } - public ItemOption(OptionType optionType, Long price, String name, Item item) { + public ItemOption(OptionType optionType, String name, Item item) { this.optionType = optionType; - this.price = price; this.name = name; this.item = item; } + + public static ItemOption of(OptionType type, String name) { + ItemOption itemOption = new ItemOption(); + itemOption.optionType = type; + itemOption.name = name; + return itemOption; + } } From 33f10cba9c3d99b4ea38c56abad7a83a83abcc49 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Tue, 8 Mar 2022 18:38:03 +0900 Subject: [PATCH 02/13] =?UTF-8?q?feat(store):=20Just=20pick-up=20=EB=A7=A4?= =?UTF-8?q?=EC=9E=A5=20=EB=A9=94=EB=89=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storeservice/StoreServiceApplication.java | 114 +++++++++++------- .../category/service/CategoryService.java | 5 +- .../web/CategoryCustomerApiController.java | 78 ++++++++++++ .../web/CategoryOwnerApiController.java | 2 +- .../domain/item/service/ItemServiceImpl.java | 8 +- .../domain/store/dto/StoreDto.java | 19 +++ .../domain/store/entity/Store.java | 8 +- .../exception/NotExistStoreException.java | 11 ++ .../domain/store/service/StoreService.java | 2 + .../store/service/StoreServiceImpl.java | 14 ++- .../domain/store/web/StoreController.java | 30 +++++ .../web/CategoryOwnerApiControllerTest.java | 2 +- 12 files changed, 237 insertions(+), 56 deletions(-) create mode 100644 store-service/src/main/java/com/justpickup/storeservice/domain/category/web/CategoryCustomerApiController.java create mode 100644 store-service/src/main/java/com/justpickup/storeservice/domain/store/dto/StoreDto.java create mode 100644 store-service/src/main/java/com/justpickup/storeservice/domain/store/exception/NotExistStoreException.java diff --git a/store-service/src/main/java/com/justpickup/storeservice/StoreServiceApplication.java b/store-service/src/main/java/com/justpickup/storeservice/StoreServiceApplication.java index 42b2047..0ed30c0 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/StoreServiceApplication.java +++ b/store-service/src/main/java/com/justpickup/storeservice/StoreServiceApplication.java @@ -1,7 +1,15 @@ package com.justpickup.storeservice; +import com.justpickup.storeservice.domain.category.dto.CategoryDto; +import com.justpickup.storeservice.domain.category.entity.Category; +import com.justpickup.storeservice.domain.category.repository.CategoryRepository; import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore; import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreRepository; +import com.justpickup.storeservice.domain.item.entity.Item; +import com.justpickup.storeservice.domain.item.repository.ItemRepository; +import com.justpickup.storeservice.domain.item.service.ItemService; +import com.justpickup.storeservice.domain.itemoption.entity.ItemOption; +import com.justpickup.storeservice.domain.itemoption.entity.OptionType; import com.justpickup.storeservice.domain.map.entity.Map; import com.justpickup.storeservice.domain.store.entity.Store; import com.justpickup.storeservice.domain.store.repository.StoreRepository; @@ -24,55 +32,79 @@ public class StoreServiceApplication { } @Bean - CommandLineRunner run(StoreRepository storeRepository, FavoriteStoreRepository favoriteStoreRepository) { + CommandLineRunner run(StoreRepository storeRepository, FavoriteStoreRepository favoriteStoreRepository, + ItemRepository itemRepository, CategoryRepository categoryRepository) { return args -> { List stores = new ArrayList<>(); - stores.add( - Store.of( - new Address("서울시", "마포구 도화동", "201-20"), - Map.of(37.5398271003404, 126.94769672415691), - 1L, - "커피온리 마포역점" - ) - ); + createStores(storeRepository, stores); - stores.add( - Store.of( - new Address("서울시", "마포구 도화동", "50-10"), - Map.of(37.54010719003089, 126.94556661330861), - 2L, - "만랩커피 마포점" - ) - ); + createFavoriteStore(favoriteStoreRepository, stores); - stores.add( - Store.of( - new Address("서울시", "마포구 도화동", "555"), - Map.of(37.539797393793755, 126.9453578838543), - 3L, - "이디야커피 마포오벨리스크점" - ) - ); + stores.forEach(store -> { + Category 카페인 = categoryRepository.save(Category.of("카페인", 0, store)); + Category 디카페인 = categoryRepository.save(Category.of("디카페인", 1, store)); + Category 티 = categoryRepository.save(Category.of("티", 2, store)); - stores.add( - Store.of( - new Address("서울시", "영등포구 도림로", "31길 2"), - Map.of(37.493033141569505, 126.89593667847592), - 4L, - "이디야커피 대림역점" - ) - ); + ItemOption ice = ItemOption.of(OptionType.REQUIRED, "ICE"); + ItemOption hot = ItemOption.of(OptionType.REQUIRED, "HOT"); - storeRepository.saveAll(stores); - - List userList = List.of(1L,2L,3L,4L,5L,6L,7L); - userList.forEach(userId -> { - stores.forEach(store -> { - favoriteStoreRepository.save(FavoriteStore.of(userId, store)); - }); + Item 아메리카노 = Item.of("아메리카노", 1500L, 카페인, store, List.of(ice, hot)); + Item 카페라떼 = Item.of("카페라떼", 2000L, 카페인, store, List.of(ice, hot)); + Item 카페모카 = Item.of("카페모카", 3900L, 카페인, store, List.of(ice, hot)); + Item 콜드브루 = Item.of("콜드브루", 2500L, 카페인, store, List.of(ice)); + Item 녹차라떼 = Item.of("녹차라떼", 3000L, 디카페인, store, List.of(ice, hot)); + Item 딸기라떼 = Item.of("딸기라떼", 3000L, 디카페인, store, List.of(ice, hot)); + Item 녹차 = Item.of("녹차", 3000L, 티, store, List.of(hot)); + Item 히비스커스 = Item.of("히비스커스 티", 3000L, 티, store, List.of(hot)); + itemRepository.saveAll(List.of(아메리카노, 카페라떼, 콜드브루, 녹차라떼, 딸기라떼, 녹차, 히비스커스)); }); - }; } + + + private void createFavoriteStore(FavoriteStoreRepository favoriteStoreRepository, List stores) { + List userList = List.of(1L,2L,3L,4L,5L,6L,7L); + userList.forEach(userId -> stores.forEach(store -> favoriteStoreRepository.save(FavoriteStore.of(userId, store)))); + } + + private void createStores(StoreRepository storeRepository, List stores) { + stores.add( + Store.of( + new Address("서울시", "마포구 도화동", "201-20"), + Map.of(37.5398271003404, 126.94769672415691), + 1L, + "커피온리 마포역점" + ) + ); + + stores.add( + Store.of( + new Address("서울시", "마포구 도화동", "50-10"), + Map.of(37.54010719003089, 126.94556661330861), + 2L, + "만랩커피 마포점" + ) + ); + + stores.add( + Store.of( + new Address("서울시", "마포구 도화동", "555"), + Map.of(37.539797393793755, 126.9453578838543), + 3L, + "이디야커피 마포오벨리스크점" + ) + ); + + stores.add( + Store.of( + new Address("서울시", "영등포구 도림로", "31길 2"), + Map.of(37.493033141569505, 126.89593667847592), + 4L, + "이디야커피 대림역점" + ) + ); + + storeRepository.saveAll(stores); + } } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/category/service/CategoryService.java b/store-service/src/main/java/com/justpickup/storeservice/domain/category/service/CategoryService.java index 25dd471..1ef04de 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/category/service/CategoryService.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/category/service/CategoryService.java @@ -7,7 +7,6 @@ import com.justpickup.storeservice.domain.category.repository.CategoryRepository import com.justpickup.storeservice.domain.category.repository.CategoryRepositoryCustom; import com.justpickup.storeservice.domain.store.entity.Store; import com.justpickup.storeservice.domain.store.repository.StoreRepository; -import com.justpickup.storeservice.global.exception.CustomException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; @@ -27,7 +26,7 @@ public class CategoryService { private final CategoryRepositoryCustom categoryRepositoryCustom; private final StoreRepository storeRepository; - public List getCategoryList(Long storeId){ + public List getCategoriesWithItem(Long storeId){ return categoryRepositoryCustom.getCategoryList(storeId) .stream() @@ -74,6 +73,6 @@ public class CategoryService { .orElseThrow(() -> new NotFoundStoreException(HttpStatus.BAD_REQUEST,"존재하지않는 Category"))); } ); - } + } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/category/web/CategoryCustomerApiController.java b/store-service/src/main/java/com/justpickup/storeservice/domain/category/web/CategoryCustomerApiController.java new file mode 100644 index 0000000..882f3a0 --- /dev/null +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/category/web/CategoryCustomerApiController.java @@ -0,0 +1,78 @@ +package com.justpickup.storeservice.domain.category.web; + +import com.justpickup.storeservice.domain.category.dto.CategoryDto; +import com.justpickup.storeservice.domain.category.service.CategoryService; +import com.justpickup.storeservice.global.dto.Result; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/customer/") +public class CategoryCustomerApiController { + + private final CategoryService categoryService; + + @GetMapping("/categories") + public ResponseEntity getCategories(@RequestParam("storeId") Long storeId) { + List categoryList = categoryService.getCategoriesWithItem(storeId); + + GetCategoriesResponse getCategoriesResponse = new GetCategoriesResponse(categoryList); + + return ResponseEntity.ok(Result.createSuccessResult(getCategoriesResponse)); + } + + @Data @NoArgsConstructor + static class GetCategoriesResponse { + private List<_Category> categories; + + public GetCategoriesResponse(List categoryDtoList) { + this. categories = categoryDtoList + .stream() + .map(_Category::new) + .collect(Collectors.toList()); + } + + @Data + static class _Category { + private Long id; + private String name; + private Integer order; + private List<_Item> items; + + public _Category(CategoryDto categoryDto) { + List<_Item> items = categoryDto.getItems() + .stream() + .map(itemDto -> new _Item(itemDto.getId(), itemDto.getName(), itemDto.getPrice())) + .collect(Collectors.toList()); + + this.id = categoryDto.getId(); + this.name = categoryDto.getName(); + this.order = categoryDto.getOrder(); + this.items = items; + } + } + + @Data + static class _Item { + private Long id; + private String name; + private Long price; + + public _Item(Long id, String name, Long price) { + this.id = id; + this.name = name; + this.price = price; + } + } + } +} diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiController.java b/store-service/src/main/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiController.java index a444af3..1da4a2e 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiController.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiController.java @@ -24,7 +24,7 @@ public class CategoryOwnerApiController { @GetMapping("/category") public ResponseEntity getCategoryList(@RequestHeader(value = "user-id") String userId ){ Long storeId = Long.parseLong(userId); - List categoryList = categoryService.getCategoryList(storeId); + List categoryList = categoryService.getCategoriesWithItem(storeId); List categoryResponseList = categoryList.stream() .map(CategoryResponse::new) diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/item/service/ItemServiceImpl.java b/store-service/src/main/java/com/justpickup/storeservice/domain/item/service/ItemServiceImpl.java index 21a50e6..b81c672 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/item/service/ItemServiceImpl.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/item/service/ItemServiceImpl.java @@ -20,9 +20,7 @@ import org.springframework.data.support.PageableExecutionUtils; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; @Service @@ -61,7 +59,7 @@ public class ItemServiceImpl implements ItemService { Page itemList = itemRepositoryCustom.findItem(storeId,word,pageable); return PageableExecutionUtils.getPage(itemList.stream() - .map(ItemDto::createWithCategoryItemDto) + .map(ItemDto::createWithCategory) .collect(Collectors.toList()),pageable,itemList::getTotalElements); } @@ -106,9 +104,7 @@ public class ItemServiceImpl implements ItemService { List itemOptions = itemOptionDtos .stream() - .map(itemOptionDto -> { - return ItemOption.of(itemOptionDto.getOptionType(), itemOptionDto.getName()); - }) + .map(itemOptionDto -> ItemOption.of(itemOptionDto.getOptionType(), itemOptionDto.getName())) .collect(Collectors.toList()); Item createdItem = Item.of(itemName, itemPrice, category, store, itemOptions); diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/store/dto/StoreDto.java b/store-service/src/main/java/com/justpickup/storeservice/domain/store/dto/StoreDto.java new file mode 100644 index 0000000..0885526 --- /dev/null +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/store/dto/StoreDto.java @@ -0,0 +1,19 @@ +package com.justpickup.storeservice.domain.store.dto; + +import com.justpickup.storeservice.domain.store.entity.Store; +import lombok.Getter; + +@Getter +public class StoreDto { + + private Long id; + private String name; + private String phoneNumber; + + public StoreDto(Store store) { + this.id = store.getId(); + this.name = store.getName(); + this.phoneNumber = store.getPhoneNumber(); + } + +} diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/store/entity/Store.java b/store-service/src/main/java/com/justpickup/storeservice/domain/store/entity/Store.java index e50396f..58fc886 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/store/entity/Store.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/store/entity/Store.java @@ -13,6 +13,7 @@ import lombok.NoArgsConstructor; import javax.persistence.*; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import static javax.persistence.FetchType.LAZY; @@ -48,13 +49,14 @@ public class Store extends BaseEntity { private Long userId; @OneToMany(mappedBy = "store") - private List categories; + private List categories = new ArrayList<>(); @OneToMany(mappedBy = "store") - private List items; + private List items = new ArrayList<>(); @OneToMany(mappedBy = "store") - private List favoriteStores; + private List favoriteStores = new ArrayList<>(); + // == 연관관계 편의 메소드 == // public void addCategory(Category category) { categories.add(category); diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/store/exception/NotExistStoreException.java b/store-service/src/main/java/com/justpickup/storeservice/domain/store/exception/NotExistStoreException.java new file mode 100644 index 0000000..c8a4bcc --- /dev/null +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/store/exception/NotExistStoreException.java @@ -0,0 +1,11 @@ +package com.justpickup.storeservice.domain.store.exception; + +import com.justpickup.storeservice.global.exception.CustomException; +import org.springframework.http.HttpStatus; + +public class NotExistStoreException extends CustomException { + + public NotExistStoreException(String message) { + super(HttpStatus.CONFLICT, message); + } +} diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/store/service/StoreService.java b/store-service/src/main/java/com/justpickup/storeservice/domain/store/service/StoreService.java index afb2099..1787b50 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/store/service/StoreService.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/store/service/StoreService.java @@ -2,6 +2,7 @@ package com.justpickup.storeservice.domain.store.service; import com.justpickup.storeservice.domain.store.dto.SearchStoreCondition; import com.justpickup.storeservice.domain.store.dto.SearchStoreResult; +import com.justpickup.storeservice.domain.store.dto.StoreDto; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.SliceImpl; @@ -10,4 +11,5 @@ import java.util.List; public interface StoreService { SliceImpl findSearchStoreScroll(SearchStoreCondition condition, Pageable pageable); List findFavoriteStore(SearchStoreCondition condition, Long userId); + StoreDto findStore(Long storeId); } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/store/service/StoreServiceImpl.java b/store-service/src/main/java/com/justpickup/storeservice/domain/store/service/StoreServiceImpl.java index c535f7e..3caf57e 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/store/service/StoreServiceImpl.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/store/service/StoreServiceImpl.java @@ -3,6 +3,10 @@ package com.justpickup.storeservice.domain.store.service; import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreCustom; import com.justpickup.storeservice.domain.store.dto.SearchStoreCondition; import com.justpickup.storeservice.domain.store.dto.SearchStoreResult; +import com.justpickup.storeservice.domain.store.dto.StoreDto; +import com.justpickup.storeservice.domain.store.entity.Store; +import com.justpickup.storeservice.domain.store.exception.NotExistStoreException; +import com.justpickup.storeservice.domain.store.repository.StoreRepository; import com.justpickup.storeservice.domain.store.repository.StoreRepositoryCustom; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Pageable; @@ -10,7 +14,6 @@ import org.springframework.data.domain.SliceImpl; import org.springframework.stereotype.Service; import java.util.List; -import java.util.stream.Collectors; @Service @RequiredArgsConstructor @@ -18,6 +21,7 @@ public class StoreServiceImpl implements StoreService { private final StoreRepositoryCustom storeRepositoryCustom; private final FavoriteStoreCustom favoriteStoreCustom; + private final StoreRepository storeRepository; @Override public SliceImpl findSearchStoreScroll(SearchStoreCondition condition, Pageable pageable) { @@ -41,4 +45,12 @@ public class StoreServiceImpl implements StoreService { }); return favoriteStores; } + + @Override + public StoreDto findStore(Long storeId) { + Store store = storeRepository.findById(storeId) + .orElseThrow(() -> new NotExistStoreException(storeId + "는 없는 매장 고유번호입니다.")); + + return new StoreDto(store); + } } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/store/web/StoreController.java b/store-service/src/main/java/com/justpickup/storeservice/domain/store/web/StoreController.java index 11854d5..3bbe6f2 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/store/web/StoreController.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/store/web/StoreController.java @@ -1,6 +1,14 @@ package com.justpickup.storeservice.domain.store.web; +import com.justpickup.storeservice.domain.store.dto.StoreDto; +import com.justpickup.storeservice.domain.store.service.StoreService; +import com.justpickup.storeservice.global.dto.Result; +import lombok.Data; +import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; +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.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -9,4 +17,26 @@ import org.springframework.web.bind.annotation.RestController; @RequestMapping("/store") public class StoreController { + private final StoreService storeService; + + @GetMapping("/{storeId}") + public ResponseEntity getStore(@PathVariable("storeId") Long storeId) { + StoreDto storeDto = storeService.findStore(storeId); + + GetStoreResponse getStoreResponse = new GetStoreResponse(storeDto); + return ResponseEntity.ok(Result.createSuccessResult(getStoreResponse)); + } + + @Data @NoArgsConstructor + static class GetStoreResponse { + private Long id; + private String name; + private String phoneNumber; + + public GetStoreResponse(StoreDto storeDto) { + this.id = storeDto.getId(); + this.name = storeDto.getName(); + this.phoneNumber = storeDto.getPhoneNumber(); + } + } } diff --git a/store-service/src/test/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiControllerTest.java b/store-service/src/test/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiControllerTest.java index c809974..cfcf940 100644 --- a/store-service/src/test/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiControllerTest.java +++ b/store-service/src/test/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiControllerTest.java @@ -75,7 +75,7 @@ class CategoryOwnerApiControllerTest { .order(2) .build()); - given(categoryService.getCategoryList(any())).willReturn(categoryDtoList); + given(categoryService.getCategoriesWithItem(any())).willReturn(categoryDtoList); //when ResultActions actions = mockMvc.perform(MockMvcRequestBuilders.get("/api/owner/category") From 5a4a2ae94be1298fd2d97d1f8fbe29b55b21d37f Mon Sep 17 00:00:00 2001 From: bum12ark Date: Tue, 8 Mar 2022 20:49:47 +0900 Subject: [PATCH 03/13] =?UTF-8?q?test(store):=20Just=20pick-up=20=EB=A7=A4?= =?UTF-8?q?=EC=9E=A5=20=EB=A9=94=EB=89=B4=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- store-service/src/docs/asciidoc/api-docs.adoc | 4 +- .../storeservice/StoreServiceApplication.java | 95 --------------- .../storeservice/domain/item/dto/ItemDto.java | 7 +- .../item/repository/ItemRepository.java | 4 - .../ItemOptionRepositoryCustom.java | 9 +- .../domain/store/dto/StoreDto.java | 5 +- .../repository/StoreRepositoryCustom.java | 3 +- .../global/SqlCommandLineRunner.java | 108 ++++++++++++++++++ .../web/CategoryOwnerApiControllerTest.java | 9 -- .../item/web/ItemOwnerApiControllerTest.java | 22 +--- .../domain/store/web/StoreControllerTest.java | 69 +++++++++++ .../web/StoreCustomerApiControllerTest.java | 9 +- 12 files changed, 201 insertions(+), 143 deletions(-) create mode 100644 store-service/src/main/java/com/justpickup/storeservice/global/SqlCommandLineRunner.java create mode 100644 store-service/src/test/java/com/justpickup/storeservice/domain/store/web/StoreControllerTest.java diff --git a/store-service/src/docs/asciidoc/api-docs.adoc b/store-service/src/docs/asciidoc/api-docs.adoc index ea28906..cdb3467 100644 --- a/store-service/src/docs/asciidoc/api-docs.adoc +++ b/store-service/src/docs/asciidoc/api-docs.adoc @@ -95,8 +95,8 @@ operation::put-categoryList[snippets='curl-request,http-request,http-response,re == 매장 === 매장 검색 조회 operation::api-customer-store-search[snippets='curl-request,http-request,http-response,request-parameters,response-fields'] - === 자주찾는 매장 operation::favoriteStore-get[snippets='curl-request,http-request,http-response,request-headers,request-parameters,response-fields'] - +=== 매장 조회 +operation::store-get[snippets='curl-request,http-request,http-response,path-parameters,response-fields'] diff --git a/store-service/src/main/java/com/justpickup/storeservice/StoreServiceApplication.java b/store-service/src/main/java/com/justpickup/storeservice/StoreServiceApplication.java index 0ed30c0..e0e9bd9 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/StoreServiceApplication.java +++ b/store-service/src/main/java/com/justpickup/storeservice/StoreServiceApplication.java @@ -1,27 +1,8 @@ package com.justpickup.storeservice; -import com.justpickup.storeservice.domain.category.dto.CategoryDto; -import com.justpickup.storeservice.domain.category.entity.Category; -import com.justpickup.storeservice.domain.category.repository.CategoryRepository; -import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore; -import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreRepository; -import com.justpickup.storeservice.domain.item.entity.Item; -import com.justpickup.storeservice.domain.item.repository.ItemRepository; -import com.justpickup.storeservice.domain.item.service.ItemService; -import com.justpickup.storeservice.domain.itemoption.entity.ItemOption; -import com.justpickup.storeservice.domain.itemoption.entity.OptionType; -import com.justpickup.storeservice.domain.map.entity.Map; -import com.justpickup.storeservice.domain.store.entity.Store; -import com.justpickup.storeservice.domain.store.repository.StoreRepository; -import com.justpickup.storeservice.global.entity.Address; -import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; -import org.springframework.context.annotation.Bean; - -import java.util.ArrayList; -import java.util.List; @SpringBootApplication @EnableEurekaClient @@ -31,80 +12,4 @@ public class StoreServiceApplication { SpringApplication.run(StoreServiceApplication.class, args); } - @Bean - CommandLineRunner run(StoreRepository storeRepository, FavoriteStoreRepository favoriteStoreRepository, - ItemRepository itemRepository, CategoryRepository categoryRepository) { - return args -> { - List stores = new ArrayList<>(); - - createStores(storeRepository, stores); - - createFavoriteStore(favoriteStoreRepository, stores); - - stores.forEach(store -> { - Category 카페인 = categoryRepository.save(Category.of("카페인", 0, store)); - Category 디카페인 = categoryRepository.save(Category.of("디카페인", 1, store)); - Category 티 = categoryRepository.save(Category.of("티", 2, store)); - - ItemOption ice = ItemOption.of(OptionType.REQUIRED, "ICE"); - ItemOption hot = ItemOption.of(OptionType.REQUIRED, "HOT"); - - Item 아메리카노 = Item.of("아메리카노", 1500L, 카페인, store, List.of(ice, hot)); - Item 카페라떼 = Item.of("카페라떼", 2000L, 카페인, store, List.of(ice, hot)); - Item 카페모카 = Item.of("카페모카", 3900L, 카페인, store, List.of(ice, hot)); - Item 콜드브루 = Item.of("콜드브루", 2500L, 카페인, store, List.of(ice)); - Item 녹차라떼 = Item.of("녹차라떼", 3000L, 디카페인, store, List.of(ice, hot)); - Item 딸기라떼 = Item.of("딸기라떼", 3000L, 디카페인, store, List.of(ice, hot)); - Item 녹차 = Item.of("녹차", 3000L, 티, store, List.of(hot)); - Item 히비스커스 = Item.of("히비스커스 티", 3000L, 티, store, List.of(hot)); - itemRepository.saveAll(List.of(아메리카노, 카페라떼, 콜드브루, 녹차라떼, 딸기라떼, 녹차, 히비스커스)); - }); - }; - } - - - private void createFavoriteStore(FavoriteStoreRepository favoriteStoreRepository, List stores) { - List userList = List.of(1L,2L,3L,4L,5L,6L,7L); - userList.forEach(userId -> stores.forEach(store -> favoriteStoreRepository.save(FavoriteStore.of(userId, store)))); - } - - private void createStores(StoreRepository storeRepository, List stores) { - stores.add( - Store.of( - new Address("서울시", "마포구 도화동", "201-20"), - Map.of(37.5398271003404, 126.94769672415691), - 1L, - "커피온리 마포역점" - ) - ); - - stores.add( - Store.of( - new Address("서울시", "마포구 도화동", "50-10"), - Map.of(37.54010719003089, 126.94556661330861), - 2L, - "만랩커피 마포점" - ) - ); - - stores.add( - Store.of( - new Address("서울시", "마포구 도화동", "555"), - Map.of(37.539797393793755, 126.9453578838543), - 3L, - "이디야커피 마포오벨리스크점" - ) - ); - - stores.add( - Store.of( - new Address("서울시", "영등포구 도림로", "31길 2"), - Map.of(37.493033141569505, 126.89593667847592), - 4L, - "이디야커피 대림역점" - ) - ); - - storeRepository.saveAll(stores); - } } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/item/dto/ItemDto.java b/store-service/src/main/java/com/justpickup/storeservice/domain/item/dto/ItemDto.java index 6b094d2..1174460 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/item/dto/ItemDto.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/item/dto/ItemDto.java @@ -52,7 +52,7 @@ public class ItemDto { .build(); } - public static ItemDto createWithCategoryItemDto(Item item) { + public static ItemDto createWithCategory(Item item) { return ItemDto.builder() .id(item.getId()) .name(item.getName()) @@ -79,9 +79,4 @@ public class ItemDto { .build(); } - // TODO: 2022/02/03 queryDsl 쿼리 생성 시 구현 필요 -// public static ItemDto createFullItemDto(Item item) { -// return null -// } - } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/item/repository/ItemRepository.java b/store-service/src/main/java/com/justpickup/storeservice/domain/item/repository/ItemRepository.java index 3e6b1d9..dc6a081 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/item/repository/ItemRepository.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/item/repository/ItemRepository.java @@ -1,12 +1,8 @@ package com.justpickup.storeservice.domain.item.repository; import com.justpickup.storeservice.domain.item.entity.Item; -import com.justpickup.storeservice.domain.store.entity.Store; import org.springframework.data.jpa.repository.JpaRepository; -import java.util.List; - public interface ItemRepository extends JpaRepository { - List findByStore(Store store); } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/repository/ItemOptionRepositoryCustom.java b/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/repository/ItemOptionRepositoryCustom.java index 3cc1316..b211a40 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/repository/ItemOptionRepositoryCustom.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/itemoption/repository/ItemOptionRepositoryCustom.java @@ -1,16 +1,15 @@ package com.justpickup.storeservice.domain.itemoption.repository; -import com.justpickup.storeservice.domain.item.entity.Item; -import com.justpickup.storeservice.domain.item.entity.QItem; import com.justpickup.storeservice.domain.itemoption.entity.ItemOption; import com.justpickup.storeservice.domain.itemoption.entity.QItemOption; import com.querydsl.jpa.impl.JPAQueryFactory; import lombok.RequiredArgsConstructor; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; import java.util.List; +import static com.justpickup.storeservice.domain.item.entity.QItem.item; + @Repository @RequiredArgsConstructor public class ItemOptionRepositoryCustom { @@ -21,7 +20,9 @@ public class ItemOptionRepositoryCustom { return queryFactory.selectFrom(QItemOption.itemOption) .join(QItemOption.itemOption.item) - .on(QItem.item.id.eq(itemId)) + .on(item.id.eq(itemId)) .fetch(); } + + } diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/store/dto/StoreDto.java b/store-service/src/main/java/com/justpickup/storeservice/domain/store/dto/StoreDto.java index 0885526..a015ae7 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/store/dto/StoreDto.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/store/dto/StoreDto.java @@ -1,11 +1,14 @@ package com.justpickup.storeservice.domain.store.dto; import com.justpickup.storeservice.domain.store.entity.Store; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; @Getter +@AllArgsConstructor +@Builder public class StoreDto { - private Long id; private String name; private String phoneNumber; diff --git a/store-service/src/main/java/com/justpickup/storeservice/domain/store/repository/StoreRepositoryCustom.java b/store-service/src/main/java/com/justpickup/storeservice/domain/store/repository/StoreRepositoryCustom.java index 55093ed..4c45d7c 100644 --- a/store-service/src/main/java/com/justpickup/storeservice/domain/store/repository/StoreRepositoryCustom.java +++ b/store-service/src/main/java/com/justpickup/storeservice/domain/store/repository/StoreRepositoryCustom.java @@ -1,6 +1,5 @@ package com.justpickup.storeservice.domain.store.repository; -import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore; import com.justpickup.storeservice.domain.favoritestore.entity.QFavoriteStore; import com.justpickup.storeservice.domain.store.dto.SearchStoreCondition; import com.justpickup.storeservice.domain.store.dto.SearchStoreResult; @@ -83,7 +82,7 @@ public class StoreRepositoryCustom { return content; } - private NumberExpression getHaversineDistance (double SearchLatitude, double SearchLongitude){ + private NumberExpression getHaversineDistance(double SearchLatitude, double SearchLongitude){ Expression latitude = Expressions.constant(SearchLatitude); Expression longitude = Expressions.constant(SearchLongitude); diff --git a/store-service/src/main/java/com/justpickup/storeservice/global/SqlCommandLineRunner.java b/store-service/src/main/java/com/justpickup/storeservice/global/SqlCommandLineRunner.java new file mode 100644 index 0000000..9440a00 --- /dev/null +++ b/store-service/src/main/java/com/justpickup/storeservice/global/SqlCommandLineRunner.java @@ -0,0 +1,108 @@ +package com.justpickup.storeservice.global; + +import com.justpickup.storeservice.domain.category.entity.Category; +import com.justpickup.storeservice.domain.category.repository.CategoryRepository; +import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore; +import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreRepository; +import com.justpickup.storeservice.domain.item.entity.Item; +import com.justpickup.storeservice.domain.item.repository.ItemRepository; +import com.justpickup.storeservice.domain.itemoption.entity.ItemOption; +import com.justpickup.storeservice.domain.itemoption.entity.OptionType; +import com.justpickup.storeservice.domain.map.entity.Map; +import com.justpickup.storeservice.domain.store.entity.Store; +import com.justpickup.storeservice.domain.store.repository.StoreRepository; +import com.justpickup.storeservice.global.entity.Address; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class SqlCommandLineRunner implements CommandLineRunner { + + private final StoreRepository storeRepository; + private final FavoriteStoreRepository favoriteStoreRepository; + private final ItemRepository itemRepository; + private final CategoryRepository categoryRepository; + + @Override + public void run(String... args) throws Exception { + List stores = new ArrayList<>(); + + createStores(storeRepository, stores); + + createFavoriteStore(favoriteStoreRepository, stores); + + createItemAndCategories(itemRepository, categoryRepository, stores); + } + + private void createItemAndCategories(ItemRepository itemRepository, CategoryRepository categoryRepository, List stores) { + stores.forEach(store -> { + Category 카페인 = categoryRepository.save(Category.of("카페인", 0, store)); + Category 디카페인 = categoryRepository.save(Category.of("디카페인", 1, store)); + Category 티 = categoryRepository.save(Category.of("티", 2, store)); + + ItemOption ice = ItemOption.of(OptionType.REQUIRED, "ICE"); + ItemOption hot = ItemOption.of(OptionType.REQUIRED, "HOT"); + + Item 아메리카노 = Item.of("아메리카노", 1500L, 카페인, store, List.of(ice, hot)); + Item 카페라떼 = Item.of("카페라떼", 2000L, 카페인, store, List.of(ice, hot)); + Item 카페모카 = Item.of("카페모카", 3900L, 카페인, store, List.of(ice, hot)); + Item 콜드브루 = Item.of("콜드브루", 2500L, 카페인, store, List.of(ice)); + Item 녹차라떼 = Item.of("녹차라떼", 3000L, 디카페인, store, List.of(ice, hot)); + Item 딸기라떼 = Item.of("딸기라떼", 3000L, 디카페인, store, List.of(ice, hot)); + Item 녹차 = Item.of("녹차", 3000L, 티, store, List.of(hot)); + Item 히비스커스 = Item.of("히비스커스 티", 3000L, 티, store, List.of(hot)); + itemRepository.saveAll(List.of(아메리카노, 카페라떼, 콜드브루, 녹차라떼, 딸기라떼, 녹차, 히비스커스)); + }); + } + + + private void createFavoriteStore(FavoriteStoreRepository favoriteStoreRepository, List stores) { + List userList = List.of(1L,2L,3L,4L,5L,6L,7L); + userList.forEach(userId -> stores.forEach(store -> favoriteStoreRepository.save(FavoriteStore.of(userId, store)))); + } + + private void createStores(StoreRepository storeRepository, List stores) { + stores.add( + Store.of( + new Address("서울시", "마포구 도화동", "201-20"), + Map.of(37.5398271003404, 126.94769672415691), + 1L, + "커피온리 마포역점" + ) + ); + + stores.add( + Store.of( + new Address("서울시", "마포구 도화동", "50-10"), + Map.of(37.54010719003089, 126.94556661330861), + 2L, + "만랩커피 마포점" + ) + ); + + stores.add( + Store.of( + new Address("서울시", "마포구 도화동", "555"), + Map.of(37.539797393793755, 126.9453578838543), + 3L, + "이디야커피 마포오벨리스크점" + ) + ); + + stores.add( + Store.of( + new Address("서울시", "영등포구 도림로", "31길 2"), + Map.of(37.493033141569505, 126.89593667847592), + 4L, + "이디야커피 대림역점" + ) + ); + + storeRepository.saveAll(stores); + } +} diff --git a/store-service/src/test/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiControllerTest.java b/store-service/src/test/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiControllerTest.java index cfcf940..63bdf20 100644 --- a/store-service/src/test/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiControllerTest.java +++ b/store-service/src/test/java/com/justpickup/storeservice/domain/category/web/CategoryOwnerApiControllerTest.java @@ -45,17 +45,9 @@ class CategoryOwnerApiControllerTest { @MockBean private CategoryService categoryService; - @MockBean - private StoreRepository storeRepository; - - @MockBean - private FavoriteStoreRepository favoriteStoreRepository; - - @Test @DisplayName("카테고리리스트_가져오기_성공") void getCategoryList_success() throws Exception { - //given Long storeId = 1L; List categoryDtoList = new ArrayList<>(); @@ -108,7 +100,6 @@ class CategoryOwnerApiControllerTest { } - @Test @DisplayName("카테고리리스트_수정_성공") void putCategoryList_success() throws Exception { diff --git a/store-service/src/test/java/com/justpickup/storeservice/domain/item/web/ItemOwnerApiControllerTest.java b/store-service/src/test/java/com/justpickup/storeservice/domain/item/web/ItemOwnerApiControllerTest.java index b999e7a..83a7d83 100644 --- a/store-service/src/test/java/com/justpickup/storeservice/domain/item/web/ItemOwnerApiControllerTest.java +++ b/store-service/src/test/java/com/justpickup/storeservice/domain/item/web/ItemOwnerApiControllerTest.java @@ -56,12 +56,6 @@ class ItemOwnerApiControllerTest { @MockBean ItemService itemService; - @MockBean - private StoreRepository storeRepository; - - @MockBean - private FavoriteStoreRepository favoriteStoreRepository; - @Test @DisplayName("상품 리스트 조회") void getItemList() throws Exception { @@ -177,9 +171,9 @@ class ItemOwnerApiControllerTest { Long categoryId = 1L; List requiredOption = - List.of(new ItemOwnerApiController.ItemRequest.ItemOptionRequest(null, "HOT",OptionType.REQUIRED,null)); + List.of(new ItemOwnerApiController.ItemRequest.ItemOptionRequest(null, "HOT",OptionType.REQUIRED)); List otherOption = - List.of(new ItemOwnerApiController.ItemRequest.ItemOptionRequest(null, "샷 추가",OptionType.OTHER,null)); + List.of(new ItemOwnerApiController.ItemRequest.ItemOptionRequest(null, "샷 추가", OptionType.OTHER)); ItemOwnerApiController.ItemRequest itemRequest = @@ -208,12 +202,10 @@ class ItemOwnerApiControllerTest { fieldWithPath("requiredOption[*].id").description("옵션 고유번호"), fieldWithPath("requiredOption[*].name").description("옵션 이름"), fieldWithPath("requiredOption[*].optionType").description("옵션 타입"), - fieldWithPath("requiredOption[*].price").description("옵션 가격"), fieldWithPath("otherOption").description("추가옵션"), fieldWithPath("otherOption[*].id").description("옵션 고유번호"), fieldWithPath("otherOption[*].name").description("옵션 이름"), - fieldWithPath("otherOption[*].optionType").description("옵션 타입"), - fieldWithPath("otherOption[*].price").description("옵션 가격") + fieldWithPath("otherOption[*].optionType").description("옵션 타입") )) ); } @@ -227,9 +219,9 @@ class ItemOwnerApiControllerTest { Long categoryId = 1L; List requiredOption = - List.of(new ItemOwnerApiController.ItemRequest.ItemOptionRequest(null, "HOT",OptionType.REQUIRED,null)); + List.of(new ItemOwnerApiController.ItemRequest.ItemOptionRequest(null, "HOT",OptionType.REQUIRED)); List otherOption = - List.of(new ItemOwnerApiController.ItemRequest.ItemOptionRequest(null, "샷 추가",OptionType.OTHER,null)); + List.of(new ItemOwnerApiController.ItemRequest.ItemOptionRequest(null, "샷 추가",OptionType.OTHER)); ItemOwnerApiController.ItemRequest itemRequest = @@ -257,12 +249,10 @@ class ItemOwnerApiControllerTest { fieldWithPath("requiredOption[*].id").description("옵션 고유번호"), fieldWithPath("requiredOption[*].name").description("옵션 이름"), fieldWithPath("requiredOption[*].optionType").description("옵션 타입"), - fieldWithPath("requiredOption[*].price").description("옵션 가격"), fieldWithPath("otherOption").description("추가옵션"), fieldWithPath("otherOption[*].id").description("옵션 고유번호"), fieldWithPath("otherOption[*].name").description("옵션 이름"), - fieldWithPath("otherOption[*].optionType").description("옵션 타입"), - fieldWithPath("otherOption[*].price").description("옵션 가격") + fieldWithPath("otherOption[*].optionType").description("옵션 타입") )) ); } diff --git a/store-service/src/test/java/com/justpickup/storeservice/domain/store/web/StoreControllerTest.java b/store-service/src/test/java/com/justpickup/storeservice/domain/store/web/StoreControllerTest.java new file mode 100644 index 0000000..09737d0 --- /dev/null +++ b/store-service/src/test/java/com/justpickup/storeservice/domain/store/web/StoreControllerTest.java @@ -0,0 +1,69 @@ +package com.justpickup.storeservice.domain.store.web; + +import com.justpickup.storeservice.config.TestConfig; +import com.justpickup.storeservice.domain.store.dto.StoreDto; +import com.justpickup.storeservice.domain.store.service.StoreService; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import static org.mockito.BDDMockito.given; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(StoreController.class) +@Import(TestConfig.class) +@AutoConfigureRestDocs(uriHost = "just-pickup.com", uriPort = 8000) +class StoreControllerTest { + + private final String url = "/store"; + + @Autowired + MockMvc mockMvc; + + @MockBean + StoreService storeService; + + @Test + @DisplayName("[store] 매장 정보 가져오기") + void getStore() throws Exception { + //given + String storeId = "1"; + given(storeService.findStore(1L)).willReturn(getWillReturnStore()); + + //when + ResultActions actions = mockMvc.perform(get("/store/{storeId}", storeId)); + + //then + actions.andExpect(status().isOk()) + .andDo(print()) + .andDo(document("store-get", + pathParameters( + parameterWithName("storeId").description("매장 고유번호") + ), + responseFields( + fieldWithPath("code").description("결과 코드 SUCCESS/ERROR"), + fieldWithPath("message").description("메시지"), + fieldWithPath("data.id").description("매장 고유번호"), + fieldWithPath("data.name").description("매장 이름"), + fieldWithPath("data.phoneNumber").description("매장 번호") + ) + )); + } + + private StoreDto getWillReturnStore() { + return StoreDto.builder().id(1L).name("이디야커피 대림역점").phoneNumber("010-1234-5678").build(); + } +} \ No newline at end of file diff --git a/store-service/src/test/java/com/justpickup/storeservice/domain/store/web/StoreCustomerApiControllerTest.java b/store-service/src/test/java/com/justpickup/storeservice/domain/store/web/StoreCustomerApiControllerTest.java index 9946375..f9eefc1 100644 --- a/store-service/src/test/java/com/justpickup/storeservice/domain/store/web/StoreCustomerApiControllerTest.java +++ b/store-service/src/test/java/com/justpickup/storeservice/domain/store/web/StoreCustomerApiControllerTest.java @@ -93,16 +93,17 @@ class StoreCustomerApiControllerTest { fieldWithPath("message").description("메시지"), fieldWithPath("data[*].id").description("매장 고유번호"), fieldWithPath("data[*].name").description("매장 이름"), - fieldWithPath("data[*].distance").description("고객과의 거리차이 m/km") + fieldWithPath("data[*].distance").description("고객과의 거리차이 m/km"), + fieldWithPath("data[*].favoriteCounts").description("즐겨찾기 회수") ) )); } private List getWillReturnSearchStore(){ - SearchStoreResult result_1 = new SearchStoreResult(1L, "이디야커피 마포오벨리스크점", 145.11980562222007); - SearchStoreResult result_2 = new SearchStoreResult(2L, "만랩커피 마포점", 150.97181089895466); - SearchStoreResult result_3 = new SearchStoreResult(3L, "커피온리 마포역점", 341.25696860337655); + SearchStoreResult result_1 = new SearchStoreResult(1L, "이디야커피 마포오벨리스크점", 145.11980562222007, 5L); + SearchStoreResult result_2 = new SearchStoreResult(2L, "만랩커피 마포점", 150.97181089895466, 5L); + SearchStoreResult result_3 = new SearchStoreResult(3L, "커피온리 마포역점", 341.25696860337655, 5L); return List.of(result_1,result_2,result_3); } From af9f86ff5ca7fd00cbe787bad58d96de22bf3cd2 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Tue, 8 Mar 2022 20:50:49 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat(customer-vue):=20=EA=B3=A0=EA=B0=9D?= =?UTF-8?q?=20=EB=A7=A4=EC=9E=A5=20=EC=83=81=ED=92=88=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- customer-vue/src/api/store.js | 85 ++++++-------- .../src/components/StoreNavigation.vue | 32 +++++ customer-vue/src/router/router.js | 16 ++- customer-vue/src/views/Layout/StoreLayout.vue | 62 ++++++++++ customer-vue/src/views/SearchStore.vue | 11 +- customer-vue/src/views/StoreView.vue | 111 ++++++++++++++++++ 6 files changed, 264 insertions(+), 53 deletions(-) create mode 100644 customer-vue/src/components/StoreNavigation.vue create mode 100644 customer-vue/src/views/Layout/StoreLayout.vue create mode 100644 customer-vue/src/views/StoreView.vue diff --git a/customer-vue/src/api/store.js b/customer-vue/src/api/store.js index 9fae59a..ab10acc 100644 --- a/customer-vue/src/api/store.js +++ b/customer-vue/src/api/store.js @@ -1,56 +1,39 @@ import axios from "axios"; export default { - requestNearbyStore(latitude, longitude, storeName, page, size) { - const options = { - params: { - latitude: latitude, - longitude: longitude, - storeName: storeName, - page: page, - size: size - } + requestNearbyStore(latitude, longitude, storeName, page, size) { + const options = { + params: { + latitude: latitude, + longitude: longitude, + storeName: storeName, + page: page, + size: size } - return axios.get(process.env.VUE_APP_STORE_API_URL + '/store/search', options); - }, - getCategoryList(){ - return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+'/store-service/category/'); - }, - putCategoryList(data){ - return axios({ - method:'put', - url:process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+'/store-service/category', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json;charset=UTF-8' - }, - data: data, - responseType:'json' - }) - }, - getItemById(itemId){ - return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+'/store-service/item/'+itemId) - }, - saveItem(method, itemData){ - return axios({ - method:method, - url: process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+'/store-service/item', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json;charset=UTF-8' - }, - data: itemData, - responseType:'json' - }) - }, - getFavoriteStore(latitude, longitude,){ - const options = { - params: { - latitude: latitude, - longitude: longitude, - } - } - return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+'/store-service/api/customer/store/favorite',options) - }, - + } + return axios.get(process.env.VUE_APP_STORE_API_URL + '/store/search', options); + }, + getItemById(itemId){ + return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+'/store-service/item/'+itemId) + }, + getFavoriteStore(latitude, longitude,){ + const options = { + params: { + latitude: latitude, + longitude: longitude, + } + } + return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL+'/store-service/api/customer/store/favorite',options) + }, + requestCategoriesWithItem(storeId) { + const options = { + params: { + "storeId": storeId + } + } + return axios.get(process.env.VUE_APP_STORE_API_URL + "/categories", options); + }, + requestStore(storeId) { + return axios.get(process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/store-service/store/" + storeId); + } } \ No newline at end of file diff --git a/customer-vue/src/components/StoreNavigation.vue b/customer-vue/src/components/StoreNavigation.vue new file mode 100644 index 0000000..b6e22a7 --- /dev/null +++ b/customer-vue/src/components/StoreNavigation.vue @@ -0,0 +1,32 @@ + + + + + \ No newline at end of file diff --git a/customer-vue/src/router/router.js b/customer-vue/src/router/router.js index 8be971a..2d7d474 100644 --- a/customer-vue/src/router/router.js +++ b/customer-vue/src/router/router.js @@ -4,6 +4,7 @@ import jwt from "@/common/jwt"; import auth from "@/api/auth"; import HomeLayout from '../views/Layout/HomeLayout.vue'; +import StoreLayout from "@/views/Layout/StoreLayout"; const ACCESS_TOKEN_NAME = "accessToken"; const EXPIRED_TIME_NAME = "expiredTime"; @@ -61,7 +62,20 @@ const routes = [ }, ] }, - + { + path: '/store', + redirect: 'store', + beforeEnter: authCheck, + component: StoreLayout, + children: [ + { + path: "/store/:storeId", + name: "store", + component: () => import('../views/StoreView'), + props: true + }, + ] + }, { path: '/auth', name: 'auth', diff --git a/customer-vue/src/views/Layout/StoreLayout.vue b/customer-vue/src/views/Layout/StoreLayout.vue new file mode 100644 index 0000000..9dc2dea --- /dev/null +++ b/customer-vue/src/views/Layout/StoreLayout.vue @@ -0,0 +1,62 @@ + + + + + \ No newline at end of file diff --git a/customer-vue/src/views/SearchStore.vue b/customer-vue/src/views/SearchStore.vue index 15171aa..24c1ded 100644 --- a/customer-vue/src/views/SearchStore.vue +++ b/customer-vue/src/views/SearchStore.vue @@ -26,7 +26,10 @@ - + +
+ + +
+
+
+

+ {{ category.name }} +

+
+ + + + + {{ item.name }} + +
+ {{ item.price }}원 +
+ + +
+ + + + +
+
+
+
+
+
+ + + + + \ No newline at end of file From e757c626cdb39296e9a774e471d49f4543c7ff02 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Wed, 9 Mar 2022 14:06:29 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat(notification):=20[API]=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=20=EA=B3=A0=EC=9C=A0=EB=B2=88=ED=98=B8?= =?UTF-8?q?=EB=A1=9C=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- notification-service/build.gradle | 1 - .../notification/dto/FindNotificationDto.java | 28 +++++++++ .../notification/entity/Notification.java | 27 ++++++++- .../repository/NotificationRepository.java | 10 ++++ .../service/NotificationService.java | 9 +++ .../service/NotificationServiceImpl.java | 24 ++++++++ .../web/NotificationController.java | 59 +++++++++++++++++++ .../global/SqlCommandLineRunner.java | 36 +++++++++++ .../notificationservice/global/dto/Code.java | 5 ++ .../global/dto/Result.java | 44 ++++++++++++++ .../notificationservice/global/dto/Yn.java | 14 +++++ .../global/entity/BaseEntity.java | 7 +++ .../global/exception/CustomException.java | 17 ++++++ .../exception/GlobalExceptionHandler.java | 55 +++++++++++++++++ 14 files changed, 334 insertions(+), 2 deletions(-) create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/dto/FindNotificationDto.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/global/SqlCommandLineRunner.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Code.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Result.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Yn.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/global/exception/CustomException.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/global/exception/GlobalExceptionHandler.java diff --git a/notification-service/build.gradle b/notification-service/build.gradle index ec207f2..3e1fa5f 100644 --- a/notification-service/build.gradle +++ b/notification-service/build.gradle @@ -34,7 +34,6 @@ dependencies { implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' implementation 'org.springframework.cloud:spring-cloud-starter-openfeign' /*implementation 'org.springframework.boot:spring-boot-starter-amqp'*/ - /*implementation 'org.springframework.boot:spring-boot-starter-security'*/ /*implementation 'org.springframework.cloud:spring-cloud-starter-config'*/ /*implementation 'org.springframework.kafka:spring-kafka'*/ // https://mvnrepository.com/artifact/com.github.gavlyukovskiy/p6spy-spring-boot-starter diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/dto/FindNotificationDto.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/dto/FindNotificationDto.java new file mode 100644 index 0000000..1b382f6 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/dto/FindNotificationDto.java @@ -0,0 +1,28 @@ +package com.justpickup.notificationservice.domain.notification.dto; + +import com.justpickup.notificationservice.domain.notification.entity.Notification; +import com.justpickup.notificationservice.global.dto.Yn; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.time.LocalDateTime; + +@Getter +@AllArgsConstructor(staticName = "of") +public class FindNotificationDto { + private Long id; + private Long userId; + private String message; + private String title; + private Yn readYn; + private LocalDateTime createdAt; + + public FindNotificationDto(Notification entity) { + this.id = entity.getId(); + this.userId = entity.getUserId(); + this.message = entity.getMessage(); + this.title = entity.getTitle(); + this.readYn = entity.getReadYn(); + this.createdAt = entity.getCreatedAt(); + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/entity/Notification.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/entity/Notification.java index e9757d7..90afec7 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/entity/Notification.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/entity/Notification.java @@ -1,5 +1,6 @@ package com.justpickup.notificationservice.domain.notification.entity; +import com.justpickup.notificationservice.global.dto.Yn; import com.justpickup.notificationservice.global.entity.BaseEntity; import lombok.AccessLevel; import lombok.Getter; @@ -13,7 +14,7 @@ import javax.persistence.*; @NoArgsConstructor(access = AccessLevel.PROTECTED) public class Notification extends BaseEntity { - @Id @GeneratedValue + @Id @GeneratedValue @Column(name = "notification_id") private Long id; @@ -22,4 +23,28 @@ public class Notification extends BaseEntity { */ private Long userId; + private String title; + + private String message; + + @Enumerated(EnumType.STRING) + private Yn readYn; + + // == 생성 메소드 == // + public static Notification of(Long userId, String message, String title) { + Notification notification = new Notification(); + notification.userId = userId; + notification.message = message; + notification.title = title; + notification.readYn = Yn.N; + return notification; + } + + public void modifyReadY() { + this.readYn = Yn.Y; + } + + public void modifyReadN() { + this.readYn = Yn.N; + } } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java new file mode 100644 index 0000000..85936c1 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java @@ -0,0 +1,10 @@ +package com.justpickup.notificationservice.domain.notification.repository; + +import com.justpickup.notificationservice.domain.notification.entity.Notification; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface NotificationRepository extends JpaRepository { + List findByUserId(Long userId); +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java new file mode 100644 index 0000000..7656fe3 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java @@ -0,0 +1,9 @@ +package com.justpickup.notificationservice.domain.notification.service; + +import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; + +import java.util.List; + +public interface NotificationService { + List findNotificationByUserId(Long id); +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java new file mode 100644 index 0000000..a4e2903 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java @@ -0,0 +1,24 @@ +package com.justpickup.notificationservice.domain.notification.service; + +import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; +import com.justpickup.notificationservice.domain.notification.repository.NotificationRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class NotificationServiceImpl implements NotificationService { + + private final NotificationRepository notificationRepository; + + @Override + public List findNotificationByUserId(Long userId) { + return notificationRepository.findByUserId(userId) + .stream() + .map(FindNotificationDto::new) + .collect(Collectors.toList()); + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java new file mode 100644 index 0000000..399b7b2 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java @@ -0,0 +1,59 @@ +package com.justpickup.notificationservice.domain.notification.web; + +import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; +import com.justpickup.notificationservice.domain.notification.service.NotificationService; +import com.justpickup.notificationservice.global.dto.Result; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.format.DateTimeFormatter; +import java.util.List; +import java.util.stream.Collectors; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/notification") +public class NotificationController { + + private final NotificationService notificationService; + + @GetMapping("") + public ResponseEntity getNotificationByUserId(@RequestHeader("user-id") String userIdHeader) { + Long userId = Long.valueOf(userIdHeader); + + List notifications = notificationService.findNotificationByUserId(userId); + + GetNotificationResponse response = new GetNotificationResponse(notifications); + return ResponseEntity.ok(Result.createSuccessResult(response)); + } + + @Data @NoArgsConstructor + static class GetNotificationResponse { + private List<_Notification> notifications; + + public GetNotificationResponse(List notifications) { + this.notifications = + notifications.stream().map(_Notification::new).collect(Collectors.toList()); + } + + @Data + static class _Notification { + private Long id; + private String message; + private String title; + private boolean read; + private String time; + + public _Notification(FindNotificationDto dto) { + this.id = dto.getId(); + this.message = dto.getMessage(); + this.title = dto.getTitle(); + this.read = dto.getReadYn().isY(); + this.time = dto.getCreatedAt().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")); + } + } + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/global/SqlCommandLineRunner.java b/notification-service/src/main/java/com/justpickup/notificationservice/global/SqlCommandLineRunner.java new file mode 100644 index 0000000..d97a4b5 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/global/SqlCommandLineRunner.java @@ -0,0 +1,36 @@ +package com.justpickup.notificationservice.global; + +import com.justpickup.notificationservice.domain.notification.entity.Notification; +import com.justpickup.notificationservice.domain.notification.repository.NotificationRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.ArrayList; +import java.util.List; + +@Component +@RequiredArgsConstructor +public class SqlCommandLineRunner implements CommandLineRunner { + + private final NotificationRepository notificationRepository; + + @Override + @Transactional + public void run(String... args) throws Exception { + for (long userId = 1; userId < 10; userId++) { + List notifications = new ArrayList<>(); + for (int notification = 1; notification <= 5; notification++) { + Notification of = Notification.of(userId, notification + "번 매장의 주문이 수락되었습니다.", "주문이 수락되었어요"); + notifications.add(of); + } + for (int notification = 6; notification <= 10; notification++) { + Notification of = Notification.of(userId, notification + "번 매장의 주문이 수락되었습니다.", "주문이 수락되었어요"); + of.modifyReadY(); + notifications.add(of); + } + notificationRepository.saveAll(notifications); + } + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Code.java b/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Code.java new file mode 100644 index 0000000..eea0092 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Code.java @@ -0,0 +1,5 @@ +package com.justpickup.notificationservice.global.dto; + +public enum Code { + SUCCESS, ERROR +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Result.java b/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Result.java new file mode 100644 index 0000000..3a6a7b7 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Result.java @@ -0,0 +1,44 @@ +package com.justpickup.notificationservice.global.dto; + +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data @NoArgsConstructor +public class Result { + private Code code; + private String message; + private T data; + + @Builder + public Result(Code code, String message, T data) { + this.code = code; + this.message = message; + this.data = data; + } + + public static Result createErrorResult(String message) { + return Result.builder() + .code(Code.ERROR) + .message(message) + .data(null) + .build(); + } + + // 해당 는 클래스의 T와 다름 + public static Result createSuccessResult(T data) { + return Result.builder() + .code(Code.SUCCESS) + .message("") + .data(data) + .build(); + } + + public static Result success(){ + return Result.builder() + .code(Code.SUCCESS) + .message("성공") + .data(null) + .build(); + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Yn.java b/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Yn.java new file mode 100644 index 0000000..d3ad242 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/global/dto/Yn.java @@ -0,0 +1,14 @@ +package com.justpickup.notificationservice.global.dto; + +import lombok.Getter; + +@Getter +public enum Yn { + Y(true), N(false); + + private boolean y; + + Yn(boolean y) { + this.y = y; + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/global/entity/BaseEntity.java b/notification-service/src/main/java/com/justpickup/notificationservice/global/entity/BaseEntity.java index 613ae6e..f27ba47 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/global/entity/BaseEntity.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/global/entity/BaseEntity.java @@ -1,14 +1,21 @@ package com.justpickup.notificationservice.global.entity; +import lombok.Getter; +import org.hibernate.annotations.CreationTimestamp; +import org.hibernate.annotations.UpdateTimestamp; + import javax.persistence.MappedSuperclass; import java.time.LocalDateTime; @MappedSuperclass +@Getter public abstract class BaseEntity { + @CreationTimestamp private LocalDateTime createdAt; private Long createdBy; + @UpdateTimestamp private LocalDateTime lastModifiedAt; private Long lastModifiedBy; diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/global/exception/CustomException.java b/notification-service/src/main/java/com/justpickup/notificationservice/global/exception/CustomException.java new file mode 100644 index 0000000..e27cf67 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/global/exception/CustomException.java @@ -0,0 +1,17 @@ +package com.justpickup.notificationservice.global.exception; + +import com.justpickup.notificationservice.global.dto.Result; +import lombok.Getter; +import org.springframework.http.HttpStatus; + +@Getter +public class CustomException extends RuntimeException { + + private HttpStatus status; + private Result errorResult; + + protected CustomException(HttpStatus status, String message) { + this.status = status; + this.errorResult = Result.createErrorResult(message); + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/global/exception/GlobalExceptionHandler.java b/notification-service/src/main/java/com/justpickup/notificationservice/global/exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..a763569 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/global/exception/GlobalExceptionHandler.java @@ -0,0 +1,55 @@ +package com.justpickup.notificationservice.global.exception; + +import com.justpickup.notificationservice.global.dto.Result; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +@Slf4j +public class GlobalExceptionHandler { + + @ExceptionHandler(CustomException.class) + public ResponseEntity customExceptionHandler(CustomException ce) { + HttpStatus status = ce.getStatus(); + Result errorResult = ce.getErrorResult(); + + return ResponseEntity.status(status) + .body(errorResult); + } + + @ExceptionHandler(BindException.class) + public ResponseEntity bindExceptionHandler(BindException exception) { + return getValidationErrorBody(exception); + } + + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException exception) { + return getValidationErrorBody(exception); + } + + private ResponseEntity getValidationErrorBody(BindException exception) { + BindingResult bindingResult = exception.getBindingResult(); + + StringBuilder builder = new StringBuilder(); + bindingResult.getFieldErrors() + .forEach(fieldError -> { + builder.append("["); + builder.append(fieldError.getField()); + builder.append("](은)는 "); + builder.append(fieldError.getDefaultMessage()); + builder.append(" 입력된 값: ["); + builder.append(fieldError.getRejectedValue()); + builder.append("]"); + }); + + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(Result.createErrorResult(builder.toString())); + } + +} From bd5d91a840ad4692f62bd1385c287202c6b05ac5 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Wed, 9 Mar 2022 14:07:26 +0900 Subject: [PATCH 06/13] =?UTF-8?q?test(notification):=20[API]=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=EC=9E=90=20=EA=B3=A0=EC=9C=A0=EB=B2=88=ED=98=B8?= =?UTF-8?q?=EB=A1=9C=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/TestConfig.java | 18 ++++ .../web/NotificationControllerTest.java | 96 +++++++++++++++++++ 2 files changed, 114 insertions(+) create mode 100644 notification-service/src/test/java/com/justpickup/notificationservice/config/TestConfig.java create mode 100644 notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationControllerTest.java diff --git a/notification-service/src/test/java/com/justpickup/notificationservice/config/TestConfig.java b/notification-service/src/test/java/com/justpickup/notificationservice/config/TestConfig.java new file mode 100644 index 0000000..d4f484a --- /dev/null +++ b/notification-service/src/test/java/com/justpickup/notificationservice/config/TestConfig.java @@ -0,0 +1,18 @@ +package com.justpickup.notificationservice.config; + +import org.springframework.boot.test.autoconfigure.restdocs.RestDocsMockMvcConfigurationCustomizer; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +import static org.springframework.restdocs.operation.preprocess.Preprocessors.prettyPrint; + +@TestConfiguration +public class TestConfig { + + @Bean + public RestDocsMockMvcConfigurationCustomizer restDocsMockMvcConfigurationCustomizer() { + return configurer -> configurer.operationPreprocessors() + .withRequestDefaults(prettyPrint()) + .withResponseDefaults(prettyPrint()); + } +} diff --git a/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationControllerTest.java b/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationControllerTest.java new file mode 100644 index 0000000..25c07fe --- /dev/null +++ b/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationControllerTest.java @@ -0,0 +1,96 @@ +package com.justpickup.notificationservice.domain.notification.web; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.justpickup.notificationservice.config.TestConfig; +import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; +import com.justpickup.notificationservice.domain.notification.service.NotificationService; +import com.justpickup.notificationservice.global.dto.Code; +import com.justpickup.notificationservice.global.dto.Yn; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.BDDMockito.given; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(NotificationController.class) +@Import(TestConfig.class) +@AutoConfigureRestDocs(uriHost = "https://just-pickup.com", uriPort = 8000) +class NotificationControllerTest { + + @Autowired + MockMvc mockMvc; + + @Autowired + ObjectMapper objectMapper; + + @MockBean + NotificationService notificationService; + + private final String url = "/notification"; + + @Test + @DisplayName("[GET] 회원 고유번호로 알림 가져오기") + void getNotificationByUserId() throws Exception { + // GIVEN + long userId = 1L; + given(notificationService.findNotificationByUserId(userId)) + .willReturn(getNotificationByUserIdWillReturn(userId)); + + // THEN + ResultActions actions + = mockMvc.perform(get(url).header("user-id", String.valueOf(userId))); + + // WHEN + actions.andExpect(status().isOk()) + .andExpect(jsonPath("code").value(Code.SUCCESS.name())) + .andExpect(jsonPath("message").value("")) + .andExpect(jsonPath("data").isNotEmpty()) + .andDo(print()) + .andDo(document("notification-get", + requestHeaders( + headerWithName("user-id").description("회원 고유번호") + ), + responseFields( + fieldWithPath("code").description("결과코드 SUCCESS/ERROR"), + fieldWithPath("message").description("메시지"), + fieldWithPath("data.notifications[*].id").description("알림 고유번호"), + fieldWithPath("data.notifications[*].message").description("알림 내용"), + fieldWithPath("data.notifications[*].title").description("알림 제목"), + fieldWithPath("data.notifications[*].read").description("알림 읽음 여부"), + fieldWithPath("data.notifications[*].time").description("알림 생성 시간 [YYYY-MM-DD HH:MM]") + ) + ) + ) + ; + } + + private List getNotificationByUserIdWillReturn(long userId) { + List returnList = new ArrayList<>(); + for (long id = 1; id <= 5; id++) { + returnList.add(FindNotificationDto.of(id, userId, id + "번 메시지 예시입니다.", "제목" + id, Yn.Y, LocalDateTime.now())); + } + for (long id = 6; id <= 10; id++) { + returnList.add(FindNotificationDto.of(id, userId, id + "번 메시지 예시입니다.", "제목" + id, Yn.N, LocalDateTime.now())); + } + return returnList; + } +} From 35bbdd4595d029c92fb42e878d63134fd2c6133f Mon Sep 17 00:00:00 2001 From: bum12ark Date: Wed, 9 Mar 2022 14:09:20 +0900 Subject: [PATCH 07/13] =?UTF-8?q?feat(customer-vue):=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- customer-vue/src/api/notification.js | 9 +++ customer-vue/src/components/AppNavigation.vue | 35 +++++++-- customer-vue/src/router/router.js | 5 ++ customer-vue/src/views/NotificationView.vue | 75 +++++++++++++++++++ 4 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 customer-vue/src/api/notification.js create mode 100644 customer-vue/src/views/NotificationView.vue diff --git a/customer-vue/src/api/notification.js b/customer-vue/src/api/notification.js new file mode 100644 index 0000000..12440df --- /dev/null +++ b/customer-vue/src/api/notification.js @@ -0,0 +1,9 @@ +import axios from "axios"; + +const url = process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/notification-service/notification"; + +export default { + requestNotification() { + return axios.get(url); + } +} \ No newline at end of file diff --git a/customer-vue/src/components/AppNavigation.vue b/customer-vue/src/components/AppNavigation.vue index 8650ed4..b75d874 100644 --- a/customer-vue/src/components/AppNavigation.vue +++ b/customer-vue/src/components/AppNavigation.vue @@ -13,18 +13,43 @@ - - mdi-magnify - + + + + mdi-bell-outline + + \ No newline at end of file diff --git a/customer-vue/src/router/router.js b/customer-vue/src/router/router.js index 2d7d474..382d246 100644 --- a/customer-vue/src/router/router.js +++ b/customer-vue/src/router/router.js @@ -55,6 +55,11 @@ const routes = [ name: 'favorite-store', component: () => import('../views/FavoriteStore') }, + { + path: "/notification", + name: 'notification', + component: () => import('../views/NotificationView') + }, { path: '/login', name: 'login', diff --git a/customer-vue/src/views/NotificationView.vue b/customer-vue/src/views/NotificationView.vue new file mode 100644 index 0000000..712b2c1 --- /dev/null +++ b/customer-vue/src/views/NotificationView.vue @@ -0,0 +1,75 @@ + + + + + \ No newline at end of file From 0e26ed921487eb86e2de550fc7b7c96bfe624b51 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Wed, 9 Mar 2022 14:59:10 +0900 Subject: [PATCH 08/13] =?UTF-8?q?feat(notification):=20[API]=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EC=9D=BD=EC=9D=8C,=20=EC=9D=BD=EC=9D=8C=20?= =?UTF-8?q?=ED=95=B4=EC=A0=9C=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/UpdateNotificationDto.java | 11 ++++++++ .../notification/entity/Notification.java | 8 ++---- .../exception/NotExistNotification.java | 11 ++++++++ .../repository/NotificationRepository.java | 3 ++- .../service/NotificationService.java | 2 ++ .../service/NotificationServiceImpl.java | 25 ++++++++++++++++++- .../web/NotificationController.java | 17 +++++++++++++ .../global/SqlCommandLineRunner.java | 3 ++- 8 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/dto/UpdateNotificationDto.java create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/exception/NotExistNotification.java diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/dto/UpdateNotificationDto.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/dto/UpdateNotificationDto.java new file mode 100644 index 0000000..04c4a67 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/dto/UpdateNotificationDto.java @@ -0,0 +1,11 @@ +package com.justpickup.notificationservice.domain.notification.dto; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor(staticName = "of") +public class UpdateNotificationDto { + private Long id; + private boolean read; +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/entity/Notification.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/entity/Notification.java index 90afec7..96d159f 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/entity/Notification.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/entity/Notification.java @@ -40,11 +40,7 @@ public class Notification extends BaseEntity { return notification; } - public void modifyReadY() { - this.readYn = Yn.Y; - } - - public void modifyReadN() { - this.readYn = Yn.N; + public void modifyReadYn(Yn readYn) { + this.readYn = readYn; } } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/exception/NotExistNotification.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/exception/NotExistNotification.java new file mode 100644 index 0000000..b3530b5 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/exception/NotExistNotification.java @@ -0,0 +1,11 @@ +package com.justpickup.notificationservice.domain.notification.exception; + +import com.justpickup.notificationservice.global.exception.CustomException; +import org.springframework.http.HttpStatus; + +public class NotExistNotification extends CustomException { + + public NotExistNotification(String message) { + super(HttpStatus.CONFLICT, message); + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java index 85936c1..19e481b 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java @@ -1,10 +1,11 @@ package com.justpickup.notificationservice.domain.notification.repository; import com.justpickup.notificationservice.domain.notification.entity.Notification; +import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; import java.util.List; public interface NotificationRepository extends JpaRepository { - List findByUserId(Long userId); + List findByUserId(Long userId, Sort sort); } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java index 7656fe3..48ab26f 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java @@ -1,9 +1,11 @@ package com.justpickup.notificationservice.domain.notification.service; import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; +import com.justpickup.notificationservice.domain.notification.dto.UpdateNotificationDto; import java.util.List; public interface NotificationService { List findNotificationByUserId(Long id); + void updateNotification(UpdateNotificationDto dto); } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java index a4e2903..59198e5 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java @@ -1,24 +1,47 @@ package com.justpickup.notificationservice.domain.notification.service; import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; +import com.justpickup.notificationservice.domain.notification.dto.UpdateNotificationDto; +import com.justpickup.notificationservice.domain.notification.entity.Notification; +import com.justpickup.notificationservice.domain.notification.exception.NotExistNotification; import com.justpickup.notificationservice.domain.notification.repository.NotificationRepository; +import com.justpickup.notificationservice.global.dto.Yn; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Order; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; import java.util.stream.Collectors; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class NotificationServiceImpl implements NotificationService { private final NotificationRepository notificationRepository; @Override public List findNotificationByUserId(Long userId) { - return notificationRepository.findByUserId(userId) + Order readYnAsc = Order.asc("readYn"); + Order createdAtDesc = Order.desc("createdAt"); + + Sort sort = Sort.by(List.of(readYnAsc, createdAtDesc)); + return notificationRepository.findByUserId(userId, sort) .stream() .map(FindNotificationDto::new) .collect(Collectors.toList()); } + + @Transactional + @Override + public void updateNotification(UpdateNotificationDto dto) { + Long id = dto.getId(); + Notification notification = notificationRepository.findById(id) + .orElseThrow(() -> new NotExistNotification(id + "는 없는 알림 고유번호입니다.")); + + Yn readYn = dto.isRead() ? Yn.Y : Yn.N; + notification.modifyReadYn(readYn); + } } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java index 399b7b2..097e1c5 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java @@ -1,6 +1,7 @@ package com.justpickup.notificationservice.domain.notification.web; import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; +import com.justpickup.notificationservice.domain.notification.dto.UpdateNotificationDto; import com.justpickup.notificationservice.domain.notification.service.NotificationService; import com.justpickup.notificationservice.global.dto.Result; import lombok.Data; @@ -56,4 +57,20 @@ public class NotificationController { } } } + + @PatchMapping("/{notificationId}") + public ResponseEntity patchNotification(@PathVariable("notificationId") Long notificationId, + @RequestBody PatchNotificationRequest notificationRequest) { + + UpdateNotificationDto dto = UpdateNotificationDto.of(notificationId, notificationRequest.isRead()); + + notificationService.updateNotification(dto); + + return ResponseEntity.ok(Result.createSuccessResult(null)); + } + + @Data @NoArgsConstructor + static class PatchNotificationRequest { + private boolean read; + } } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/global/SqlCommandLineRunner.java b/notification-service/src/main/java/com/justpickup/notificationservice/global/SqlCommandLineRunner.java index d97a4b5..147ecaf 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/global/SqlCommandLineRunner.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/global/SqlCommandLineRunner.java @@ -2,6 +2,7 @@ package com.justpickup.notificationservice.global; import com.justpickup.notificationservice.domain.notification.entity.Notification; import com.justpickup.notificationservice.domain.notification.repository.NotificationRepository; +import com.justpickup.notificationservice.global.dto.Yn; import lombok.RequiredArgsConstructor; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @@ -27,7 +28,7 @@ public class SqlCommandLineRunner implements CommandLineRunner { } for (int notification = 6; notification <= 10; notification++) { Notification of = Notification.of(userId, notification + "번 매장의 주문이 수락되었습니다.", "주문이 수락되었어요"); - of.modifyReadY(); + of.modifyReadYn(Yn.Y); notifications.add(of); } notificationRepository.saveAll(notifications); From b6802702e72a943c6b4bd5c2d4e679108843b7a3 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Wed, 9 Mar 2022 15:18:57 +0900 Subject: [PATCH 09/13] =?UTF-8?q?test(notification):=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EC=9D=BD=EC=9D=8C,=20=ED=95=B4=EC=A0=9C=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/docs/asciidoc/api-docs.adoc | 72 +++++++++++++++++++ .../web/NotificationController.java | 3 +- .../web/NotificationControllerTest.java | 44 +++++++++++- 3 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 notification-service/src/docs/asciidoc/api-docs.adoc diff --git a/notification-service/src/docs/asciidoc/api-docs.adoc b/notification-service/src/docs/asciidoc/api-docs.adoc new file mode 100644 index 0000000..f5b2a97 --- /dev/null +++ b/notification-service/src/docs/asciidoc/api-docs.adoc @@ -0,0 +1,72 @@ +:doctype: book +:icons: font +:source-highlighter: highlightjs +:toc: left +:toclevels: 2 +:sectlinks: + + +[[overview]] += 개요 + +[[overview-http-verbs]] +== HTTP 동사 + +본 REST API에서 사용하는 HTTP 동사(verbs)는 가능한한 표준 HTTP와 REST 규약을 따릅니다. + +|=== +| 동사 | 용례 + +| `GET` +| 리소스를 가져올 때 사용 + +| `POST` +| 새 리소스를 만들 때 사용 + +| `PUT` +| 기존 리소스를 수정할 때 사용 + +| `PATCH` +| 기존 리소스의 일부를 수정할 때 사용 + +| `DELETE` +| 기존 리소스를 삭제할 떄 사용 +|=== + +[[overview-http-status-codes]] +== HTTP 상태 코드 + +본 REST API에서 사용하는 HTTP 상태 코드는 가능한 표준 HTTP와 REST 규약을 따릅니다. + +|=== +| 상태 코드 | 용례 + +| `200 OK` +| 요청을 성공적으로 처리함 + +| `201 Created` +| 새 리소스를 성공적으로 생성함. 응답의 `Location` 헤더에 해당 리소스의 URI가 담겨있다. + +| `204 No Content` +| 기존 리소스를 성공적으로 수정함. + +| `400 Bad Request` +| 잘못된 요청을 보낸 경우. 응답 본문에 더 오류에 대한 정보가 담겨있다. + +| `404 Not Found` +| 요청한 리소스가 없음. + +| `409 Conflict` +| 클라이언트의 요청이 서버의 상태와 충돌이 발생한 경우. +|=== + +[[snippets-write-convention]] +== snippets 작성 컨벤션 +domain-httpRequestCode-etc + +== 알림 +=== 알림 조회 - 회원 고유번호 +operation::notification-get[snippets='curl-request,http-request,http-response,request-headers,response-fields'] +=== 알림 수정 +operation::notification-patch[snippets='curl-request,http-request,http-response,path-parameters,request-fields,response-fields'] + diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java index 097e1c5..3428cdb 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java @@ -4,6 +4,7 @@ import com.justpickup.notificationservice.domain.notification.dto.FindNotificati import com.justpickup.notificationservice.domain.notification.dto.UpdateNotificationDto; import com.justpickup.notificationservice.domain.notification.service.NotificationService; import com.justpickup.notificationservice.global.dto.Result; +import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; @@ -69,7 +70,7 @@ public class NotificationController { return ResponseEntity.ok(Result.createSuccessResult(null)); } - @Data @NoArgsConstructor + @Data @NoArgsConstructor @AllArgsConstructor static class PatchNotificationRequest { private boolean read; } diff --git a/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationControllerTest.java b/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationControllerTest.java index 25c07fe..d2c29b3 100644 --- a/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationControllerTest.java +++ b/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationControllerTest.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.justpickup.notificationservice.config.TestConfig; import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; import com.justpickup.notificationservice.domain.notification.service.NotificationService; +import com.justpickup.notificationservice.domain.notification.web.NotificationController.PatchNotificationRequest; import com.justpickup.notificationservice.global.dto.Code; import com.justpickup.notificationservice.global.dto.Yn; import org.junit.jupiter.api.DisplayName; @@ -13,6 +14,8 @@ import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDoc import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.restdocs.request.RequestDocumentation; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.ResultActions; @@ -25,8 +28,10 @@ import static org.springframework.restdocs.headers.HeaderDocumentation.headerWit import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch; +import static org.springframework.restdocs.payload.PayloadDocumentation.*; +import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; +import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -93,4 +98,39 @@ class NotificationControllerTest { } return returnList; } + + @Test + @DisplayName("[API] 알림 수정") + void patchNotification() throws Exception { + // GIVEN + long notificationId = 1L; + PatchNotificationRequest request = new PatchNotificationRequest(true); + String requestBody = objectMapper.writeValueAsString(request); + + // WHEN + ResultActions actions = mockMvc.perform( + patch(url + "/{notificationId}", String.valueOf(notificationId)) + .content(requestBody) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + ); + + // THEN + actions.andExpect(status().isOk()) + .andDo(print()) + .andDo(document("notification-patch", + pathParameters( + parameterWithName("notificationId").description("알림 고유번호") + ), + requestFields( + fieldWithPath("read").description("읽음 여부") + ), + responseFields( + fieldWithPath("code").description("결과코드 SUCCESS/ERROR"), + fieldWithPath("message").description("메시지"), + fieldWithPath("data").description("데이터") + ) + )) + ; + } } From 582594ac295c6d7d68caeb7a2ac9905076f3dbab Mon Sep 17 00:00:00 2001 From: bum12ark Date: Thu, 10 Mar 2022 10:29:49 +0900 Subject: [PATCH 10/13] =?UTF-8?q?feat(customer-apigateway):=20=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=20=EC=84=9C=EB=B9=84=EC=8A=A4=20cors=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D,=20exception=20handler=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../handler/GlobalExceptionHandler.java | 6 +++--- .../src/main/resources/application.yml | 9 +++++++++ 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/customer-apigateway-service/src/main/java/com/justpickup/customerapigatewayservice/handler/GlobalExceptionHandler.java b/customer-apigateway-service/src/main/java/com/justpickup/customerapigatewayservice/handler/GlobalExceptionHandler.java index b40813e..8c8b633 100644 --- a/customer-apigateway-service/src/main/java/com/justpickup/customerapigatewayservice/handler/GlobalExceptionHandler.java +++ b/customer-apigateway-service/src/main/java/com/justpickup/customerapigatewayservice/handler/GlobalExceptionHandler.java @@ -44,10 +44,10 @@ public class GlobalExceptionHandler implements ErrorWebExceptionHandler { exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON); responseBody.put("code", "INVALID"); responseBody.put("message", "Invalid Access Token"); - }else{ - exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED); + } else { + exchange.getResponse().setStatusCode(exchange.getResponse().getStatusCode()); exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON); - responseBody.put("code", "INVALID"); + responseBody.put("code", ex.getMessage()); } DataBuffer wrap = null; diff --git a/customer-apigateway-service/src/main/resources/application.yml b/customer-apigateway-service/src/main/resources/application.yml index ba88654..c3cb663 100644 --- a/customer-apigateway-service/src/main/resources/application.yml +++ b/customer-apigateway-service/src/main/resources/application.yml @@ -38,6 +38,7 @@ spring: - PUT - OPTIONS - DELETE + - PATCH allowedHeaders: '*' allow-credentials: true routes: @@ -57,6 +58,14 @@ spring: - AuthorizationHeaderFilter - RewritePath=/store-service/(?.*),/$\{segment} + - id: notification-service + uri: lb://NOTIFICATION-SERVICE + predicates: + - Path=/notification-service/** + filters: + - AuthorizationHeaderFilter + - RewritePath=/notification-service/(?.*),/$\{segment} + - id: user-service uri: lb://USER-SERVICE predicates: From 5d7ae678990ebc4365706bc03fa3549cc62420f3 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Thu, 10 Mar 2022 10:31:50 +0900 Subject: [PATCH 11/13] =?UTF-8?q?feat(notification):=20[API]=20=EC=9D=BD?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=95=8C=EB=9E=8C=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/NotificationRepository.java | 2 ++ .../service/NotificationService.java | 2 ++ .../service/NotificationServiceImpl.java | 5 ++++ .../web/NotificationApiController.java | 29 +++++++++++++++++++ .../web/NotificationController.java | 5 ++-- 5 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationApiController.java diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java index 19e481b..ae319c1 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/repository/NotificationRepository.java @@ -1,6 +1,7 @@ package com.justpickup.notificationservice.domain.notification.repository; import com.justpickup.notificationservice.domain.notification.entity.Notification; +import com.justpickup.notificationservice.global.dto.Yn; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; @@ -8,4 +9,5 @@ import java.util.List; public interface NotificationRepository extends JpaRepository { List findByUserId(Long userId, Sort sort); + long countByUserIdAndReadYn(Long userId, Yn readYn); } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java index 48ab26f..3d35ecb 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationService.java @@ -2,10 +2,12 @@ package com.justpickup.notificationservice.domain.notification.service; import com.justpickup.notificationservice.domain.notification.dto.FindNotificationDto; import com.justpickup.notificationservice.domain.notification.dto.UpdateNotificationDto; +import com.justpickup.notificationservice.global.dto.Yn; import java.util.List; public interface NotificationService { List findNotificationByUserId(Long id); void updateNotification(UpdateNotificationDto dto); + Long findNotificationCounts(Long userId, Yn readYn); } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java index 59198e5..5c7d6de 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/service/NotificationServiceImpl.java @@ -44,4 +44,9 @@ public class NotificationServiceImpl implements NotificationService { Yn readYn = dto.isRead() ? Yn.Y : Yn.N; notification.modifyReadYn(readYn); } + + @Override + public Long findNotificationCounts(Long userId, Yn readYn) { + return notificationRepository.countByUserIdAndReadYn(userId, readYn); + } } diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationApiController.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationApiController.java new file mode 100644 index 0000000..ba2e6d5 --- /dev/null +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationApiController.java @@ -0,0 +1,29 @@ +package com.justpickup.notificationservice.domain.notification.web; + +import com.justpickup.notificationservice.domain.notification.service.NotificationService; +import com.justpickup.notificationservice.global.dto.Result; +import com.justpickup.notificationservice.global.dto.Yn; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor +public class NotificationApiController { + + private final NotificationService notificationService; + + @GetMapping("/notification/counts") + public ResponseEntity getNotificationCounts(@RequestHeader("user-id") String userIdHeader) { + + Long userId = Long.valueOf(userIdHeader); + Yn readYn = Yn.N; + Long counts = notificationService.findNotificationCounts(userId, readYn); + + return ResponseEntity.ok(Result.createSuccessResult(counts)); + } +} diff --git a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java index 3428cdb..2d3cbc1 100644 --- a/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java +++ b/notification-service/src/main/java/com/justpickup/notificationservice/domain/notification/web/NotificationController.java @@ -17,12 +17,11 @@ import java.util.stream.Collectors; @RestController @RequiredArgsConstructor -@RequestMapping("/notification") public class NotificationController { private final NotificationService notificationService; - @GetMapping("") + @GetMapping("/notifications") public ResponseEntity getNotificationByUserId(@RequestHeader("user-id") String userIdHeader) { Long userId = Long.valueOf(userIdHeader); @@ -59,7 +58,7 @@ public class NotificationController { } } - @PatchMapping("/{notificationId}") + @PatchMapping("/notification/{notificationId}") public ResponseEntity patchNotification(@PathVariable("notificationId") Long notificationId, @RequestBody PatchNotificationRequest notificationRequest) { From d385f5b22a75c468a064387a04c727362bf2d189 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Thu, 10 Mar 2022 10:41:23 +0900 Subject: [PATCH 12/13] =?UTF-8?q?test(notification):=20=EC=9D=BD=EC=A7=80?= =?UTF-8?q?=20=EC=95=8A=EC=9D=80=20=EC=95=8C=EB=9E=8C=20=EA=B0=9C=EC=88=98?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/docs/asciidoc/api-docs.adoc | 3 + .../web/NotificationApiControllerTest.java | 69 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationApiControllerTest.java diff --git a/notification-service/src/docs/asciidoc/api-docs.adoc b/notification-service/src/docs/asciidoc/api-docs.adoc index f5b2a97..ef87720 100644 --- a/notification-service/src/docs/asciidoc/api-docs.adoc +++ b/notification-service/src/docs/asciidoc/api-docs.adoc @@ -70,3 +70,6 @@ operation::notification-get[snippets='curl-request,http-request,http-response,re === 알림 수정 operation::notification-patch[snippets='curl-request,http-request,http-response,path-parameters,request-fields,response-fields'] +== API +=== 읽지 않은 알림 개수 조회 +operation::api-get-notification-counts[snippets='curl-request,http-request,http-response,request-headers,response-fields'] diff --git a/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationApiControllerTest.java b/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationApiControllerTest.java new file mode 100644 index 0000000..4e2242f --- /dev/null +++ b/notification-service/src/test/java/com/justpickup/notificationservice/domain/notification/web/NotificationApiControllerTest.java @@ -0,0 +1,69 @@ +package com.justpickup.notificationservice.domain.notification.web; + +import com.justpickup.notificationservice.config.TestConfig; +import com.justpickup.notificationservice.domain.notification.service.NotificationService; +import com.justpickup.notificationservice.global.dto.Yn; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.BDDMockito.given; +import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; +import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; +import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; +import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(NotificationApiController.class) +@Import(TestConfig.class) +@AutoConfigureRestDocs(uriHost = "https://just-pickup.com", uriPort = 8000) +class NotificationApiControllerTest { + + @Autowired + MockMvc mockMvc; + + @MockBean + NotificationService notificationService; + + private final String url = "/api/"; + + @Test + @DisplayName("[API] [GET] 읽지 않은 알림 개수 가져오기") + void getNotificationCounts() throws Exception { + // GIVEN + Long userId = 1L; + given(notificationService.findNotificationCounts(userId, Yn.N)) + .willReturn(10L); + + // THEN + ResultActions actions = mockMvc.perform(get(url + "/notification/counts") + .header("user-id", String.valueOf(userId))); + + // WHEN + actions.andExpect(status().isOk()) + .andDo(print()) + .andDo(document("api-get-notification-counts", + requestHeaders( + headerWithName("user-id").description("회원 고유번호") + ), + responseFields( + fieldWithPath("code").description("결과코드 SUCCESS/ERROR"), + fieldWithPath("message").description("메시지"), + fieldWithPath("data").description("알림 개수") + ) + ) + ) + ; + } + +} \ No newline at end of file From 9426f03cc83ed4f3265f9e352172f4ccd00e26a9 Mon Sep 17 00:00:00 2001 From: bum12ark Date: Thu, 10 Mar 2022 10:43:38 +0900 Subject: [PATCH 13/13] =?UTF-8?q?feat(customer-vue):=20=EC=95=8C=EB=A6=BC?= =?UTF-8?q?=20=EC=B2=B4=ED=81=AC=EB=B0=95=EC=8A=A4=20=EB=B0=8F=20=EA=B0=9C?= =?UTF-8?q?=EC=88=98=20=ED=99=94=EB=A9=B4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 알림 페이지 체크박스 클릭 시 읽음 처리 및 읽음 해제 처리 - App bar 읽지 않은 알림 개수 표시 - 알림 읽었을 시에 앱바 알림 개수 연동 --- customer-vue/src/api/notification.js | 14 ++++++++++-- customer-vue/src/components/AppNavigation.vue | 14 +++--------- customer-vue/src/views/Layout/HomeLayout.vue | 22 +++++++++++++++++-- customer-vue/src/views/NotificationView.vue | 19 +++++++++++----- 4 files changed, 49 insertions(+), 20 deletions(-) diff --git a/customer-vue/src/api/notification.js b/customer-vue/src/api/notification.js index 12440df..f0c753b 100644 --- a/customer-vue/src/api/notification.js +++ b/customer-vue/src/api/notification.js @@ -1,9 +1,19 @@ import axios from "axios"; -const url = process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/notification-service/notification"; +const url = process.env.VUE_APP_CUSTOMER_SERVICE_BASEURL + "/notification-service"; export default { requestNotification() { - return axios.get(url); + return axios.get(url + "/notifications"); + }, + patchNotification(id, isRead) { + const body = { + read: isRead + } + + return axios.patch(url + "/notification/" + id, body) + }, + countsNotification() { + return axios.get(url + "/api/notification/counts"); } } \ No newline at end of file diff --git a/customer-vue/src/components/AppNavigation.vue b/customer-vue/src/components/AppNavigation.vue index b75d874..a6456a2 100644 --- a/customer-vue/src/components/AppNavigation.vue +++ b/customer-vue/src/components/AppNavigation.vue @@ -20,8 +20,8 @@ @click="goNotification" > @@ -34,17 +34,9 @@ diff --git a/customer-vue/src/views/NotificationView.vue b/customer-vue/src/views/NotificationView.vue index 712b2c1..6f3f810 100644 --- a/customer-vue/src/views/NotificationView.vue +++ b/customer-vue/src/views/NotificationView.vue @@ -16,13 +16,13 @@ @@ -35,7 +35,7 @@