diff --git a/user-service/src/main/java/com/justpickup/userservice/UserServiceApplication.java b/user-service/src/main/java/com/justpickup/userservice/UserServiceApplication.java index e7ad12a..bfefc09 100644 --- a/user-service/src/main/java/com/justpickup/userservice/UserServiceApplication.java +++ b/user-service/src/main/java/com/justpickup/userservice/UserServiceApplication.java @@ -3,8 +3,10 @@ package com.justpickup.userservice; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; +import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication +@EnableFeignClients @EnableEurekaClient public class UserServiceApplication { diff --git a/user-service/src/main/java/com/justpickup/userservice/domain/user/dto/PostOwnerDto.java b/user-service/src/main/java/com/justpickup/userservice/domain/user/dto/PostOwnerDto.java new file mode 100644 index 0000000..05b773f --- /dev/null +++ b/user-service/src/main/java/com/justpickup/userservice/domain/user/dto/PostOwnerDto.java @@ -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); + } + +} diff --git a/user-service/src/main/java/com/justpickup/userservice/domain/user/dto/PostStoreDto.java b/user-service/src/main/java/com/justpickup/userservice/domain/user/dto/PostStoreDto.java new file mode 100644 index 0000000..85a590f --- /dev/null +++ b/user-service/src/main/java/com/justpickup/userservice/domain/user/dto/PostStoreDto.java @@ -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(); + } +} diff --git a/user-service/src/main/java/com/justpickup/userservice/domain/user/entity/User.java b/user-service/src/main/java/com/justpickup/userservice/domain/user/entity/User.java index 757013b..ec79e70 100644 --- a/user-service/src/main/java/com/justpickup/userservice/domain/user/entity/User.java +++ b/user-service/src/main/java/com/justpickup/userservice/domain/user/entity/User.java @@ -4,6 +4,7 @@ import com.justpickup.userservice.global.entity.BaseEntity; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import javax.persistence.*; @@ -31,7 +32,7 @@ public abstract class User extends BaseEntity { public User(String email, String password, String name, String phoneNumber) { this.email = email; - this.password = password; + this.password = new BCryptPasswordEncoder().encode(password); this.name = name; this.phoneNumber = phoneNumber; } diff --git a/user-service/src/main/java/com/justpickup/userservice/domain/user/service/UserService.java b/user-service/src/main/java/com/justpickup/userservice/domain/user/service/UserService.java index 5a120c6..5f7bc63 100644 --- a/user-service/src/main/java/com/justpickup/userservice/domain/user/service/UserService.java +++ b/user-service/src/main/java/com/justpickup/userservice/domain/user/service/UserService.java @@ -1,13 +1,15 @@ package com.justpickup.userservice.domain.user.service; 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 java.util.List; public interface UserService { CustomerDto findCustomerByUserId(Long userId); - void saveStoreOwner(StoreOwnerDto storeOwnerDto); List findCustomerByUserIds(List userIds); StoreOwnerDto findOwnerById(Long userId); + void saveStoreOwner(PostOwnerDto toPostOwnerDto, PostStoreDto toPostStoreDto); } diff --git a/user-service/src/main/java/com/justpickup/userservice/domain/user/service/UserServiceImpl.java b/user-service/src/main/java/com/justpickup/userservice/domain/user/service/UserServiceImpl.java index 1c0aade..254523c 100644 --- a/user-service/src/main/java/com/justpickup/userservice/domain/user/service/UserServiceImpl.java +++ b/user-service/src/main/java/com/justpickup/userservice/domain/user/service/UserServiceImpl.java @@ -1,6 +1,8 @@ package com.justpickup.userservice.domain.user.service; 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.entity.Customer; 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.StoreOwnerRepository; import com.justpickup.userservice.domain.user.repository.UserRepository; +import com.justpickup.userservice.global.client.store.StoreClient; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; @@ -35,7 +37,7 @@ public class UserServiceImpl implements UserService, UserDetailsService { private final CustomerRepository customerRepository; private final StoreOwnerRepository storeOwnerRepository; private final UserRepository userRepository; - private final PasswordEncoder passwordEncoder; + private final StoreClient storeClient; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { @@ -55,22 +57,6 @@ public class UserServiceImpl implements UserService, UserDetailsService { 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 public List findCustomerByUserIds(List userIds) { return customerRepository.findAllById(userIds) @@ -87,4 +73,21 @@ public class UserServiceImpl implements UserService, UserDetailsService { 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); + + } } diff --git a/user-service/src/main/java/com/justpickup/userservice/domain/user/web/UserController.java b/user-service/src/main/java/com/justpickup/userservice/domain/user/web/UserController.java index 52392f4..15882b7 100644 --- a/user-service/src/main/java/com/justpickup/userservice/domain/user/web/UserController.java +++ b/user-service/src/main/java/com/justpickup/userservice/domain/user/web/UserController.java @@ -11,11 +11,12 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; 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.constraints.Email; -import javax.validation.constraints.NotEmpty; import java.util.List; import java.util.stream.Collectors; @@ -109,37 +110,4 @@ public class UserController { this.name = dto.getName(); } } - - @PostMapping("/store-owner") - public ResponseEntity 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(); - } - } - - } diff --git a/user-service/src/main/java/com/justpickup/userservice/domain/user/web/UserOwnerApiController.java b/user-service/src/main/java/com/justpickup/userservice/domain/user/web/UserOwnerApiController.java new file mode 100644 index 0000000..a6f025f --- /dev/null +++ b/user-service/src/main/java/com/justpickup/userservice/domain/user/web/UserOwnerApiController.java @@ -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 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(); + } + } +} diff --git a/user-service/src/main/java/com/justpickup/userservice/global/client/exception/FeignClientException.java b/user-service/src/main/java/com/justpickup/userservice/global/client/exception/FeignClientException.java new file mode 100644 index 0000000..57c0803 --- /dev/null +++ b/user-service/src/main/java/com/justpickup/userservice/global/client/exception/FeignClientException.java @@ -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); + } +} diff --git a/user-service/src/main/java/com/justpickup/userservice/global/client/exception/FeignClientExceptionErrorDecoder.java b/user-service/src/main/java/com/justpickup/userservice/global/client/exception/FeignClientExceptionErrorDecoder.java new file mode 100644 index 0000000..4d26d5d --- /dev/null +++ b/user-service/src/main/java/com/justpickup/userservice/global/client/exception/FeignClientExceptionErrorDecoder.java @@ -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); + } +} \ No newline at end of file diff --git a/user-service/src/main/java/com/justpickup/userservice/global/client/store/PostStoreRequest.java b/user-service/src/main/java/com/justpickup/userservice/global/client/store/PostStoreRequest.java new file mode 100644 index 0000000..50265f6 --- /dev/null +++ b/user-service/src/main/java/com/justpickup/userservice/global/client/store/PostStoreRequest.java @@ -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; + } +} diff --git a/user-service/src/main/java/com/justpickup/userservice/global/client/store/StoreClient.java b/user-service/src/main/java/com/justpickup/userservice/global/client/store/StoreClient.java new file mode 100644 index 0000000..f2cae96 --- /dev/null +++ b/user-service/src/main/java/com/justpickup/userservice/global/client/store/StoreClient.java @@ -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 postStore(@Valid @RequestBody PostStoreRequest postStoreRequest, + @RequestHeader("user-id") Long userId); +} diff --git a/user-service/src/main/java/com/justpickup/userservice/global/config/FeignClientConfig.java b/user-service/src/main/java/com/justpickup/userservice/global/config/FeignClientConfig.java new file mode 100644 index 0000000..d4b4e7b --- /dev/null +++ b/user-service/src/main/java/com/justpickup/userservice/global/config/FeignClientConfig.java @@ -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; + } +} diff --git a/user-service/src/main/java/com/justpickup/userservice/global/exception/GlobalExceptionHandler.java b/user-service/src/main/java/com/justpickup/userservice/global/exception/GlobalExceptionHandler.java index e1e6473..a15e4b2 100644 --- a/user-service/src/main/java/com/justpickup/userservice/global/exception/GlobalExceptionHandler.java +++ b/user-service/src/main/java/com/justpickup/userservice/global/exception/GlobalExceptionHandler.java @@ -27,6 +27,8 @@ public class GlobalExceptionHandler { HttpStatus status = ce.getStatus(); Result errorResult = ce.getErrorResult(); + log.warn("[CustomException] {}, {}", status, errorResult); + return ResponseEntity.status(status) .body(errorResult); } diff --git a/user-service/src/main/java/com/justpickup/userservice/global/security/SecurityConfig.java b/user-service/src/main/java/com/justpickup/userservice/global/security/SecurityConfig.java index 1f573a5..535a575 100644 --- a/user-service/src/main/java/com/justpickup/userservice/global/security/SecurityConfig.java +++ b/user-service/src/main/java/com/justpickup/userservice/global/security/SecurityConfig.java @@ -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.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.JwtTokenProvider; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; 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.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserService; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.crypto.password.PasswordEncoder; @Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig extends WebSecurityConfigurerAdapter { private final UserDetailsService userDetailsService; - private final BCryptPasswordEncoder bCryptPasswordEncoder; + private final PasswordEncoder bCryptPasswordEncoder; private final JwtTokenProvider jwtTokenProvider; private final RefreshTokenServiceImpl refreshTokenServiceImpl; private final CookieProvider cookieProvider;