feat(회원가입 매장 등록 로직 추가): 회원가입 시 매장 정보 입력 추가

This commit is contained in:
bum12ark
2022-03-21 13:08:19 +09:00
parent be5e3abbee
commit 064797b6f4
15 changed files with 305 additions and 62 deletions

View File

@@ -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 {

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.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;
}

View File

@@ -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<CustomerDto> findCustomerByUserIds(List<Long> userIds);
StoreOwnerDto findOwnerById(Long userId);
void saveStoreOwner(PostOwnerDto toPostOwnerDto, PostStoreDto toPostStoreDto);
}

View File

@@ -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<CustomerDto> findCustomerByUserIds(List<Long> 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);
}
}

View File

@@ -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<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();
Result errorResult = ce.getErrorResult();
log.warn("[CustomException] {}, {}", status, errorResult);
return ResponseEntity.status(status)
.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.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;