Merge branch 'master' into 고객_주문내역
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
package com.justpickup.customerapigatewayservice;
|
||||
|
||||
import com.justpickup.customerapigatewayservice.handler.GlobalExceptionHandler;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
|
||||
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableEurekaClient
|
||||
@@ -12,4 +15,9 @@ public class CustomerApigatewayServiceApplication {
|
||||
SpringApplication.run(CustomerApigatewayServiceApplication.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ErrorWebExceptionHandler globalExceptionHandler() {
|
||||
return new GlobalExceptionHandler();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,4 +42,14 @@ export default {
|
||||
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)
|
||||
},
|
||||
|
||||
}
|
||||
59
customer-vue/src/components/SlideStore.vue
Normal file
59
customer-vue/src/components/SlideStore.vue
Normal file
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div >
|
||||
<v-slide-group
|
||||
show-arrows="desktop"
|
||||
>
|
||||
<v-slide-item
|
||||
:class="storeList.isActive"
|
||||
v-for="n in 3"
|
||||
:key="n"
|
||||
>
|
||||
<v-skeleton-loader
|
||||
class="my-3 mx-3"
|
||||
elevation="7"
|
||||
height="250"
|
||||
width="165"
|
||||
type="card"
|
||||
:key="n"
|
||||
></v-skeleton-loader>
|
||||
</v-slide-item>
|
||||
<v-slide-item
|
||||
v-for="item in storeList.data"
|
||||
:key="item.id"
|
||||
>
|
||||
<v-card
|
||||
elevation="7"
|
||||
class="my-3 mx-3"
|
||||
height="250"
|
||||
width="165"
|
||||
>
|
||||
<v-skeleton-loader>
|
||||
<v-img
|
||||
height="165"
|
||||
width="165"
|
||||
src="https://cdn.vuetifyjs.com/images/cards/cooking.png"
|
||||
></v-img>
|
||||
<v-card-subtitle style="white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">{{item.name}}</v-card-subtitle>
|
||||
<v-card-text>
|
||||
거리 : {{item.distance}}
|
||||
</v-card-text>
|
||||
</v-skeleton-loader>
|
||||
</v-card>
|
||||
</v-slide-item>
|
||||
</v-slide-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "SlideStore",
|
||||
props:{
|
||||
storeList:Array,
|
||||
},
|
||||
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,5 +1,7 @@
|
||||
import Vue from 'vue';
|
||||
import VueRouter from 'vue-router';
|
||||
import jwt from "@/common/jwt";
|
||||
import auth from "@/api/auth";
|
||||
|
||||
import HomeLayout from '../views/Layout/HomeLayout.vue';
|
||||
const ACCESS_TOKEN_NAME = "accessToken";
|
||||
@@ -7,9 +9,21 @@ const EXPIRED_TIME_NAME = "expiredTime";
|
||||
|
||||
Vue.use(VueRouter);
|
||||
|
||||
const auth = async function (to, from, next) {
|
||||
localStorage.setItem(ACCESS_TOKEN_NAME, to.query.accessToken);
|
||||
localStorage.setItem(EXPIRED_TIME_NAME, to.query.expiredTime)
|
||||
const authCheck = async function (to, from, next) {
|
||||
if(to.path==="/login"){
|
||||
next();
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (jwt.isExpired()) {
|
||||
// refresh 호출
|
||||
await auth.requestReissue();
|
||||
} else {
|
||||
await auth.requestCheckAccessToken();
|
||||
}
|
||||
} catch (error) {
|
||||
await router.replace("/login");
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
@@ -17,6 +31,7 @@ const routes = [
|
||||
{
|
||||
path: '/',
|
||||
redirect: 'home',
|
||||
beforeEnter: authCheck,
|
||||
component: HomeLayout,
|
||||
children: [
|
||||
{
|
||||
@@ -34,24 +49,22 @@ const routes = [
|
||||
name: 'order-history',
|
||||
component: () => import('../views/OrderHistory')
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
redirect: 'login',
|
||||
component: HomeLayout,
|
||||
children: [
|
||||
{
|
||||
path: "/login",
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import('../views/LoginPage')
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
path: '/auth',
|
||||
name: 'auth',
|
||||
beforeEnter: auth,
|
||||
beforeEnter: async function (to, from, next) {
|
||||
localStorage.setItem(ACCESS_TOKEN_NAME, to.query.accessToken);
|
||||
localStorage.setItem(EXPIRED_TIME_NAME, to.query.expiredTime)
|
||||
next();
|
||||
},
|
||||
component: () => import('../views/Layout/AuthSuccess.vue')
|
||||
|
||||
},
|
||||
|
||||
@@ -1,13 +1,76 @@
|
||||
<template>
|
||||
<v-card>
|
||||
<v-card-title>Hello</v-card-title>
|
||||
<v-card-text>Nice to meet you</v-card-text>
|
||||
</v-card>
|
||||
<v-container
|
||||
fill-height
|
||||
>
|
||||
<v-row>
|
||||
<v-col>
|
||||
<v-card>
|
||||
|
||||
<v-card-title>Hello</v-card-title>
|
||||
<v-card-text>Nice to meet you</v-card-text>
|
||||
</v-card>
|
||||
</v-col>
|
||||
</v-row>
|
||||
<v-row justify="center">
|
||||
<v-col>
|
||||
<div class="text-h5" >즐겨찾는 매장입니다.</div>
|
||||
<slide-store
|
||||
:store-list="favoriteStoreList"
|
||||
></slide-store>
|
||||
</v-col>
|
||||
</v-row>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import slideStore from "@/components/SlideStore";
|
||||
import storeApi from "@/api/store";
|
||||
|
||||
export default {
|
||||
name: "HomeView"
|
||||
name: "HomeView",
|
||||
components:{
|
||||
slideStore
|
||||
},
|
||||
data(){
|
||||
return{
|
||||
latitude:0,
|
||||
longitude:0,
|
||||
favoriteStoreList:{
|
||||
data:[],
|
||||
isActive:'',
|
||||
|
||||
},
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
const location = await this.getLocation();
|
||||
this.latitude = location.latitude;
|
||||
this.longitude = location.longitude;
|
||||
storeApi.getFavoriteStore(this.latitude,this.longitude)
|
||||
.then(response =>{
|
||||
this.favoriteStoreList.isActive = 'd-none'
|
||||
this.favoriteStoreList.data = response.data.data;
|
||||
});
|
||||
},
|
||||
methods:{
|
||||
getLocation: async function() {
|
||||
console.log("initGeoLocation");
|
||||
return new Promise(function (resolve, reject) {
|
||||
if ('geolocation' in navigator) {
|
||||
navigator.geolocation.getCurrentPosition((position) => {
|
||||
const coords = position.coords;
|
||||
|
||||
resolve({
|
||||
latitude: coords.latitude,
|
||||
longitude: coords.longitude
|
||||
})
|
||||
})
|
||||
} else {
|
||||
reject();
|
||||
}
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ export default {
|
||||
);
|
||||
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -2,12 +2,12 @@ import axios from "axios";
|
||||
|
||||
export default {
|
||||
getCategoryList(){
|
||||
return axios.get(process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/category');
|
||||
return axios.get(process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/customer/category');
|
||||
},
|
||||
putCategoryList(data){
|
||||
return axios({
|
||||
method:'put',
|
||||
url:process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/category',
|
||||
url:process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/customer/category',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
@@ -17,12 +17,14 @@ export default {
|
||||
})
|
||||
},
|
||||
getItemById(itemId){
|
||||
return axios.get(process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/item/'+itemId)
|
||||
return axios.get(process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/customer/item/'+itemId)
|
||||
},
|
||||
saveItem(method, itemData){
|
||||
const _url = process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/customer/item'+(method==='put'?+"/"+itemData.itemId:'')
|
||||
console.log(_url)
|
||||
return axios({
|
||||
method:method,
|
||||
url: process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/item',
|
||||
url: _url,
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json;charset=UTF-8'
|
||||
@@ -31,4 +33,7 @@ export default {
|
||||
responseType:'json'
|
||||
})
|
||||
},
|
||||
getMenu(searchParam){
|
||||
return axios.get(process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/api/customer/item',searchParam);
|
||||
},
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-subheader class="py-0 d-flex justify-space-between rounded-lg">
|
||||
<h3>Category List</h3>
|
||||
<div class="text-subtitle-1">Category List</div>
|
||||
<div style="text-align: right">
|
||||
<span class="group pa-2">
|
||||
<v-btn
|
||||
|
||||
@@ -146,12 +146,7 @@ export default {
|
||||
word: vm.word,
|
||||
page: vm.page-1
|
||||
}
|
||||
this.$axios({
|
||||
method:'get',
|
||||
url:process.env.VUE_APP_OWNER_SERVICE_BASEURL+'/store-service/item',
|
||||
params : searchParam,
|
||||
responseType:'json'
|
||||
})
|
||||
store.getMenu(searchParam)
|
||||
.then(function (response) {
|
||||
const page = response.data.data.page;
|
||||
vm.menus = response.data.data.itemList;
|
||||
@@ -203,7 +198,6 @@ export default {
|
||||
method='put'
|
||||
else
|
||||
method='post'
|
||||
|
||||
store.saveItem(method,itemData)
|
||||
.then(response => console.log(response))
|
||||
.catch(reason => console.log(reason))
|
||||
|
||||
@@ -2,7 +2,7 @@ module.exports = {
|
||||
transpileDependencies: [
|
||||
'vuetify'
|
||||
],
|
||||
devServer: {
|
||||
disableHostCheck: true
|
||||
devServer:{
|
||||
allowedHosts: ['just-pickup.com'],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,4 +81,7 @@ 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']
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.justpickup.storeservice;
|
||||
|
||||
import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore;
|
||||
import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreRepository;
|
||||
import com.justpickup.storeservice.domain.map.entity.Map;
|
||||
import com.justpickup.storeservice.domain.store.entity.Store;
|
||||
import com.justpickup.storeservice.domain.store.repository.StoreRepository;
|
||||
@@ -22,7 +24,7 @@ public class StoreServiceApplication {
|
||||
}
|
||||
|
||||
@Bean
|
||||
CommandLineRunner run(StoreRepository storeRepository) {
|
||||
CommandLineRunner run(StoreRepository storeRepository, FavoriteStoreRepository favoriteStoreRepository) {
|
||||
return args -> {
|
||||
List<Store> stores = new ArrayList<>();
|
||||
|
||||
@@ -63,6 +65,14 @@ public class StoreServiceApplication {
|
||||
);
|
||||
|
||||
storeRepository.saveAll(stores);
|
||||
|
||||
List<Long> userList = List.of(1L,2L,3L,4L,5L,6L,7L);
|
||||
userList.forEach(userId -> {
|
||||
stores.forEach(store -> {
|
||||
favoriteStoreRepository.save(FavoriteStore.of(userId, store));
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package com.justpickup.storeservice.domain.category.dto;
|
||||
|
||||
import com.justpickup.storeservice.domain.category.entity.Category;
|
||||
import com.justpickup.storeservice.domain.category.web.CategoryController;
|
||||
import com.justpickup.storeservice.domain.category.web.CategoryOwnerApiController;
|
||||
import com.justpickup.storeservice.domain.item.dto.ItemDto;
|
||||
import com.justpickup.storeservice.domain.item.entity.Item;
|
||||
import com.justpickup.storeservice.domain.store.entity.Store;
|
||||
import lombok.*;
|
||||
|
||||
@@ -32,19 +31,18 @@ public class CategoryDto {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public CategoryDto(CategoryController.PutCategoryRequest.Category category) {
|
||||
public CategoryDto(CategoryOwnerApiController.PutCategoryRequest.Category category) {
|
||||
this.id = category.getCategoryId();
|
||||
this.name = category.getName();
|
||||
this.order = category.getOrder();
|
||||
}
|
||||
|
||||
public static Category createCategory(CategoryDto categoryDto){
|
||||
Category category = Category.createCategory(
|
||||
return Category.createCategory(
|
||||
categoryDto.getId()
|
||||
,categoryDto.getName()
|
||||
, categoryDto.getOrder()
|
||||
, categoryDto.getStore());
|
||||
return category;
|
||||
}
|
||||
|
||||
public void setStore(Store store){
|
||||
|
||||
@@ -10,14 +10,14 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class CategoryController {
|
||||
@RequestMapping("/api/owner")
|
||||
public class CategoryOwnerApiController {
|
||||
|
||||
private final CategoryService categoryService;
|
||||
|
||||
@@ -2,9 +2,7 @@ package com.justpickup.storeservice.domain.favoritestore.entity;
|
||||
|
||||
import com.justpickup.storeservice.domain.store.entity.Store;
|
||||
import com.justpickup.storeservice.global.entity.BaseEntity;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.*;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@@ -25,4 +23,11 @@ public class FavoriteStore extends BaseEntity {
|
||||
@ManyToOne(fetch = LAZY)
|
||||
@JoinColumn(name = "store_id")
|
||||
private Store store;
|
||||
|
||||
public static FavoriteStore of(Long userId , Store store){
|
||||
FavoriteStore favoriteStore = new FavoriteStore();
|
||||
favoriteStore.userId = userId;
|
||||
favoriteStore.store = store;
|
||||
return favoriteStore;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.justpickup.storeservice.domain.favoritestore.repository;
|
||||
|
||||
import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface FavoriteStoreRepository extends JpaRepository<FavoriteStore,Long> {
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.justpickup.storeservice.domain.store.entity;
|
||||
|
||||
import com.justpickup.storeservice.domain.category.entity.Category;
|
||||
import com.justpickup.storeservice.domain.favoritestore.entity.FavoriteStore;
|
||||
import com.justpickup.storeservice.domain.item.entity.Item;
|
||||
import com.justpickup.storeservice.domain.map.entity.Map;
|
||||
import com.justpickup.storeservice.global.entity.Address;
|
||||
@@ -52,6 +53,8 @@ public class Store extends BaseEntity {
|
||||
@OneToMany(mappedBy = "store")
|
||||
private List<Item> items;
|
||||
|
||||
@OneToMany(mappedBy = "store")
|
||||
private List<FavoriteStore> favoriteStores;
|
||||
// == 연관관계 편의 메소드 == //
|
||||
public void addCategory(Category category) {
|
||||
categories.add(category);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
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;
|
||||
import com.querydsl.core.types.Expression;
|
||||
@@ -28,25 +30,8 @@ public class StoreRepositoryCustom {
|
||||
private final JPAQueryFactory queryFactory;
|
||||
|
||||
public SliceImpl<SearchStoreResult> findSearchStoreScroll(SearchStoreCondition condition, Pageable pageable) {
|
||||
Expression<Double> latitude = Expressions.constant(condition.getLatitude());
|
||||
Expression<Double> longitude = Expressions.constant(condition.getLongitude());
|
||||
|
||||
NumberExpression<Double> haversineDistance = getHaversineDistance(condition.getLatitude(),condition.getLongitude());
|
||||
NumberPath<Double> distanceAlias = Expressions.numberPath(Double.class, "distance");
|
||||
int earthRadius = 6371;
|
||||
|
||||
NumberExpression<Double> haversineDistance = acos(
|
||||
cos(radians(latitude))
|
||||
.multiply(cos(radians(store.map.latitude)))
|
||||
.multiply(
|
||||
cos(radians(store.map.longitude)
|
||||
.subtract(radians(longitude)))
|
||||
)
|
||||
.add(
|
||||
sin(radians(latitude))
|
||||
.multiply(sin(radians(store.map.latitude)))
|
||||
)
|
||||
)
|
||||
.multiply(Expressions.constant(earthRadius * 1000));
|
||||
|
||||
List<SearchStoreResult> content = queryFactory.select(
|
||||
Projections.constructor(SearchStoreResult.class,
|
||||
@@ -77,4 +62,47 @@ public class StoreRepositoryCustom {
|
||||
return storeName == null ? null : store.name.contains(storeName);
|
||||
}
|
||||
|
||||
public List<SearchStoreResult> findFavoriteStore(SearchStoreCondition condition,Long userId){
|
||||
|
||||
NumberExpression<Double> haversineDistance = getHaversineDistance(condition.getLatitude(),condition.getLongitude());
|
||||
NumberPath<Double> distanceAlias = Expressions.numberPath(Double.class, "distance");
|
||||
List<SearchStoreResult> content = queryFactory.select(
|
||||
Projections.constructor(SearchStoreResult.class,
|
||||
store.id,
|
||||
store.name,
|
||||
haversineDistance.as(distanceAlias))
|
||||
)
|
||||
.from(store)
|
||||
.join(store.map)
|
||||
.join(store.favoriteStores, QFavoriteStore.favoriteStore)
|
||||
.on(QFavoriteStore.favoriteStore.userId.eq(userId))
|
||||
.orderBy(distanceAlias.asc())
|
||||
.fetch();
|
||||
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
private NumberExpression<Double> getHaversineDistance (double SearchLatitude, double SearchLongitude){
|
||||
Expression<Double> latitude = Expressions.constant(SearchLatitude);
|
||||
Expression<Double> longitude = Expressions.constant(SearchLongitude);
|
||||
|
||||
int earthRadius = 6371;
|
||||
|
||||
NumberExpression<Double> haversineDistance = acos(
|
||||
cos(radians(latitude))
|
||||
.multiply(cos(radians(store.map.latitude)))
|
||||
.multiply(
|
||||
cos(radians(store.map.longitude)
|
||||
.subtract(radians(longitude)))
|
||||
)
|
||||
.add(
|
||||
sin(radians(latitude))
|
||||
.multiply(sin(radians(store.map.latitude)))
|
||||
)
|
||||
)
|
||||
.multiply(Expressions.constant(earthRadius * 1000));
|
||||
return haversineDistance;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,6 +5,9 @@ import com.justpickup.storeservice.domain.store.dto.SearchStoreResult;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface StoreService {
|
||||
SliceImpl<SearchStoreResult> findSearchStoreScroll(SearchStoreCondition condition, Pageable pageable);
|
||||
List<SearchStoreResult> findFavoriteStore(SearchStoreCondition condition, Long userId);
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class StoreServiceImpl implements StoreService {
|
||||
@@ -28,4 +30,9 @@ public class StoreServiceImpl implements StoreService {
|
||||
|
||||
return searchStoreScroll;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SearchStoreResult> findFavoriteStore(SearchStoreCondition condition, Long userId) {
|
||||
return storeRepositoryCustom.findFavoriteStore(condition,userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,14 @@ import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
import org.springframework.data.web.PageableDefault;
|
||||
import org.springframework.http.HttpStatus;
|
||||
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;
|
||||
|
||||
@@ -22,12 +24,38 @@ import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@RestController
|
||||
@Slf4j
|
||||
@RequestMapping("api/customer/store")
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/api/customer/store")
|
||||
public class StoreCustomerApiController {
|
||||
|
||||
private final StoreService storeService;
|
||||
|
||||
@GetMapping("/favorite")
|
||||
public ResponseEntity getFavoriteStore(@Valid SearchStoreCondition condition,
|
||||
@RequestHeader(value = "user-id") String userId){
|
||||
|
||||
List<SearchStoreResult> favoriteStore = storeService.findFavoriteStore(condition,Long.parseLong(userId));
|
||||
|
||||
List<FavoriteStoreResponse> searchStoreResponse
|
||||
= favoriteStore.stream().map(FavoriteStoreResponse::new).collect(Collectors.toList());
|
||||
|
||||
return ResponseEntity.status(HttpStatus.OK).body(Result.createSuccessResult(searchStoreResponse));
|
||||
}
|
||||
|
||||
@Data @NoArgsConstructor
|
||||
static class FavoriteStoreResponse {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String distance;
|
||||
|
||||
public FavoriteStoreResponse(SearchStoreResult storeResult) {
|
||||
this.id = storeResult.getStoreId();
|
||||
this.name = storeResult.getStoreName();
|
||||
this.distance = storeResult.convertDistanceToString();
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/search")
|
||||
public ResponseEntity<Result> searchStore(@Valid SearchStoreCondition condition,
|
||||
@PageableDefault(page = 0, size = 2) Pageable pageable) {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.justpickup.storeservice.domain.category.web;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.justpickup.storeservice.config.TestConfig;
|
||||
import com.justpickup.storeservice.domain.category.dto.CategoryDto;
|
||||
@@ -15,7 +14,6 @@ import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation;
|
||||
import org.springframework.restdocs.request.RequestDocumentation;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
@@ -25,15 +23,14 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.*;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||
|
||||
@WebMvcTest(CategoryController.class)
|
||||
@WebMvcTest(CategoryOwnerApiController.class)
|
||||
@Import(TestConfig.class)
|
||||
@AutoConfigureRestDocs(uriHost = "127.0.0.1",uriPort = 8001)
|
||||
class CategoryControllerTest {
|
||||
class CategoryOwnerApiControllerTest {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mockMvc;
|
||||
@@ -101,30 +98,30 @@ class CategoryControllerTest {
|
||||
|
||||
//given
|
||||
Long storeId = 1L;
|
||||
List<CategoryController.PutCategoryRequest.Category> categoryList = new ArrayList<>();
|
||||
categoryList.add(CategoryController.PutCategoryRequest.Category.builder()
|
||||
List<CategoryOwnerApiController.PutCategoryRequest.Category> categoryList = new ArrayList<>();
|
||||
categoryList.add(CategoryOwnerApiController.PutCategoryRequest.Category.builder()
|
||||
.categoryId(10L)
|
||||
.name("카테고리1")
|
||||
.order(2)
|
||||
.build());
|
||||
|
||||
categoryList.add(CategoryController.PutCategoryRequest.Category.builder()
|
||||
categoryList.add(CategoryOwnerApiController.PutCategoryRequest.Category.builder()
|
||||
.categoryId(11L)
|
||||
.name("카테고리2")
|
||||
.order(1)
|
||||
.build());
|
||||
|
||||
List<CategoryController.PutCategoryRequest.Category> deletedList = new ArrayList<>();
|
||||
List<CategoryOwnerApiController.PutCategoryRequest.Category> deletedList = new ArrayList<>();
|
||||
|
||||
deletedList.add(CategoryController.PutCategoryRequest.Category.builder()
|
||||
deletedList.add(CategoryOwnerApiController.PutCategoryRequest.Category.builder()
|
||||
.categoryId(11L)
|
||||
.name("Non Coffee")
|
||||
.order(3)
|
||||
.build());
|
||||
|
||||
|
||||
CategoryController.PutCategoryRequest putCategoryRequest =
|
||||
CategoryController.PutCategoryRequest.builder()
|
||||
CategoryOwnerApiController.PutCategoryRequest putCategoryRequest =
|
||||
CategoryOwnerApiController.PutCategoryRequest.builder()
|
||||
.storeId(storeId)
|
||||
.categoryList(categoryList)
|
||||
.deletedList(deletedList)
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.justpickup.storeservice.domain.store.web;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.justpickup.storeservice.config.TestConfig;
|
||||
import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreRepository;
|
||||
import com.justpickup.storeservice.config.TestConfig;
|
||||
import com.justpickup.storeservice.domain.store.dto.SearchStoreCondition;
|
||||
import com.justpickup.storeservice.domain.store.dto.SearchStoreResult;
|
||||
@@ -12,6 +15,7 @@ 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.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.SliceImpl;
|
||||
@@ -20,6 +24,10 @@ import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
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.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.BDDMockito.given;
|
||||
@@ -29,6 +37,7 @@ import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWit
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
|
||||
import static org.springframework.restdocs.request.RequestDocumentation.requestParameters;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@@ -48,6 +57,61 @@ class StoreCustomerApiControllerTest {
|
||||
@MockBean
|
||||
StoreRepository storeRepository;
|
||||
|
||||
@MockBean
|
||||
FavoriteStoreRepository favoriteStoreRepository;
|
||||
|
||||
@Test
|
||||
@DisplayName("즐겨찾는 매장")
|
||||
void getFavoriteStore() throws Exception {
|
||||
//given
|
||||
|
||||
double latitude = 37.5403912;
|
||||
double longitude = 126.9438922;
|
||||
SearchStoreCondition condition = new SearchStoreCondition(latitude, longitude, null);
|
||||
given(storeService.findFavoriteStore(any(SearchStoreCondition.class),eq(2L)))
|
||||
.willReturn(getWillReturnSearchStore());
|
||||
|
||||
|
||||
//when
|
||||
String s = new ObjectMapper()
|
||||
.writeValueAsString(condition);
|
||||
|
||||
ResultActions resultActions = mockMvc.perform(get("/api/customer/store/favorite")
|
||||
.param("latitude",String.valueOf(condition.getLatitude()))
|
||||
.param("longitude",String.valueOf(condition.getLongitude()))
|
||||
.header("user-id","2")
|
||||
);
|
||||
|
||||
//then
|
||||
resultActions.andExpect(status().isOk())
|
||||
.andDo(print())
|
||||
.andDo(document("favoriteStore-get",
|
||||
requestHeaders(
|
||||
headerWithName("user-id").description("로그인한 유저 id")
|
||||
),
|
||||
requestParameters(
|
||||
parameterWithName("latitude").description("고객의 위도 [필수]"),
|
||||
parameterWithName("longitude").description("고객의 경도 [필수]")
|
||||
),
|
||||
responseFields(
|
||||
fieldWithPath("code").description("결과 코드 SUCCESS/ERROR"),
|
||||
fieldWithPath("message").description("메시지"),
|
||||
fieldWithPath("data[*].id").description("매장 고유번호"),
|
||||
fieldWithPath("data[*].name").description("매장 이름"),
|
||||
fieldWithPath("data[*].distance").description("고객과의 거리차이 m/km")
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
private List<SearchStoreResult> 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);
|
||||
|
||||
return List.of(result_1,result_2,result_3);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("[API] [GET] 매장 검색 페이지 조회")
|
||||
void getSearchStore() throws Exception {
|
||||
@@ -95,5 +159,6 @@ class StoreCustomerApiControllerTest {
|
||||
SearchStoreResult result_1 = new SearchStoreResult(1L, "이디야커피 마포오벨리스크점", 145.11980562222007, 10L);
|
||||
SearchStoreResult result_2 = new SearchStoreResult(2L, "만랩커피 마포점", 150.97181089895466, 5L);
|
||||
return new SliceImpl<>(List.of(result_1, result_2), pageable,true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user