Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import backend.airo.api.annotation.UserPrincipal;
import backend.airo.api.global.dto.Response;
import backend.airo.api.post.dto.*;
import backend.airo.domain.post.Post;
import backend.airo.domain.user.User;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
Expand All @@ -16,6 +17,7 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Positive;
import org.springframework.data.domain.Slice;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -82,6 +84,18 @@ Response<PostListResponse> getPostList(



@Operation(summary = "게시물 스크롤 조회", description = "최신순 스크롤 게시물 목록을 조회합니다.")
@ApiResponses(value = {
@ApiResponse(responseCode = "200",
description = "게시물 목록 조회 성공",
content = @Content(schema = @Schema(implementation = PostListResponse.class)))
})
@GetMapping
Response<PostSliceResponse> getPostSlice(
@Valid @ModelAttribute PostSliceRequest request);




@Operation(summary = "게시물 수정", description = "기존 게시물을 수정합니다.")
@ApiResponses(value = {
Expand Down
30 changes: 12 additions & 18 deletions src/main/java/backend/airo/api/image/ImageController.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
import backend.airo.api.image.dto.ImageCreateRequest;
import backend.airo.api.image.dto.ImageReorderRequest;
import backend.airo.api.image.dto.ImageResponse;
import backend.airo.application.image.usecase.ImageCreateUseCase;
import backend.airo.application.image.usecase.ImageDeleteUseCase;
import backend.airo.application.image.usecase.ImageReadUseCase;
import backend.airo.application.image.usecase.ImageUpdateUseCase;
import backend.airo.application.image.usecase.ImageUseCase;
import backend.airo.domain.image.Image;
import backend.airo.domain.user.User;
import jakarta.validation.Valid;
Expand All @@ -32,10 +29,7 @@
@RequiredArgsConstructor
public class ImageController implements ImageControllerSwagger {

private final ImageReadUseCase imageReadUseCase;
private final ImageCreateUseCase imageCreateUseCase;
private final ImageUpdateUseCase imageUpdateUseCase;
private final ImageDeleteUseCase imageDeleteUseCase;
private final ImageUseCase imageUseCase;

@Override
@PostMapping
Expand All @@ -46,7 +40,7 @@ public Response<ImageResponse> uploadSingleImage(

log.info("단일 이미지 업로드 요청 - 사용자 ID: {}, 이미지 URL: {}", user.getId(), request.imageUrl());

Image image = imageCreateUseCase.uploadSingleImage(request.toImage(user.getId()));
Image image = imageUseCase.uploadSingleImage(request.toImage(user.getId()));
ImageResponse response = ImageResponse.from(image);
return Response.success(response);
}
Expand All @@ -64,7 +58,7 @@ public Response<List<ImageResponse>> uploadMultipleImages(
.map(request -> request.toImage(user.getId()))
.toList();

List<Image> uploadedImages = imageCreateUseCase.uploadMultipleImages(images);
List<Image> uploadedImages = imageUseCase.uploadMultipleImages(images);
List<ImageResponse> responses = uploadedImages.stream()
.map(ImageResponse::from)
.toList();
Expand All @@ -77,7 +71,7 @@ public Response<List<ImageResponse>> uploadMultipleImages(
public Response<ImageResponse> getImage(@PathVariable @Min(1) Long imageId) {
log.info("이미지 조회 요청 - 이미지 ID: {}", imageId);

Image image = imageReadUseCase.getSingleImage(imageId);
Image image = imageUseCase.getSingleImage(imageId);
ImageResponse response = ImageResponse.from(image);

return Response.success(response);
Expand All @@ -88,7 +82,7 @@ public Response<ImageResponse> getImage(@PathVariable @Min(1) Long imageId) {
public Response<List<ImageResponse>> getImagesByPost(@PathVariable Long postId) {
log.info("게시물별 이미지 목록 조회 요청 - 게시물 ID: {}", postId);

List<Image> images = imageReadUseCase.getSortedImagesByPost(postId);
List<Image> images = imageUseCase.getSortedImagesByPost(postId);
List<ImageResponse> responses = images.stream()
.map(ImageResponse::from)
.toList();
Expand All @@ -101,7 +95,7 @@ public Response<List<ImageResponse>> getImagesByPost(@PathVariable Long postId)
public Response<Page<ImageResponse>> getImages(Pageable pageable) {
log.info("이미지 목록 조회 요청 - 페이지: {}, 크기: {}", pageable.getPageNumber(), pageable.getPageSize());

Page<Image> images = imageReadUseCase.getPagedImages(pageable);
Page<Image> images = imageUseCase.getPagedImages(pageable);
Page<ImageResponse> responses = images.map(ImageResponse::from);

return Response.success(responses);
Expand All @@ -116,7 +110,7 @@ public Response<List<ImageResponse>> reorderImages(
) {
log.info("이미지 순서 재정렬 요청 - 사용자 ID: {}, 이미지 개수: {}", user.getId(), request.imageIds().size());

List<Image> reorderedImages = imageUpdateUseCase.reorderImages(request.imageIds());
List<Image> reorderedImages = imageUseCase.reorderImages(request.imageIds());
List<ImageResponse> responses = reorderedImages.stream()
.map(ImageResponse::from)
.toList();
Expand All @@ -132,7 +126,7 @@ public Response<Void> deleteImage(
@PathVariable Long imageId) {
log.info("이미지 삭제 요청 - 사용자 ID: {}, 이미지 ID: {}", user.getId(), imageId);

imageDeleteUseCase.deleteImageWithAuth(imageId, user.getId());
imageUseCase.deleteImageWithAuth(imageId, user.getId());
return Response.success("삭제 성공");
}

Expand All @@ -145,7 +139,7 @@ public Response<Void> deleteMultipleImages(
) {
log.info("다중 이미지 삭제 요청 - 사용자 ID: {}, 이미지 개수: {}", user.getId(), imageIds.size());

imageDeleteUseCase.deleteMultipleImages(imageIds, user.getId());
imageUseCase.deleteMultipleImages(imageIds, user.getId());
return Response.success("삭제 성공");
}

Expand All @@ -157,7 +151,7 @@ public Response<Page<ImageResponse>> getMyImages(
) {
log.info("내 이미지 목록 조회 요청 - 사용자 ID: {}", user.getId());

Page<Image> images = imageReadUseCase.getPagedImages(pageable);
Page<Image> images = imageUseCase.getPagedImages(pageable);
Page<ImageResponse> responses = images.map(ImageResponse::from);

return Response.success(responses);
Expand All @@ -171,7 +165,7 @@ public Response<List<ImageResponse>> getMyImagesByPost(
) {
log.info("내 게시물 이미지 목록 조회 요청 - 사용자 ID: {}, 게시물 ID: {}", user.getId(), postId);

List<Image> images = imageReadUseCase.getSortedImagesByPost(postId);
List<Image> images = imageUseCase.getSortedImagesByPost(postId);
List<ImageResponse> responses = images.stream()
.map(ImageResponse::from)
.toList();
Expand Down
42 changes: 28 additions & 14 deletions src/main/java/backend/airo/api/post/PostController.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
import backend.airo.api.annotation.UserPrincipal;
import backend.airo.api.global.dto.Response;
import backend.airo.api.global.swagger.PostControllerSwagger;
import backend.airo.application.post.usecase.PostCreateUseCase;
import backend.airo.application.post.usecase.PostDeleteUseCase;
import backend.airo.application.post.usecase.PostReadUseCase;
import backend.airo.application.post.usecase.PostUpdateUseCase;
import backend.airo.application.post.usecase.PostCacheUseCase;
import backend.airo.application.post.usecase.PostUseCase;
import backend.airo.domain.post.Post;
import backend.airo.api.post.dto.*;
import backend.airo.domain.user.User;
Expand All @@ -16,6 +14,7 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Slice;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
Expand All @@ -28,10 +27,7 @@
@RequiredArgsConstructor
public class PostController implements PostControllerSwagger {

private final PostCreateUseCase postCreateUseCase;
private final PostReadUseCase postReadUseCase;
private final PostUpdateUseCase postUpdateUseCase;
private final PostDeleteUseCase postDeleteUseCase;
private final PostCacheUseCase postUseCase;

// ===== 게시물 생성 =====

Expand All @@ -45,7 +41,7 @@ public Response<PostResponse> createPost(

log.info("게시물 생성 요청: title={}, userId={}", request.title(), user.getId());

Post createdPost = postCreateUseCase.createPost(request, user.getId());
Post createdPost = postUseCase.createPost(request, user.getId());
PostResponse response = PostResponse.fromDomain(createdPost);

return Response.success(response);
Expand All @@ -60,7 +56,7 @@ public Response<PostDetailResponse> getPost(
@UserPrincipal User user,
@PathVariable @Positive Long postId) {

PostDetailResponse response = postReadUseCase.getPostDetail(postId, user.getId());
PostDetailResponse response = postUseCase.getPostDetail(postId, user.getId());

return Response.success(response);
}
Expand All @@ -72,22 +68,40 @@ public Response<ThumbnailResponseDto> getThumbnail(
@UserPrincipal User user,
@PathVariable @Positive Long thumbnailId) {

ThumbnailResponseDto response = postReadUseCase.getThumbnailById(thumbnailId);
ThumbnailResponseDto response = postUseCase.getThumbnailById(thumbnailId);

return Response.success(response);
}

// ===== 게시물 List조회 =====

@Override
@GetMapping
public Response<PostListResponse> getPostList(
@Valid @ModelAttribute PostListRequest request) {

Page<Post> postPage = postReadUseCase.getPostList(request);
Page<Post> postPage = postUseCase.getPostList(request);
PostListResponse response = PostListResponse.fromDomain(postPage);

return Response.success(response);
}

@Override
@GetMapping("/scroll")
public Response<PostSliceResponse> getPostSlice(
@Valid @ModelAttribute PostSliceRequest request) {

log.debug("무한스크롤 조회 요청: size={}, lastPostId={}",
request.size(), request.lastPostId());

Slice<PostSummaryResponse> postSlice = postUseCase.getPostSlice(request);
PostSliceResponse response = PostSliceResponse.fromDomain(postSlice);

return Response.success(response);
}



// ===== 게시물 수정 =====
@Override
@PutMapping("/{postId}")
Expand All @@ -97,7 +111,7 @@ public Response<PostResponse> updatePost(
@PathVariable @Positive Long postId,
@Valid @RequestBody PostUpdateRequest request,
@UserPrincipal User user) {
Post updatedPost = postUpdateUseCase.updatePost(postId, user.getId(), request);
Post updatedPost = postUseCase.updatePost(postId, user.getId(), request);

PostResponse response = PostResponse.fromDomain(updatedPost);

Expand All @@ -112,7 +126,7 @@ public Response<Void> deletePost(
@PathVariable @Positive Long postId,
@UserPrincipal User user) {

postDeleteUseCase.deletePost(postId, user.getId());
postUseCase.deletePost(postId, user.getId());

return Response.success("삭제 성공");
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/backend/airo/api/post/dto/PostListRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import jakarta.validation.constraints.*;

import java.util.List;
import java.util.Objects;

/**
* 게시물 목록 조회 요청 DTO
Expand All @@ -26,4 +27,9 @@ public record PostListRequest(
if (sortBy == null) sortBy = "publishedAt";
if (status == null) status = PostStatus.PUBLISHED;
}

@Override
public int hashCode() {
return Objects.hash(page, size, keyword, status);
}
}
25 changes: 25 additions & 0 deletions src/main/java/backend/airo/api/post/dto/PostSliceRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package backend.airo.api.post.dto;

import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.Positive;

import java.util.Objects;

public record PostSliceRequest(
@Min(value = 1, message = "사이즈는 1 이상이어야 합니다")
@Max(value = 100, message = "사이즈는 100 이하여야 합니다")
int size,

@Positive(message = "마지막 게시물 ID는 양수여야 합니다")
Long lastPostId
) {
public PostSliceRequest {
if (size <= 0) size = 20; // 기본값
}

@Override
public int hashCode() {
return Objects.hash(size, lastPostId);
}
}
42 changes: 42 additions & 0 deletions src/main/java/backend/airo/api/post/dto/PostSliceResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package backend.airo.api.post.dto;

import backend.airo.domain.post.Post;
import org.springframework.data.domain.Slice;

import java.util.List;

public record PostSliceResponse(
List<PostSummaryResponse> posts,
boolean hasNext,
int size,
Long lastPostId
) {
// public static PostSliceResponse fromDomain(Slice<Post> slice) {
// List<PostSummaryResponse> posts = slice.getContent().stream()
// .map(PostSummaryResponse::fromDomain)
// .toList();
//
// Long lastPostId = posts.isEmpty() ? null :
// posts.get(posts.size() - 1).id();
//
// return new PostSliceResponse(
// posts,
// slice.hasNext(),
// slice.getSize(),
// lastPostId
// );
// }


public static PostSliceResponse fromDomain(Slice<PostSummaryResponse> slice) {
Long lastPostId = slice.getContent().isEmpty() ? null :
slice.getContent().get(slice.getContent().size() - 1).id();

return new PostSliceResponse(
slice.getContent(),
slice.hasNext(),
slice.getSize(),
lastPostId
);
}
}
46 changes: 46 additions & 0 deletions src/main/java/backend/airo/api/post/dto/PostSummaryResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package backend.airo.api.post.dto;

import backend.airo.domain.post.Post;
import backend.airo.domain.post.enums.PostEmotionTag;
import backend.airo.domain.post.enums.PostStatus;
import com.fasterxml.jackson.annotation.JsonTypeInfo;

import java.util.ArrayList;
import java.util.List;

@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public record PostSummaryResponse(
Long id,
String title,
String content,
PostStatus status,
Integer viewCount,
List<PostEmotionTag> emotionTags,
Long userId
// LocalDateTime createdAt,
// LocalDateTime updatedAt
) {
public static PostSummaryResponse fromDomain(Post post) {
return new PostSummaryResponse(
post.getId(),
post.getTitle(),
post.getContent(),
post.getStatus(),
post.getViewCount(),
post.getEmotionTags() != null ?
new ArrayList<>(post.getEmotionTags()) : new ArrayList<>(),
post.getUserId()
);
}

public PostSummaryResponse(
Long id,
String title,
String content,
PostStatus status,
Integer viewCount,
Long userId
) {
this(id, title, content, status, viewCount, new ArrayList<>(), userId);
}
}
Loading