diff --git a/.gitignore b/.gitignore index 028fb02..6ea9293 100644 --- a/.gitignore +++ b/.gitignore @@ -36,7 +36,7 @@ out/ ### VS Code ### .vscode/ -/src/main/resources/*.env +*.env *.yml /src/main/generated/ diff --git a/build.gradle b/build.gradle index 7994f2c..e8ab524 100644 --- a/build.gradle +++ b/build.gradle @@ -30,6 +30,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-oauth2-client' implementation 'org.springframework.boot:spring-boot-starter-webflux' implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.mysql:mysql-connector-j' diff --git a/src/main/java/naughty/tuzamate/domain/post/controller/PostController.java b/src/main/java/naughty/tuzamate/domain/post/controller/PostController.java index 2967fa8..66d5048 100644 --- a/src/main/java/naughty/tuzamate/domain/post/controller/PostController.java +++ b/src/main/java/naughty/tuzamate/domain/post/controller/PostController.java @@ -49,7 +49,7 @@ public CustomResponse getPost(@PathVariable Long post public CustomResponse getPostList( @PathVariable BoardType boardType, @RequestParam(required = false) Long cursor, - @RequestParam(defaultValue = "10") @Max(30) int size) { + @RequestParam(defaultValue = "10") @Max(10) int size) { PostResDTO.PostPreviewListDTO resDTO = postQueryService.getPostList(boardType, cursor, size); return CustomResponse.onSuccess(GeneralSuccessCode.OK, resDTO); diff --git a/src/main/java/naughty/tuzamate/domain/post/converter/PostConverter.java b/src/main/java/naughty/tuzamate/domain/post/converter/PostConverter.java index 2821964..a5d3750 100644 --- a/src/main/java/naughty/tuzamate/domain/post/converter/PostConverter.java +++ b/src/main/java/naughty/tuzamate/domain/post/converter/PostConverter.java @@ -9,6 +9,7 @@ import naughty.tuzamate.domain.user.entity.User; import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; @NoArgsConstructor(access = AccessLevel.PRIVATE) diff --git a/src/main/java/naughty/tuzamate/domain/post/service/query/PostQueryServiceImpl.java b/src/main/java/naughty/tuzamate/domain/post/service/query/PostQueryServiceImpl.java index 2148e42..8586228 100644 --- a/src/main/java/naughty/tuzamate/domain/post/service/query/PostQueryServiceImpl.java +++ b/src/main/java/naughty/tuzamate/domain/post/service/query/PostQueryServiceImpl.java @@ -9,6 +9,7 @@ import naughty.tuzamate.global.error.GeneralErrorCode; import naughty.tuzamate.global.error.exception.CustomException; import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -36,15 +37,17 @@ public PostResDTO.PostPreviewDTO getPost(Long postId) { @Override @Transactional(readOnly = true) public PostResDTO.PostPreviewListDTO getPostList(BoardType boardType, Long cursor, int size) { - PageRequest pr = PageRequest.of(0, size); - Slice slice = postRepository.findByBoardTypeAndCursor(boardType, cursor, pr); + cursor = normalizeCursor(cursor); + size = normalizeSize(size); - List previews = slice.getContent() - .stream() + Pageable pageable = PageRequest.of(0, size); + Slice slice = postRepository.findByBoardTypeAndCursor(boardType, cursor, pageable); + + List previews = slice.stream() .map(PostConverter::toPostPreviewDTO) .toList(); - Long nextCursor = slice.hasNext() ? previews.get(previews.size() - 1).id() : null; + Long nextCursor = (slice.hasNext() && !previews.isEmpty()) ? previews.get(previews.size() - 1).id() : null; return PostResDTO.PostPreviewListDTO.builder() .postPreviewDTOList(previews) @@ -52,4 +55,13 @@ public PostResDTO.PostPreviewListDTO getPostList(BoardType boardType, Long curso .hasNext(slice.hasNext()) .build(); } + + private Long normalizeCursor(Long cursor) { + return (cursor == null || cursor == 0) ? Long.MAX_VALUE : cursor; + } + + // 요청 사이즈가 1보다 작으면 기본값 10, 10보다 크면 최대값 10으로 제한 + private int normalizeSize(int size) { + return (size < 1 || size > 10) ? 10 : size; + } } \ No newline at end of file diff --git a/src/main/java/naughty/tuzamate/global/config/FireBaseConfig.java b/src/main/java/naughty/tuzamate/global/config/FireBaseConfig.java index 085e9fa..dc06844 100644 --- a/src/main/java/naughty/tuzamate/global/config/FireBaseConfig.java +++ b/src/main/java/naughty/tuzamate/global/config/FireBaseConfig.java @@ -9,30 +9,43 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; @Slf4j @Configuration public class FireBaseConfig { + // String 대신 Resource 타입으로 주입받음 @Value("${firebase.service-account.path}") - private String SERVICE_ACCOUNT_PATH; + private Resource serviceAccountResource; @Bean public FirebaseApp firebaseApp() { - try (FileInputStream serviceAccount = new FileInputStream(SERVICE_ACCOUNT_PATH)) { + try { + // 주입받은 Resource에서 바로 InputStream을 얻음 + InputStream serviceAccount = serviceAccountResource.getInputStream(); + FirebaseOptions options = FirebaseOptions.builder() .setCredentials(GoogleCredentials.fromStream(serviceAccount)) .build(); - log.info("Successfully initialized firebase app"); - return FirebaseApp.initializeApp(options); + // 앱이 이미 초기화되었는지 확인 (중복 초기화 방지) + if (FirebaseApp.getApps().isEmpty()) { + log.info("Successfully initialized firebase app"); + return FirebaseApp.initializeApp(options); + } else { + return FirebaseApp.getInstance(); + } } catch (IOException exception) { log.error("Fail to initialize firebase app: {}", exception.getMessage(), exception); - return null; + // 초기화 실패 시 null 대신 예외를 던져서 애플리케이션이 문제를 인지하게 하는 것이 더 좋습니다. + throw new RuntimeException("Failed to initialize Firebase app.", exception); } }