Merge remote-tracking branch 'origin/master'

This commit is contained in:
hoon7566
2022-03-21 13:26:44 +09:00
33 changed files with 824 additions and 239 deletions

View File

@@ -89,7 +89,7 @@ spring:
- id: user-service - id: user-service
uri: lb://USER-SERVICE uri: lb://USER-SERVICE
predicates: predicates:
- Path=/user-service/store-owner - Path=/user-service/api/owner/store-owner
- Method=POST - Method=POST
filters: filters:
- RewritePath=/user-service/(?<segment>.*),/$\{segment} - RewritePath=/user-service/(?<segment>.*),/$\{segment}

View File

@@ -13,6 +13,7 @@
"core-js": "^3.6.5", "core-js": "^3.6.5",
"moment": "^2.29.1", "moment": "^2.29.1",
"vue": "^2.6.11", "vue": "^2.6.11",
"vue-daum-postcode": "^0.10.0",
"vue-router": "^3.2.0", "vue-router": "^3.2.0",
"vuedraggable": "^2.24.3", "vuedraggable": "^2.24.3",
"vuetify": "^2.4.0" "vuetify": "^2.4.0"

View File

@@ -1,8 +1,23 @@
import jwt from '../common/jwt.js'; import jwt from '../common/jwt.js';
export default { export default {
requestRegisterUser(user) { requestRegisterUser(user, store) {
return axios.post(process.env.VUE_APP_USER_URL + "/store-owner", user); const param = {
email: user.email,
password: user.password,
name: user.name,
phoneNumber: user.phoneNumber,
businessNumber: user.businessNumber,
storeName: store.storeName,
storePhoneNumber: store.storePhoneNumber,
address: store.storeAddress,
zipcode: store.zipcode,
latitude: store.latitude,
longitude: store.longitude,
}
return axios.post(process.env.VUE_APP_USER_URL + "/api/owner/store-owner", param);
}, },
async requestLoginUser(email, password) { async requestLoginUser(email, password) {

View File

@@ -57,6 +57,8 @@ axios.interceptors.response.use(
} }
window.location.href = "/"; window.location.href = "/";
alert("권한이 없습니다. 다시 로그인해주세요."); alert("권한이 없습니다. 다시 로그인해주세요.");
} else {
if (error.response.data.message) alert(error.response.data.message);
} }
return Promise.reject(error); return Promise.reject(error);
} }

View File

@@ -1,9 +1,11 @@
<template> <template>
<div>
<v-card width="800" class="mx-auto mt-5"> <v-card width="800" class="mx-auto mt-5">
<v-card-title> <v-card-title>
<h1>Register</h1> <h1>Register</h1>
</v-card-title> </v-card-title>
<v-card-text> <v-card-text>
<h3>회원 정보</h3>
<v-form <v-form
ref="form" ref="form"
lazy-validation lazy-validation
@@ -35,6 +37,50 @@
:rules="[v => !!v || '사업자번호는 필수 값입니다']" :rules="[v => !!v || '사업자번호는 필수 값입니다']"
label="사업자번호" label="사업자번호"
></v-text-field> ></v-text-field>
<br>
<h3>매장 정보</h3>
<v-text-field
v-model="storeName"
:rules="[v => !!v || '매장정보는 필수 값입니다']"
label="매장 이름"
></v-text-field>
<v-text-field
v-model="storePhoneNumber"
:rules="[v => !!v || '매장전화번호는 필수 값입니다']"
label="매장 전화번호"
></v-text-field>
<v-text-field
v-model="storeAddress"
:rules="[v => !!v || '매장 주소는 필수 값입니다']"
label="매장 주소"
readonly
>
<template v-slot:append-outer>
<v-btn
@click="dialog = true"
small
>우편번호 검색</v-btn>
</template>
</v-text-field>
<v-row>
<v-col sm="6">
<v-text-field
v-model="latitude"
:rules="[v => !!v || '매장 위도는 필수 값입니다']"
label="위도"
readonly
></v-text-field>
</v-col>
<v-col sm="6">
<v-text-field
v-model="longitude"
:rules="[v => !!v || '매장 경도는 필수 값입니다']"
label="경도"
readonly
></v-text-field>
</v-col>
</v-row>
</v-form> </v-form>
</v-card-text> </v-card-text>
<v-divider></v-divider> <v-divider></v-divider>
@@ -43,25 +89,57 @@
<v-btn color="info" v-on:click="register">Register</v-btn> <v-btn color="info" v-on:click="register">Register</v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
<v-dialog
v-model="dialog"
width="500"
>
<VueDaumPostcode
@complete="complete"
></VueDaumPostcode>
</v-dialog>
<div id="map"></div>
</div>
</template> </template>
<script> <script>
import userApi from '../api/user.js' import userApi from '../api/user.js'
import { VueDaumPostcode } from 'vue-daum-postcode'
export default { export default {
name: "RegisterUser", name: "RegisterUser",
components: {
VueDaumPostcode
},
mounted() {
const script = document.createElement("script");
// eslint-disable-next-line no-undef
script.onload = () => kakao.maps.load(this.initMap);
script.src =
"//dapi.kakao.com/v2/maps/sdk.js?autoload=false&libraries=services&appkey=013b300ace1c317f0f39ce53201f831b";
document.head.appendChild(script);
},
data: function() { data: function() {
return { return {
email: '', email: 'test@gmail.com',
password: '', password: '1234',
name: '', name: '테스트 계정',
phoneNumber: '', phoneNumber: '010-1111-2222',
businessNumber: '' businessNumber: '03912',
storeName: '테스트 매장',
storePhoneNumber: '010-1111-2222',
storeAddress: '',
zipcode: '',
latitude: '',
longitude: '',
dialog: false,
map: '',
} }
}, },
methods: { methods: {
register: function() { register: async function() {
if (!this.$refs.form.validate()) return; if (!this.$refs.form.validate()) return;
const user = { const user = {
@@ -72,21 +150,63 @@ export default {
businessNumber: this.businessNumber businessNumber: this.businessNumber
} }
userApi.requestRegisterUser(user) const store = {
.then( (response) => { storeName: this.storeName,
if (response.status == '201') { storePhoneNumber: this.storePhoneNumber,
alert("사용자 등록이 성공되었습니다."); storeAddress: this.storeAddress,
this.$router.push('/login'); zipcode: this.zipcode,
latitude: this.latitude,
longitude: this.longitude,
}
try {
await userApi.requestRegisterUser(user, store);
alert("회원 가입에 성공하였습니다. \n로그인 페이지로 이동합니다.");
await this.$router.push('/login');
} catch (error) {
console.log(error)
}
},
initMap() {
const container = document.getElementById("map");
const options = {
// eslint-disable-next-line no-undef
center: new kakao.maps.LatLng(33.450701, 126.570667),
level: 5,
};
// eslint-disable-next-line no-undef
this.map = new kakao.maps.Map(container, options);
},
complete: function(addressResult) {
this.storeAddress = addressResult.address;
this.zipcode = addressResult.zonecode;
this.dialog = false;
Promise.resolve(this.storeAddress).then(value => {
return new Promise((resolve, reject) => {
// eslint-disable-next-line no-undef
const geocoder = new daum.maps.services.Geocoder();
geocoder.addressSearch(value, (result, status) => {
// eslint-disable-next-line no-undef
if (status === daum.maps.services.Status.OK) {
const {x, y} = result[0];
resolve({lat: y, long: x})
} else { } else {
alert("사용자 등록에 실패하였습니다. 다시 시도해주세요."); reject();
} }
}) })
.catch( (error) => { }).then(result => {
console.log(error); this.latitude = result.lat;
let message = error.response.data.message; this.longitude = result.long;
if (message) alert(message); }).catch(error => {
console.log("[RegisterUser]", error);
alert("해당 주소의 위도, 경도를 가져오는 도중 오류가 발생하였습니다. \n다시 시도해주세요.");
}); });
} })
},
} }
} }
</script> </script>

View File

@@ -108,6 +108,8 @@ operation::store-get[snippets='curl-request,http-request,http-response,path-para
operation::api-get-store-byUserId[snippets='curl-request,http-request,http-response,request-headers,response-fields'] operation::api-get-store-byUserId[snippets='curl-request,http-request,http-response,request-headers,response-fields']
=== 매장 리스트 조회 === 매장 리스트 조회
operation::stores-get[snippets='curl-request,http-request,http-response,path-parameters,response-fields'] operation::stores-get[snippets='curl-request,http-request,http-response,path-parameters,response-fields']
=== 매장 생성 (점주 서비스)
operation::api-post-store[snippets='curl-request,http-request,http-response,request-headers,request-fields']
== 즐겨찾는 매장 == 즐겨찾는 매장
=== 즐겨찾는 매장 조회 === 즐겨찾는 매장 조회

View File

@@ -0,0 +1,75 @@
package com.justpickup.storeservice.domain.store.dto;
import com.justpickup.storeservice.domain.map.entity.Map;
import com.justpickup.storeservice.domain.store.entity.Store;
import com.justpickup.storeservice.global.entity.Address;
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED)
public class PostStoreDto {
private String name;
private String phoneNumber;
private Long userId;
private _PostStoreAddress address;
private _PostStoreMap map;
@Builder
public PostStoreDto(String name, String phoneNumber, Long userId, _PostStoreAddress address, _PostStoreMap map) {
this.name = name;
this.phoneNumber = phoneNumber;
this.userId = userId;
this.address = address;
this.map = map;
}
public static PostStoreDto of(Store store) {
PostStoreDto postStoreDto = new PostStoreDto();
postStoreDto.name = store.getName();
postStoreDto.phoneNumber = store.getPhoneNumber();
postStoreDto.userId = store.getUserId();
postStoreDto.address = _PostStoreAddress.of(store.getAddress());
postStoreDto.map = _PostStoreMap.of(store.getMap());
return postStoreDto;
}
@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class _PostStoreAddress {
private String address;
private String zipcode;
@Builder
public _PostStoreAddress(String address, String zipcode) {
this.address = address;
this.zipcode = zipcode;
}
public static _PostStoreAddress of(Address address) {
_PostStoreAddress postStoreAddress = new _PostStoreAddress();
postStoreAddress.address = address.getAddress();
postStoreAddress.zipcode = address.getAddress();
return postStoreAddress;
}
}
@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class _PostStoreMap {
private Double latitude;
private Double longitude;
@Builder
public _PostStoreMap(Double latitude, Double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public static _PostStoreMap of(Map map) {
_PostStoreMap postStoreMap = new _PostStoreMap();
postStoreMap.latitude = map.getLatitude();
postStoreMap.longitude = map.getLongitude();
return postStoreMap;
}
}
}

View File

@@ -68,12 +68,13 @@ public class Store extends BaseEntity {
item.setStore(this); item.setStore(this);
} }
public static Store of(Address address, Map map, Long userId, String name) { public static Store of(Address address, Map map, Long userId, String name, String phoneNumber) {
Store store = new Store(); Store store = new Store();
store.address = address; store.address = address;
store.map = map; store.map = map;
store.userId = userId; store.userId = userId;
store.name = name; store.name = name;
store.phoneNumber = phoneNumber;
return store; return store;
} }
} }

View File

@@ -1,9 +1,6 @@
package com.justpickup.storeservice.domain.store.service; package com.justpickup.storeservice.domain.store.service;
import com.justpickup.storeservice.domain.store.dto.SearchStoreCondition; import com.justpickup.storeservice.domain.store.dto.*;
import com.justpickup.storeservice.domain.store.dto.SearchStoreResult;
import com.justpickup.storeservice.domain.store.dto.StoreByUserIdDto;
import com.justpickup.storeservice.domain.store.dto.StoreDto;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.SliceImpl; import org.springframework.data.domain.SliceImpl;
@@ -15,4 +12,5 @@ public interface StoreService {
StoreDto findStoreById(Long storeId); StoreDto findStoreById(Long storeId);
StoreByUserIdDto findStoreByUserId(Long userId); StoreByUserIdDto findStoreByUserId(Long userId);
List<StoreDto> findStoreAllById(Iterable<Long> storeIds); List<StoreDto> findStoreAllById(Iterable<Long> storeIds);
PostStoreDto saveStore(PostStoreDto postStoreDto);
} }

View File

@@ -1,18 +1,18 @@
package com.justpickup.storeservice.domain.store.service; package com.justpickup.storeservice.domain.store.service;
import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreCustom; import com.justpickup.storeservice.domain.favoritestore.repository.FavoriteStoreCustom;
import com.justpickup.storeservice.domain.store.dto.SearchStoreCondition; import com.justpickup.storeservice.domain.map.entity.Map;
import com.justpickup.storeservice.domain.store.dto.SearchStoreResult; import com.justpickup.storeservice.domain.store.dto.*;
import com.justpickup.storeservice.domain.store.dto.StoreByUserIdDto;
import com.justpickup.storeservice.domain.store.dto.StoreDto;
import com.justpickup.storeservice.domain.store.entity.Store; import com.justpickup.storeservice.domain.store.entity.Store;
import com.justpickup.storeservice.domain.store.exception.NotExistStoreException; import com.justpickup.storeservice.domain.store.exception.NotExistStoreException;
import com.justpickup.storeservice.domain.store.repository.StoreRepository; import com.justpickup.storeservice.domain.store.repository.StoreRepository;
import com.justpickup.storeservice.domain.store.repository.StoreRepositoryCustom; import com.justpickup.storeservice.domain.store.repository.StoreRepositoryCustom;
import com.justpickup.storeservice.global.entity.Address;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.SliceImpl; import org.springframework.data.domain.SliceImpl;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -71,4 +71,20 @@ public class StoreServiceImpl implements StoreService {
.map(StoreDto::of) .map(StoreDto::of)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Transactional
@Override
public PostStoreDto saveStore(PostStoreDto postStoreDto) {
PostStoreDto._PostStoreAddress postStoreAddress = postStoreDto.getAddress();
Address address = new Address(postStoreAddress.getAddress(), postStoreAddress.getZipcode());
PostStoreDto._PostStoreMap postStoreMap = postStoreDto.getMap();
Map map = Map.of(postStoreMap.getLatitude(), postStoreMap.getLongitude());
Store store =
Store.of(address, map, postStoreDto.getUserId(), postStoreDto.getName(), postStoreDto.getPhoneNumber());
Store savedStore = storeRepository.save(store);
return PostStoreDto.of(savedStore);
}
} }

View File

@@ -7,9 +7,7 @@ import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;

View File

@@ -1,16 +1,18 @@
package com.justpickup.storeservice.domain.store.web; package com.justpickup.storeservice.domain.store.web;
import com.justpickup.storeservice.domain.store.dto.PostStoreDto;
import com.justpickup.storeservice.domain.store.dto.StoreByUserIdDto; import com.justpickup.storeservice.domain.store.dto.StoreByUserIdDto;
import com.justpickup.storeservice.domain.store.service.StoreService; import com.justpickup.storeservice.domain.store.service.StoreService;
import com.justpickup.storeservice.global.dto.Result; import com.justpickup.storeservice.global.dto.Result;
import lombok.Data; import lombok.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping; import javax.validation.Valid;
import org.springframework.web.bind.annotation.RestController; import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@RestController @RestController
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -38,6 +40,47 @@ public class StoreOwnerApiController {
this.id = dto.getId(); this.id = dto.getId();
this.name = dto.getName(); this.name = dto.getName();
} }
}
@PostMapping("/owner/store")
public ResponseEntity<Result> postStore(@Valid @RequestBody PostStoreRequest postStoreRequest,
@RequestHeader(value="user-id") String userHeader) {
Long userId = Long.valueOf(userHeader);
storeService.saveStore(postStoreRequest.toPostStoreDto(userId));
return ResponseEntity.status(HttpStatus.CREATED).build();
}
@Data @NoArgsConstructor @AllArgsConstructor @Builder
static class PostStoreRequest {
@NotEmpty
private String name;
@NotEmpty
private String phoneNumber;
@NotEmpty
private String address;
@NotEmpty
private String zipcode;
@NotNull
private Double latitude;
@NotNull
private Double longitude;
public PostStoreDto toPostStoreDto(Long userId) {
PostStoreDto._PostStoreAddress address =
PostStoreDto._PostStoreAddress.builder().address(this.address).zipcode(this.zipcode).build();
PostStoreDto._PostStoreMap map =
PostStoreDto._PostStoreMap.builder().latitude(this.latitude).longitude(this.longitude).build();
return PostStoreDto.builder()
.name(this.name)
.phoneNumber(this.phoneNumber)
.userId(userId)
.address(address)
.map(map)
.build();
}
} }
} }

View File

@@ -116,7 +116,7 @@ public class SqlCommandLineRunner implements CommandLineRunner {
List<Item> items = List.of(아메리카노, 카페라떼, 카페모카, 콜드브루, 녹차라떼, 딸기라떼, 녹차, 히비스커스); List<Item> items = List.of(아메리카노, 카페라떼, 카페모카, 콜드브루, 녹차라떼, 딸기라떼, 녹차, 히비스커스);
itemRepository.saveAll(items); itemRepository.saveAll(items);
items.forEach(item -> store.addItem(item)); items.forEach(store::addItem);
}); });
} }
@@ -136,37 +136,41 @@ public class SqlCommandLineRunner implements CommandLineRunner {
void createStores(StoreRepository storeRepository, List<Store> stores) { void createStores(StoreRepository storeRepository, List<Store> stores) {
stores.add( stores.add(
Store.of( Store.of(
new Address("서울시", "마포구 도화동", "201-20"), new Address("서울시 마포구 도화동", "201-20"),
Map.of(37.5398271003404, 126.94769672415691), Map.of(37.5398271003404, 126.94769672415691),
1L, 1L,
"커피온리 마포역점" "커피온리 마포역점",
"010-1234-5678"
) )
); );
stores.add( stores.add(
Store.of( Store.of(
new Address("서울시", "마포구 도화동", "50-10"), new Address("서울시 마포구 도화동", "50-10"),
Map.of(37.54010719003089, 126.94556661330861), Map.of(37.54010719003089, 126.94556661330861),
2L, 2L,
"만랩커피 마포점" "만랩커피 마포점",
"010-1234-5678"
) )
); );
stores.add( stores.add(
Store.of( Store.of(
new Address("서울시", "마포구 도화동", "555"), new Address("서울시 마포구 도화동", "555"),
Map.of(37.539797393793755, 126.9453578838543), Map.of(37.539797393793755, 126.9453578838543),
3L, 3L,
"이디야커피 마포오벨리스크점" "이디야커피 마포오벨리스크점",
"010-1234-5678"
) )
); );
stores.add( stores.add(
Store.of( Store.of(
new Address("서울시", "영등포구 도림로", "31길 2"), new Address("서울시 영등포구 도림로", "31길 2"),
Map.of(37.493033141569505, 126.89593667847592), Map.of(37.493033141569505, 126.89593667847592),
4L, 4L,
"이디야커피 대림역점" "이디야커피 대림역점",
"010-1234-5678"
) )
); );

View File

@@ -11,7 +11,6 @@ import javax.persistence.Embeddable;
@NoArgsConstructor(access = AccessLevel.PROTECTED) @NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor @Getter @AllArgsConstructor @Getter
public class Address { public class Address {
private String city; private String address;
private String street;
private String zipcode; private String zipcode;
} }

View File

@@ -1,5 +1,6 @@
package com.justpickup.storeservice.domain.store.web; package com.justpickup.storeservice.domain.store.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.justpickup.storeservice.config.TestConfig; import com.justpickup.storeservice.config.TestConfig;
import com.justpickup.storeservice.domain.store.dto.StoreByUserIdDto; import com.justpickup.storeservice.domain.store.dto.StoreByUserIdDto;
import com.justpickup.storeservice.domain.store.service.StoreService; import com.justpickup.storeservice.domain.store.service.StoreService;
@@ -11,6 +12,7 @@ import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDoc
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.ResultActions;
@@ -20,8 +22,8 @@ import static org.springframework.restdocs.headers.HeaderDocumentation.headerWit
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; import static org.springframework.restdocs.payload.PayloadDocumentation.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; 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.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -36,6 +38,9 @@ class StoreOwnerApiControllerTest {
@Autowired @Autowired
MockMvc mockMvc; MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@MockBean @MockBean
StoreService storeService; StoreService storeService;
@@ -70,6 +75,48 @@ class StoreOwnerApiControllerTest {
) )
)) ))
; ;
}
@Test
@DisplayName("[API] 점주 등록")
void postStore() throws Exception {
// GIVEN
StoreOwnerApiController.PostStoreRequest request = StoreOwnerApiController.PostStoreRequest.builder()
.name("점주 이름")
.phoneNumber("010-1234-5678")
.address("서울특별시 마포구 용강동 123-1길")
.zipcode("129845")
.latitude(30.90199982)
.longitude(112.1298347)
.build();
Long userId = 1L;
String content = objectMapper.writeValueAsString(request);
// THEN
ResultActions actions = mockMvc.perform(post(url + "/owner/store")
.content(content)
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.header("user-id", String.valueOf(userId))
);
// WHEN
actions.andExpect(status().isCreated())
.andDo(print())
.andDo(document("api-post-store",
requestHeaders(
headerWithName("user-id").description("JWT 유저 고유 번호")
),
requestFields(
fieldWithPath("name").description("매징 이름"),
fieldWithPath("phoneNumber").description("매장 번호"),
fieldWithPath("address").description("매장 주소"),
fieldWithPath("zipcode").description("매장 우편번호"),
fieldWithPath("latitude").description("위도"),
fieldWithPath("longitude").description("경도")
)
))
;
} }
} }

View File

@@ -76,6 +76,4 @@ operation::customers-get[snippets='curl-request,http-request,http-response,path-
== 점주 == 점주
=== 회원가입 - 점주 === 회원가입 - 점주
operation::storeOwner-post[snippets='curl-request,http-request,http-response,request-fields,response-fields'] operation::api-owner-post-store-owner[snippets='curl-request,http-request,http-response,request-fields']
=== 회원가입 - 점주 : 중복 이메일
operation::storeOwner-post-duplicateUserEmailException[snippets='curl-request,http-request,http-response,request-fields,response-fields']

View File

@@ -3,8 +3,10 @@ package com.justpickup.userservice;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication @SpringBootApplication
@EnableFeignClients
@EnableEurekaClient @EnableEurekaClient
public class UserServiceApplication { public class UserServiceApplication {

View File

@@ -0,0 +1,31 @@
package com.justpickup.userservice.domain.user.dto;
import com.justpickup.userservice.domain.user.entity.StoreOwner;
import com.justpickup.userservice.global.client.store.PostStoreRequest;
import lombok.Builder;
import lombok.Getter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Getter
public class PostOwnerDto {
private String email;
private String password;
private String name;
private String phoneNumber;
private String businessNumber;
@Builder
public PostOwnerDto(String email, String password, String name, String phoneNumber, String businessNumber) {
this.email = email;
this.password = password;
this.name = name;
this.phoneNumber = phoneNumber;
this.businessNumber = businessNumber;
}
public StoreOwner toStoreOwner() {
return new StoreOwner(this.email, this.password, this.name, this.phoneNumber, this.businessNumber);
}
}

View File

@@ -0,0 +1,37 @@
package com.justpickup.userservice.domain.user.dto;
import com.justpickup.userservice.global.client.store.PostStoreRequest;
import lombok.Builder;
import lombok.Getter;
@Getter
public class PostStoreDto {
private String name;
private String phoneNumber;
private String address;
private String zipcode;
private Double latitude;
private Double longitude;
@Builder
public PostStoreDto(String name, String phoneNumber, String address, String zipcode, Double latitude, Double longitude) {
this.name = name;
this.phoneNumber = phoneNumber;
this.address = address;
this.zipcode = zipcode;
this.latitude = latitude;
this.longitude = longitude;
}
public PostStoreRequest toPostStoreRequest() {
return PostStoreRequest.builder()
.name(this.name)
.phoneNumber(this.phoneNumber)
.address(this.address)
.zipcode(this.zipcode)
.latitude(this.latitude)
.longitude(this.longitude)
.build();
}
}

View File

@@ -4,6 +4,7 @@ import com.justpickup.userservice.global.entity.BaseEntity;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import javax.persistence.*; import javax.persistence.*;
@@ -31,7 +32,7 @@ public abstract class User extends BaseEntity {
public User(String email, String password, String name, String phoneNumber) { public User(String email, String password, String name, String phoneNumber) {
this.email = email; this.email = email;
this.password = password; this.password = new BCryptPasswordEncoder().encode(password);
this.name = name; this.name = name;
this.phoneNumber = phoneNumber; this.phoneNumber = phoneNumber;
} }

View File

@@ -1,13 +1,15 @@
package com.justpickup.userservice.domain.user.service; package com.justpickup.userservice.domain.user.service;
import com.justpickup.userservice.domain.user.dto.CustomerDto; import com.justpickup.userservice.domain.user.dto.CustomerDto;
import com.justpickup.userservice.domain.user.dto.PostOwnerDto;
import com.justpickup.userservice.domain.user.dto.PostStoreDto;
import com.justpickup.userservice.domain.user.dto.StoreOwnerDto; import com.justpickup.userservice.domain.user.dto.StoreOwnerDto;
import java.util.List; import java.util.List;
public interface UserService { public interface UserService {
CustomerDto findCustomerByUserId(Long userId); CustomerDto findCustomerByUserId(Long userId);
void saveStoreOwner(StoreOwnerDto storeOwnerDto);
List<CustomerDto> findCustomerByUserIds(List<Long> userIds); List<CustomerDto> findCustomerByUserIds(List<Long> userIds);
StoreOwnerDto findOwnerById(Long userId); StoreOwnerDto findOwnerById(Long userId);
void saveStoreOwner(PostOwnerDto toPostOwnerDto, PostStoreDto toPostStoreDto);
} }

View File

@@ -1,6 +1,8 @@
package com.justpickup.userservice.domain.user.service; package com.justpickup.userservice.domain.user.service;
import com.justpickup.userservice.domain.user.dto.CustomerDto; import com.justpickup.userservice.domain.user.dto.CustomerDto;
import com.justpickup.userservice.domain.user.dto.PostOwnerDto;
import com.justpickup.userservice.domain.user.dto.PostStoreDto;
import com.justpickup.userservice.domain.user.dto.StoreOwnerDto; import com.justpickup.userservice.domain.user.dto.StoreOwnerDto;
import com.justpickup.userservice.domain.user.entity.Customer; import com.justpickup.userservice.domain.user.entity.Customer;
import com.justpickup.userservice.domain.user.entity.StoreOwner; import com.justpickup.userservice.domain.user.entity.StoreOwner;
@@ -10,13 +12,13 @@ import com.justpickup.userservice.domain.user.exception.NotExistUserException;
import com.justpickup.userservice.domain.user.repository.CustomerRepository; import com.justpickup.userservice.domain.user.repository.CustomerRepository;
import com.justpickup.userservice.domain.user.repository.StoreOwnerRepository; import com.justpickup.userservice.domain.user.repository.StoreOwnerRepository;
import com.justpickup.userservice.domain.user.repository.UserRepository; import com.justpickup.userservice.domain.user.repository.UserRepository;
import com.justpickup.userservice.global.client.store.StoreClient;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
@@ -35,7 +37,7 @@ public class UserServiceImpl implements UserService, UserDetailsService {
private final CustomerRepository customerRepository; private final CustomerRepository customerRepository;
private final StoreOwnerRepository storeOwnerRepository; private final StoreOwnerRepository storeOwnerRepository;
private final UserRepository userRepository; private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder; private final StoreClient storeClient;
@Override @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -55,22 +57,6 @@ public class UserServiceImpl implements UserService, UserDetailsService {
return new CustomerDto(customer); return new CustomerDto(customer);
} }
@Override
@Transactional
public void saveStoreOwner(StoreOwnerDto storeOwnerDto) {
String email = storeOwnerDto.getEmail();
boolean exists = userRepository.existsByEmail(email);
if (exists) throw new DuplicateUserEmail(email + "은 중복된 이메일입니다.");
String encode = passwordEncoder.encode(storeOwnerDto.getPassword());
StoreOwner storeOwner = new StoreOwner(email, encode, storeOwnerDto.getName(),
storeOwnerDto.getPhoneNumber(), storeOwnerDto.getBusinessNumber());
userRepository.save(storeOwner);
}
@Override @Override
public List<CustomerDto> findCustomerByUserIds(List<Long> userIds) { public List<CustomerDto> findCustomerByUserIds(List<Long> userIds) {
return customerRepository.findAllById(userIds) return customerRepository.findAllById(userIds)
@@ -87,4 +73,21 @@ public class UserServiceImpl implements UserService, UserDetailsService {
return StoreOwnerDto.of(storeOwner); return StoreOwnerDto.of(storeOwner);
} }
@Transactional
@Override
public void saveStoreOwner(PostOwnerDto postOwnerDto, PostStoreDto postStoreDto) {
StoreOwner storeOwner = postOwnerDto.toStoreOwner();
String email = storeOwner.getEmail();
if (userRepository.existsByEmail(email)) {
throw new DuplicateUserEmail(email + "은 중복된 이메일 입니다.");
}
StoreOwner savedOwner = storeOwnerRepository.save(storeOwner);
Long userId = savedOwner.getId();
storeClient.postStore(postStoreDto.toPostStoreRequest(), userId);
}
} }

View File

@@ -11,11 +11,12 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid; import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -109,37 +110,4 @@ public class UserController {
this.name = dto.getName(); this.name = dto.getName();
} }
} }
@PostMapping("/store-owner")
public ResponseEntity<Result> joinStoreOwner(@Valid @RequestBody JoinStoreOwnerRequest joinRequest) {
// 회원 가입
userService.saveStoreOwner(joinRequest.toStoreOwnerDto());
return ResponseEntity.status(HttpStatus.CREATED)
.body(Result.createSuccessResult(null));
}
@Data @NoArgsConstructor @AllArgsConstructor
static class JoinStoreOwnerRequest {
@Email(message = "email 형식이 아닙니다.")
@NotEmpty
private String email;
@NotEmpty
private String password;
@NotEmpty
private String name;
@NotEmpty
private String phoneNumber;
@NotEmpty
private String businessNumber;
public StoreOwnerDto toStoreOwnerDto() {
return StoreOwnerDto.builder()
.email(email).password(password).name(name)
.password(password).businessNumber(businessNumber)
.build();
}
}
} }

View File

@@ -0,0 +1,86 @@
package com.justpickup.userservice.domain.user.web;
import com.justpickup.userservice.domain.user.dto.PostOwnerDto;
import com.justpickup.userservice.domain.user.dto.PostStoreDto;
import com.justpickup.userservice.domain.user.service.UserService;
import com.justpickup.userservice.global.dto.Result;
import lombok.*;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api")
public class UserOwnerApiController {
private final UserService userService;
@PostMapping("/owner/store-owner")
public ResponseEntity<Result> postStoreOwner(@Valid @RequestBody PostStoreOwnerRequest postStoreOwnerRequest) {
userService.saveStoreOwner(
postStoreOwnerRequest.toPostOwnerDto(), postStoreOwnerRequest.toPostStoreDto()
);
return ResponseEntity.status(HttpStatus.CREATED)
.body(Result.createSuccessResult(null));
}
@Data @NoArgsConstructor @AllArgsConstructor @Builder
static class PostStoreOwnerRequest {
@Email(message = "email 형식이 아닙니다.")
@NotEmpty
private String email;
@NotEmpty
private String password;
@NotEmpty
private String name;
@NotEmpty
private String phoneNumber;
@NotEmpty
private String businessNumber;
@NotEmpty
private String storeName;
@NotEmpty
private String storePhoneNumber;
@NotEmpty
private String address;
@NotEmpty
private String zipcode;
@NotNull
private Double latitude;
@NotNull
private Double longitude;
public PostOwnerDto toPostOwnerDto() {
return PostOwnerDto.builder()
.email(this.email)
.password(this.password)
.name(this.name)
.phoneNumber(this.phoneNumber)
.businessNumber(this.businessNumber)
.build();
}
public PostStoreDto toPostStoreDto() {
return PostStoreDto.builder()
.name(this.storeName)
.phoneNumber(this.phoneNumber)
.address(this.address)
.zipcode(this.zipcode)
.latitude(this.latitude)
.longitude(this.longitude)
.build();
}
}
}

View File

@@ -0,0 +1,11 @@
package com.justpickup.userservice.global.client.exception;
import com.justpickup.userservice.global.exception.CustomException;
import org.springframework.http.HttpStatus;
public class FeignClientException extends CustomException {
public FeignClientException(HttpStatus status, String message) {
super(status, message);
}
}

View File

@@ -0,0 +1,38 @@
package com.justpickup.userservice.global.client.exception;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.justpickup.userservice.global.dto.Result;
import feign.Response;
import feign.codec.ErrorDecoder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
@RequiredArgsConstructor
@Slf4j
public class FeignClientExceptionErrorDecoder implements ErrorDecoder {
private final ObjectMapper objectMapper;
@Override
public Exception decode(String methodKey, Response response) {
String message = null;
if (response.body() != null) {
try {
Result result = objectMapper.readValue(response.body().asInputStream(), Result.class);
message = result.getMessage();
} catch (IOException e) {
String catchErrorMessage = "Error Deserializing response body from failed feign request response.";
log.warn(methodKey + catchErrorMessage, e);
return new FeignClientException(HttpStatus.INTERNAL_SERVER_ERROR, "고객센터로 문의해주세요.");
}
}
return new FeignClientException(HttpStatus.INTERNAL_SERVER_ERROR, message);
}
}

View File

@@ -0,0 +1,33 @@
package com.justpickup.userservice.global.client.store;
import lombok.Builder;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
@Data
public class PostStoreRequest {
@NotEmpty
private String name;
@NotEmpty
private String phoneNumber;
@NotEmpty
private String address;
@NotEmpty
private String zipcode;
@NotNull
private Double latitude;
@NotNull
private Double longitude;
@Builder
public PostStoreRequest(String name, String phoneNumber, String address, String zipcode, Double latitude, Double longitude) {
this.name = name;
this.phoneNumber = phoneNumber;
this.address = address;
this.zipcode = zipcode;
this.latitude = latitude;
this.longitude = longitude;
}
}

View File

@@ -0,0 +1,18 @@
package com.justpickup.userservice.global.client.store;
import com.justpickup.userservice.global.dto.Result;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import javax.validation.Valid;
@FeignClient("STORE-SERVICE")
public interface StoreClient {
@PostMapping("/api/owner/store")
ResponseEntity<Result> postStore(@Valid @RequestBody PostStoreRequest postStoreRequest,
@RequestHeader("user-id") Long userId);
}

View File

@@ -0,0 +1,14 @@
package com.justpickup.userservice.global.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignClientConfig {
@Bean
public Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}

View File

@@ -27,6 +27,8 @@ public class GlobalExceptionHandler {
HttpStatus status = ce.getStatus(); HttpStatus status = ce.getStatus();
Result errorResult = ce.getErrorResult(); Result errorResult = ce.getErrorResult();
log.warn("[CustomException] {}, {}", status, errorResult);
return ResponseEntity.status(status) return ResponseEntity.status(status)
.body(errorResult); .body(errorResult);
} }

View File

@@ -2,9 +2,8 @@ package com.justpickup.userservice.global.security;
import com.justpickup.userservice.domain.jwt.service.OAuthService; import com.justpickup.userservice.domain.jwt.service.OAuthService;
import com.justpickup.userservice.domain.jwt.service.RefreshTokenServiceImpl; import com.justpickup.userservice.domain.jwt.service.RefreshTokenServiceImpl;
import com.justpickup.userservice.global.utils.JwtTokenProvider;
import com.justpickup.userservice.domain.user.service.UserService;
import com.justpickup.userservice.global.utils.CookieProvider; import com.justpickup.userservice.global.utils.CookieProvider;
import com.justpickup.userservice.global.utils.JwtTokenProvider;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.AuthenticationManager;
@@ -14,16 +13,14 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@RequiredArgsConstructor @RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter { public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService; private final UserDetailsService userDetailsService;
private final BCryptPasswordEncoder bCryptPasswordEncoder; private final PasswordEncoder bCryptPasswordEncoder;
private final JwtTokenProvider jwtTokenProvider; private final JwtTokenProvider jwtTokenProvider;
private final RefreshTokenServiceImpl refreshTokenServiceImpl; private final RefreshTokenServiceImpl refreshTokenServiceImpl;
private final CookieProvider cookieProvider; private final CookieProvider cookieProvider;

View File

@@ -3,7 +3,6 @@ package com.justpickup.userservice.domain.user.web;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.justpickup.userservice.config.TestConfig; import com.justpickup.userservice.config.TestConfig;
import com.justpickup.userservice.domain.user.dto.CustomerDto; import com.justpickup.userservice.domain.user.dto.CustomerDto;
import com.justpickup.userservice.domain.user.exception.DuplicateUserEmail;
import com.justpickup.userservice.domain.user.exception.NotExistUserException; import com.justpickup.userservice.domain.user.exception.NotExistUserException;
import com.justpickup.userservice.domain.user.service.UserService; import com.justpickup.userservice.domain.user.service.UserService;
import com.justpickup.userservice.global.dto.Code; import com.justpickup.userservice.global.dto.Code;
@@ -20,8 +19,6 @@ import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.restdocs.headers.HeaderDocumentation;
import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.ResultActions;
@@ -29,15 +26,13 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.BDDMockito.willThrow;
import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName; import static org.springframework.restdocs.headers.HeaderDocumentation.headerWithName;
import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders; import static org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document; import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get; import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post; import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.*; import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName; import static org.springframework.restdocs.request.RequestDocumentation.parameterWithName;
import static org.springframework.restdocs.request.RequestDocumentation.pathParameters; 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.MockMvcResultHandlers.print;
@@ -185,74 +180,6 @@ class UserControllerTest {
; ;
} }
@Test
@DisplayName("회원가입 - 점주")
void registerStoreOwner() throws Exception {
UserController.JoinStoreOwnerRequest requestBody =
new UserController.JoinStoreOwnerRequest("test@naver.com", "1234", "Park",
"010-1234-5678", "1234");
ResultActions actions = mockMvc.perform(post("/store-owner")
.content(objectMapper.writeValueAsString(requestBody))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
);
actions.andExpect(status().isCreated())
.andDo(print())
.andDo(document("storeOwner-post",
requestFields(
fieldWithPath("email").description("이메일"),
fieldWithPath("password").description("비밀번호"),
fieldWithPath("name").description("이름"),
fieldWithPath("phoneNumber").description("휴대폰번호"),
fieldWithPath("businessNumber").description("사업자등록번호")
),
responseFields(
fieldWithPath("code").description("결과코드 SUCCESS/ERROR"),
fieldWithPath("message").description("메시지"),
fieldWithPath("data").description("데이터")
)
))
;
}
@Test
@DisplayName("회원가입 - 점주 : 존재하는 회원 이메일")
void registerStoreOwnerDuplicateUserEmailException() throws Exception {
String email = "test@naver.com";
UserController.JoinStoreOwnerRequest requestBody =
new UserController.JoinStoreOwnerRequest(email, "1234", "Park",
"010-1234-5678", "1234");
willThrow(new DuplicateUserEmail(email + "은 중복된 이메일입니다."))
.given(userService).saveStoreOwner(any());
ResultActions actions = mockMvc.perform(post("/store-owner")
.content(objectMapper.writeValueAsString(requestBody))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
);
actions.andExpect(status().isConflict())
.andDo(print())
.andDo(document("storeOwner-post-duplicateUserEmailException",
requestFields(
fieldWithPath("email").description("이메일"),
fieldWithPath("password").description("비밀번호"),
fieldWithPath("name").description("이름"),
fieldWithPath("phoneNumber").description("휴대폰번호"),
fieldWithPath("businessNumber").description("사업자등록번호")
),
responseFields(
fieldWithPath("code").description("결과코드 SUCCESS/ERROR"),
fieldWithPath("message").description("메시지"),
fieldWithPath("data").description("데이터")
)
))
;
}
@Test @Test
@DisplayName("[GET] 고객 리스트 조회") @DisplayName("[GET] 고객 리스트 조회")
void getCustomers() throws Exception { void getCustomers() throws Exception {

View File

@@ -0,0 +1,96 @@
package com.justpickup.userservice.domain.user.web;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.justpickup.userservice.config.TestConfig;
import com.justpickup.userservice.domain.user.service.UserService;
import com.justpickup.userservice.global.security.SecurityConfig;
import com.justpickup.userservice.global.utils.CookieProvider;
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.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.boot.test.mock.mockito.SpyBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@WebMvcTest(controllers = UserOwnerApiController.class,
excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)}
)
@AutoConfigureMockMvc(addFilters = false)
@Import(TestConfig.class)
@AutoConfigureRestDocs(uriHost = "admin.just-pickup.com", uriPort = 8001)
class UserOwnerApiControllerTest {
@Autowired
MockMvc mockMvc;
@Autowired
ObjectMapper objectMapper;
@SpyBean
CookieProvider cookieProvider;
@MockBean
UserService userService;
@Test
@DisplayName("점주 서비스 회원가입")
void postStoreOwner() throws Exception {
// GIVEN
UserOwnerApiController.PostStoreOwnerRequest requestBody
= UserOwnerApiController.PostStoreOwnerRequest.builder()
.email("test@gmail.com")
.password("1234")
.name("테스트 이름")
.phoneNumber("010-1234-5678")
.businessNumber("03124")
.storeName("테스트 매장")
.storePhoneNumber("010-1234-5678")
.address("충북 청주시 서원구 1순환로 627")
.zipcode("28562")
.latitude(36.6375346629654)
.longitude(127.459726819858)
.build();
String content = objectMapper.writeValueAsString(requestBody);
// THEN
ResultActions actions = mockMvc.perform(post("/api/owner/store-owner")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(content)
);
// WHEN
actions.andExpect(status().isCreated())
.andDo(print())
.andDo(document("api-owner-post-store-owner",
requestFields(
fieldWithPath("email").description("이메일"),
fieldWithPath("password").description("비밀번호"),
fieldWithPath("name").description("이름"),
fieldWithPath("phoneNumber").description("핸드폰 번호"),
fieldWithPath("businessNumber").description("사업자번호"),
fieldWithPath("storeName").description("매장 이름"),
fieldWithPath("storePhoneNumber").description("매장 번호"),
fieldWithPath("address").description("매장 주소"),
fieldWithPath("zipcode").description("매장 우편번호"),
fieldWithPath("latitude").description("위도"),
fieldWithPath("longitude").description("경도")
)
)
)
;
}
}