From d7497daf11e03929320d59765275e79be5d9332e Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 12:47:32 +0900 Subject: [PATCH 01/34] =?UTF-8?q?LV=200=20:=20application.yml=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/main/resources/application.yml diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 000000000..8234ac847 --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,18 @@ +spring: + datasource: + url: jdbc:mysql://localhost:3306/nbcam + username: root + password: 12345678 + driver-class-name: com.mysql.cj.jdbc.Driver + jpa: + show-sql: true + hibernate: + ddl-auto: create-drop + properties: + hibernate: + format_sql: true + defer-datasource-initialization: true + +jwt : + secret : + key : asdlkfjovicxne.m,njsalhzxclvkenmzxlcmvlwaieholiufhlckm \ No newline at end of file From 7a33bda947eb4da741c3cddb7db972ab0df44aee Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 12:59:03 +0900 Subject: [PATCH 02/34] =?UTF-8?q?LV=200=20:=20secretKey=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20base64=EB=A1=9C=20=EC=9D=B8=EC=BD=94=EB=94=A9?= =?UTF-8?q?=EB=90=9C=20=ED=82=A4=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 8234ac847..70ce7249f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,4 +15,4 @@ spring: jwt : secret : - key : asdlkfjovicxne.m,njsalhzxclvkenmzxlcmvlwaieholiufhlckm \ No newline at end of file + key : dGhpc0lzVmVyeUxvbmdTZWNyZXRLZXlGb3JKd3RUb2tlblNpZ25pbmcxMjM0NTY= \ No newline at end of file From 9b016e00cfb9276bc63d768849cda4118e20fbdb Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 14:34:41 +0900 Subject: [PATCH 03/34] =?UTF-8?q?LV=201=20:=20ArgumentResolver=20WebMvcCon?= =?UTF-8?q?fig.java=20=ED=8C=8C=EC=9D=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/expert/config/WebMvcConfig.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/org/example/expert/config/WebMvcConfig.java diff --git a/src/main/java/org/example/expert/config/WebMvcConfig.java b/src/main/java/org/example/expert/config/WebMvcConfig.java new file mode 100644 index 000000000..db2ea20b6 --- /dev/null +++ b/src/main/java/org/example/expert/config/WebMvcConfig.java @@ -0,0 +1,21 @@ +package org.example.expert.config; + + +import lombok.RequiredArgsConstructor; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +@RequiredArgsConstructor +public class WebMvcConfig implements WebMvcConfigurer { + + private final AuthUserArgumentResolver authUserArgumentResolver; + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(authUserArgumentResolver); + } +} \ No newline at end of file From 60c22579a1463c18d3fa9f51eecc88fa33c3cd07 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 14:35:45 +0900 Subject: [PATCH 04/34] =?UTF-8?q?LV=201=20:=20ArgumentResolver=20AuthUserA?= =?UTF-8?q?rgumentResolver.java=20=ED=8C=8C=EC=9D=BC=EC=97=90=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/example/expert/config/AuthUserArgumentResolver.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java b/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java index db00211de..c2eda0459 100644 --- a/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java +++ b/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java @@ -1,17 +1,22 @@ package org.example.expert.config; import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.example.expert.domain.auth.exception.AuthException; import org.example.expert.domain.common.annotation.Auth; import org.example.expert.domain.common.dto.AuthUser; import org.example.expert.domain.user.enums.UserRole; import org.springframework.core.MethodParameter; import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; +@Slf4j +@RequiredArgsConstructor public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver { @Override From d73b82186a6d471fc823551fd39c821dc710c4f6 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 14:41:25 +0900 Subject: [PATCH 05/34] =?UTF-8?q?LV=201=20:=20ArgumentResolver=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/example/expert/config/AuthUserArgumentResolver.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java b/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java index c2eda0459..5c56648f4 100644 --- a/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java +++ b/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java @@ -2,20 +2,17 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.example.expert.domain.auth.exception.AuthException; import org.example.expert.domain.common.annotation.Auth; import org.example.expert.domain.common.dto.AuthUser; import org.example.expert.domain.user.enums.UserRole; import org.springframework.core.MethodParameter; import org.springframework.lang.Nullable; -import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -@Slf4j @RequiredArgsConstructor public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver { From fec0dee0e4f80a1853f5a39506380b8fc0fe620d Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 14:50:21 +0900 Subject: [PATCH 06/34] =?UTF-8?q?LV=201=20:=20ArgumentResolver=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EC=96=B4=EB=85=B8=ED=85=8C?= =?UTF-8?q?=EC=9D=B4=EC=85=98=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/example/expert/config/AuthUserArgumentResolver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java b/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java index 5c56648f4..a60772a9c 100644 --- a/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java +++ b/src/main/java/org/example/expert/config/AuthUserArgumentResolver.java @@ -1,19 +1,19 @@ package org.example.expert.config; import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; import org.example.expert.domain.auth.exception.AuthException; import org.example.expert.domain.common.annotation.Auth; import org.example.expert.domain.common.dto.AuthUser; import org.example.expert.domain.user.enums.UserRole; import org.springframework.core.MethodParameter; import org.springframework.lang.Nullable; +import org.springframework.stereotype.Component; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; -@RequiredArgsConstructor +@Component public class AuthUserArgumentResolver implements HandlerMethodArgumentResolver { @Override From 3854395a4a37087ba84a1e3d8a5001b9c71b35c1 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 15:22:19 +0900 Subject: [PATCH 07/34] =?UTF-8?q?LV=202=20:=20RefactoringQuiz=20-=201=20ea?= =?UTF-8?q?rly=20return=20=EC=9D=B4=EB=AF=B8=20=EC=A1=B4=EC=9E=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EC=9D=B4=EB=A9=94=EC=9D=BC=EC=9D=B8=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EB=B0=94=EB=A1=9C=20=EB=A6=AC=ED=84=B4=ED=95=98?= =?UTF-8?q?=EA=B2=8C=20=ED=95=98=EC=97=AC=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EA=B3=BC=EC=A0=95=EC=9D=B4=20=EC=88=98=ED=96=89?= =?UTF-8?q?=EB=90=98=EB=8A=94=20=EA=B2=83=EC=9D=84=20=EB=B0=A9=EC=A7=80,?= =?UTF-8?q?=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20import=EB=AC=B8=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/example/expert/config/WebMvcConfig.java | 1 - .../example/expert/domain/auth/service/AuthService.java | 8 +++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/example/expert/config/WebMvcConfig.java b/src/main/java/org/example/expert/config/WebMvcConfig.java index db2ea20b6..0d124f03e 100644 --- a/src/main/java/org/example/expert/config/WebMvcConfig.java +++ b/src/main/java/org/example/expert/config/WebMvcConfig.java @@ -1,6 +1,5 @@ package org.example.expert.config; - import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; diff --git a/src/main/java/org/example/expert/domain/auth/service/AuthService.java b/src/main/java/org/example/expert/domain/auth/service/AuthService.java index 3dd3bb7c1..1b1757d57 100644 --- a/src/main/java/org/example/expert/domain/auth/service/AuthService.java +++ b/src/main/java/org/example/expert/domain/auth/service/AuthService.java @@ -26,13 +26,15 @@ public class AuthService { @Transactional public SignupResponse signup(SignupRequest signupRequest) { + if (userRepository.existsByEmail(signupRequest.getEmail())) { + throw new InvalidRequestException("이미 존재하는 이메일입니다."); + } + String encodedPassword = passwordEncoder.encode(signupRequest.getPassword()); UserRole userRole = UserRole.of(signupRequest.getUserRole()); - if (userRepository.existsByEmail(signupRequest.getEmail())) { - throw new InvalidRequestException("이미 존재하는 이메일입니다."); - } + User newUser = new User( signupRequest.getEmail(), From d05f39e2643575f43f510e18fce9a547762a879d Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 15:41:19 +0900 Subject: [PATCH 08/34] =?UTF-8?q?LV=202=20:=20RefactoringQuiz=20-=202=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20if-else=20=EA=B5=AC?= =?UTF-8?q?=EB=AC=B8=20if-else=EC=9D=98=20else=EB=AC=B8=EC=97=90=20?= =?UTF-8?q?=EB=8B=A4=EC=8B=9C=20if=EB=AC=B8=EC=9D=84=20=EB=84=A3=EC=96=B4?= =?UTF-8?q?=20=EA=B0=80=EB=8F=85=EC=84=B1=EC=9D=B4=20=EB=96=A8=EC=96=B4?= =?UTF-8?q?=EC=A7=80=EB=8A=94=20=EA=B2=83=EC=9D=84=20=ED=94=84=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EB=9E=A8=20=ED=9D=90=EB=A6=84=EC=97=90=20=EB=A7=9E?= =?UTF-8?q?=EC=B6=B0=20if=EB=AC=B8=EB=A7=8C=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/example/expert/client/WeatherClient.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/example/expert/client/WeatherClient.java b/src/main/java/org/example/expert/client/WeatherClient.java index d8ec223e7..d6ae4a6ea 100644 --- a/src/main/java/org/example/expert/client/WeatherClient.java +++ b/src/main/java/org/example/expert/client/WeatherClient.java @@ -26,13 +26,16 @@ public String getTodayWeather() { ResponseEntity responseEntity = restTemplate.getForEntity(buildWeatherApiUri(), WeatherDto[].class); + if (!responseEntity.getStatusCode().is2xxSuccessful()) { + throw new ServerException( + "날씨 데이터를 가져오는데 실패했습니다. 상태 코드: " + responseEntity.getStatusCode() + ); + } + WeatherDto[] weatherArray = responseEntity.getBody(); - if (!HttpStatus.OK.equals(responseEntity.getStatusCode())) { - throw new ServerException("날씨 데이터를 가져오는데 실패했습니다. 상태 코드: " + responseEntity.getStatusCode()); - } else { - if (weatherArray == null || weatherArray.length == 0) { - throw new ServerException("날씨 데이터가 없습니다."); - } + + if (weatherArray == null || weatherArray.length == 0) { + throw new ServerException("날씨 데이터가 없습니다."); } String today = getCurrentDate(); From 32be086c76a811f8fec15325262dd07f1ad58ecc Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 15:41:43 +0900 Subject: [PATCH 09/34] =?UTF-8?q?LV=202=20:=20RefactoringQuiz=20-=202=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20if-else=20=EA=B5=AC?= =?UTF-8?q?=EB=AC=B8=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20import?= =?UTF-8?q?=EB=AC=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/example/expert/client/WeatherClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/org/example/expert/client/WeatherClient.java b/src/main/java/org/example/expert/client/WeatherClient.java index d6ae4a6ea..a4fefc2bd 100644 --- a/src/main/java/org/example/expert/client/WeatherClient.java +++ b/src/main/java/org/example/expert/client/WeatherClient.java @@ -3,7 +3,6 @@ import org.example.expert.client.dto.WeatherDto; import org.example.expert.domain.common.exception.ServerException; import org.springframework.boot.web.client.RestTemplateBuilder; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; From 9a47406ac34f8768df29c96dd1b801fd23ea11da Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 15:57:08 +0900 Subject: [PATCH 10/34] =?UTF-8?q?LV=202=20:=20RefactoringQuiz=20-=203=20va?= =?UTF-8?q?lidation=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20request=20DTO=EC=97=90=20=EC=A0=95=EA=B7=9C?= =?UTF-8?q?=EC=8B=9D=EC=9D=84=20=EC=9D=B4=EC=9A=A9=ED=95=9C=20validation?= =?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 --- .../domain/user/dto/request/UserChangePasswordRequest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/example/expert/domain/user/dto/request/UserChangePasswordRequest.java b/src/main/java/org/example/expert/domain/user/dto/request/UserChangePasswordRequest.java index 3ba93dde5..334e245f4 100644 --- a/src/main/java/org/example/expert/domain/user/dto/request/UserChangePasswordRequest.java +++ b/src/main/java/org/example/expert/domain/user/dto/request/UserChangePasswordRequest.java @@ -1,6 +1,7 @@ package org.example.expert.domain.user.dto.request; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -12,6 +13,11 @@ public class UserChangePasswordRequest { @NotBlank private String oldPassword; + @NotBlank + @Pattern( + regexp = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d).{8,}$", + message = "비밀번호는 8자 이상이며, 대문자/소문자/숫자를 포함해야 합니다." + ) private String newPassword; } From 03366dbfb88a0f0104373ec2d2cde6f5b4e4f20c Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 16:00:13 +0900 Subject: [PATCH 11/34] =?UTF-8?q?LV=202=20:=20RefactoringQuiz=20-=203=20va?= =?UTF-8?q?lidation=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=EC=97=90=20@Val?= =?UTF-8?q?id=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=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 --- .../example/expert/domain/user/controller/UserController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/example/expert/domain/user/controller/UserController.java b/src/main/java/org/example/expert/domain/user/controller/UserController.java index bb1ef7a95..5ae291070 100644 --- a/src/main/java/org/example/expert/domain/user/controller/UserController.java +++ b/src/main/java/org/example/expert/domain/user/controller/UserController.java @@ -1,5 +1,6 @@ package org.example.expert.domain.user.controller; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.example.expert.domain.common.annotation.Auth; import org.example.expert.domain.common.dto.AuthUser; @@ -21,7 +22,7 @@ public ResponseEntity getUser(@PathVariable long userId) { } @PutMapping("/users") - public void changePassword(@Auth AuthUser authUser, @RequestBody UserChangePasswordRequest userChangePasswordRequest) { + public void changePassword(@Auth AuthUser authUser, @Valid @RequestBody UserChangePasswordRequest userChangePasswordRequest) { userService.changePassword(authUser.getId(), userChangePasswordRequest); } } From 5372dd0eadf187fd52a2a5ebd07106b5851fdf81 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 16:00:44 +0900 Subject: [PATCH 12/34] =?UTF-8?q?LV=202=20:=20RefactoringQuiz=20-=203=20va?= =?UTF-8?q?lidation=20UserService=EC=97=90=20=EC=9E=91=EC=84=B1=EB=90=9C?= =?UTF-8?q?=20=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/example/expert/domain/user/service/UserService.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/org/example/expert/domain/user/service/UserService.java b/src/main/java/org/example/expert/domain/user/service/UserService.java index 565c213f9..3ca0c117b 100644 --- a/src/main/java/org/example/expert/domain/user/service/UserService.java +++ b/src/main/java/org/example/expert/domain/user/service/UserService.java @@ -25,12 +25,6 @@ public UserResponse getUser(long userId) { @Transactional public void changePassword(long userId, UserChangePasswordRequest userChangePasswordRequest) { - if (userChangePasswordRequest.getNewPassword().length() < 8 || - !userChangePasswordRequest.getNewPassword().matches(".*\\d.*") || - !userChangePasswordRequest.getNewPassword().matches(".*[A-Z].*")) { - throw new InvalidRequestException("새 비밀번호는 8자 이상이어야 하고, 숫자와 대문자를 포함해야 합니다."); - } - User user = userRepository.findById(userId) .orElseThrow(() -> new InvalidRequestException("User not found")); From e5ac6cc2aca2a3df171676831d04489c219ab69d Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 16:58:09 +0900 Subject: [PATCH 13/34] =?UTF-8?q?LV=203=20:=20RefactoringQuiz=20-=203=20va?= =?UTF-8?q?lidation=20@EntityGraph=20=EC=8B=9D=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expert/domain/todo/repository/TodoRepository.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java b/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java index 064e74f9a..b2ccab304 100644 --- a/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java +++ b/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java @@ -3,10 +3,12 @@ import org.example.expert.domain.todo.entity.Todo; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import java.util.List; import java.util.Optional; public interface TodoRepository extends JpaRepository { @@ -19,5 +21,8 @@ public interface TodoRepository extends JpaRepository { "WHERE t.id = :todoId") Optional findByIdWithUser(@Param("todoId") Long todoId); + @EntityGraph(attributePaths = {"user"}) + Optional findTodoById(Long todoId); + int countById(Long todoId); } From 1d5a57009a8a2381119cdc570b420a77765f035e Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 16:59:22 +0900 Subject: [PATCH 14/34] =?UTF-8?q?LV=203=20:=20validation=20=EA=B5=90?= =?UTF-8?q?=EC=B2=B4=ED=95=98=EB=A9=B4=EC=84=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expert/domain/todo/repository/TodoRepository.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java b/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java index b2ccab304..e6d4658d8 100644 --- a/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java +++ b/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java @@ -8,7 +8,6 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import java.util.List; import java.util.Optional; public interface TodoRepository extends JpaRepository { @@ -16,11 +15,6 @@ public interface TodoRepository extends JpaRepository { @Query("SELECT t FROM Todo t LEFT JOIN FETCH t.user u ORDER BY t.modifiedAt DESC") Page findAllByOrderByModifiedAtDesc(Pageable pageable); - @Query("SELECT t FROM Todo t " + - "LEFT JOIN FETCH t.user " + - "WHERE t.id = :todoId") - Optional findByIdWithUser(@Param("todoId") Long todoId); - @EntityGraph(attributePaths = {"user"}) Optional findTodoById(Long todoId); From 5521f605b01cf308954d224c3b4438b56bf12b85 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 17:00:13 +0900 Subject: [PATCH 15/34] =?UTF-8?q?LV=203=20:=20validation=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=EC=97=90=EC=84=9C=20=EB=B3=80=EA=B2=BD?= =?UTF-8?q?=EB=90=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/example/expert/domain/todo/service/TodoService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/example/expert/domain/todo/service/TodoService.java b/src/main/java/org/example/expert/domain/todo/service/TodoService.java index cc63523d1..031e10359 100644 --- a/src/main/java/org/example/expert/domain/todo/service/TodoService.java +++ b/src/main/java/org/example/expert/domain/todo/service/TodoService.java @@ -66,7 +66,7 @@ public Page getTodos(int page, int size) { @Transactional(readOnly = true) public TodoResponse getTodo(long todoId) { - Todo todo = todoRepository.findByIdWithUser(todoId) + Todo todo = todoRepository.findTodoById(todoId) .orElseThrow(() -> new InvalidRequestException("Todo not found")); User user = todo.getUser(); From 43113bef2384c8cea40d48c89edf3510a8f1c721 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 17:00:36 +0900 Subject: [PATCH 16/34] =?UTF-8?q?LV=203=20:=20validation=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20import?= =?UTF-8?q?=EB=AC=B8,=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/expert/domain/todo/repository/TodoRepository.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java b/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java index e6d4658d8..e31c4976c 100644 --- a/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java +++ b/src/main/java/org/example/expert/domain/todo/repository/TodoRepository.java @@ -6,7 +6,6 @@ import org.springframework.data.jpa.repository.EntityGraph; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; -import org.springframework.data.repository.query.Param; import java.util.Optional; @@ -17,6 +16,4 @@ public interface TodoRepository extends JpaRepository { @EntityGraph(attributePaths = {"user"}) Optional findTodoById(Long todoId); - - int countById(Long todoId); } From c7ac151160f28b952d65c2afb8ea53c724181c29 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 17:55:03 +0900 Subject: [PATCH 17/34] =?UTF-8?q?LV=204=20:=20PasswordEncoderTest=20matche?= =?UTF-8?q?s=EC=9D=98=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=EA=B0=80=20?= =?UTF-8?q?=EB=B0=98=EB=8C=80=EB=A1=9C=20=EB=93=A4=EC=96=B4=EA=B0=80?= =?UTF-8?q?=EC=9E=88=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/example/expert/config/PasswordEncoderTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/org/example/expert/config/PasswordEncoderTest.java b/src/test/java/org/example/expert/config/PasswordEncoderTest.java index 694643d7e..d73b436fa 100644 --- a/src/test/java/org/example/expert/config/PasswordEncoderTest.java +++ b/src/test/java/org/example/expert/config/PasswordEncoderTest.java @@ -16,11 +16,11 @@ class PasswordEncoderTest { @Test void matches_메서드가_정상적으로_동작한다() { // given - String rawPassword = "testPassword"; + String rawPassword = "springsecretKeyspringsecretKeyspringsecretKey"; String encodedPassword = passwordEncoder.encode(rawPassword); // when - boolean matches = passwordEncoder.matches(encodedPassword, rawPassword); + boolean matches = passwordEncoder.matches(rawPassword, encodedPassword); // then assertTrue(matches); From bc56aaa5e490916564f30ff3a032709a71258efa Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 19:26:38 +0900 Subject: [PATCH 18/34] =?UTF-8?q?LV=204=20:=20=EB=A7=A4=EB=8B=88=EC=A0=80?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=88=98=EC=A0=95=20NPE=20=EC=97=90=EB=9F=AC?= =?UTF-8?q?=EB=A5=BC=20=EB=8D=98=EC=A7=84=EB=8B=A4=20->=20InvalidRequestEx?= =?UTF-8?q?ception=20=EC=97=90=EB=9F=AC=EB=A5=BC=20=EB=8D=98=EC=A7=84?= =?UTF-8?q?=EB=8B=A4=20=EB=A1=9C=20=EC=88=98=EC=A0=95=20Manager=20Not=20fo?= =?UTF-8?q?und=20->=20Todo=20not=20found?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/manager/service/ManagerServiceTest.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/test/java/org/example/expert/domain/manager/service/ManagerServiceTest.java b/src/test/java/org/example/expert/domain/manager/service/ManagerServiceTest.java index 47ddd6205..9480bf7b1 100644 --- a/src/test/java/org/example/expert/domain/manager/service/ManagerServiceTest.java +++ b/src/test/java/org/example/expert/domain/manager/service/ManagerServiceTest.java @@ -12,6 +12,7 @@ import org.example.expert.domain.user.entity.User; import org.example.expert.domain.user.enums.UserRole; import org.example.expert.domain.user.repository.UserRepository; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -38,15 +39,22 @@ class ManagerServiceTest { @InjectMocks private ManagerService managerService; + @BeforeEach + void init() { + todoRepository.save(new Todo()); + } + @Test - public void manager_목록_조회_시_Todo가_없다면_NPE_에러를_던진다() { + public void manager_목록_조회_시_Todo가_없다면_InvalidRequestException_에러를_던진다() { // given long todoId = 1L; given(todoRepository.findById(todoId)).willReturn(Optional.empty()); // when & then - InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> managerService.getManagers(todoId)); - assertEquals("Manager not found", exception.getMessage()); + InvalidRequestException exception = assertThrows( + InvalidRequestException.class, + () -> managerService.getManagers(todoId)); + assertEquals("Todo not found", exception.getMessage()); } @Test From 658dc8dd7b1801ffec43de737407aab4d61066b4 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 19:42:42 +0900 Subject: [PATCH 19/34] =?UTF-8?q?LV=204=20:=20comment=20=EB=93=B1=EB=A1=9D?= =?UTF-8?q?=20=EC=A4=91=20=EC=97=90=EB=9F=AC=20=EB=B0=9C=EC=83=9D=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98=EC=A0=95=20SeverExcepti?= =?UTF-8?q?on=20->=20InvalidRequestException=20=EC=97=90=EB=9F=AC=EB=A5=BC?= =?UTF-8?q?=20=EB=8D=98=EC=A7=80=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- .../expert/domain/comment/service/CommentServiceTest.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 70ce7249f..6f2436aee 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -15,4 +15,4 @@ spring: jwt : secret : - key : dGhpc0lzVmVyeUxvbmdTZWNyZXRLZXlGb3JKd3RUb2tlblNpZ25pbmcxMjM0NTY= \ No newline at end of file + key : c3ByaW5nc2VjcmV0S2V5c3ByaW5nc2VjcmV0S2V5c3ByaW5nc2VjcmV0S2V5 \ No newline at end of file diff --git a/src/test/java/org/example/expert/domain/comment/service/CommentServiceTest.java b/src/test/java/org/example/expert/domain/comment/service/CommentServiceTest.java index ba6797dcd..af14002d2 100644 --- a/src/test/java/org/example/expert/domain/comment/service/CommentServiceTest.java +++ b/src/test/java/org/example/expert/domain/comment/service/CommentServiceTest.java @@ -5,6 +5,7 @@ import org.example.expert.domain.comment.entity.Comment; import org.example.expert.domain.comment.repository.CommentRepository; import org.example.expert.domain.common.dto.AuthUser; +import org.example.expert.domain.common.exception.InvalidRequestException; import org.example.expert.domain.common.exception.ServerException; import org.example.expert.domain.todo.entity.Todo; import org.example.expert.domain.todo.repository.TodoRepository; @@ -43,7 +44,7 @@ class CommentServiceTest { given(todoRepository.findById(anyLong())).willReturn(Optional.empty()); // when - ServerException exception = assertThrows(ServerException.class, () -> { + InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> { commentService.saveComment(authUser, todoId, request); }); From 7fb63e5ff82df692779983ada0c98f21843df770 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Fri, 8 May 2026 19:58:14 +0900 Subject: [PATCH 20/34] =?UTF-8?q?LV=204=20:=20ManagerService=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95=20if(todo.getUser()=20?= =?UTF-8?q?=3D=3D=20null)=20=EA=B2=80=EC=82=AC=20=EB=A1=9C=EC=A7=81?= =?UTF-8?q?=EC=9D=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/expert/domain/manager/service/ManagerService.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/example/expert/domain/manager/service/ManagerService.java b/src/main/java/org/example/expert/domain/manager/service/ManagerService.java index ad3c08ce4..fee150c72 100644 --- a/src/main/java/org/example/expert/domain/manager/service/ManagerService.java +++ b/src/main/java/org/example/expert/domain/manager/service/ManagerService.java @@ -35,6 +35,10 @@ public ManagerSaveResponse saveManager(AuthUser authUser, long todoId, ManagerSa Todo todo = todoRepository.findById(todoId) .orElseThrow(() -> new InvalidRequestException("Todo not found")); + if(todo.getUser() == null) { + throw new InvalidRequestException("일정을 생성한 유저만 담당자를 지정할 수 있습니다."); + } + if (!ObjectUtils.nullSafeEquals(user.getId(), todo.getUser().getId())) { throw new InvalidRequestException("일정을 생성한 유저만 담당자를 지정할 수 있습니다."); } From fe0fee8d85f318593b02304b0d47b1b34da1b3f5 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Sun, 10 May 2026 16:51:56 +0900 Subject: [PATCH 21/34] =?UTF-8?q?LV=205=20:=20Interceptor=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=83=9D=EC=84=B1=20=ED=9B=84=20WebMvcConfig?= =?UTF-8?q?=EC=97=90=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/expert/config/WebMvcConfig.java | 11 +++++++++++ .../interceptor/CheckAdminInterceptor.java | 19 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java diff --git a/src/main/java/org/example/expert/config/WebMvcConfig.java b/src/main/java/org/example/expert/config/WebMvcConfig.java index 0d124f03e..cec1bd2ce 100644 --- a/src/main/java/org/example/expert/config/WebMvcConfig.java +++ b/src/main/java/org/example/expert/config/WebMvcConfig.java @@ -1,8 +1,10 @@ package org.example.expert.config; import lombok.RequiredArgsConstructor; +import org.example.expert.domain.common.interceptor.CheckAdminInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import java.util.List; @@ -12,9 +14,18 @@ public class WebMvcConfig implements WebMvcConfigurer { private final AuthUserArgumentResolver authUserArgumentResolver; + private final CheckAdminInterceptor checkAdminInterceptork; @Override public void addArgumentResolvers(List resolvers) { resolvers.add(authUserArgumentResolver); } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(checkAdminInterceptork) + .addPathPatterns("/admin/**"); + } + + } \ No newline at end of file diff --git a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java new file mode 100644 index 000000000..d8ba0f302 --- /dev/null +++ b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java @@ -0,0 +1,19 @@ +package org.example.expert.domain.common.interceptor; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.web.servlet.HandlerInterceptor; + +import java.io.IOException; + +@Slf4j +@Component +public class CheckAdminInterceptor implements HandlerInterceptor { + + @Override + public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { + + } +} From 21854aee56023ab26b8ec60c2923548e694e664d Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Sun, 10 May 2026 17:11:44 +0900 Subject: [PATCH 22/34] =?UTF-8?q?LV=205=20:=20Interceptor=EB=A5=BC=20?= =?UTF-8?q?=EC=82=AC=EC=9A=A9=ED=95=9C=20=EB=A1=9C=EA=B9=85=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/interceptor/CheckAdminInterceptor.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java index d8ba0f302..2539bf66e 100644 --- a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java +++ b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java @@ -3,6 +3,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; +import org.apache.tomcat.util.net.openssl.ciphers.Authentication; +import org.example.expert.domain.user.enums.UserRole; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; @@ -14,6 +16,14 @@ public class CheckAdminInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { + UserRole userRole = UserRole.of(request.getAuthType()); + if(userRole == UserRole.ADMIN) { + log.warn("관리자 아님. 접근 거부"); + response.sendError(HttpServletResponse.SC_FORBIDDEN, "관리자만 접근할 수 있습니다."); + return false; + } + + return true; } } From bcb8976ecd4eee3cd14508e57f9a31fb06fdd230 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Sun, 10 May 2026 19:36:52 +0900 Subject: [PATCH 23/34] =?UTF-8?q?LV=205=20:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EC=98=A4=EB=A5=98?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/common/interceptor/CheckAdminInterceptor.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java index 2539bf66e..bef85e8a2 100644 --- a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java +++ b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java @@ -2,8 +2,8 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.apache.tomcat.util.net.openssl.ciphers.Authentication; import org.example.expert.domain.user.enums.UserRole; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; @@ -12,13 +12,14 @@ @Slf4j @Component +@RequiredArgsConstructor public class CheckAdminInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { UserRole userRole = UserRole.of(request.getAuthType()); - if(userRole == UserRole.ADMIN) { + if(!(userRole == UserRole.ADMIN)) { log.warn("관리자 아님. 접근 거부"); response.sendError(HttpServletResponse.SC_FORBIDDEN, "관리자만 접근할 수 있습니다."); return false; From e13060a28bb03366edac384982a7e524d7f7267d Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Sun, 10 May 2026 19:43:32 +0900 Subject: [PATCH 24/34] =?UTF-8?q?LV=205=20:=20=EA=B4=80=EB=A6=AC=EC=9E=90?= =?UTF-8?q?=20=EC=9D=B8=EC=A6=9D=20=EC=84=B1=EA=B3=B5=20=EC=8B=9C=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/common/interceptor/CheckAdminInterceptor.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java index bef85e8a2..52dc8c864 100644 --- a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java +++ b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java @@ -9,6 +9,7 @@ import org.springframework.web.servlet.HandlerInterceptor; import java.io.IOException; +import java.time.LocalDateTime; @Slf4j @Component @@ -18,12 +19,14 @@ public class CheckAdminInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { UserRole userRole = UserRole.of(request.getAuthType()); + LocalDateTime reqTime = LocalDateTime.now(); if(!(userRole == UserRole.ADMIN)) { log.warn("관리자 아님. 접근 거부"); response.sendError(HttpServletResponse.SC_FORBIDDEN, "관리자만 접근할 수 있습니다."); return false; } + log.info("관리자 인증 성공, 요청 시각 {}, 요청 URL {}", reqTime, request.getRequestURL()); return true; } From e84ac01b76372c05bf3bd1b1f5c7f3dff709e11e Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Sun, 10 May 2026 20:46:42 +0900 Subject: [PATCH 25/34] =?UTF-8?q?LV=205=20:=20Aspect=20=ED=81=B4=EB=9E=98?= =?UTF-8?q?=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/common/aspect/LoggingAop.java | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java diff --git a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java new file mode 100644 index 000000000..41a93f67a --- /dev/null +++ b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java @@ -0,0 +1,24 @@ +package org.example.expert.domain.common.aspect; + +import lombok.extern.slf4j.Slf4j; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.stereotype.Component; + +@Aspect +@Slf4j +@Component +public class LoggingAop { + + @Around("execution(* org.example.expert.domain.comment.service*(..))") + public Object commentAop(ProceedingJoinPoint joinPoint) throws Throwable { + long start = System.currentTimeMillis(); + + Object result = joinPoint.proceed(); // 실제 메서드 실행 -> Filter에서 doFilter 와 비슷함. + + long end = System.currentTimeMillis(); + log.info("[AOP] {} 실행됨 in {}ms" , joinPoint.getSignature() , end - start); + return result; + } +} From 3bf63b184004d274e70ac7f9900e9d85bf59ad4e Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Sun, 10 May 2026 21:43:10 +0900 Subject: [PATCH 26/34] =?UTF-8?q?LV=206=20:=20Admin=20Facade=3F=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9=20AOP=20=EC=9E=91=EC=84=B1=20=EB=8F=84?= =?UTF-8?q?=EC=A4=91=20=EA=B0=90=EC=8B=9C=20=EA=B2=BD=EB=A1=9C=EB=A5=BC=20?= =?UTF-8?q?=EB=94=B0=EB=A1=9C=20=EC=A0=81=EC=96=B4=EC=A3=BC=EB=8A=94?= =?UTF-8?q?=EA=B2=8C=20=EB=B9=84=ED=9A=A8=EC=9C=A8=EC=A0=81=EC=9D=B4?= =?UTF-8?q?=EB=9D=BC=EA=B3=A0=20=EC=83=9D=EA=B0=81=ED=95=98=EC=97=AC=20?= =?UTF-8?q?=ED=8C=8C=EC=82=AC=EB=93=9C=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=ED=9B=84=20=ED=95=B4=EB=8B=B9=20=EA=B2=BD?= =?UTF-8?q?=EB=A1=9C=EB=A5=BC=20=EC=82=AC=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expert/domain/admin/AdminFacade.java | 24 +++++++++++++++++++ .../admin/controller/AdminController.java | 24 +++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 src/main/java/org/example/expert/domain/admin/AdminFacade.java create mode 100644 src/main/java/org/example/expert/domain/admin/controller/AdminController.java diff --git a/src/main/java/org/example/expert/domain/admin/AdminFacade.java b/src/main/java/org/example/expert/domain/admin/AdminFacade.java new file mode 100644 index 000000000..c4569d506 --- /dev/null +++ b/src/main/java/org/example/expert/domain/admin/AdminFacade.java @@ -0,0 +1,24 @@ +package org.example.expert.domain.admin; + +import lombok.RequiredArgsConstructor; +import org.example.expert.domain.admin.service.CommentAdminService; +import org.example.expert.domain.user.dto.request.UserRoleChangeRequest; +import org.example.expert.domain.admin.service.UserAdminService; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class AdminFacade { + + private final CommentAdminService commentAdminService; + private final UserAdminService userAdminService; + + public void deleteComment(long commentId) { + commentAdminService.deleteComment(commentId); + } + + public void changeUserRole(long userId, UserRoleChangeRequest request) { + userAdminService.changeUserRole(userId, request); + } + +} diff --git a/src/main/java/org/example/expert/domain/admin/controller/AdminController.java b/src/main/java/org/example/expert/domain/admin/controller/AdminController.java new file mode 100644 index 000000000..60f9e8109 --- /dev/null +++ b/src/main/java/org/example/expert/domain/admin/controller/AdminController.java @@ -0,0 +1,24 @@ +package org.example.expert.domain.admin.controller; + +import lombok.RequiredArgsConstructor; +import org.example.expert.domain.admin.AdminFacade; +import org.example.expert.domain.user.dto.request.UserRoleChangeRequest; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequiredArgsConstructor +public class AdminController { + + private final AdminFacade adminFacade; + + @DeleteMapping("/comments/{commentId}") + public void deleteComment(@PathVariable long commentId) { + adminFacade.deleteComment(commentId); + } + + @PatchMapping("/users/{userId}") + public void changeUserRole(@PathVariable long userId, + @RequestBody UserRoleChangeRequest request) { + adminFacade.changeUserRole(userId, request); + } +} From 3b8c49ebde67945668c1eaf5d85d2475a79fe7bd Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Sun, 10 May 2026 21:45:11 +0900 Subject: [PATCH 27/34] =?UTF-8?q?LV=206=20:=20Admin=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=20=EC=83=9D=EC=84=B1=20Admin=20=ED=8C=A8=ED=82=A4?= =?UTF-8?q?=EC=A7=80=EB=A5=BC=20=EC=83=9D=EC=84=B1=ED=95=98=EC=97=AC=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=EC=9D=84=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/{comment => admin}/service/CommentAdminService.java | 2 +- .../expert/domain/{user => admin}/service/UserAdminService.java | 2 +- .../domain/comment/controller/CommentAdminController.java | 2 +- .../expert/domain/user/controller/UserAdminController.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/org/example/expert/domain/{comment => admin}/service/CommentAdminService.java (90%) rename src/main/java/org/example/expert/domain/{user => admin}/service/UserAdminService.java (94%) diff --git a/src/main/java/org/example/expert/domain/comment/service/CommentAdminService.java b/src/main/java/org/example/expert/domain/admin/service/CommentAdminService.java similarity index 90% rename from src/main/java/org/example/expert/domain/comment/service/CommentAdminService.java rename to src/main/java/org/example/expert/domain/admin/service/CommentAdminService.java index 5b0c4666a..412958bb4 100644 --- a/src/main/java/org/example/expert/domain/comment/service/CommentAdminService.java +++ b/src/main/java/org/example/expert/domain/admin/service/CommentAdminService.java @@ -1,4 +1,4 @@ -package org.example.expert.domain.comment.service; +package org.example.expert.domain.admin.service; import lombok.RequiredArgsConstructor; import org.example.expert.domain.comment.repository.CommentRepository; diff --git a/src/main/java/org/example/expert/domain/user/service/UserAdminService.java b/src/main/java/org/example/expert/domain/admin/service/UserAdminService.java similarity index 94% rename from src/main/java/org/example/expert/domain/user/service/UserAdminService.java rename to src/main/java/org/example/expert/domain/admin/service/UserAdminService.java index a0040471c..9a6968e30 100644 --- a/src/main/java/org/example/expert/domain/user/service/UserAdminService.java +++ b/src/main/java/org/example/expert/domain/admin/service/UserAdminService.java @@ -1,4 +1,4 @@ -package org.example.expert.domain.user.service; +package org.example.expert.domain.admin.service; import lombok.RequiredArgsConstructor; import org.example.expert.domain.common.exception.InvalidRequestException; diff --git a/src/main/java/org/example/expert/domain/comment/controller/CommentAdminController.java b/src/main/java/org/example/expert/domain/comment/controller/CommentAdminController.java index 33a2a86c0..379d5b9f2 100644 --- a/src/main/java/org/example/expert/domain/comment/controller/CommentAdminController.java +++ b/src/main/java/org/example/expert/domain/comment/controller/CommentAdminController.java @@ -1,7 +1,7 @@ package org.example.expert.domain.comment.controller; import lombok.RequiredArgsConstructor; -import org.example.expert.domain.comment.service.CommentAdminService; +import org.example.expert.domain.admin.service.CommentAdminService; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; diff --git a/src/main/java/org/example/expert/domain/user/controller/UserAdminController.java b/src/main/java/org/example/expert/domain/user/controller/UserAdminController.java index 53d45c8b5..4526ac3e3 100644 --- a/src/main/java/org/example/expert/domain/user/controller/UserAdminController.java +++ b/src/main/java/org/example/expert/domain/user/controller/UserAdminController.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import org.example.expert.domain.user.dto.request.UserRoleChangeRequest; -import org.example.expert.domain.user.service.UserAdminService; +import org.example.expert.domain.admin.service.UserAdminService; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; From 228d15f32334e87b7015313295efbcb6f651fee5 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Mon, 11 May 2026 00:28:53 +0900 Subject: [PATCH 28/34] =?UTF-8?q?LV=206=20:=20RequestMapping=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20=EC=9D=B4=EC=A0=84=EC=97=90=20=EC=9E=91=EC=84=B1?= =?UTF-8?q?=EB=90=9C=20=EC=96=B4=EB=93=9C=EB=AF=BC=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=EB=9F=AC=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/controller/AdminController.java | 1 + .../controller/CommentAdminController.java | 19 ----------------- .../user/controller/UserAdminController.java | 21 ------------------- 3 files changed, 1 insertion(+), 40 deletions(-) delete mode 100644 src/main/java/org/example/expert/domain/comment/controller/CommentAdminController.java delete mode 100644 src/main/java/org/example/expert/domain/user/controller/UserAdminController.java diff --git a/src/main/java/org/example/expert/domain/admin/controller/AdminController.java b/src/main/java/org/example/expert/domain/admin/controller/AdminController.java index 60f9e8109..7b02259de 100644 --- a/src/main/java/org/example/expert/domain/admin/controller/AdminController.java +++ b/src/main/java/org/example/expert/domain/admin/controller/AdminController.java @@ -5,6 +5,7 @@ import org.example.expert.domain.user.dto.request.UserRoleChangeRequest; import org.springframework.web.bind.annotation.*; +@RequestMapping("/admin") @RestController @RequiredArgsConstructor public class AdminController { diff --git a/src/main/java/org/example/expert/domain/comment/controller/CommentAdminController.java b/src/main/java/org/example/expert/domain/comment/controller/CommentAdminController.java deleted file mode 100644 index 379d5b9f2..000000000 --- a/src/main/java/org/example/expert/domain/comment/controller/CommentAdminController.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.example.expert.domain.comment.controller; - -import lombok.RequiredArgsConstructor; -import org.example.expert.domain.admin.service.CommentAdminService; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -public class CommentAdminController { - - private final CommentAdminService commentAdminService; - - @DeleteMapping("/admin/comments/{commentId}") - public void deleteComment(@PathVariable long commentId) { - commentAdminService.deleteComment(commentId); - } -} diff --git a/src/main/java/org/example/expert/domain/user/controller/UserAdminController.java b/src/main/java/org/example/expert/domain/user/controller/UserAdminController.java deleted file mode 100644 index 4526ac3e3..000000000 --- a/src/main/java/org/example/expert/domain/user/controller/UserAdminController.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.example.expert.domain.user.controller; - -import lombok.RequiredArgsConstructor; -import org.example.expert.domain.user.dto.request.UserRoleChangeRequest; -import org.example.expert.domain.admin.service.UserAdminService; -import org.springframework.web.bind.annotation.PatchMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RestController; - -@RestController -@RequiredArgsConstructor -public class UserAdminController { - - private final UserAdminService userAdminService; - - @PatchMapping("/admin/users/{userId}") - public void changeUserRole(@PathVariable long userId, @RequestBody UserRoleChangeRequest userRoleChangeRequest) { - userAdminService.changeUserRole(userId, userRoleChangeRequest); - } -} From 0a31f5edc79b750ce962308bd4792f6d2506d6b8 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Mon, 11 May 2026 02:02:42 +0900 Subject: [PATCH 29/34] =?UTF-8?q?Lv=206=20:=20admin=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20dto=EB=8F=84=20admin=20=ED=8C=A8=ED=82=A4=EC=A7=80=EB=A1=9C?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/example/expert/domain/admin/AdminFacade.java | 2 +- .../example/expert/domain/admin/controller/AdminController.java | 2 +- .../{user/dto/request => admin/dto}/UserRoleChangeRequest.java | 2 +- .../example/expert/domain/admin/service/UserAdminService.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/main/java/org/example/expert/domain/{user/dto/request => admin/dto}/UserRoleChangeRequest.java (79%) diff --git a/src/main/java/org/example/expert/domain/admin/AdminFacade.java b/src/main/java/org/example/expert/domain/admin/AdminFacade.java index c4569d506..a0d5391d3 100644 --- a/src/main/java/org/example/expert/domain/admin/AdminFacade.java +++ b/src/main/java/org/example/expert/domain/admin/AdminFacade.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import org.example.expert.domain.admin.service.CommentAdminService; -import org.example.expert.domain.user.dto.request.UserRoleChangeRequest; +import org.example.expert.domain.admin.dto.UserRoleChangeRequest; import org.example.expert.domain.admin.service.UserAdminService; import org.springframework.stereotype.Component; diff --git a/src/main/java/org/example/expert/domain/admin/controller/AdminController.java b/src/main/java/org/example/expert/domain/admin/controller/AdminController.java index 7b02259de..c337cda1e 100644 --- a/src/main/java/org/example/expert/domain/admin/controller/AdminController.java +++ b/src/main/java/org/example/expert/domain/admin/controller/AdminController.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import org.example.expert.domain.admin.AdminFacade; -import org.example.expert.domain.user.dto.request.UserRoleChangeRequest; +import org.example.expert.domain.admin.dto.UserRoleChangeRequest; import org.springframework.web.bind.annotation.*; @RequestMapping("/admin") diff --git a/src/main/java/org/example/expert/domain/user/dto/request/UserRoleChangeRequest.java b/src/main/java/org/example/expert/domain/admin/dto/UserRoleChangeRequest.java similarity index 79% rename from src/main/java/org/example/expert/domain/user/dto/request/UserRoleChangeRequest.java rename to src/main/java/org/example/expert/domain/admin/dto/UserRoleChangeRequest.java index 0d8061fa2..d67518dfa 100644 --- a/src/main/java/org/example/expert/domain/user/dto/request/UserRoleChangeRequest.java +++ b/src/main/java/org/example/expert/domain/admin/dto/UserRoleChangeRequest.java @@ -1,4 +1,4 @@ -package org.example.expert.domain.user.dto.request; +package org.example.expert.domain.admin.dto; import lombok.AllArgsConstructor; import lombok.Getter; diff --git a/src/main/java/org/example/expert/domain/admin/service/UserAdminService.java b/src/main/java/org/example/expert/domain/admin/service/UserAdminService.java index 9a6968e30..4c3fbb4b4 100644 --- a/src/main/java/org/example/expert/domain/admin/service/UserAdminService.java +++ b/src/main/java/org/example/expert/domain/admin/service/UserAdminService.java @@ -2,7 +2,7 @@ import lombok.RequiredArgsConstructor; import org.example.expert.domain.common.exception.InvalidRequestException; -import org.example.expert.domain.user.dto.request.UserRoleChangeRequest; +import org.example.expert.domain.admin.dto.UserRoleChangeRequest; import org.example.expert.domain.user.entity.User; import org.example.expert.domain.user.enums.UserRole; import org.example.expert.domain.user.repository.UserRepository; From e1a79807d16dcde7212dc9ff3b5cd215e94af6c7 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Mon, 11 May 2026 02:05:08 +0900 Subject: [PATCH 30/34] =?UTF-8?q?hotfix=20:=20=ED=8F=AC=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EB=A7=A8=EC=97=90=EC=84=9C=20=EA=B6=8C=ED=95=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EC=9A=94=EC=B2=AD=EC=9D=B4=20=EC=88=98=ED=96=89=20?= =?UTF-8?q?=EC=95=88=EB=90=98=EB=8A=94=20=EB=AC=B8=EC=A0=9C=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20Interceptor=EC=97=90=EC=84=9C=20UserRole=EC=9D=84?= =?UTF-8?q?=20=EC=9E=98=EB=AA=BB=20=EB=B0=9B=EB=8A=94=20=EB=AC=B8=EC=A0=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../expert/domain/common/interceptor/CheckAdminInterceptor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java index 52dc8c864..4a9cf8670 100644 --- a/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java +++ b/src/main/java/org/example/expert/domain/common/interceptor/CheckAdminInterceptor.java @@ -18,7 +18,7 @@ public class CheckAdminInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { - UserRole userRole = UserRole.of(request.getAuthType()); + UserRole userRole = UserRole.of((String)request.getAttribute("userRole")); LocalDateTime reqTime = LocalDateTime.now(); if(!(userRole == UserRole.ADMIN)) { From b36f3c2c12400b8765a64558a7138c7d631a9bda Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Mon, 11 May 2026 02:06:40 +0900 Subject: [PATCH 31/34] =?UTF-8?q?Lv=205=20:=20AOP=EB=A5=BC=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=ED=95=9C=20=EB=A1=9C=EA=B7=B8=20=EC=B6=9C=EB=A0=A5,?= =?UTF-8?q?=20=EA=B6=8C=ED=95=9C=EB=B3=84=20=EC=A0=91=EA=B7=BC=EC=9D=84=20?= =?UTF-8?q?=EC=9C=84=ED=95=9C=20SecurityConfig=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 1 + .../example/expert/config/SecurityConfig.java | 21 +++++++++++ .../domain/common/aspect/LoggingAop.java | 35 ++++++++++++++++--- 3 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/example/expert/config/SecurityConfig.java diff --git a/build.gradle b/build.gradle index 02cdc00bb..46d9ab916 100644 --- a/build.gradle +++ b/build.gradle @@ -32,6 +32,7 @@ dependencies { annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + implementation 'org.springframework.boot:spring-boot-starter-security' // bcrypt implementation 'at.favre.lib:bcrypt:0.10.2' diff --git a/src/main/java/org/example/expert/config/SecurityConfig.java b/src/main/java/org/example/expert/config/SecurityConfig.java new file mode 100644 index 000000000..930b32576 --- /dev/null +++ b/src/main/java/org/example/expert/config/SecurityConfig.java @@ -0,0 +1,21 @@ +package org.example.expert.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.web.SecurityFilterChain; + +@Configuration +public class SecurityConfig { + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http + .csrf(AbstractHttpConfigurer::disable) + .authorizeHttpRequests(auth -> auth.anyRequest().permitAll()); + + return http.build(); + } +} \ No newline at end of file diff --git a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java index 41a93f67a..1a2ee887c 100644 --- a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java +++ b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java @@ -1,24 +1,49 @@ package org.example.expert.domain.common.aspect; +import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import java.util.Arrays; @Aspect @Slf4j @Component public class LoggingAop { - @Around("execution(* org.example.expert.domain.comment.service*(..))") + @Around("execution(* org.example.expert.domain.admin.controller*(..))") public Object commentAop(ProceedingJoinPoint joinPoint) throws Throwable { - long start = System.currentTimeMillis(); - Object result = joinPoint.proceed(); // 실제 메서드 실행 -> Filter에서 doFilter 와 비슷함. + ServletRequestAttributes attr = + (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); + HttpServletRequest request = attr.getRequest(); // + String requestBody = Arrays.toString(joinPoint.getArgs()); + + long start = System.currentTimeMillis(); // API 요청 시각 + + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); + String userId = auth.getName(); + + Object result = joinPoint.proceed(); // 응답 본문 + + log.info(" 유저 아이디 : {}," + + " API 요청 시각 : {}" + + " API 요청 URL : {}" + + " 요청 본문 : {}" + + " 응답 본문 : {}", + userId, + start, + request.getRequestURI(), + requestBody, + result); - long end = System.currentTimeMillis(); - log.info("[AOP] {} 실행됨 in {}ms" , joinPoint.getSignature() , end - start); return result; } } From 3288cf885e14290f1f6e11ffeb95b4f7928f0a71 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Mon, 11 May 2026 03:05:25 +0900 Subject: [PATCH 32/34] =?UTF-8?q?Lv=205=20:=20AOP=20=EB=A7=B5=ED=95=91=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/example/expert/config/SecurityConfig.java | 1 - .../org/example/expert/domain/common/aspect/LoggingAop.java | 5 ++--- .../java/org/example/expert/domain/user/enums/UserRole.java | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/example/expert/config/SecurityConfig.java b/src/main/java/org/example/expert/config/SecurityConfig.java index 930b32576..01c413115 100644 --- a/src/main/java/org/example/expert/config/SecurityConfig.java +++ b/src/main/java/org/example/expert/config/SecurityConfig.java @@ -3,7 +3,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.web.SecurityFilterChain; diff --git a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java index 1a2ee887c..d4a02d61a 100644 --- a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java +++ b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java @@ -17,8 +17,7 @@ @Slf4j @Component public class LoggingAop { - - @Around("execution(* org.example.expert.domain.admin.controller*(..))") + @Around("execution(* org.example.expert.domain.admin.controller.AdminController.*(..))") public Object commentAop(ProceedingJoinPoint joinPoint) throws Throwable { ServletRequestAttributes attr = @@ -46,4 +45,4 @@ public Object commentAop(ProceedingJoinPoint joinPoint) throws Throwable { return result; } -} +} \ No newline at end of file diff --git a/src/main/java/org/example/expert/domain/user/enums/UserRole.java b/src/main/java/org/example/expert/domain/user/enums/UserRole.java index 6fe177896..00aebef12 100644 --- a/src/main/java/org/example/expert/domain/user/enums/UserRole.java +++ b/src/main/java/org/example/expert/domain/user/enums/UserRole.java @@ -11,6 +11,6 @@ public static UserRole of(String role) { return Arrays.stream(UserRole.values()) .filter(r -> r.name().equalsIgnoreCase(role)) .findFirst() - .orElseThrow(() -> new InvalidRequestException("유효하지 않은 UerRole")); + .orElseThrow(() -> new InvalidRequestException("유효하지 않은 UserRole")); } } From 9ec7e2df6856c87c5b288aece9091e5599f60f1e Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Mon, 11 May 2026 11:03:45 +0900 Subject: [PATCH 33/34] =?UTF-8?q?Lv=205=20:=20AOP=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EC=9A=94=EC=B2=AD=EB=B3=B8=EB=AC=B8=EA=B3=BC=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=EB=B3=B8=EB=AC=B8=EC=9D=B4=20=EC=A0=9C=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EC=B6=9C=EB=A0=A5=EB=90=98=EC=A7=80=20=EC=95=8A?= =?UTF-8?q?=EB=8A=94=20=ED=98=84=EC=83=81=20=EC=88=98=EC=A0=95=20objectMap?= =?UTF-8?q?per=EB=A5=BC=20=EC=9D=B4=EC=9A=A9=ED=95=98=EC=97=AC=20json=20?= =?UTF-8?q?=ED=98=95=EC=8B=9D=EC=9C=BC=EB=A1=9C=20=EC=B6=9C=EB=A0=A5?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/expert/config/WebMvcConfig.java | 4 +-- .../domain/common/aspect/LoggingAop.java | 29 +++++++++++++------ 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/example/expert/config/WebMvcConfig.java b/src/main/java/org/example/expert/config/WebMvcConfig.java index cec1bd2ce..3e6bdc644 100644 --- a/src/main/java/org/example/expert/config/WebMvcConfig.java +++ b/src/main/java/org/example/expert/config/WebMvcConfig.java @@ -14,7 +14,7 @@ public class WebMvcConfig implements WebMvcConfigurer { private final AuthUserArgumentResolver authUserArgumentResolver; - private final CheckAdminInterceptor checkAdminInterceptork; + private final CheckAdminInterceptor checkAdminInterceptor; @Override public void addArgumentResolvers(List resolvers) { @@ -23,7 +23,7 @@ public void addArgumentResolvers(List resolvers) @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(checkAdminInterceptork) + registry.addInterceptor(checkAdminInterceptor) .addPathPatterns("/admin/**"); } diff --git a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java index d4a02d61a..74d37219d 100644 --- a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java +++ b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java @@ -1,10 +1,13 @@ package org.example.expert.domain.common.aspect; +import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; +import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; @@ -12,36 +15,44 @@ import org.springframework.web.context.request.ServletRequestAttributes; import java.util.Arrays; +import java.util.logging.Logger; @Aspect @Slf4j @Component +@RequiredArgsConstructor public class LoggingAop { + + private final ObjectMapper objectMapper; + @Around("execution(* org.example.expert.domain.admin.controller.AdminController.*(..))") public Object commentAop(ProceedingJoinPoint joinPoint) throws Throwable { + long start = System.currentTimeMillis(); // API 요청 시각 ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); - HttpServletRequest request = attr.getRequest(); // - String requestBody = Arrays.toString(joinPoint.getArgs()); + HttpServletRequest request = attr.getRequest(); + + Object[] args = joinPoint.getArgs(); + String requestBody = objectMapper.writeValueAsString(args); // 요청 본문 - long start = System.currentTimeMillis(); // API 요청 시각 Authentication auth = SecurityContextHolder.getContext().getAuthentication(); String userId = auth.getName(); - Object result = joinPoint.proceed(); // 응답 본문 + Object result = joinPoint.proceed(); + String responseBody = objectMapper.writeValueAsString(result); // 응답 본문 log.info(" 유저 아이디 : {}," + - " API 요청 시각 : {}" + - " API 요청 URL : {}" + - " 요청 본문 : {}" + - " 응답 본문 : {}", + " API 요청 시각 : {}" + + " API 요청 URL : {}" + + " 요청 본문 : {}" + + " 응답 본문 : {}", userId, start, request.getRequestURI(), requestBody, - result); + responseBody); return result; } From 52ecfea0b1485e480b9080fddb7f6d5ee4109767 Mon Sep 17 00:00:00 2001 From: "jy030506@naver.com" Date: Mon, 11 May 2026 11:04:07 +0900 Subject: [PATCH 34/34] =?UTF-8?q?Lv=205=20:=20=EC=82=AC=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20import=EB=AC=B8=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/example/expert/domain/common/aspect/LoggingAop.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java index 74d37219d..a9b8c4651 100644 --- a/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java +++ b/src/main/java/org/example/expert/domain/common/aspect/LoggingAop.java @@ -7,16 +7,12 @@ import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; -import org.slf4j.LoggerFactory; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; -import java.util.Arrays; -import java.util.logging.Logger; - @Aspect @Slf4j @Component