diff --git a/src/main/java/com/goat/server/directory/application/DirectoryService.java b/src/main/java/com/goat/server/directory/application/DirectoryService.java index b42a068..656b6e1 100644 --- a/src/main/java/com/goat/server/directory/application/DirectoryService.java +++ b/src/main/java/com/goat/server/directory/application/DirectoryService.java @@ -13,6 +13,7 @@ import com.goat.server.mypage.domain.User; import com.goat.server.review.application.ReviewService; import com.goat.server.review.dto.response.ReviewSimpleResponse; +import jakarta.validation.Valid; import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -86,7 +87,7 @@ public void deleteDirectoryPermanent(Long userId, Long directoryId) { * 폴더 생성 */ @Transactional - public void initDirectory(Long userId, DirectoryInitRequest directoryInitRequest) { + public void initDirectory(Long userId, @Valid DirectoryInitRequest directoryInitRequest) { User user = userService.findUser(userId); Directory parentDirectory = getParentDirectory(directoryInitRequest); diff --git a/src/main/java/com/goat/server/directory/domain/Directory.java b/src/main/java/com/goat/server/directory/domain/Directory.java index 8e0d48a..f1a19f1 100644 --- a/src/main/java/com/goat/server/directory/domain/Directory.java +++ b/src/main/java/com/goat/server/directory/domain/Directory.java @@ -1,11 +1,15 @@ package com.goat.server.directory.domain; +import com.goat.server.directory.domain.type.DirectoryColor; +import com.goat.server.directory.domain.type.DirectoryIcon; import com.goat.server.global.domain.BaseTimeEntity; import com.goat.server.mypage.domain.User; import com.goat.server.review.domain.Review; import jakarta.persistence.CascadeType; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -33,8 +37,11 @@ public class Directory extends BaseTimeEntity { @Column(name = "directory_title", length = 100) private String title; - @Column(name = "directory_color", length = 50) - private String directoryColor; + @Enumerated(EnumType.STRING) + private DirectoryIcon directoryIcon; + + @Enumerated(EnumType.STRING) + private DirectoryColor directoryColor; @Column(name = "depth") private Long depth; @@ -54,14 +61,20 @@ public class Directory extends BaseTimeEntity { private List reviewList = new ArrayList<>(); @Builder - public Directory(String title, String directoryColor, Long depth, User user, Directory parentDirectory) { + public Directory(String title, + DirectoryIcon directoryIcon, + DirectoryColor directoryColor, + Long depth, User user, + Directory parentDirectory) { this.title = title; + this.directoryIcon = directoryIcon; this.directoryColor = directoryColor; this.depth = depth; this.user = user; this.parentDirectory = parentDirectory; } + public void updateParentDirectory(Directory parentDirectory) { this.parentDirectory = parentDirectory; this.depth = parentDirectory.getDepth() + 1; diff --git a/src/main/java/com/goat/server/directory/domain/type/DirectoryColor.java b/src/main/java/com/goat/server/directory/domain/type/DirectoryColor.java new file mode 100644 index 0000000..baf00b5 --- /dev/null +++ b/src/main/java/com/goat/server/directory/domain/type/DirectoryColor.java @@ -0,0 +1,12 @@ +package com.goat.server.directory.domain.type; + +public enum DirectoryColor { + RED, + ORANGE, + YELLOW, + PINK, + GREEN, + CYAN, + BLUE, + PURPLE, +} diff --git a/src/main/java/com/goat/server/directory/domain/type/DirectoryIcon.java b/src/main/java/com/goat/server/directory/domain/type/DirectoryIcon.java new file mode 100644 index 0000000..73b1b0a --- /dev/null +++ b/src/main/java/com/goat/server/directory/domain/type/DirectoryIcon.java @@ -0,0 +1,8 @@ +package com.goat.server.directory.domain.type; + +public enum DirectoryIcon { + PENCIL, + BOOK, + INSIGHT, + BOOK2 +} diff --git a/src/main/java/com/goat/server/directory/dto/request/DirectoryInitRequest.java b/src/main/java/com/goat/server/directory/dto/request/DirectoryInitRequest.java index 7dfdc19..bd16e56 100644 --- a/src/main/java/com/goat/server/directory/dto/request/DirectoryInitRequest.java +++ b/src/main/java/com/goat/server/directory/dto/request/DirectoryInitRequest.java @@ -1,12 +1,17 @@ package com.goat.server.directory.dto.request; import com.goat.server.directory.domain.Directory; +import com.goat.server.directory.domain.type.DirectoryColor; +import com.goat.server.directory.domain.type.DirectoryIcon; +import com.goat.server.directory.util.EnumValid; import com.goat.server.mypage.domain.User; public record DirectoryInitRequest( String directoryName, Long parentDirectoryId, - String directoryColor + @EnumValid(enumClass = DirectoryColor.class) String directoryColor, + @EnumValid(enumClass = DirectoryIcon.class) String directoryIcon, + String directoryDescription ) { public Directory toEntity(User user, Directory parentDirectory) { return Directory.builder() @@ -14,7 +19,8 @@ public Directory toEntity(User user, Directory parentDirectory) { .parentDirectory(parentDirectory) .depth(parentDirectory == null ? 1 : parentDirectory.getDepth() + 1) .title(directoryName) - .directoryColor(directoryColor) + .directoryColor(DirectoryColor.valueOf(directoryColor)) + .directoryIcon(DirectoryIcon.valueOf(directoryIcon)) .build(); } } \ No newline at end of file diff --git a/src/main/java/com/goat/server/directory/dto/response/DirectoryResponse.java b/src/main/java/com/goat/server/directory/dto/response/DirectoryResponse.java index 9d530ab..e5112b6 100644 --- a/src/main/java/com/goat/server/directory/dto/response/DirectoryResponse.java +++ b/src/main/java/com/goat/server/directory/dto/response/DirectoryResponse.java @@ -1,13 +1,16 @@ package com.goat.server.directory.dto.response; import com.goat.server.directory.domain.Directory; +import com.goat.server.directory.domain.type.DirectoryColor; +import com.goat.server.directory.domain.type.DirectoryIcon; import lombok.Builder; @Builder public record DirectoryResponse( Long directoryId, String directoryName, - String directoryColor + DirectoryColor directoryColor, + DirectoryIcon directoryIcon ) { public static DirectoryResponse from(Directory directory) { @@ -15,6 +18,7 @@ public static DirectoryResponse from(Directory directory) { .directoryId(directory.getId()) .directoryName(directory.getTitle()) .directoryColor(directory.getDirectoryColor()) + .directoryIcon(directory.getDirectoryIcon()) .build(); } } diff --git a/src/main/java/com/goat/server/directory/presentation/DirectoryController.java b/src/main/java/com/goat/server/directory/presentation/DirectoryController.java index 9f228f5..6a84db9 100644 --- a/src/main/java/com/goat/server/directory/presentation/DirectoryController.java +++ b/src/main/java/com/goat/server/directory/presentation/DirectoryController.java @@ -56,7 +56,7 @@ public ResponseEntity> getDirectorySubList( @PostMapping public ResponseEntity> initDirectory( @AuthenticationPrincipal Long userId, - @RequestBody DirectoryInitRequest directoryInitRequest) { + @Valid @RequestBody DirectoryInitRequest directoryInitRequest) { directoryService.initDirectory(userId, directoryInitRequest); diff --git a/src/main/java/com/goat/server/directory/repository/DirectoryRepositoryImpl.java b/src/main/java/com/goat/server/directory/repository/DirectoryRepositoryImpl.java index efe5580..2d88fde 100644 --- a/src/main/java/com/goat/server/directory/repository/DirectoryRepositoryImpl.java +++ b/src/main/java/com/goat/server/directory/repository/DirectoryRepositoryImpl.java @@ -27,7 +27,8 @@ public List findAllDirectoryResponseBySortAndSearch( .select(Projections.constructor(DirectoryResponse.class, directory.id, directory.title, - directory.directoryColor)) + directory.directoryColor, + directory.directoryIcon)) .from(directory) .where(directory.user.userId.eq(userId), isSearchExpression(parentDirectoryId, search)) .orderBy(sortExpression(sort)) diff --git a/src/main/java/com/goat/server/directory/repository/init/DirectoryInitializer.java b/src/main/java/com/goat/server/directory/repository/init/DirectoryInitializer.java index 16c9746..b53f24b 100644 --- a/src/main/java/com/goat/server/directory/repository/init/DirectoryInitializer.java +++ b/src/main/java/com/goat/server/directory/repository/init/DirectoryInitializer.java @@ -1,5 +1,7 @@ package com.goat.server.directory.repository.init; +import com.goat.server.directory.domain.type.DirectoryColor; +import com.goat.server.directory.domain.type.DirectoryIcon; import com.goat.server.global.util.LocalDummyDataInit; import com.goat.server.directory.domain.Directory; import com.goat.server.directory.repository.DirectoryRepository; @@ -41,21 +43,23 @@ public void run(ApplicationArguments args) { Directory DUMMY_TRASH_DIRECTORY1 = Directory.builder() .title("trash_directory") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(admin) .build(); Directory DUMMY_TRASH_DIRECTORY2 = Directory.builder() .title("trash_directory") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.PINK) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(user) .build(); Directory DUMMY_TRASH_DIRECTORY3 = Directory.builder() .title("trash_directory") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) .depth(1L) .parentDirectory(null) .user(guest) @@ -63,21 +67,24 @@ public void run(ApplicationArguments args) { Directory DUMMY_PARENT_DIRECTORY1 = Directory.builder() .title("dummyDirectory1") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(user) .build(); Directory DUMMY_PARENT_DIRECTORY2 = Directory.builder() .title("dummyDirectory2") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(user) .build(); Directory DUMMY_PARENT_DIRECTORY3 = Directory.builder() .title("dummyDirectory3") - .directoryColor("#FF000F") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(admin) @@ -85,21 +92,24 @@ public void run(ApplicationArguments args) { Directory DUMMY_CHILD_DIRECTORY1 = Directory.builder() .title("dummyDirectory4") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(2L) .parentDirectory(DUMMY_PARENT_DIRECTORY1) .user(user) .build(); Directory DUMMY_CHILD_DIRECTORY2 = Directory.builder() .title("dummyDirectory5") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(2L) .parentDirectory(DUMMY_PARENT_DIRECTORY1) .user(user) .build(); Directory DUMMY_CHILD_DIRECTORY3 = Directory.builder() .title("dummyDirectory6") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(2L) .parentDirectory(DUMMY_CHILD_DIRECTORY2) .user(user) @@ -107,21 +117,24 @@ public void run(ApplicationArguments args) { Directory DUMMY_STORAGE_DIRECTORY1 = Directory.builder() .title("storage_directory") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(admin) .build(); Directory DUMMY_STORAGE_DIRECTORY2 = Directory.builder() .title("storage_directory") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(user) .build(); Directory DUMMY_STORAGE_DIRECTORY3 = Directory.builder() .title("storage_directory") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.CYAN) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(guest) diff --git a/src/main/java/com/goat/server/directory/util/EnumValid.java b/src/main/java/com/goat/server/directory/util/EnumValid.java new file mode 100644 index 0000000..2833260 --- /dev/null +++ b/src/main/java/com/goat/server/directory/util/EnumValid.java @@ -0,0 +1,19 @@ +package com.goat.server.directory.util; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.FIELD, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = EnumValidator.class) +public @interface EnumValid { + + Class> enumClass(); + String message() default "지정되지 않은 Enum 값입니다."; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/com/goat/server/directory/util/EnumValidator.java b/src/main/java/com/goat/server/directory/util/EnumValidator.java new file mode 100644 index 0000000..49cf05d --- /dev/null +++ b/src/main/java/com/goat/server/directory/util/EnumValidator.java @@ -0,0 +1,23 @@ +package com.goat.server.directory.util; + +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; +import java.util.Arrays; +import java.util.Set; +import java.util.stream.Collectors; + +public class EnumValidator implements ConstraintValidator { + private Set acceptedValues; + + @Override + public void initialize(EnumValid enumAnnotation) { + acceptedValues = Arrays.stream(enumAnnotation.enumClass().getEnumConstants()) + .map(Enum::name) + .collect(Collectors.toSet()); + } + + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + return acceptedValues.contains(value); + } +} diff --git a/src/main/java/com/goat/server/global/exception/errorcode/GlobalErrorCode.java b/src/main/java/com/goat/server/global/exception/errorcode/GlobalErrorCode.java index 6fa83da..66f7cb6 100644 --- a/src/main/java/com/goat/server/global/exception/errorcode/GlobalErrorCode.java +++ b/src/main/java/com/goat/server/global/exception/errorcode/GlobalErrorCode.java @@ -15,6 +15,7 @@ public enum GlobalErrorCode implements ErrorCode { RESOURCE_NOT_FOUND(HttpStatus.NOT_FOUND, "Resource not exists"), INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Internal server error"), ACCESS_DENIED(HttpStatus.FORBIDDEN, "You don't have permission to access this resource"), + INVALID_METHOD(HttpStatus.METHOD_NOT_ALLOWED, "Invalid Method"), ; private final HttpStatus httpStatus; diff --git a/src/main/java/com/goat/server/global/exception/handler/GlobalExceptionHandler.java b/src/main/java/com/goat/server/global/exception/handler/GlobalExceptionHandler.java index ac79735..5daa626 100644 --- a/src/main/java/com/goat/server/global/exception/handler/GlobalExceptionHandler.java +++ b/src/main/java/com/goat/server/global/exception/handler/GlobalExceptionHandler.java @@ -3,50 +3,64 @@ import com.goat.server.directory.exception.DirectoryCanNotDeleteException; import com.goat.server.directory.exception.DirectoryNotFoundException; import com.goat.server.mypage.exception.UserNotFoundException; +import jakarta.servlet.http.HttpServletRequest; import java.util.List; import com.goat.server.global.exception.CustomFeignException; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatusCode; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.validation.BindException; +import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import com.goat.server.global.exception.errorcode.ErrorCode; import com.goat.server.global.exception.errorcode.GlobalErrorCode; import com.goat.server.global.exception.response.ErrorResponse; import com.goat.server.global.exception.response.ErrorResponse.ValidationError; import com.goat.server.global.exception.response.ErrorResponse.ValidationErrors; +import org.springframework.web.context.request.WebRequest; +import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; -@Slf4j @RestControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { + private static final Logger log = LoggerFactory.getLogger("ErrorLogger"); + private static final String LOG_FORMAT_INFO = "\n[🔵INFO] - ({} {})\n(id: {}, role: {})\n{}\n {}: {}"; + private static final String LOG_FORMAT_WARN = "\n[🟠WARN] - ({} {})\n(id: {}, role: {})"; + private static final String LOG_FORMAT_ERROR = "\n[🔴ERROR] - ({} {})\n(id: {}, role: {})"; + @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity handleIllegalArgument(final IllegalArgumentException e) { - final ErrorCode errorCode = GlobalErrorCode.INVALID_PARAMETER; + public ResponseEntity handleIllegalArgument(IllegalArgumentException e, HttpServletRequest request) { + logInfo(GlobalErrorCode.INVALID_PARAMETER, e, request); + ErrorCode errorCode = GlobalErrorCode.INVALID_PARAMETER; return handleExceptionInternal(errorCode, e.getMessage()); } @ExceptionHandler(UserNotFoundException.class) - public ResponseEntity handleUserNotFound(final UserNotFoundException e) { - final ErrorCode errorCode = e.getErrorCode(); + public ResponseEntity handleUserNotFound(UserNotFoundException e, HttpServletRequest request) { + logInfo(e.getErrorCode(), e, request); + ErrorCode errorCode = e.getErrorCode(); return handleExceptionInternal(errorCode); } @ExceptionHandler(DirectoryNotFoundException.class) - public ResponseEntity handleDirectoryNotFound(final DirectoryNotFoundException e) { - final ErrorCode errorCode = e.getErrorCode(); + public ResponseEntity handleDirectoryNotFound(DirectoryNotFoundException e, HttpServletRequest request) { + logInfo(e.getErrorCode(), e, request); + ErrorCode errorCode = e.getErrorCode(); return handleExceptionInternal(errorCode); } @ExceptionHandler(DirectoryCanNotDeleteException.class) - public ResponseEntity handleDirectoryCanNotDelete(final DirectoryCanNotDeleteException e) { - final ErrorCode errorCode = e.getErrorCode(); + public ResponseEntity handleDirectoryCanNotDelete(DirectoryCanNotDeleteException e, + HttpServletRequest request) { + logInfo(e.getErrorCode(), e, request); + ErrorCode errorCode = e.getErrorCode(); return handleExceptionInternal(errorCode); } @@ -54,39 +68,51 @@ public ResponseEntity handleDirectoryCanNotDelete(final DirectoryCanNotD * Feign 관련 exception 처리 */ @ExceptionHandler(CustomFeignException.class) - public ErrorResponse handleTokenNotExist(final CustomFeignException e) { - final ErrorCode errorCode = e.getErrorCode(); + public ErrorResponse handleTokenNotExist(CustomFeignException e, HttpServletRequest request) { + logInfo(e.getErrorCode(), e, request); + ErrorCode errorCode = e.getErrorCode(); return makeErrorResponse(errorCode, e.getMessage()); } + @ExceptionHandler(Exception.class) + public ResponseEntity handleAllException(Exception e, HttpServletRequest request) { + logError(e, request); + ErrorCode errorCode = GlobalErrorCode.INTERNAL_SERVER_ERROR; + return handleExceptionInternal(errorCode); + } /** * DTO @Valid 관련 exception 처리 */ @Override - public ResponseEntity handleMethodArgumentNotValid( - final MethodArgumentNotValidException e, - final HttpHeaders headers, - final HttpStatusCode status, - final WebRequest request) { - log.warn("handleIllegalArgument", e); - final ErrorCode errorCode = GlobalErrorCode.INVALID_PARAMETER; + protected ResponseEntity handleMethodArgumentNotValid( + MethodArgumentNotValidException e, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + ErrorCode errorCode = GlobalErrorCode.INVALID_PARAMETER; return handleExceptionInternal(e, errorCode); } - @ExceptionHandler(Exception.class) - public ResponseEntity handleAllException(final Exception ex) { - log.warn("handleAllException", ex); - final ErrorCode errorCode = GlobalErrorCode.INTERNAL_SERVER_ERROR; + /** + * HTTP Method 관련 exception 처리 + */ + @Override + protected ResponseEntity handleHttpRequestMethodNotSupported( + HttpRequestMethodNotSupportedException e, + HttpHeaders headers, + HttpStatusCode status, + WebRequest request) { + ErrorCode errorCode = GlobalErrorCode.INVALID_METHOD; return handleExceptionInternal(errorCode); } - private ResponseEntity handleExceptionInternal(final ErrorCode errorCode) { + private ResponseEntity handleExceptionInternal(ErrorCode errorCode) { return ResponseEntity.status(errorCode.getHttpStatus()) .body(makeErrorResponse(errorCode)); } - private ErrorResponse makeErrorResponse(final ErrorCode errorCode) { + private ErrorResponse makeErrorResponse(ErrorCode errorCode) { return ErrorResponse.builder() .isSuccess(false) .code(errorCode.name()) @@ -95,12 +121,12 @@ private ErrorResponse makeErrorResponse(final ErrorCode errorCode) { .build(); } - private ResponseEntity handleExceptionInternal(final ErrorCode errorCode, final String message) { + private ResponseEntity handleExceptionInternal(ErrorCode errorCode, String message) { return ResponseEntity.status(errorCode.getHttpStatus()) .body(makeErrorResponse(errorCode, message)); } - private ErrorResponse makeErrorResponse(final ErrorCode errorCode, final String message) { + private ErrorResponse makeErrorResponse(ErrorCode errorCode, String message) { return ErrorResponse.builder() .isSuccess(false) .code(errorCode.name()) @@ -109,12 +135,12 @@ private ErrorResponse makeErrorResponse(final ErrorCode errorCode, final String .build(); } - private ResponseEntity handleExceptionInternal(final BindException e, final ErrorCode errorCode) { + private ResponseEntity handleExceptionInternal(BindException e, ErrorCode errorCode) { return ResponseEntity.status(errorCode.getHttpStatus()) .body(makeErrorResponse(e, errorCode)); } - private ErrorResponse makeErrorResponse(final BindException e, final ErrorCode errorCode) { + private ErrorResponse makeErrorResponse(BindException e, ErrorCode errorCode) { final List validationErrorList = e.getBindingResult() .getFieldErrors() .stream() @@ -128,4 +154,37 @@ private ErrorResponse makeErrorResponse(final BindException e, final ErrorCode e .results(new ValidationErrors(validationErrorList)) .build(); } + + private void logInfo(ErrorCode ec, Exception e, HttpServletRequest request) { + log.info(LOG_FORMAT_INFO, request.getMethod(), request.getRequestURI(), getUserId(), + getRole(), ec.getHttpStatus(), e.getClass().getName(), e.getMessage()); + } + + private void logWarn(Exception e, HttpServletRequest request) { + log.warn(LOG_FORMAT_WARN, request.getMethod(), request.getRequestURI(), getUserId(), getRole(), e); + } + + private void logError(Exception e, HttpServletRequest request) { + log.error(LOG_FORMAT_ERROR, request.getMethod(), request.getRequestURI(), getUserId(), getRole(), e); + } + + private String getUserId() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication != null && authentication.isAuthenticated()) { + return authentication.getName(); // 사용자의 id + } else { + return "anonymous"; + } + } + + private String getRole() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + + if (authentication != null && authentication.isAuthenticated()) { + return authentication.getAuthorities().toString(); // 사용자의 role + } else { + return "anonymous"; + } + } } diff --git a/src/main/java/com/goat/server/mypage/application/MypageService.java b/src/main/java/com/goat/server/mypage/application/MypageService.java index 131b23a..cd5216d 100644 --- a/src/main/java/com/goat/server/mypage/application/MypageService.java +++ b/src/main/java/com/goat/server/mypage/application/MypageService.java @@ -1,6 +1,5 @@ package com.goat.server.mypage.application; -import com.goat.server.mypage.domain.Major; import com.goat.server.mypage.domain.User; import com.goat.server.mypage.dto.request.GoalRequest; import com.goat.server.mypage.dto.request.MypageDetailsRequest; @@ -15,8 +14,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.List; -import java.util.stream.Collectors; @Slf4j @Transactional(readOnly = true) @@ -28,44 +25,38 @@ public class MypageService { private final ReviewRepository reviewRepository; /** - * 마이페이지에서 닉네임, 학년, 전공들, 복습횟수, 한줄목표 조회하기, 프로필 이미지 조회하기 + * 마이페이지에서 닉네임, 복습횟수, 한줄목표, 프로필 이미지 조회하기 */ - public MypageHomeResponse getUserWithMajors(Long userId) { - User user = userRepository.findUserWithMajors(userId).orElseThrow(); - - List majorNames = user.getMajorList().stream() - .map(Major::getMajorName) - .collect(Collectors.toList()); + public MypageHomeResponse getMypageHome(Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new UserNotFoundException(MypageErrorCode.USER_NOT_FOUND)); Long totalReviewCnt = reviewRepository.sumReviewCntByUser(user.getUserId()); - return MypageHomeResponse.of(user, majorNames, totalReviewCnt); + return MypageHomeResponse.of(user, totalReviewCnt); } /** * 마이페이지에서 세부 정보 조회하기 (프로필 이미지, 닉네임, 전공들, 학년 ) */ public MypageDetailsResponse getMypageDetails(Long userId) { - User user = userRepository.findUserWithMajors(userId).orElseThrow(); - - List majorNames = user.getMajorList().stream() - .map(Major::getMajorName) - .collect(Collectors.toList()); + User user = userRepository.findById(userId) + .orElseThrow(() -> new UserNotFoundException(MypageErrorCode.USER_NOT_FOUND)); - return MypageDetailsResponse.of(user, majorNames); + return MypageDetailsResponse.from(user); } /** - * 마이페이지에서 세부 정보 수정하기 (프로필 이미지, 닉네임, 전공들, 학년 ) + * 마이페이지에서 세부 정보 수정하기 (닉네임) */ @Transactional public void updateMypageDetails(Long userId, MypageDetailsRequest request) { - User user = userRepository.findUserWithMajors(userId).orElseThrow(); + User user = userRepository.findById(userId) + .orElseThrow(() -> new UserNotFoundException(MypageErrorCode.USER_NOT_FOUND)); user.updateMypageDetails(request); } - /** * 한줄 목표 업데이트 */ @@ -75,5 +66,4 @@ public void updateGoal(Long userId, GoalRequest goalRequest) { .orElseThrow(() -> new UserNotFoundException(MypageErrorCode.USER_NOT_FOUND)); user.updateGoal(goalRequest.goal()); } - -} +} \ No newline at end of file diff --git a/src/main/java/com/goat/server/mypage/domain/User.java b/src/main/java/com/goat/server/mypage/domain/User.java index a6bab1f..c0f71ad 100644 --- a/src/main/java/com/goat/server/mypage/domain/User.java +++ b/src/main/java/com/goat/server/mypage/domain/User.java @@ -91,29 +91,9 @@ public void updateProfileImage(ImageInfo imageInfo) { this.imageInfo = imageInfo; } - //마이페이지에서 세부 내용 업데이트 (닉네임, 학년, 전공) + //마이페이지에서 세부 내용 업데이트 (닉네임) public void updateMypageDetails(MypageDetailsRequest request) { this.nickname = request.nickname(); - this.grade = request.grade(); - - List newMajorNames = request.majorList().stream() - .map(String::valueOf) - .toList(); - - this.majorList.removeIf(existingMajor -> !newMajorNames.contains(existingMajor.getMajorName())); - - // 전공 추가 - for (String majorName : newMajorNames) { - boolean exists = this.majorList.stream() - .anyMatch(existingMajor -> existingMajor.getMajorName().equals(majorName)); - - if (!exists) { - this.majorList.add(Major.builder() - .majorName(majorName) - .user(this) - .build()); - } - } } //프로필 url 가져오는 메서드 diff --git a/src/main/java/com/goat/server/mypage/dto/request/MypageDetailsRequest.java b/src/main/java/com/goat/server/mypage/dto/request/MypageDetailsRequest.java index 0721955..bf8d57b 100644 --- a/src/main/java/com/goat/server/mypage/dto/request/MypageDetailsRequest.java +++ b/src/main/java/com/goat/server/mypage/dto/request/MypageDetailsRequest.java @@ -1,14 +1,9 @@ package com.goat.server.mypage.dto.request; -import com.goat.server.mypage.domain.type.Grade; import lombok.Builder; -import java.util.List; - @Builder public record MypageDetailsRequest( - String nickname, - Grade grade, - List majorList + String nickname ) { } diff --git a/src/main/java/com/goat/server/mypage/dto/response/MypageDetailsResponse.java b/src/main/java/com/goat/server/mypage/dto/response/MypageDetailsResponse.java index 394d542..532ecc1 100644 --- a/src/main/java/com/goat/server/mypage/dto/response/MypageDetailsResponse.java +++ b/src/main/java/com/goat/server/mypage/dto/response/MypageDetailsResponse.java @@ -1,24 +1,17 @@ package com.goat.server.mypage.dto.response; import com.goat.server.mypage.domain.User; -import com.goat.server.mypage.domain.type.Grade; import lombok.Builder; -import java.util.List; - @Builder public record MypageDetailsResponse( String imageUrl, - String nickname, - Grade grade, - List majorList + String nickname ) { - public static MypageDetailsResponse of(User user, List majorNames) { + public static MypageDetailsResponse from(User user) { return MypageDetailsResponse.builder() .imageUrl(user.getProfileImageUrl()) .nickname(user.getNickname()) - .grade(user.getGrade()) - .majorList(majorNames) .build(); } } diff --git a/src/main/java/com/goat/server/mypage/dto/response/MypageHomeResponse.java b/src/main/java/com/goat/server/mypage/dto/response/MypageHomeResponse.java index 3f2faaf..0fb378a 100644 --- a/src/main/java/com/goat/server/mypage/dto/response/MypageHomeResponse.java +++ b/src/main/java/com/goat/server/mypage/dto/response/MypageHomeResponse.java @@ -1,27 +1,20 @@ package com.goat.server.mypage.dto.response; import com.goat.server.mypage.domain.User; -import com.goat.server.mypage.domain.type.Grade; import lombok.Builder; -import java.util.List; - @Builder public record MypageHomeResponse ( String imageUrl, String nickname, - Grade grade, String goal, - Long totalReviewCnt, - List majorList + Long totalReviewCnt ) { - public static MypageHomeResponse of(User user, List majorNames, Long totalReviewCnt) { + public static MypageHomeResponse of(User user, Long totalReviewCnt) { return MypageHomeResponse.builder() .imageUrl(user.getProfileImageUrl()) .nickname(user.getNickname()) - .grade(user.getGrade()) .goal(user.getGoal()) - .majorList(majorNames) .totalReviewCnt(totalReviewCnt) .build(); } diff --git a/src/main/java/com/goat/server/mypage/presentation/MypageController.java b/src/main/java/com/goat/server/mypage/presentation/MypageController.java index cd419ef..1330184 100644 --- a/src/main/java/com/goat/server/mypage/presentation/MypageController.java +++ b/src/main/java/com/goat/server/mypage/presentation/MypageController.java @@ -29,18 +29,18 @@ public class MypageController { private final MypageService mypageService; private final UserService userService; - @Operation(summary = "마이페이지 정보 보기", description = "마이페이지 정보 보기") + @Operation(summary = "마이페이지 첫화면 정보 보기", description = "마이페이지에서 프로필이미지, 닉네임, 목표, 복습횟수 정보 보기") @GetMapping("/info") public ResponseEntity> getMypageAllDetail(@AuthenticationPrincipal Long userId) { - MypageHomeResponse mypageHomeResponse = mypageService.getUserWithMajors(userId); + MypageHomeResponse mypageHomeResponse = mypageService.getMypageHome(userId); return ResponseEntity .status(HttpStatus.OK) .body(ResponseTemplate.from(mypageHomeResponse)); } - @Operation(summary = "마이페이지 세부 정보 보기", description = "마이페이지에서 프로필이미지, 닉네임, 전공, 학년 보기") + @Operation(summary = "마이페이지 세부 정보 보기", description = "마이페이지에서 프로필이미지, 닉네임 보기") @GetMapping("/info/details") public ResponseEntity> getMypageDetails(@AuthenticationPrincipal Long userId) { @@ -51,7 +51,7 @@ public ResponseEntity> getMypageDetails(@Authentication .body(ResponseTemplate.from(mypageDetailsResponse)); } - @Operation(summary = "마이페이지 세부 정보 수정하기", description = "마이페이지에서 닉네임, 전공, 학년 수정하기") + @Operation(summary = "마이페이지 세부 정보 수정하기", description = "마이페이지에서 닉네임 수정하기") @PutMapping("/info/details") public ResponseEntity> updateUserDetails( @AuthenticationPrincipal Long userId, @@ -64,7 +64,7 @@ public ResponseEntity> updateUserDetails( .body(ResponseTemplate.EMPTY_RESPONSE); } - @Operation(summary = "마이페이지 프로필 이미지 수정하기", description = "마이페이지 프로필 이미지 수정하기") + @Operation(summary = "마이페이지 프로필 이미지 수정하기", description = "마이페이지에서 프로필 이미지 수정하기") @PutMapping (consumes = {MediaType.MULTIPART_FORM_DATA_VALUE}, value ="/info/profile") public ResponseEntity> updateProfileImage( @AuthenticationPrincipal Long userId, diff --git a/src/main/resources/console-appender.xml b/src/main/resources/console-appender.xml new file mode 100644 index 0000000..f85a928 --- /dev/null +++ b/src/main/resources/console-appender.xml @@ -0,0 +1,7 @@ + + + + ${CONSOLE_LOG_PATTERN} + + + \ No newline at end of file diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..d0055a4 --- /dev/null +++ b/src/main/resources/logback-spring.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/logs/common/file-error-appender.xml b/src/main/resources/logs/common/file-error-appender.xml new file mode 100644 index 0000000..6bcd2b1 --- /dev/null +++ b/src/main/resources/logs/common/file-error-appender.xml @@ -0,0 +1,19 @@ + + + + ${FILE_LOG_PATTERN} + + + ERROR + ACCEPT + DENY + + + ${LOG_PATH}/log/common/error/error-%d{yyyy-MM-dd}.%i.log + + 100MB + 30 + 3GB + + + \ No newline at end of file diff --git a/src/main/resources/logs/common/file-info-appender.xml b/src/main/resources/logs/common/file-info-appender.xml new file mode 100644 index 0000000..91fa2c8 --- /dev/null +++ b/src/main/resources/logs/common/file-info-appender.xml @@ -0,0 +1,19 @@ + + + + ${FILE_LOG_PATTERN} + + + INFO + ACCEPT + DENY + + + ${LOG_PATH}/log/common/info/info-%d{yyyy-MM-dd}.%i.log + + 100MB + 30 + 3GB + + + \ No newline at end of file diff --git a/src/main/resources/logs/common/file-warn-appender.xml b/src/main/resources/logs/common/file-warn-appender.xml new file mode 100644 index 0000000..1202b79 --- /dev/null +++ b/src/main/resources/logs/common/file-warn-appender.xml @@ -0,0 +1,19 @@ + + + + ${FILE_LOG_PATTERN} + + + WARN + ACCEPT + DENY + + + ${LOG_PATH}/log/common/warn/warn-%d{yyyy-MM-dd}.%i.log + + 100MB + 30 + 3GB + + + \ No newline at end of file diff --git a/src/main/resources/logs/error/file-error-appender.xml b/src/main/resources/logs/error/file-error-appender.xml new file mode 100644 index 0000000..4ed8057 --- /dev/null +++ b/src/main/resources/logs/error/file-error-appender.xml @@ -0,0 +1,19 @@ + + + + ${FILE_LOG_PATTERN} + + + ERROR + ACCEPT + DENY + + + ${LOG_PATH}/log/error/error/error-%d{yyyy-MM-dd}.%i.log + + 100MB + 100 + 4GB + + + \ No newline at end of file diff --git a/src/main/resources/logs/error/file-info-appender.xml b/src/main/resources/logs/error/file-info-appender.xml new file mode 100644 index 0000000..02a9eda --- /dev/null +++ b/src/main/resources/logs/error/file-info-appender.xml @@ -0,0 +1,19 @@ + + + + ${FILE_LOG_PATTERN} + + + INFO + ACCEPT + DENY + + + ${LOG_PATH}/log/error/info/info-%d{yyyy-MM-dd}.%i.log + + 100MB + 100 + 4GB + + + \ No newline at end of file diff --git a/src/main/resources/logs/error/file-warn-appender.xml b/src/main/resources/logs/error/file-warn-appender.xml new file mode 100644 index 0000000..56b7df7 --- /dev/null +++ b/src/main/resources/logs/error/file-warn-appender.xml @@ -0,0 +1,19 @@ + + + + ${FILE_LOG_PATTERN} + + + WARN + ACCEPT + DENY + + + ${LOG_PATH}/log/error/warn/warn-%d{yyyy-MM-dd}.%i.log + + 100MB + 100 + 4GB + + + \ No newline at end of file diff --git a/src/test/java/com/goat/server/directory/application/DirectoryServiceTest.java b/src/test/java/com/goat/server/directory/application/DirectoryServiceTest.java index 8819e78..dba84a9 100644 --- a/src/test/java/com/goat/server/directory/application/DirectoryServiceTest.java +++ b/src/test/java/com/goat/server/directory/application/DirectoryServiceTest.java @@ -59,8 +59,10 @@ void getDirectoryListTest() { //given given(directoryRepository.existsById(PARENT_DIRECTORY1.getId())) .willReturn(true); - given(directoryRepository.findAllDirectoryResponseBySortAndSearch(eq(USER_USER.getUserId()), eq(PARENT_DIRECTORY1.getId()), any(), any())) - .willReturn(List.of(DirectoryResponse.from(CHILD_DIRECTORY1), DirectoryResponse.from(CHILD_DIRECTORY2))); + given(directoryRepository.findAllDirectoryResponseBySortAndSearch(eq(USER_USER.getUserId()), + eq(PARENT_DIRECTORY1.getId()), any(), any())) + .willReturn( + List.of(DirectoryResponse.from(CHILD_DIRECTORY1), DirectoryResponse.from(CHILD_DIRECTORY2))); given(reviewService.getReviewSimpleResponseList(any(), eq(PARENT_DIRECTORY1.getId()), any(), any())).willReturn( List.of(ReviewSimpleResponse.from(DUMMY_REVIEW1), ReviewSimpleResponse.from(DUMMY_REVIEW2))); @@ -82,8 +84,10 @@ void getDirectoryListTest() { @DisplayName("과목과 폴더 가져 오기 테스트 - 루트 폴더") void getDirectoryListTest2() { //given - given(directoryRepository.findAllDirectoryResponseBySortAndSearch(eq(USER_USER.getUserId()), eq(0L), any(), any())) - .willReturn(List.of(DirectoryResponse.from(PARENT_DIRECTORY1), DirectoryResponse.from(PARENT_DIRECTORY2))); + given(directoryRepository.findAllDirectoryResponseBySortAndSearch(eq(USER_USER.getUserId()), eq(0L), any(), + any())) + .willReturn( + List.of(DirectoryResponse.from(PARENT_DIRECTORY1), DirectoryResponse.from(PARENT_DIRECTORY2))); //when DirectoryTotalShowResponse directorySubList = @@ -118,7 +122,7 @@ void deleteDirectoryTemporalTest() { void initDirectoryTest() { //given DirectoryInitRequest directoryInitRequest = - new DirectoryInitRequest("폴더", 0L, "#FF0000"); + new DirectoryInitRequest("폴더", 0L, "BLUE", "PENCIL", "description"); given(userService.findUser(USER_USER.getUserId())).willReturn(USER_USER); @@ -131,7 +135,7 @@ void initDirectoryTest() { Directory savedDirectory = directoryCaptor.getValue(); assertThat(savedDirectory.getTitle()).isEqualTo(directoryInitRequest.directoryName()); assertThat(savedDirectory.getParentDirectory()).isNull(); - assertThat(savedDirectory.getDirectoryColor()).isEqualTo(directoryInitRequest.directoryColor()); + assertThat(savedDirectory.getDirectoryColor().toString()).isEqualTo(directoryInitRequest.directoryColor()); } @Test @@ -139,7 +143,7 @@ void initDirectoryTest() { void initDirectoryTest2() { //given DirectoryInitRequest directoryInitRequest = - new DirectoryInitRequest("폴더", PARENT_DIRECTORY1.getId(), "#FF0000"); + new DirectoryInitRequest("폴더", PARENT_DIRECTORY1.getId(), "BLUE", "PENCIL", "description"); given(userService.findUser(USER_USER.getUserId())).willReturn(USER_USER); given(directoryRepository.findById(PARENT_DIRECTORY1.getId())) @@ -154,7 +158,7 @@ void initDirectoryTest2() { Directory savedDirectory = directoryCaptor.getValue(); assertThat(savedDirectory.getTitle()).isEqualTo(directoryInitRequest.directoryName()); assertThat(savedDirectory.getParentDirectory()).isEqualTo(PARENT_DIRECTORY1); - assertThat(savedDirectory.getDirectoryColor()).isEqualTo(directoryInitRequest.directoryColor()); + assertThat(savedDirectory.getDirectoryColor().toString()).isEqualTo(directoryInitRequest.directoryColor()); } @Test diff --git a/src/test/java/com/goat/server/directory/fixture/DirectoryFixture.java b/src/test/java/com/goat/server/directory/fixture/DirectoryFixture.java index eab7fc7..814580a 100644 --- a/src/test/java/com/goat/server/directory/fixture/DirectoryFixture.java +++ b/src/test/java/com/goat/server/directory/fixture/DirectoryFixture.java @@ -1,6 +1,8 @@ package com.goat.server.directory.fixture; import com.goat.server.directory.domain.Directory; +import com.goat.server.directory.domain.type.DirectoryColor; +import com.goat.server.directory.domain.type.DirectoryIcon; import com.goat.server.mypage.fixture.UserFixture; import org.springframework.test.util.ReflectionTestUtils; @@ -8,7 +10,8 @@ public class DirectoryFixture { public static final Directory TRASH_DIRECTORY = Directory.builder() .title("trash_directory") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.BLUE) + .directoryIcon(DirectoryIcon.BOOK) .depth(1L) .parentDirectory(null) .user(UserFixture.USER_USER) @@ -16,14 +19,16 @@ public class DirectoryFixture { public static final Directory PARENT_DIRECTORY1 = Directory.builder() .title("directory1") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.BLUE) + .directoryIcon(DirectoryIcon.BOOK) .parentDirectory(null) .depth(1L) .user(UserFixture.USER_USER) .build(); public static final Directory PARENT_DIRECTORY2 = Directory.builder() .title("directory2") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.BLUE) + .directoryIcon(DirectoryIcon.BOOK) .parentDirectory(null) .depth(1L) .user(UserFixture.USER_USER) @@ -31,23 +36,26 @@ public class DirectoryFixture { public static final Directory CHILD_DIRECTORY1 = Directory.builder() .title("directory3") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.BLUE) + .directoryIcon(DirectoryIcon.BOOK) .parentDirectory(PARENT_DIRECTORY1) .depth(2L) .user(UserFixture.USER_USER) .build(); public static final Directory CHILD_DIRECTORY2 = Directory.builder() .title("directory3") - .directoryColor("#FF00FF") + .directoryColor(DirectoryColor.BLUE) + .directoryIcon(DirectoryIcon.BOOK) .parentDirectory(PARENT_DIRECTORY1) .depth(2L) .user(UserFixture.USER_USER) .build(); static { - ReflectionTestUtils.setField(PARENT_DIRECTORY1, "id", 1L); - ReflectionTestUtils.setField(PARENT_DIRECTORY2, "id", 2L); - ReflectionTestUtils.setField(CHILD_DIRECTORY1, "id", 3L); - ReflectionTestUtils.setField(CHILD_DIRECTORY2, "id", 4L); + ReflectionTestUtils.setField(TRASH_DIRECTORY, "id", 1L); + ReflectionTestUtils.setField(PARENT_DIRECTORY1, "id", 2L); + ReflectionTestUtils.setField(PARENT_DIRECTORY2, "id", 3L); + ReflectionTestUtils.setField(CHILD_DIRECTORY1, "id", 4L); + ReflectionTestUtils.setField(CHILD_DIRECTORY2, "id", 5L); } } diff --git a/src/test/java/com/goat/server/directory/presentation/DirectoryControllerTest.java b/src/test/java/com/goat/server/directory/presentation/DirectoryControllerTest.java index e98cab1..e674d3c 100644 --- a/src/test/java/com/goat/server/directory/presentation/DirectoryControllerTest.java +++ b/src/test/java/com/goat/server/directory/presentation/DirectoryControllerTest.java @@ -58,7 +58,8 @@ void getDirectoryListTest() throws Exception { List reviewSimpleResponseList = List.of(ReviewSimpleResponse.from(DUMMY_REVIEW1), ReviewSimpleResponse.from(DUMMY_REVIEW2)); DirectoryTotalShowResponse directoryTotalShowResponse = - DirectoryTotalShowResponse.of(PARENT_DIRECTORY1.getId(), directoryResponseList, reviewSimpleResponseList); + DirectoryTotalShowResponse.of(PARENT_DIRECTORY1.getId(), directoryResponseList, + reviewSimpleResponseList); given(directoryService.getDirectorySubList(anyLong(), eq(PARENT_DIRECTORY1.getId()), any(), any())) .willReturn(directoryTotalShowResponse); @@ -88,7 +89,7 @@ void getDirectoryListTest() throws Exception { void initDirectoryTest() throws Exception { //given DirectoryInitRequest request = - new DirectoryInitRequest("폴더 이름", PARENT_DIRECTORY1.getId(), "#FFFFFF"); + new DirectoryInitRequest("폴더 이름", PARENT_DIRECTORY1.getId(), "BLUE", "PENCIL", "설명"); //when ResultActions resultActions =