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 site.kikihi.custom.global.response.page.PageRequest;
import site.kikihi.custom.global.response.page.SliceResponse;
import site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark.BookmarkRequest;
import site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark.BookmarkSyncRequest;
import site.kikihi.custom.platform.adapter.in.web.dto.request.product.CategoryType;
import site.kikihi.custom.platform.adapter.in.web.dto.response.bookmark.BookmarkListResponse;
import site.kikihi.custom.platform.adapter.in.web.swagger.BookmarkControllerSpec;
Expand All @@ -18,7 +19,7 @@
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;

import java.util.UUID;
import java.util.*;

@Slf4j
@RestController
Expand All @@ -39,17 +40,38 @@ public ApiResponse<String> saveBookmark(
@RequestBody @Valid BookmarkRequest request,
@AuthenticationPrincipal PrincipalDetails principalDetails) {

// 아이디 추출
/// 아이디 추출
UUID userId = principalDetails.getId();
request.setUserId(userId);

// 서비스 계층
service.saveBookmark(request);
/// 서비스 계층
service.saveBookmark(userId, request);

// 리턴
/// 리턴
return ApiResponse.created();
}

/**
* 로컬 스토리지에 저장한 북마크를 한번에 저장할 수 있도록 하는 서비스 로직
*
* @param request 북마크 생성 요청 DTO
*/
@PostMapping("/sync")
public ApiResponse<String> synceBookmark(
@AuthenticationPrincipal PrincipalDetails principalDetails,
@RequestBody BookmarkSyncRequest request
) {

/// 아이디 추출
UUID userId = principalDetails.getId();

/// 서비스 계층
service.syncBookmarks(userId, request);

/// 리턴
return ApiResponse.created();

}

/**
* 나의 북마크 목록을 조회합니다.
*
Expand Down Expand Up @@ -84,17 +106,20 @@ public ApiResponse<SliceResponse<BookmarkListResponse>> loadBookmarkByCategory(

/**
* 북마크를 삭제하는 로직입니다.
* @param bookmarkId 북마크 ID
* @param principalDetails 유저 ID
*
* @param ids 북마크 ID
* @param principalDetails 유저 ID
*/
@DeleteMapping("/{bookmarkId}")
public ApiResponse<String> deleteBookmark(@PathVariable Long bookmarkId,@AuthenticationPrincipal PrincipalDetails principalDetails) {
@DeleteMapping()
public ApiResponse<String> deleteBookmark(
@RequestParam List<Long> ids,
@AuthenticationPrincipal PrincipalDetails principalDetails) {

// 아이디 추출
UUID userId = principalDetails.getId();

// 서비스 계층
service.deleteBookmarkById(bookmarkId, userId);
service.deleteBookmarkById(ids, userId);

return ApiResponse.deleted();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@
)
public class BookmarkRequest {

@Schema(description = "북마크할 상품 ID", example = "101")
@Schema(description = "북마크할 상품 ID", example = "6896ed7d5198cf586e933d6e")
private String productId;

@Schema(description = "사용자 UUID", example = "95ea60b2-f63b-434e-afc5-d5e5d6a505e7")
private UUID userId;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import java.util.List;

@Data
public class BookmarkSyncRequest {

@Schema(description = "북마크할 상품들", example = "6896ed7d5198cf586e933d6e")
private List<BookmarkRequest> productIds;

}
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
package site.kikihi.custom.platform.adapter.in.web.swagger;

import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import site.kikihi.custom.global.response.ApiResponse;
import site.kikihi.custom.global.response.page.PageRequest;
import site.kikihi.custom.global.response.page.SliceResponse;
import site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark.BookmarkRequest;
import site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark.BookmarkSyncRequest;
import site.kikihi.custom.platform.adapter.in.web.dto.request.product.CategoryType;
import site.kikihi.custom.platform.adapter.in.web.dto.response.bookmark.BookmarkListResponse;
import site.kikihi.custom.security.oauth2.domain.PrincipalDetails;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.ExampleObject;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.http.MediaType;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.List;

@Tag(name = "북마크 API", description = "북마크 기능을 수행하는 API 입니다.")
public interface BookmarkControllerSpec {
Expand All @@ -32,21 +32,39 @@ public interface BookmarkControllerSpec {
*/
@Operation(
summary = "북마크 생성 API",
description = "JWT 기반으로 북마크를 생성할 수 있습니다.",
description = "JWT 기반으로 북마크를 생성할 수 있습니다."
)
ApiResponse<String> saveBookmark(
@RequestBody @Valid BookmarkRequest request,

@Parameter(hidden = true)
@AuthenticationPrincipal PrincipalDetails principalDetails);


/**
* 북마크 싱크합니다.
*
* @param request 북마크 생성 요청 DTO
* @param principalDetails 인증 정보
*/
@Operation(
summary = "북마크 싱크 API",
description = "JWT 기반으로 한번에 로컬 스토리지에 저장한 내용을 여러 개의 북마크에 대해서 싱크 맞춥니다.",
requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
content = @Content(
mediaType = MediaType.APPLICATION_JSON_VALUE,
examples = {
@ExampleObject(name = "북마크 생성 성공 예시", value = SUCCESS_PAYLOAD),
@ExampleObject(name = "여러개 북마크 생성 성공 예시", value = MULTI_SUCCESS_PAYLOAD),
@ExampleObject(name = "단일 북마크 생성 성공 예시", value = SINGLE_SUCCESS_PAYLOAD),
}
)
)
)
ApiResponse<String> saveBookmark(
@RequestBody @Valid BookmarkRequest request,
ApiResponse<String> synceBookmark(
@AuthenticationPrincipal PrincipalDetails principalDetails,
@RequestBody BookmarkSyncRequest request
);

@Parameter(hidden = true)
@AuthenticationPrincipal PrincipalDetails principalDetails);


/**
Expand Down Expand Up @@ -74,21 +92,34 @@ ApiResponse<SliceResponse<BookmarkListResponse>> loadBookmarkByCategory(
summary = "북마크를 삭제 API",
description = "JWT 기반으로 본인이 기존에 북마크한 상품의 북마크를 해제할 수 있습니다."
)
@DeleteMapping("/{bookmarkId}")
ApiResponse<String> deleteBookmark(
public ApiResponse<String> deleteBookmark(

@Parameter(example = "1")
@PathVariable Long bookmarkId,
@Parameter(example = "[1]", description = "삭제할 북마크 목록 (여러 개 입력 가능)")
@RequestParam List<Long> ids,

@Parameter(hidden = true)
@AuthenticationPrincipal PrincipalDetails principalDetails);


String MULTI_SUCCESS_PAYLOAD = """
{
"productIds": [
{ "productId": "689b3eb15198cf586e9341ba" },
{ "productId": "689b3ea65198cf586e9341b9" },
{ "productId": "689b3e995198cf586e9341b8" },
{ "productId": "689b3e8b5198cf586e9341b7" },
{ "productId": "689b3e785198cf586e9341b6" }
]
}

""";


String SUCCESS_PAYLOAD = """
String SINGLE_SUCCESS_PAYLOAD = """
{
"productId": "6896ed675198cf586e933d6c"
}
"productIds": [
{ "productId": "689b3eb15198cf586e9341ba" }
]
}

""";
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package site.kikihi.custom.platform.application.in.bookmark;

import site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark.BookmarkRequest;
import site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark.BookmarkSyncRequest;
import site.kikihi.custom.platform.adapter.in.web.dto.response.bookmark.BookmarkListResponse;
import site.kikihi.custom.platform.domain.bookmark.Bookmark;
import org.springframework.data.domain.Pageable;
Expand All @@ -20,11 +21,16 @@
public interface BookmarkUseCase {

/// 저장하기
Bookmark saveBookmark(BookmarkRequest request);
Bookmark saveBookmark(UUID userId, BookmarkRequest request);

Slice<BookmarkListResponse> loadBookmarksByUserIdAndCategory(UUID userId, String category, Pageable pageable);

/// 비회원을 위한 싱크 맞추기
void syncBookmarks(UUID userId, BookmarkSyncRequest request);

/// 삭제하기
void deleteBookmarkById(Long id, UUID userId);

void deleteBookmarkById(List<Long> ids, UUID userId);

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import site.kikihi.custom.global.response.ErrorCode;
import site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark.BookmarkRequest;
import site.kikihi.custom.platform.adapter.in.web.dto.request.bookmark.BookmarkSyncRequest;
import site.kikihi.custom.platform.adapter.in.web.dto.response.bookmark.BookmarkListResponse;
import site.kikihi.custom.platform.application.in.bookmark.BookmarkUseCase;
import site.kikihi.custom.platform.application.out.bookmark.BookmarkPort;
Expand Down Expand Up @@ -36,17 +37,16 @@ public class BookmarkService implements BookmarkUseCase {
* @param request Bookmark 생성을 위한 Request
*/
@Override
public Bookmark saveBookmark(BookmarkRequest request) {
public Bookmark saveBookmark(UUID userId, BookmarkRequest request) {

/// 유저 예외 처리
User user = getUser(request.getUserId());
User user = getUser(userId);

/// 상품 예외 처리
Product product = productPort.getProduct(request.getProductId())
.orElseThrow(() -> new NoSuchElementException(ErrorCode.PRODUCT_NOT_FOUND.getMessage()));
Product product = getProduct(request.getProductId());

/// 이미 눌렀다면 예외 처리 발생
boolean checked = port.checkBookmarkByUserIdAndProductId(request.getUserId(), request.getProductId());
boolean checked = port.checkBookmarkByUserIdAndProductId(userId, request.getProductId());

if (checked) {
throw new IllegalStateException(ErrorCode.BOOKMARK_ALREADY.getMessage());
Expand All @@ -58,6 +58,27 @@ public Bookmark saveBookmark(BookmarkRequest request) {
return port.saveBookmark(bookmark);
}



/**
* 로컬 스토리지에 저장한 북마크를 한번에 저장할 수 있도록 하는 서비스 로직
*
* @param userId 북마크를 저장할 유저 Id
* @param request 저장할 요청 DTO
*/
@Override
public void syncBookmarks(UUID userId, BookmarkSyncRequest request) {

/// 상품 ID들
List<BookmarkRequest> productIds = request.getProductIds();

/// 서비스를 연속으로 실현하여 작동
List<Bookmark> list = productIds.stream()
.map(req -> saveBookmark(userId, req))
.toList();

}

/**
* 나의 북마크 조회
* @param userId 북마크 조회할 유저 Id
Expand Down Expand Up @@ -123,6 +144,25 @@ public void deleteBookmarkById(Long id, UUID userId) {

}

/**
* 북마크 삭제 기능 구현
* @param ids 삭제할 북마크 Ids
* @param userId 북마크를 삭제할 유저 Id
*/
@Override
public void deleteBookmarkById(List<Long> ids, UUID userId) {

/// 삭제에 대한 반복문 실행

/// TODO! 지울 때마다 유저가 생성한 북마크인지 체크하기 위해서 진행
for (Long id : ids) {

/// 서비스 로직 실행
deleteBookmarkById(id, userId);
}

}

/// 공통 함수
/**
* ID를 바탕으로 DB에서 유저를 조회하는
Expand All @@ -145,4 +185,13 @@ private static List<String> getProductIds(List<Bookmark> bookmarks) {
}


/**
* 상품 내부 조회 함수
* @param productId 상품 ID
*/
private Product getProduct(String productId) {
return productPort.getProduct(productId)
.orElseThrow(() -> new NoSuchElementException(ErrorCode.PRODUCT_NOT_FOUND.getMessage()));
}

}
Loading
Loading