From 8807b548e144b826f6c2c4d72c9c04787e4553af Mon Sep 17 00:00:00 2001 From: "DESKTOP-JH9P8S7\\taehun" Date: Thu, 5 Mar 2026 17:21:47 +0900 Subject: [PATCH 1/7] =?UTF-8?q?refactor=20:=20=EB=B0=B1=EC=97=94=EB=93=9C?= =?UTF-8?q?=20=EC=BB=A8=EB=B2=A4=EC=85=98=EC=97=90=20=EB=A7=9E=EA=B2=8C=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Exception 사용시 상황에 맞는 메서드를 생성하는 과정을 삭제하고, 대신 에러코드를 Exception을 생성할때 사용해서 나타내는 방식 사용 --- .../com/web/SearchWeb/folder/error/FolderException.java | 8 +------- .../SearchWeb/folder/service/MemberFolderServiceImpl.java | 7 ++++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/web/SearchWeb/folder/error/FolderException.java b/src/main/java/com/web/SearchWeb/folder/error/FolderException.java index d97d24a..44011f1 100644 --- a/src/main/java/com/web/SearchWeb/folder/error/FolderException.java +++ b/src/main/java/com/web/SearchWeb/folder/error/FolderException.java @@ -7,13 +7,7 @@ @Getter public class FolderException extends BusinessException { - private FolderException(ErrorCode errorCode) { + public FolderException(ErrorCode errorCode) { super(errorCode); } - - public static class NotFound extends FolderException { - public NotFound() { - super(FolderErrorCode.FOLDER_NOT_FOUND); - } - } } diff --git a/src/main/java/com/web/SearchWeb/folder/service/MemberFolderServiceImpl.java b/src/main/java/com/web/SearchWeb/folder/service/MemberFolderServiceImpl.java index 2023694..0cb7162 100644 --- a/src/main/java/com/web/SearchWeb/folder/service/MemberFolderServiceImpl.java +++ b/src/main/java/com/web/SearchWeb/folder/service/MemberFolderServiceImpl.java @@ -2,6 +2,7 @@ import com.web.SearchWeb.folder.dao.MemberFolderJpaDao; import com.web.SearchWeb.folder.domain.MemberFolder; +import com.web.SearchWeb.folder.error.FolderErrorCode; import com.web.SearchWeb.folder.error.FolderException; import java.util.List; import lombok.RequiredArgsConstructor; @@ -33,7 +34,7 @@ public Long create(Long ownerMemberId, Long parentFolderId, String folderName, S @Transactional(readOnly = true) public MemberFolder get(Long memberFolderId) { return memberFolderJpaRepository.findById(memberFolderId) - .orElseThrow(FolderException.NotFound::new); + .orElseThrow(() ->new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); } @Override @@ -54,7 +55,7 @@ public void update(Long memberFolderId, String folderName, String description) { validateFolderName(folderName); MemberFolder folder = memberFolderJpaRepository.findById(memberFolderId) - .orElseThrow(FolderException.NotFound::new); + .orElseThrow(() ->new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); folder.changeInfo(folderName,description); // TODO : 수정 로직 좀 더 생각해보기 @@ -64,7 +65,7 @@ public void update(Long memberFolderId, String folderName, String description) { @Transactional public void move(Long memberFolderId, Long newParentFolderId) { MemberFolder folder = memberFolderJpaRepository.findById(memberFolderId) - .orElseThrow(FolderException.NotFound::new); + .orElseThrow(() ->new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); folder.changeParent(newParentFolderId); } From 16ebb72e4cde0dbb72272e1e4bc83dbf10d503ca Mon Sep 17 00:00:00 2001 From: "DESKTOP-JH9P8S7\\taehun" Date: Fri, 6 Mar 2026 21:44:31 +0900 Subject: [PATCH 2/7] =?UTF-8?q?refactor=20:=20config=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=EC=9D=98=20=EB=82=B4=EC=9A=A9=EB=93=A4=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=EB=B3=84=EB=A1=9C=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit common : 공통 응답 형식 exception : 예외처리 관련 security : 시큐리티 설정 관련 로 정리함 --- .../com/web/SearchWeb/config/{ => common}/ApiResponse.java | 3 ++- .../SearchWeb/config/{ => exception}/BusinessException.java | 2 +- .../SearchWeb/config/{ => exception}/CommonErrorCode.java | 2 +- .../com/web/SearchWeb/config/{ => exception}/ErrorCode.java | 2 +- .../{ => security}/CustomAuthenticationFailureHandler.java | 2 +- .../{ => security}/CustomAuthenticationSuccessHandler.java | 2 +- .../config/{ => security}/GlobalExceptionHandler.java | 6 +++++- .../web/SearchWeb/config/{ => security}/SecurityConfig.java | 2 +- 8 files changed, 13 insertions(+), 8 deletions(-) rename src/main/java/com/web/SearchWeb/config/{ => common}/ApiResponse.java (92%) rename src/main/java/com/web/SearchWeb/config/{ => exception}/BusinessException.java (89%) rename src/main/java/com/web/SearchWeb/config/{ => exception}/CommonErrorCode.java (91%) rename src/main/java/com/web/SearchWeb/config/{ => exception}/ErrorCode.java (77%) rename src/main/java/com/web/SearchWeb/config/{ => security}/CustomAuthenticationFailureHandler.java (96%) rename src/main/java/com/web/SearchWeb/config/{ => security}/CustomAuthenticationSuccessHandler.java (95%) rename src/main/java/com/web/SearchWeb/config/{ => security}/GlobalExceptionHandler.java (83%) rename src/main/java/com/web/SearchWeb/config/{ => security}/SecurityConfig.java (99%) diff --git a/src/main/java/com/web/SearchWeb/config/ApiResponse.java b/src/main/java/com/web/SearchWeb/config/common/ApiResponse.java similarity index 92% rename from src/main/java/com/web/SearchWeb/config/ApiResponse.java rename to src/main/java/com/web/SearchWeb/config/common/ApiResponse.java index c1c5027..7bfd29d 100644 --- a/src/main/java/com/web/SearchWeb/config/ApiResponse.java +++ b/src/main/java/com/web/SearchWeb/config/common/ApiResponse.java @@ -1,5 +1,6 @@ -package com.web.SearchWeb.config; +package com.web.SearchWeb.config.common; +import com.web.SearchWeb.config.exception.ErrorCode; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/web/SearchWeb/config/BusinessException.java b/src/main/java/com/web/SearchWeb/config/exception/BusinessException.java similarity index 89% rename from src/main/java/com/web/SearchWeb/config/BusinessException.java rename to src/main/java/com/web/SearchWeb/config/exception/BusinessException.java index 42c7578..135353b 100644 --- a/src/main/java/com/web/SearchWeb/config/BusinessException.java +++ b/src/main/java/com/web/SearchWeb/config/exception/BusinessException.java @@ -1,4 +1,4 @@ -package com.web.SearchWeb.config; +package com.web.SearchWeb.config.exception; import lombok.Getter; diff --git a/src/main/java/com/web/SearchWeb/config/CommonErrorCode.java b/src/main/java/com/web/SearchWeb/config/exception/CommonErrorCode.java similarity index 91% rename from src/main/java/com/web/SearchWeb/config/CommonErrorCode.java rename to src/main/java/com/web/SearchWeb/config/exception/CommonErrorCode.java index 30a2e56..45d99d8 100644 --- a/src/main/java/com/web/SearchWeb/config/CommonErrorCode.java +++ b/src/main/java/com/web/SearchWeb/config/exception/CommonErrorCode.java @@ -1,4 +1,4 @@ -package com.web.SearchWeb.config; +package com.web.SearchWeb.config.exception; import lombok.Getter; import lombok.RequiredArgsConstructor; diff --git a/src/main/java/com/web/SearchWeb/config/ErrorCode.java b/src/main/java/com/web/SearchWeb/config/exception/ErrorCode.java similarity index 77% rename from src/main/java/com/web/SearchWeb/config/ErrorCode.java rename to src/main/java/com/web/SearchWeb/config/exception/ErrorCode.java index c352033..d155b3e 100644 --- a/src/main/java/com/web/SearchWeb/config/ErrorCode.java +++ b/src/main/java/com/web/SearchWeb/config/exception/ErrorCode.java @@ -1,4 +1,4 @@ -package com.web.SearchWeb.config; +package com.web.SearchWeb.config.exception; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/web/SearchWeb/config/CustomAuthenticationFailureHandler.java b/src/main/java/com/web/SearchWeb/config/security/CustomAuthenticationFailureHandler.java similarity index 96% rename from src/main/java/com/web/SearchWeb/config/CustomAuthenticationFailureHandler.java rename to src/main/java/com/web/SearchWeb/config/security/CustomAuthenticationFailureHandler.java index d6dc6c7..67dc636 100644 --- a/src/main/java/com/web/SearchWeb/config/CustomAuthenticationFailureHandler.java +++ b/src/main/java/com/web/SearchWeb/config/security/CustomAuthenticationFailureHandler.java @@ -1,4 +1,4 @@ -package com.web.SearchWeb.config; +package com.web.SearchWeb.config.security; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; diff --git a/src/main/java/com/web/SearchWeb/config/CustomAuthenticationSuccessHandler.java b/src/main/java/com/web/SearchWeb/config/security/CustomAuthenticationSuccessHandler.java similarity index 95% rename from src/main/java/com/web/SearchWeb/config/CustomAuthenticationSuccessHandler.java rename to src/main/java/com/web/SearchWeb/config/security/CustomAuthenticationSuccessHandler.java index ded250c..a6eb006 100644 --- a/src/main/java/com/web/SearchWeb/config/CustomAuthenticationSuccessHandler.java +++ b/src/main/java/com/web/SearchWeb/config/security/CustomAuthenticationSuccessHandler.java @@ -1,4 +1,4 @@ -package com.web.SearchWeb.config; +package com.web.SearchWeb.config.security; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; diff --git a/src/main/java/com/web/SearchWeb/config/GlobalExceptionHandler.java b/src/main/java/com/web/SearchWeb/config/security/GlobalExceptionHandler.java similarity index 83% rename from src/main/java/com/web/SearchWeb/config/GlobalExceptionHandler.java rename to src/main/java/com/web/SearchWeb/config/security/GlobalExceptionHandler.java index 4897c1b..208df0e 100644 --- a/src/main/java/com/web/SearchWeb/config/GlobalExceptionHandler.java +++ b/src/main/java/com/web/SearchWeb/config/security/GlobalExceptionHandler.java @@ -1,5 +1,9 @@ -package com.web.SearchWeb.config; +package com.web.SearchWeb.config.security; +import com.web.SearchWeb.config.common.ApiResponse; +import com.web.SearchWeb.config.exception.BusinessException; +import com.web.SearchWeb.config.exception.CommonErrorCode; +import com.web.SearchWeb.config.exception.ErrorCode; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/src/main/java/com/web/SearchWeb/config/SecurityConfig.java b/src/main/java/com/web/SearchWeb/config/security/SecurityConfig.java similarity index 99% rename from src/main/java/com/web/SearchWeb/config/SecurityConfig.java rename to src/main/java/com/web/SearchWeb/config/security/SecurityConfig.java index afd01bc..3903b80 100644 --- a/src/main/java/com/web/SearchWeb/config/SecurityConfig.java +++ b/src/main/java/com/web/SearchWeb/config/security/SecurityConfig.java @@ -1,4 +1,4 @@ -package com.web.SearchWeb.config; +package com.web.SearchWeb.config.security; import com.web.SearchWeb.member.service.CustomOAuth2UserService; import org.springframework.context.annotation.Bean; From 775f956bf3e2a112d3fff57cc9bf7db86fa51a2c Mon Sep 17 00:00:00 2001 From: "DESKTOP-JH9P8S7\\taehun" Date: Fri, 6 Mar 2026 21:45:51 +0900 Subject: [PATCH 3/7] =?UTF-8?q?refactor=20:=20config=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=EC=A0=95=EB=A6=AC=ED=95=98=EB=A9=B4=EC=84=9C=20=EB=B0=94?= =?UTF-8?q?=EB=80=90=20=EA=B2=BD=EB=A1=9C=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../SearchWeb/bookmark/controller/BookmarkApiController.java | 2 +- .../com/web/SearchWeb/bookmark/error/BookmarkErrorCode.java | 2 +- .../web/SearchWeb/bookmark/service/BookmarkServiceImpl.java | 4 ++-- .../java/com/web/SearchWeb/folder/error/FolderErrorCode.java | 2 +- .../java/com/web/SearchWeb/folder/error/FolderException.java | 4 ++-- .../com/web/SearchWeb/mypage/controller/MyPageController.java | 2 +- .../com/web/SearchWeb/tag/controller/MemberTagController.java | 2 +- src/main/java/com/web/SearchWeb/tag/error/TagErrorCode.java | 2 +- src/main/java/com/web/SearchWeb/tag/error/TagException.java | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/web/SearchWeb/bookmark/controller/BookmarkApiController.java b/src/main/java/com/web/SearchWeb/bookmark/controller/BookmarkApiController.java index 996db6a..3cde0dd 100644 --- a/src/main/java/com/web/SearchWeb/bookmark/controller/BookmarkApiController.java +++ b/src/main/java/com/web/SearchWeb/bookmark/controller/BookmarkApiController.java @@ -4,7 +4,7 @@ import com.web.SearchWeb.bookmark.controller.dto.BookmarkRequests; import com.web.SearchWeb.bookmark.domain.Bookmark; import com.web.SearchWeb.bookmark.service.BookmarkService; -import com.web.SearchWeb.config.ApiResponse; +import com.web.SearchWeb.config.common.ApiResponse; import com.web.SearchWeb.member.dto.CustomOAuth2User; import com.web.SearchWeb.member.dto.CustomUserDetails; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/main/java/com/web/SearchWeb/bookmark/error/BookmarkErrorCode.java b/src/main/java/com/web/SearchWeb/bookmark/error/BookmarkErrorCode.java index db718f4..360ea47 100644 --- a/src/main/java/com/web/SearchWeb/bookmark/error/BookmarkErrorCode.java +++ b/src/main/java/com/web/SearchWeb/bookmark/error/BookmarkErrorCode.java @@ -1,6 +1,6 @@ package com.web.SearchWeb.bookmark.error; -import com.web.SearchWeb.config.ErrorCode; +import com.web.SearchWeb.config.exception.ErrorCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/web/SearchWeb/bookmark/service/BookmarkServiceImpl.java b/src/main/java/com/web/SearchWeb/bookmark/service/BookmarkServiceImpl.java index d570af1..dd42321 100644 --- a/src/main/java/com/web/SearchWeb/bookmark/service/BookmarkServiceImpl.java +++ b/src/main/java/com/web/SearchWeb/bookmark/service/BookmarkServiceImpl.java @@ -15,8 +15,8 @@ import org.springframework.transaction.annotation.Transactional; import com.web.SearchWeb.bookmark.error.BookmarkErrorCode; -import com.web.SearchWeb.config.BusinessException; -import com.web.SearchWeb.config.CommonErrorCode; +import com.web.SearchWeb.config.exception.BusinessException; +import com.web.SearchWeb.config.exception.CommonErrorCode; import com.web.SearchWeb.bookmark.dto.MemberTagResultDto; import java.net.URI; diff --git a/src/main/java/com/web/SearchWeb/folder/error/FolderErrorCode.java b/src/main/java/com/web/SearchWeb/folder/error/FolderErrorCode.java index ca76170..8bf1fa9 100644 --- a/src/main/java/com/web/SearchWeb/folder/error/FolderErrorCode.java +++ b/src/main/java/com/web/SearchWeb/folder/error/FolderErrorCode.java @@ -1,6 +1,6 @@ package com.web.SearchWeb.folder.error; -import com.web.SearchWeb.config.ErrorCode; +import com.web.SearchWeb.config.exception.ErrorCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/web/SearchWeb/folder/error/FolderException.java b/src/main/java/com/web/SearchWeb/folder/error/FolderException.java index 44011f1..94b9967 100644 --- a/src/main/java/com/web/SearchWeb/folder/error/FolderException.java +++ b/src/main/java/com/web/SearchWeb/folder/error/FolderException.java @@ -1,7 +1,7 @@ package com.web.SearchWeb.folder.error; -import com.web.SearchWeb.config.BusinessException; -import com.web.SearchWeb.config.ErrorCode; +import com.web.SearchWeb.config.exception.BusinessException; +import com.web.SearchWeb.config.exception.ErrorCode; import lombok.Getter; @Getter diff --git a/src/main/java/com/web/SearchWeb/mypage/controller/MyPageController.java b/src/main/java/com/web/SearchWeb/mypage/controller/MyPageController.java index 215a849..481fb2b 100644 --- a/src/main/java/com/web/SearchWeb/mypage/controller/MyPageController.java +++ b/src/main/java/com/web/SearchWeb/mypage/controller/MyPageController.java @@ -5,7 +5,7 @@ import com.web.SearchWeb.bookmark.domain.Bookmark; import com.web.SearchWeb.bookmark.dto.BookmarkDto; import com.web.SearchWeb.bookmark.service.BookmarkService; -import com.web.SearchWeb.config.ApiResponse; +import com.web.SearchWeb.config.common.ApiResponse; import com.web.SearchWeb.member.domain.Member; import com.web.SearchWeb.member.dto.MemberUpdateDto; import com.web.SearchWeb.member.service.MemberService; diff --git a/src/main/java/com/web/SearchWeb/tag/controller/MemberTagController.java b/src/main/java/com/web/SearchWeb/tag/controller/MemberTagController.java index 026c17a..1449713 100644 --- a/src/main/java/com/web/SearchWeb/tag/controller/MemberTagController.java +++ b/src/main/java/com/web/SearchWeb/tag/controller/MemberTagController.java @@ -1,6 +1,6 @@ package com.web.SearchWeb.tag.controller; -import com.web.SearchWeb.config.ApiResponse; +import com.web.SearchWeb.config.common.ApiResponse; import com.web.SearchWeb.tag.controller.dto.MemberTagDto; import com.web.SearchWeb.tag.domain.MemberTag; import com.web.SearchWeb.tag.service.MemberTagService; diff --git a/src/main/java/com/web/SearchWeb/tag/error/TagErrorCode.java b/src/main/java/com/web/SearchWeb/tag/error/TagErrorCode.java index 16b7732..31ad34a 100644 --- a/src/main/java/com/web/SearchWeb/tag/error/TagErrorCode.java +++ b/src/main/java/com/web/SearchWeb/tag/error/TagErrorCode.java @@ -1,6 +1,6 @@ package com.web.SearchWeb.tag.error; -import com.web.SearchWeb.config.ErrorCode; +import com.web.SearchWeb.config.exception.ErrorCode; import lombok.Getter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; diff --git a/src/main/java/com/web/SearchWeb/tag/error/TagException.java b/src/main/java/com/web/SearchWeb/tag/error/TagException.java index 79c7b22..48b9807 100644 --- a/src/main/java/com/web/SearchWeb/tag/error/TagException.java +++ b/src/main/java/com/web/SearchWeb/tag/error/TagException.java @@ -1,7 +1,7 @@ package com.web.SearchWeb.tag.error; -import com.web.SearchWeb.config.BusinessException; -import com.web.SearchWeb.config.ErrorCode; +import com.web.SearchWeb.config.exception.BusinessException; +import com.web.SearchWeb.config.exception.ErrorCode; import lombok.Getter; @Getter From 01b80661d25248e44e3a890e9c16946db9bb04e5 Mon Sep 17 00:00:00 2001 From: "DESKTOP-JH9P8S7\\taehun" Date: Sun, 8 Mar 2026 21:11:13 +0900 Subject: [PATCH 4/7] =?UTF-8?q?feat=20:=20Security=EC=9D=98=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=EC=9D=84=20=EC=82=AC=EC=9A=A9=ED=95=98=EA=B8=B0=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20util=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Security를 통해서 로그인을 한 사람의 Id를 사용할 수 있도록 util클래스 생성. 추후 Security를 통해서 무언가를 자여와야 할 때 이 클래스를 사용 --- .../java/com/web/SearchWeb/config/security/SecurityUtils.java | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/main/java/com/web/SearchWeb/config/security/SecurityUtils.java diff --git a/src/main/java/com/web/SearchWeb/config/security/SecurityUtils.java b/src/main/java/com/web/SearchWeb/config/security/SecurityUtils.java new file mode 100644 index 0000000..c7986d1 --- /dev/null +++ b/src/main/java/com/web/SearchWeb/config/security/SecurityUtils.java @@ -0,0 +1,2 @@ +package com.web.SearchWeb.config.security;public class SecurityUtils { +} From 073318ef111b81038369079fc84c35fa399ae842 Mon Sep 17 00:00:00 2001 From: "DESKTOP-JH9P8S7\\taehun" Date: Sun, 8 Mar 2026 21:13:44 +0900 Subject: [PATCH 5/7] =?UTF-8?q?feat=20:=20=ED=8F=B4=EB=8D=94=20=EB=82=B4?= =?UTF-8?q?=20=ED=99=9C=EC=84=B1=20=EB=B6=81=EB=A7=88=ED=81=AC=20=EC=A1=B4?= =?UTF-8?q?=EC=9E=AC=20=EC=97=AC=EB=B6=80=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 폴더의 조회 관련 메서드에서 필요한 폴더내 활성 북마크들을 전부 불러오는 시능 추가 --- .../java/com/web/SearchWeb/bookmark/dao/BookmarkDao.java | 3 +++ .../web/SearchWeb/bookmark/dao/MybatisBookmarkDao.java | 5 +++++ src/main/resources/mapper/bookmark-mapper.xml | 9 +++++++++ 3 files changed, 17 insertions(+) diff --git a/src/main/java/com/web/SearchWeb/bookmark/dao/BookmarkDao.java b/src/main/java/com/web/SearchWeb/bookmark/dao/BookmarkDao.java index 066ad26..ba13a12 100644 --- a/src/main/java/com/web/SearchWeb/bookmark/dao/BookmarkDao.java +++ b/src/main/java/com/web/SearchWeb/bookmark/dao/BookmarkDao.java @@ -46,4 +46,7 @@ public interface BookmarkDao { // 북마크-태그 연결 일괄 추가 (Bulk Insert) int insertBookmarkTags(Long bookmarkId, List tagIds); + + // 폴더 내 활성 북마크 존재 여부 + boolean existsActiveBookmarkInFolder(Long memberFolderId); } diff --git a/src/main/java/com/web/SearchWeb/bookmark/dao/MybatisBookmarkDao.java b/src/main/java/com/web/SearchWeb/bookmark/dao/MybatisBookmarkDao.java index 221cdbc..113d01d 100644 --- a/src/main/java/com/web/SearchWeb/bookmark/dao/MybatisBookmarkDao.java +++ b/src/main/java/com/web/SearchWeb/bookmark/dao/MybatisBookmarkDao.java @@ -136,4 +136,9 @@ public List insertAndSelectTags(Long memberId, List public int insertBookmarkTags(Long bookmarkId, List tagIds) { return mapper.insertBookmarkTags(bookmarkId, tagIds); } + + @Override + public boolean existsActiveBookmarkInFolder(Long memberFolderId) { + return mapper.existsActiveBookmarkInFolder(memberFolderId); + } } diff --git a/src/main/resources/mapper/bookmark-mapper.xml b/src/main/resources/mapper/bookmark-mapper.xml index 68ae781..ea08638 100644 --- a/src/main/resources/mapper/bookmark-mapper.xml +++ b/src/main/resources/mapper/bookmark-mapper.xml @@ -228,4 +228,13 @@ DO UPDATE SET deleted_at = NULL, updated_at = now() + + From 4e8d33311811d514d28135bae71c89d04cd104be Mon Sep 17 00:00:00 2001 From: "DESKTOP-JH9P8S7\\taehun" Date: Sun, 8 Mar 2026 21:15:24 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor=20:=20=ED=8F=B4=EB=8D=94=EC=9D=98?= =?UTF-8?q?=20=EB=B9=84=EC=A7=80=EB=8B=88=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20?= =?UTF-8?q?=EB=B3=B4=EC=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 폴더의 비지니스 로직 마저 완성 자세한건 컨플루언스 문서로 기록 --- .../controller/MemberFolderController.java | 48 +++-- .../controller/dto/MemberFolderRequests.java | 30 ++- .../folder/dao/MemberFolderJpaDao.java | 6 + .../folder/error/FolderErrorCode.java | 6 +- .../folder/service/MemberFolderService.java | 14 +- .../service/MemberFolderServiceImpl.java | 203 +++++++++++++++--- 6 files changed, 253 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/web/SearchWeb/folder/controller/MemberFolderController.java b/src/main/java/com/web/SearchWeb/folder/controller/MemberFolderController.java index 2fa140e..6475278 100644 --- a/src/main/java/com/web/SearchWeb/folder/controller/MemberFolderController.java +++ b/src/main/java/com/web/SearchWeb/folder/controller/MemberFolderController.java @@ -1,15 +1,18 @@ package com.web.SearchWeb.folder.controller; -import com.web.SearchWeb.config.ApiResponse; +import com.web.SearchWeb.config.common.ApiResponse; +import com.web.SearchWeb.config.security.SecurityUtils; import com.web.SearchWeb.folder.controller.dto.MemberFolderRequests; import com.web.SearchWeb.folder.controller.dto.MemberFolderResponses; import com.web.SearchWeb.folder.domain.MemberFolder; import com.web.SearchWeb.folder.service.MemberFolderService; +import jakarta.validation.Valid; import java.util.List; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -28,9 +31,10 @@ public class MemberFolderController { // 생성 (201 Created 응답) @PostMapping - public ResponseEntity> create(@RequestBody MemberFolderRequests.Create req) { + public ResponseEntity> create(Authentication authentication, @Valid @RequestBody MemberFolderRequests.Create req) { + Long loginId = SecurityUtils.extractMemberId(authentication); Long folderId = memberFolderService.create( - req.ownerMemberId, + loginId, req.parentFolderId, req.folderName, req.description @@ -40,17 +44,22 @@ public ResponseEntity> create(@RequestBody MemberFolderRequest .body(ApiResponse.success(folderId)); } - // 단건 조회 + // 폴더 정보 단건 조회 @GetMapping("/{folderId}") - public ResponseEntity> get(@PathVariable Long folderId) { - MemberFolder folder = memberFolderService.get(folderId); + public ResponseEntity> get(Authentication authentication, @PathVariable Long folderId) { + Long loginId = SecurityUtils.extractMemberId(authentication); + MemberFolder folder = memberFolderService.get(loginId, folderId); return ResponseEntity.ok(ApiResponse.success(MemberFolderResponses.from(folder))); } // 루트 폴더 조회 @GetMapping("/owners/{ownerMemberId}/root") - public ResponseEntity>> listRoot(@PathVariable Long ownerMemberId) { - List responses = memberFolderService.listRootFolders(ownerMemberId) + public ResponseEntity>> listRoot( + Authentication authentication, + @PathVariable Long ownerMemberId + ) { + Long loginId = SecurityUtils.extractMemberId(authentication); + List responses = memberFolderService.listRootFolders(loginId, ownerMemberId) .stream() .map(MemberFolderResponses::from) .collect(Collectors.toList()); @@ -61,10 +70,12 @@ public ResponseEntity>> listRoot(@PathVa // 하위 폴더 조회 @GetMapping("/owners/{ownerMemberId}/children/{parentFolderId}") public ResponseEntity>> listChildren( + Authentication authentication, @PathVariable Long ownerMemberId, @PathVariable Long parentFolderId ) { - List responses = memberFolderService.listChildren(ownerMemberId, parentFolderId) + Long loginId = SecurityUtils.extractMemberId(authentication); + List responses = memberFolderService.listChildren(loginId, ownerMemberId, parentFolderId) .stream() .map(MemberFolderResponses::from) .collect(Collectors.toList()); @@ -74,22 +85,27 @@ public ResponseEntity>> listChildren( // 수정 (200 OK) @PutMapping("/{folderId}") - public ResponseEntity> update(@PathVariable Long folderId, @RequestBody MemberFolderRequests.Update req) { - memberFolderService.update(folderId, req.folderName, req.description); + public ResponseEntity> update(Authentication authentication, @PathVariable Long folderId, + @Valid @RequestBody MemberFolderRequests.Update req) { + Long loginId = SecurityUtils.extractMemberId(authentication); + memberFolderService.update(loginId, folderId, req.folderName, req.description); return ResponseEntity.ok(ApiResponse.success(null)); } // 이동(부모 변경) @PutMapping("/{folderId}/move") - public ResponseEntity> move(@PathVariable Long folderId, @RequestBody MemberFolderRequests.Move req) { - memberFolderService.move(folderId, req.newParentFolderId); + public ResponseEntity> move(Authentication authentication, @PathVariable Long folderId, + @Valid @RequestBody MemberFolderRequests.Move req) { + Long loginId = SecurityUtils.extractMemberId(authentication); + memberFolderService.move(loginId, folderId, req.newParentFolderId); return ResponseEntity.ok(ApiResponse.success(null)); } // 삭제 @DeleteMapping("/{folderId}") - public ResponseEntity> delete(@PathVariable Long folderId) { - memberFolderService.delete(folderId); + public ResponseEntity> delete(Authentication authentication, @PathVariable Long folderId) { + Long loginId = SecurityUtils.extractMemberId(authentication); + memberFolderService.delete(loginId, folderId); return ResponseEntity.ok(ApiResponse.success(null)); } -} \ No newline at end of file +} diff --git a/src/main/java/com/web/SearchWeb/folder/controller/dto/MemberFolderRequests.java b/src/main/java/com/web/SearchWeb/folder/controller/dto/MemberFolderRequests.java index 3e19b7e..dc367ed 100644 --- a/src/main/java/com/web/SearchWeb/folder/controller/dto/MemberFolderRequests.java +++ b/src/main/java/com/web/SearchWeb/folder/controller/dto/MemberFolderRequests.java @@ -1,29 +1,53 @@ package com.web.SearchWeb.folder.controller.dto; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.Size; +import lombok.Getter; +import lombok.NoArgsConstructor; + public class MemberFolderRequests { /** * 폴더 생성 요청 */ + + @Getter + @NoArgsConstructor public static class Create { - public Long ownerMemberId; - public Long parentFolderId; // null이면 루트 + // null이면 루트 폴더 + @Positive(message = "parentFolderId는 양수여야 합니다.") + public Long parentFolderId; + + @NotBlank(message = "folderName은 비어 있을 수 없습니다.") + @Size(max = 50, message = "folderName은 최대 50자까지 가능합니다.") public String folderName; + + @Size(max = 200, message = "description은 최대 200자까지 가능합니다.") public String description; } /** * 폴더 수정 요청 */ + @Getter + @NoArgsConstructor public static class Update { + @Size(max = 50, message = "folderName은 최대 50자까지 가능합니다.") public String folderName; + + @Size(max = 200, message = "description은 최대 200자까지 가능합니다.") public String description; } /** * 폴더 이동 요청 */ + @Getter + @NoArgsConstructor public static class Move { - public Long newParentFolderId; // null이면 루트로 이동 + // null이면 루트로 이동 + @Positive(message = "newParentFolderId는 양수여야 합니다.") + public Long newParentFolderId; } } diff --git a/src/main/java/com/web/SearchWeb/folder/dao/MemberFolderJpaDao.java b/src/main/java/com/web/SearchWeb/folder/dao/MemberFolderJpaDao.java index 314f7e7..5807f15 100644 --- a/src/main/java/com/web/SearchWeb/folder/dao/MemberFolderJpaDao.java +++ b/src/main/java/com/web/SearchWeb/folder/dao/MemberFolderJpaDao.java @@ -14,4 +14,10 @@ public interface MemberFolderJpaDao extends JpaRepository { // 사용자 전체 폴더 List findAllByOwnerMemberId(Long ownerMemberId); + + boolean existsByParentFolderId(Long parentFolderId); + + boolean existsByOwnerMemberIdAndParentFolderIdAndFolderName(Long loginId, Long parentFolderId, String normalizedFolderName); + + boolean existsByOwnerMemberIdAndParentFolderIdIsNullAndFolderName(Long loginId, String normalizedFolderName); } diff --git a/src/main/java/com/web/SearchWeb/folder/error/FolderErrorCode.java b/src/main/java/com/web/SearchWeb/folder/error/FolderErrorCode.java index 8bf1fa9..5d0e72e 100644 --- a/src/main/java/com/web/SearchWeb/folder/error/FolderErrorCode.java +++ b/src/main/java/com/web/SearchWeb/folder/error/FolderErrorCode.java @@ -9,7 +9,11 @@ @RequiredArgsConstructor public enum FolderErrorCode implements ErrorCode { FOLDER_NOT_FOUND(HttpStatus.NOT_FOUND, "F001", "폴더를 찾을 수 없습니다."), - DUPLICATE_FOLDER_NAME(HttpStatus.BAD_REQUEST, "F002", "이미 존재하는 폴더명입니다."); + DUPLICATE_FOLDER_NAME(HttpStatus.BAD_REQUEST, "F002", "이미 존재하는 폴더명입니다."), + FOLDER_FORBIDDEN(HttpStatus.FORBIDDEN,"Foo3" ,"접근이 제한된 폴더입니다." ), + INVALID_FOLDER_NAME(HttpStatus.BAD_REQUEST,"F004","폴더명으로 적절하지 않습니다" ), + INVALID_FOLDER_MOVE(HttpStatus.BAD_REQUEST, "F005", "유효하지 않은 폴더 이동입니다."), + FOLDER_NOT_EMPTY(HttpStatus.BAD_REQUEST, "F006", "하위 폴더 또는 북마크가 남아 있어 삭제할 수 없습니다."); private final HttpStatus status; private final String code; diff --git a/src/main/java/com/web/SearchWeb/folder/service/MemberFolderService.java b/src/main/java/com/web/SearchWeb/folder/service/MemberFolderService.java index ca8b448..745801e 100644 --- a/src/main/java/com/web/SearchWeb/folder/service/MemberFolderService.java +++ b/src/main/java/com/web/SearchWeb/folder/service/MemberFolderService.java @@ -6,17 +6,17 @@ public interface MemberFolderService { - Long create(Long ownerMemberId, Long parentFolderId, String folderName, String description); + Long create(Long loginId, Long parentFolderId, String folderName, String description); - MemberFolder get(Long memberFolderId); + MemberFolder get(Long loginId, Long memberFolderId); - List listRootFolders(Long ownerMemberId); + List listRootFolders(Long loginId, Long ownerMemberId); - List listChildren(Long ownerMemberId, Long parentFolderId); + List listChildren(Long loginId, Long ownerMemberId, Long parentFolderId); - void update(Long memberFolderId, String folderName, String description); + void update(Long loginId, Long memberFolderId, String folderName, String description); - void move(Long memberFolderId, Long newParentFolderId); + void move(Long loginId, Long memberFolderId, Long newParentFolderId); - void delete(Long memberFolderId); + void delete(Long loginId, Long memberFolderId); } diff --git a/src/main/java/com/web/SearchWeb/folder/service/MemberFolderServiceImpl.java b/src/main/java/com/web/SearchWeb/folder/service/MemberFolderServiceImpl.java index 0cb7162..9e26338 100644 --- a/src/main/java/com/web/SearchWeb/folder/service/MemberFolderServiceImpl.java +++ b/src/main/java/com/web/SearchWeb/folder/service/MemberFolderServiceImpl.java @@ -1,5 +1,6 @@ package com.web.SearchWeb.folder.service; +import com.web.SearchWeb.bookmark.dao.BookmarkDao; import com.web.SearchWeb.folder.dao.MemberFolderJpaDao; import com.web.SearchWeb.folder.domain.MemberFolder; import com.web.SearchWeb.folder.error.FolderErrorCode; @@ -14,74 +15,222 @@ public class MemberFolderServiceImpl implements MemberFolderService { private final MemberFolderJpaDao memberFolderJpaRepository; + private final BookmarkDao bookmarkDao; @Override @Transactional - public Long create(Long ownerMemberId, Long parentFolderId, String folderName, String description) { - validateFolderName(folderName); + public Long create(Long loginId, Long parentFolderId, String folderName, String description) { + String normalizedFolderName = normalizeFolderName(folderName); + String normalizedDescription = normalizeDescription(description); + + // 1. 부모 폴더가 있는 경우 검증 + if (parentFolderId != null) { + MemberFolder parentFolder = memberFolderJpaRepository + .findById(parentFolderId) + .orElseThrow(() -> new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); + + // 2. 부모 폴더 소유자 검증 + if (!parentFolder.getOwnerMemberId().equals(loginId)) { + throw new FolderException(FolderErrorCode.FOLDER_FORBIDDEN); + } + + // 3. 같은 부모 아래 동일 이름 폴더 중복 검증 + boolean exists = memberFolderJpaRepository + .existsByOwnerMemberIdAndParentFolderIdAndFolderName( + loginId, parentFolderId, normalizedFolderName + ); + + if (exists) { + throw new FolderException(FolderErrorCode.DUPLICATE_FOLDER_NAME); + } + } else { + // 4. 루트 폴더일 때 동일 이름 중복 검증 + boolean exists = memberFolderJpaRepository + .existsByOwnerMemberIdAndParentFolderIdIsNullAndFolderName( + loginId, normalizedFolderName + ); + + if (exists) { + throw new FolderException(FolderErrorCode.DUPLICATE_FOLDER_NAME); + } + } MemberFolder folder = MemberFolder.builder() - .ownerMemberId(ownerMemberId) + .ownerMemberId(loginId) .parentFolderId(parentFolderId) - .folderName(folderName) - .description(description) + .folderName(normalizedFolderName) + .description(normalizedDescription) .build(); return memberFolderJpaRepository.save(folder).getMemberFolderId(); } + private String normalizeFolderName(String folderName) { + if (folderName == null) { + throw new FolderException(FolderErrorCode.INVALID_FOLDER_NAME); + } + + String normalizedFolderName = folderName.trim(); + if (normalizedFolderName.isEmpty() || normalizedFolderName.length() > 50) { + throw new FolderException(FolderErrorCode.INVALID_FOLDER_NAME); + } + return normalizedFolderName; + } + + private String normalizeDescription(String description) { + if (description == null) { + return null; + } + + String normalizedDescription = description.trim(); + if (normalizedDescription.isEmpty()) { + return null; + } + + return normalizedDescription; + } + @Override @Transactional(readOnly = true) - public MemberFolder get(Long memberFolderId) { - return memberFolderJpaRepository.findById(memberFolderId) - .orElseThrow(() ->new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); + public MemberFolder get(Long loginId, Long memberFolderId) { + return getOwnedFolder(loginId, memberFolderId); } @Override @Transactional(readOnly = true) - public List listRootFolders(Long ownerMemberId) { + public List listRootFolders(Long loginId, Long ownerMemberId) { + validateOwner(loginId, ownerMemberId); return memberFolderJpaRepository.findAllByOwnerMemberIdAndParentFolderIdIsNull(ownerMemberId); } @Override @Transactional(readOnly = true) - public List listChildren(Long ownerMemberId, Long parentFolderId) { + public List listChildren(Long loginId, Long ownerMemberId, Long parentFolderId) { + validateOwner(loginId, ownerMemberId); + MemberFolder parentFolder = getOwnedFolder(loginId, parentFolderId); + if (!parentFolder.getOwnerMemberId().equals(ownerMemberId)) { + throw new FolderException(FolderErrorCode.FOLDER_FORBIDDEN); + } return memberFolderJpaRepository.findAllByOwnerMemberIdAndParentFolderId(ownerMemberId, parentFolderId); } @Override @Transactional - public void update(Long memberFolderId, String folderName, String description) { - validateFolderName(folderName); - - MemberFolder folder = memberFolderJpaRepository.findById(memberFolderId) - .orElseThrow(() ->new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); + public void update(Long loginId, Long memberFolderId, String folderName, String description) { + MemberFolder folder = getOwnedFolder(loginId, memberFolderId); + + String resolvedFolderName = folderName == null + ? folder.getFolderName() + : normalizeFolderName(folderName); + String resolvedDescription = description == null + ? folder.getDescription() + : normalizeDescription(description); + + if (!folder.getFolderName().equals(resolvedFolderName)) { + boolean exists = folder.getParentFolderId() == null + ? memberFolderJpaRepository.existsByOwnerMemberIdAndParentFolderIdIsNullAndFolderName( + folder.getOwnerMemberId(), + resolvedFolderName + ) + : memberFolderJpaRepository.existsByOwnerMemberIdAndParentFolderIdAndFolderName( + folder.getOwnerMemberId(), + folder.getParentFolderId(), + resolvedFolderName + ); + + if (exists) { + throw new FolderException(FolderErrorCode.DUPLICATE_FOLDER_NAME); + } + } - folder.changeInfo(folderName,description); - // TODO : 수정 로직 좀 더 생각해보기 + folder.changeInfo(resolvedFolderName, resolvedDescription); } @Override @Transactional - public void move(Long memberFolderId, Long newParentFolderId) { - MemberFolder folder = memberFolderJpaRepository.findById(memberFolderId) - .orElseThrow(() ->new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); + public void move(Long loginId, Long memberFolderId, Long newParentFolderId) { + MemberFolder folder = getOwnedFolder(loginId, memberFolderId); + + if ((folder.getParentFolderId() == null && newParentFolderId == null) + || (folder.getParentFolderId() != null && folder.getParentFolderId().equals(newParentFolderId))) { + return; + } + + if (newParentFolderId != null) { + if (memberFolderId.equals(newParentFolderId)) { + throw new FolderException(FolderErrorCode.INVALID_FOLDER_MOVE); + } + + MemberFolder newParentFolder = getOwnedFolder(loginId, newParentFolderId); + + if (!newParentFolder.getOwnerMemberId().equals(folder.getOwnerMemberId())) { + throw new FolderException(FolderErrorCode.FOLDER_FORBIDDEN); + } + + validateNoCycle(folder.getMemberFolderId(), newParentFolder); + + boolean exists = memberFolderJpaRepository.existsByOwnerMemberIdAndParentFolderIdAndFolderName( + folder.getOwnerMemberId(), + newParentFolderId, + folder.getFolderName() + ); + if (exists) { + throw new FolderException(FolderErrorCode.DUPLICATE_FOLDER_NAME); + } + } else { + boolean exists = memberFolderJpaRepository.existsByOwnerMemberIdAndParentFolderIdIsNullAndFolderName( + folder.getOwnerMemberId(), + folder.getFolderName() + ); + if (exists) { + throw new FolderException(FolderErrorCode.DUPLICATE_FOLDER_NAME); + } + } + folder.changeParent(newParentFolderId); } @Override @Transactional - public void delete(Long memberFolderId) { - if (!memberFolderJpaRepository.existsById(memberFolderId)) { - return; // 멱등 삭제 + public void delete(Long loginId, Long memberFolderId) { + getOwnedFolder(loginId, memberFolderId); + + if (memberFolderJpaRepository.existsByParentFolderId(memberFolderId) + || bookmarkDao.existsActiveBookmarkInFolder(memberFolderId)) { + throw new FolderException(FolderErrorCode.FOLDER_NOT_EMPTY); } + memberFolderJpaRepository.deleteById(memberFolderId); } - private void validateFolderName(String folderName) { - if (folderName == null || folderName.isBlank()) { - throw new IllegalArgumentException("folderName must not be blank"); + private MemberFolder getOwnedFolder(Long loginId, Long memberFolderId) { + MemberFolder folder = memberFolderJpaRepository.findById(memberFolderId) + .orElseThrow(() -> new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); + + validateOwner(loginId, folder.getOwnerMemberId()); + return folder; + } + + private void validateOwner(Long loginId, Long ownerMemberId) { + if (!ownerMemberId.equals(loginId)) { + throw new FolderException(FolderErrorCode.FOLDER_FORBIDDEN); } + } + + private void validateNoCycle(Long folderId, MemberFolder parentFolder) { + MemberFolder current = parentFolder; + while (current != null) { + if (current.getMemberFolderId().equals(folderId)) { + throw new FolderException(FolderErrorCode.INVALID_FOLDER_MOVE); + } + Long nextParentId = current.getParentFolderId(); + if (nextParentId == null) { + return; + } + + current = memberFolderJpaRepository.findById(nextParentId) + .orElseThrow(() -> new FolderException(FolderErrorCode.FOLDER_NOT_FOUND)); + } } -} \ No newline at end of file +} From dbd99d556218f2339ca860e5c9d9cd634f2a1d8f Mon Sep 17 00:00:00 2001 From: "DESKTOP-JH9P8S7\\taehun" Date: Sun, 8 Mar 2026 21:17:00 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor=20:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8?= =?UTF-8?q?=20=EA=B4=80=EB=A0=A8=20=EC=B2=98=EB=A6=AC=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 로그인 관련 에러코드 및 SecurityUtils 내용 추가 자세한 내용은 컨플루언스 문서로 작성 --- .../config/exception/CommonErrorCode.java | 1 + .../config/security/SecurityUtils.java | 35 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/web/SearchWeb/config/exception/CommonErrorCode.java b/src/main/java/com/web/SearchWeb/config/exception/CommonErrorCode.java index 45d99d8..8d9ed79 100644 --- a/src/main/java/com/web/SearchWeb/config/exception/CommonErrorCode.java +++ b/src/main/java/com/web/SearchWeb/config/exception/CommonErrorCode.java @@ -7,6 +7,7 @@ @Getter @RequiredArgsConstructor public enum CommonErrorCode implements ErrorCode{ + UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "C001", "로그인된 사용자만 접근 가능합니다."), // 500 Internal Server Error: 서버 내부 오류 INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "C006", "서버에 오류가 발생했습니다."); diff --git a/src/main/java/com/web/SearchWeb/config/security/SecurityUtils.java b/src/main/java/com/web/SearchWeb/config/security/SecurityUtils.java index c7986d1..55736c7 100644 --- a/src/main/java/com/web/SearchWeb/config/security/SecurityUtils.java +++ b/src/main/java/com/web/SearchWeb/config/security/SecurityUtils.java @@ -1,2 +1,35 @@ -package com.web.SearchWeb.config.security;public class SecurityUtils { +package com.web.SearchWeb.config.security; + +import com.web.SearchWeb.config.exception.BusinessException; +import com.web.SearchWeb.config.exception.CommonErrorCode; +import com.web.SearchWeb.member.dto.CustomOAuth2User; +import com.web.SearchWeb.member.dto.CustomUserDetails; +import org.springframework.security.core.Authentication; + +public final class SecurityUtils { + + private SecurityUtils() { + } + + public static Long extractMemberId(Authentication authentication) { + if (authentication == null || !authentication.isAuthenticated()) { + throw BusinessException.from(CommonErrorCode.UNAUTHORIZED); + } + + Object principal = authentication.getPrincipal(); + + if ("anonymousUser".equals(principal)) { + throw BusinessException.from(CommonErrorCode.UNAUTHORIZED); + } + + if (principal instanceof CustomUserDetails userDetails) { + return userDetails.getMemberId(); + } + + if (principal instanceof CustomOAuth2User oauth2User) { + return oauth2User.getMemberId(); + } + + throw BusinessException.from(CommonErrorCode.UNAUTHORIZED); + } }