diff --git a/application/src/main/java/com/groom/yummy/config/SecurityConfig.java b/application/src/main/java/com/groom/yummy/config/SecurityConfig.java index d9b9500..5611251 100644 --- a/application/src/main/java/com/groom/yummy/config/SecurityConfig.java +++ b/application/src/main/java/com/groom/yummy/config/SecurityConfig.java @@ -51,6 +51,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ http.authorizeHttpRequests((auth) -> auth .requestMatchers( "/login/**", "/oauth2/**", "/oauth2/authorization/**").permitAll() .requestMatchers("/swagger-ui/**", "/v3/api-docs/**", "/swagger-resources/**", "/webjars/**").permitAll() // Swagger 관련 경로 허용 + .requestMatchers("/api/v1/test/users/*").permitAll() .anyRequest().authenticated()); //세션 설정 : STATELESS diff --git a/application/src/main/java/com/groom/yummy/controller/StoreController.java b/application/src/main/java/com/groom/yummy/controller/StoreController.java index 38ec0c3..218b560 100644 --- a/application/src/main/java/com/groom/yummy/controller/StoreController.java +++ b/application/src/main/java/com/groom/yummy/controller/StoreController.java @@ -1,26 +1,32 @@ package com.groom.yummy.controller; import com.groom.yummy.dto.ResponseDto; +import com.groom.yummy.external.StoreApiClient; +import com.groom.yummy.external.dto.ApiResponse; +import com.groom.yummy.external.dto.StoreListResponse; +import com.groom.yummy.external.dto.StoreRequestDto; +import com.groom.yummy.external.dto.StoreResponseDto; import com.groom.yummy.store.Category; import com.groom.yummy.store.StoreService; import com.groom.yummy.store.dto.StoreApiResponseDto; import com.groom.yummy.webclient.SomeApiService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.util.List; +@Tag(name = "[Store] Store API") @RestController @RequestMapping("/api/v1/stores") @RequiredArgsConstructor public class StoreController { private final SomeApiService someApiService; private final StoreService storeService; + private final StoreApiClient storeApiClient; @GetMapping("/sync") public ResponseEntity> syncStores(@RequestParam String regionCode) { @@ -42,6 +48,24 @@ public ResponseEntity> syncStores(@RequestParam String regionC .body(new ResponseDto<>(null, "가게 데이터 동기화 중 오류 발생")); } } + @Operation(summary = "가게 정보 조회", description = "가게 id로 가게를 조회합니다.") + @GetMapping("/{storeId}") + public ResponseEntity> getStore(@PathVariable("storeId") Long storeId) { + StoreResponseDto storeResponseDTO = storeApiClient.getStoreByApi(storeId); + return ResponseEntity.ok(ResponseDto.of(storeResponseDTO,"storeId로 가게 조회 성공")); + } + + @Operation(summary = "가게 조회", description = "가게들을 정렬 기준에 맞게 조회합니다.") + @GetMapping + public ResponseEntity> getStoresByFilters( + @RequestParam(name = "category", required = false) Category category, + @RequestParam(name = "regionId", required = false) Long regionId, + @RequestParam(name = "name", required = false) String name, + @RequestParam(name = "page", defaultValue = "1") int page, + @RequestParam(name = "size", defaultValue = "10") int size) { + ApiResponse storeListResponseApiResponse = storeApiClient.getStoresByFilters(category, regionId,name,page,size); + return ResponseEntity.ok(storeListResponseApiResponse); + } } diff --git a/application/src/main/java/com/groom/yummy/external/StoreApiClient.java b/application/src/main/java/com/groom/yummy/external/StoreApiClient.java new file mode 100644 index 0000000..1b32b88 --- /dev/null +++ b/application/src/main/java/com/groom/yummy/external/StoreApiClient.java @@ -0,0 +1,42 @@ +package com.groom.yummy.external; + +import com.groom.yummy.external.dto.ApiResponse; +import com.groom.yummy.external.dto.StoreListResponse; +import com.groom.yummy.external.dto.StoreResponseDto; +import com.groom.yummy.store.Category; +import lombok.RequiredArgsConstructor; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.client.WebClient; + +@Service +@RequiredArgsConstructor +public class StoreApiClient { + private final WebClient webClient; + + public StoreResponseDto getStoreByApi(Long storeId){ + StoreResponseDto storeResponse = webClient.get() + .uri(uriBuilder -> uriBuilder.path("/api/v1/store/{id}") + .build(storeId)) + .retrieve() + .bodyToMono(StoreResponseDto.class) + .block(); + return storeResponse; + } + + public ApiResponse getStoresByFilters( + Category category, Long regionId, String name, int page, int size) { + return webClient.get() + .uri(uriBuilder -> uriBuilder + .path("/api/v1/stores") + .queryParam("category", category) + .queryParam("regionId", regionId) + .queryParam("name", name) + .queryParam("page", page) + .queryParam("size", size) + .build()) + .retrieve() + .bodyToMono(new ParameterizedTypeReference>() {}) + .block(); + } +} diff --git a/application/src/main/java/com/groom/yummy/external/dto/ApiResponse.java b/application/src/main/java/com/groom/yummy/external/dto/ApiResponse.java new file mode 100644 index 0000000..1177aa8 --- /dev/null +++ b/application/src/main/java/com/groom/yummy/external/dto/ApiResponse.java @@ -0,0 +1,6 @@ +package com.groom.yummy.external.dto; + +public record ApiResponse( + T data, + String message +) {} diff --git a/application/src/main/java/com/groom/yummy/external/dto/PaginationInfo.java b/application/src/main/java/com/groom/yummy/external/dto/PaginationInfo.java new file mode 100644 index 0000000..36de235 --- /dev/null +++ b/application/src/main/java/com/groom/yummy/external/dto/PaginationInfo.java @@ -0,0 +1,9 @@ +package com.groom.yummy.external.dto; + +public record PaginationInfo( + int page, + int size, + int totalPages, + long totalElements +) { +} diff --git a/application/src/main/java/com/groom/yummy/external/dto/StoreListResponse.java b/application/src/main/java/com/groom/yummy/external/dto/StoreListResponse.java new file mode 100644 index 0000000..951a967 --- /dev/null +++ b/application/src/main/java/com/groom/yummy/external/dto/StoreListResponse.java @@ -0,0 +1,9 @@ +package com.groom.yummy.external.dto; + +import java.util.List; + + +public record StoreListResponse( + List stores, + PaginationInfo pageable +) {} diff --git a/application/src/main/java/com/groom/yummy/external/dto/StoreRequestDto.java b/application/src/main/java/com/groom/yummy/external/dto/StoreRequestDto.java new file mode 100644 index 0000000..7b768f0 --- /dev/null +++ b/application/src/main/java/com/groom/yummy/external/dto/StoreRequestDto.java @@ -0,0 +1,12 @@ +package com.groom.yummy.external.dto; + +import com.groom.yummy.store.Category; +import lombok.Builder; + +@Builder +public record StoreRequestDto( + String name, + Category category, + Long regionId +) { +} diff --git a/application/src/main/java/com/groom/yummy/external/dto/StoreResponseDto.java b/application/src/main/java/com/groom/yummy/external/dto/StoreResponseDto.java new file mode 100644 index 0000000..5b2f222 --- /dev/null +++ b/application/src/main/java/com/groom/yummy/external/dto/StoreResponseDto.java @@ -0,0 +1,13 @@ +package com.groom.yummy.external.dto; + +import com.groom.yummy.store.Category; +import lombok.Builder; + +@Builder +public record StoreResponseDto( + Long storeId, + String name, + Category category, + Long regionId +) { +} diff --git a/application/src/main/java/com/groom/yummy/test/TestCreateController.java b/application/src/main/java/com/groom/yummy/test/TestCreateController.java new file mode 100644 index 0000000..91b38e7 --- /dev/null +++ b/application/src/main/java/com/groom/yummy/test/TestCreateController.java @@ -0,0 +1,79 @@ +package com.groom.yummy.test; + +import com.groom.yummy.dto.ResponseDto; +import com.groom.yummy.jwt.JwtProvider; +import com.groom.yummy.test.dto.SignInDto; +import com.groom.yummy.test.dto.TestUserCreateDto; +import com.groom.yummy.test.dto.TestUserResDto; +import com.groom.yummy.user.User; +import com.groom.yummy.user.UserRepository; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseCookie; +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 java.util.Optional; + +import static org.springframework.http.HttpHeaders.SET_COOKIE; + +@Tag(name = "[TestUser] TestUser API") +@RestController +@RequiredArgsConstructor +@Slf4j +@RequestMapping("/api/v1/test/users") +public class TestCreateController { + + private final JwtProvider jwtProvider; + private final UserRepository userRepository; + + @Operation(summary = "회원가입", description = "회원 가입 할 유저의 정보를 입력합니다. " + + "
회원가입이 완료되면 자동으로 유저의 기본 profile 사진이 등록됩니다." + + "
이후에 유저의 Token 을 통해 profile 사진을 수정할 수 있습니다.") + @PostMapping("/sign-up") + public ResponseEntity> signUp(@Valid @RequestBody TestUserCreateDto testUserCreateDto){ + User user = User.builder() + .email(testUserCreateDto.email()) + .nickname(testUserCreateDto.nickname()) + .role("ROLE_USER") + .groupJoinCount(0L) + .groupAttendanceCount(0L) + .isDeleted(false) + .build(); + + user = userRepository.save(user); + TestUserResDto testUserResDto = TestUserResDto.from(user); + return ResponseEntity.status(HttpStatus.CREATED).body( + new ResponseDto<>( + testUserResDto, + "테스트 유저 생성 성공")); + } + + + @Operation(summary = "로그인", description = "회원 가입 한 유저의 loginId와 password를 입력합니다.") + @PostMapping("/sign-in") + public ResponseEntity> signIn(@Valid @RequestBody SignInDto signInReqDto){ + + Optional optionalUser = userRepository.findByEmail(signInReqDto.email()); + User user = optionalUser.get(); + String accessToken = jwtProvider.createAccessToken(user.getId(), user.getEmail(),user.getNickname(),user.getRole()); + ResponseCookie cookie = ResponseCookie.from("Authorization", accessToken) + .httpOnly(true) + .secure(true) + .path("/") + .maxAge(120) + .sameSite("Strict") + .build(); + + return ResponseEntity.status(HttpStatus.OK) + .header(SET_COOKIE, cookie.toString()) + .body(new ResponseDto<>(1, "성공하였습니당.")); + } +} diff --git a/application/src/main/java/com/groom/yummy/test/dto/SignInDto.java b/application/src/main/java/com/groom/yummy/test/dto/SignInDto.java new file mode 100644 index 0000000..1a04d9d --- /dev/null +++ b/application/src/main/java/com/groom/yummy/test/dto/SignInDto.java @@ -0,0 +1,6 @@ +package com.groom.yummy.test.dto; + +public record SignInDto( + String email +) { +} diff --git a/application/src/main/java/com/groom/yummy/test/dto/TestUserCreateDto.java b/application/src/main/java/com/groom/yummy/test/dto/TestUserCreateDto.java new file mode 100644 index 0000000..5636750 --- /dev/null +++ b/application/src/main/java/com/groom/yummy/test/dto/TestUserCreateDto.java @@ -0,0 +1,7 @@ +package com.groom.yummy.test.dto; + +public record TestUserCreateDto( + String nickname, + String email +) { +} diff --git a/application/src/main/java/com/groom/yummy/test/dto/TestUserResDto.java b/application/src/main/java/com/groom/yummy/test/dto/TestUserResDto.java new file mode 100644 index 0000000..5ee953b --- /dev/null +++ b/application/src/main/java/com/groom/yummy/test/dto/TestUserResDto.java @@ -0,0 +1,23 @@ +package com.groom.yummy.test.dto; + +import com.groom.yummy.user.User; +import lombok.Builder; + +@Builder +public record TestUserResDto( + Long id, + String email, + String nickname, + Long joinCount, + Long participationCount +) { + public static TestUserResDto from(User user){ + return TestUserResDto.builder() + .id(user.getId()) + .email(user.getEmail()) + .nickname(user.getNickname()) + .joinCount(user.getGroupJoinCount()) + .participationCount(user.getGroupAttendanceCount()) + .build(); + } +} diff --git a/application/src/main/resources/application.yml b/application/src/main/resources/application.yml index 1a58b67..bb36afa 100644 --- a/application/src/main/resources/application.yml +++ b/application/src/main/resources/application.yml @@ -7,7 +7,7 @@ spring: jpa: hibernate: - ddl-auto: update + ddl-auto: create show-sql: true open-in-view: false properties: diff --git a/application/src/test/java/com/groom/yummy/controller/UserControllerTest.java b/application/src/test/java/com/groom/yummy/controller/UserControllerTest.java index 61022f5..86e3b67 100644 --- a/application/src/test/java/com/groom/yummy/controller/UserControllerTest.java +++ b/application/src/test/java/com/groom/yummy/controller/UserControllerTest.java @@ -35,7 +35,6 @@ @ActiveProfiles("test") @Import({SecurityConfig.class}) @WebMvcTest(controllers = {UserController.class}) -@ExtendWith(MockitoExtension.class) // Mockito 확장 사용 class UserControllerTest { @Autowired