From 9854d2f50b964976afd502ceee3e74a02a56c82b Mon Sep 17 00:00:00 2001 From: jemin Date: Tue, 9 Apr 2024 08:01:41 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20CommonException=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mellyserver/clientauth/FeignConfig.java | 9 ---- .../mellyserver/clientauth/LoginClient.java | 7 --- .../clientauth/api/NaverClient.java | 4 -- .../src/main/resources/client-auth-local.yml | 32 +++---------- .../EmailCertificationService.java | 4 +- .../common/filter/JwtExceptionFilter.java | 22 ++------- .../filter/TokenAuthenticationFilter.java | 18 -------- .../auth/config/SecurityConfig.java | 7 +-- .../mellyserver/auth/service/AuthService.java | 40 ++++++++-------- .../mellyserver/auth/token/TokenService.java | 4 +- .../common/aspect/lock/LockMessage.java | 1 - .../aspect/lock/OptimisticLockAspect.java | 15 ++---- .../mellyserver/config/async/AsyncConfig.java | 12 +++-- .../config/async/AsyncExceptionHandler.java | 16 +++++++ .../mellyserver/config/cache/CacheConfig.java | 46 ++++++++----------- .../mellyserver/config/cache/CustomCache.java | 8 ---- .../config/cache/CustomCacheManager.java | 3 +- .../controller/comment/CommentController.java | 4 +- .../exception/GlobalExceptionHandler.java | 14 ++---- .../domain/comment/CommentLikeReader.java | 4 +- .../domain/comment/CommentLikeService.java | 4 +- .../domain/comment/CommentLikeValidator.java | 4 +- .../domain/comment/CommentReader.java | 4 +- .../domain/comment/CommentWriter.java | 4 +- .../mellyserver/domain/group/GroupReader.java | 4 +- .../domain/group/GroupService.java | 3 +- .../domain/group/GroupValidator.java | 8 ++-- .../domain/memory/MemoryReader.java | 4 +- .../domain/memory/MemoryWriter.java | 33 ++++++++----- .../notification/NotificationReader.java | 4 +- .../mellyserver/domain/place/PlaceReader.java | 6 +-- .../domain/scrap/PlaceScrapService.java | 21 ++++----- .../domain/scrap/PlaceScrapValidator.java | 21 +++++---- .../domain/user/ProfileImageUploader.java | 4 +- .../mellyserver/domain/user/UserReader.java | 7 ++- ...essException.java => CommonException.java} | 4 +- .../support/exception/ErrorCode.java | 6 --- .../support/health/HealthController.java | 13 ++++++ .../support/response/ApiResponse.java | 2 +- .../support/response/ErrorResponse.java | 2 +- .../support/response/SuccessCode.java | 6 +-- .../common/mock/MockFileService.java | 4 +- .../integration/UserGroupServiceTest.java | 6 +-- .../memory/integration/MemoryServiceTest.java | 4 +- .../integration/NotificationServiceTest.java | 4 +- .../place/integration/PlaceServiceTest.java | 6 +-- .../integration/PlaceScrapServiceTest.java | 6 +-- .../integration/PlaceScrapValidatorTest.java | 6 +-- .../user/repository/UserRepositoryTest.java | 6 +-- .../{FileService.java => FileUploader.java} | 2 +- .../cmc/mellyserver/aws/S3StorageService.java | 4 +- settings.gradle | 1 - .../dbcore/comment/comment/Comment.java | 5 +- .../dbcore/memory/memory/Memory.java | 4 +- .../cmc/mellyserver/dbcore/user/User.java | 4 -- .../dbcore/user/UserRepository.java | 3 +- 56 files changed, 212 insertions(+), 287 deletions(-) create mode 100644 core/core-api/src/main/java/cmc/mellyserver/config/async/AsyncExceptionHandler.java rename core/core-api/src/main/java/cmc/mellyserver/support/exception/{BusinessException.java => CommonException.java} (68%) create mode 100644 core/core-api/src/main/java/cmc/mellyserver/support/health/HealthController.java rename infra/file/src/main/java/cmc/mellyserver/{FileService.java => FileUploader.java} (90%) diff --git a/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/FeignConfig.java b/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/FeignConfig.java index 53aee632..4a895432 100644 --- a/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/FeignConfig.java +++ b/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/FeignConfig.java @@ -3,19 +3,10 @@ import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.FeignAutoConfiguration; -import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import feign.Logger; - @EnableFeignClients @ImportAutoConfiguration({FeignAutoConfiguration.class}) @Configuration public class FeignConfig { - - @Bean - Logger.Level feignLoggerLevel() { - return Logger.Level.FULL; - } - } diff --git a/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/LoginClient.java b/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/LoginClient.java index 318244b3..940a3c2f 100644 --- a/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/LoginClient.java +++ b/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/LoginClient.java @@ -2,13 +2,6 @@ import cmc.mellyserver.clientauth.api.LoginClientResult; -/* -현재 Melly에서는 카카오, 네이버, 구글, 애플 OAuth를 사용하고 있습니다. 차후 OAuth는 얼마든지 추가될 수 있기에 확장성을 고려한 설계가 필요합니다. -따라서 LoginClient 인터페이스를 만들어서 구체 클라이언트들이 구현하도록 만들었습니다. -OAuth 리소스 서버로부터 데이터를 받아와야 하는 쪽에서는 누구에게 요청하는지 관심을 가지지 않아도 됩니다. -- support : 해당 클라이언트가 어떤 Provider인지 판별합니다 -- getUserData : 실제 유저 데이터를 받아옵니다 - */ public interface LoginClient { boolean supports(String provider); diff --git a/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/api/NaverClient.java b/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/api/NaverClient.java index dbb0f635..fe3a41ef 100644 --- a/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/api/NaverClient.java +++ b/clients/client-auth/src/main/java/cmc/mellyserver/clientauth/api/NaverClient.java @@ -7,10 +7,6 @@ import cmc.mellyserver.clientauth.LoginClient; import lombok.RequiredArgsConstructor; -/* -타 모듈은 Client 호출이 필요할때 xxClient 객체를 사용해서 호출하면 됩니다. -OpenFeign 인터페이스에 대한 접근은 패키지 내부로 숨겼습니다. - */ @Component @RequiredArgsConstructor public class NaverClient implements LoginClient { diff --git a/clients/client-auth/src/main/resources/client-auth-local.yml b/clients/client-auth/src/main/resources/client-auth-local.yml index 83421004..7ecd7eb7 100644 --- a/clients/client-auth/src/main/resources/client-auth-local.yml +++ b/clients/client-auth/src/main/resources/client-auth-local.yml @@ -1,6 +1,6 @@ client: oauth: - uri: # OAuth2 리소스 서버 주소 + uri: kakao: https://kapi.kakao.com/v2/user/me naver: https://openapi.naver.com/v1/nid/me google: https://oauth2.googleapis.com/tokeninfo @@ -10,30 +10,10 @@ spring.cloud.openfeign: client: config: default: - connectTimeout: 3000 # SYN InitialRTO 1초와 SYN/ACK InitialRTO 1초를 고려해서 3초로 설정 - readTimeout: 5000 # 외부 인증 서비스 고려해서 넉넉히 2초로 설정 - loggerLevel: full # openFeign 관련 모든 로그 출력 + connectTimeout: 3000 + readTimeout: 3000 + loggerLevel: full httpclient: - max-connections: 400 # 전체 커넥션 수 - max-connections-per-route: 100 # Route당 할당되는 최대 커넥션 수 - - circuitbreaker: - enabled: true - -resilience4j.circuitbreaker: - configs: - default: - slidingWindowType: COUNT_BASED - minimumNumberOfCalls: 3 - slidingWindowSize: 5 - waitDurationInOpenState: 5s - failureRateThreshold: 80 - slowCallDurationThreshold: 2000 - slowCallRateThreshold: 80 - permittedNumberOfCallsInHalfOpenState: 5 - automaticTransitionFromOpenToHalfOpenEnabled: true - eventConsumerBufferSize: 10 - instances: - default: - baseConfig: default + max-connections: 400 + max-connections-per-route: 100 diff --git a/core/core-api/src/main/java/cmc/mellyserver/auth/certificate/EmailCertificationService.java b/core/core-api/src/main/java/cmc/mellyserver/auth/certificate/EmailCertificationService.java index 940e3de2..a10f5e28 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/auth/certificate/EmailCertificationService.java +++ b/core/core-api/src/main/java/cmc/mellyserver/auth/certificate/EmailCertificationService.java @@ -5,7 +5,7 @@ import org.springframework.stereotype.Repository; import cmc.mellyserver.auth.service.dto.request.EmailCertificationRequest; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -28,7 +28,7 @@ public void sendCertification(String email) { public void verify(EmailCertificationRequest requestDto) { if (isVerify(requestDto)) { - throw new BusinessException(ErrorCode.NOT_VALID_ERROR); + throw new CommonException(ErrorCode.NOT_VALID_ERROR); } certificationNumberDao.delete(requestDto.email()); diff --git a/core/core-api/src/main/java/cmc/mellyserver/auth/common/filter/JwtExceptionFilter.java b/core/core-api/src/main/java/cmc/mellyserver/auth/common/filter/JwtExceptionFilter.java index 820f21b9..89046269 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/auth/common/filter/JwtExceptionFilter.java +++ b/core/core-api/src/main/java/cmc/mellyserver/auth/common/filter/JwtExceptionFilter.java @@ -10,17 +10,20 @@ import com.fasterxml.jackson.databind.ObjectMapper; import cmc.mellyserver.support.exception.ErrorCode; -import cmc.mellyserver.support.exception.LogoutOrWithdrawException; import cmc.mellyserver.support.response.ErrorResponse; import io.jsonwebtoken.JwtException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; @Component +@RequiredArgsConstructor public class JwtExceptionFilter extends OncePerRequestFilter { + private final ObjectMapper mapper; + @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { @@ -28,8 +31,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse chain.doFilter(request, response); } catch (JwtException ex) { setExpiredErrorResponse(response); - } catch (LogoutOrWithdrawException ex) { - setLogoutOrWithdrawErrorResponse(response); } } @@ -39,21 +40,6 @@ private void setExpiredErrorResponse(HttpServletResponse response) throws IOExce response.setStatus(HttpStatus.OK.value()); ErrorResponse error = ErrorResponse.of(ErrorCode.EXPIRED_TOKEN); - - ObjectMapper mapper = new ObjectMapper(); - mapper.writeValue(response.getOutputStream(), error); - - } - - private void setLogoutOrWithdrawErrorResponse(HttpServletResponse response) throws IOException { - - response.setContentType(MediaType.APPLICATION_JSON_VALUE); - response.setStatus(HttpStatus.OK.value()); - - ErrorResponse error = ErrorResponse.of(ErrorCode.LOGOUT_WITHDRAW_USER); - - ObjectMapper mapper = new ObjectMapper(); mapper.writeValue(response.getOutputStream(), error); } - } diff --git a/core/core-api/src/main/java/cmc/mellyserver/auth/common/filter/TokenAuthenticationFilter.java b/core/core-api/src/main/java/cmc/mellyserver/auth/common/filter/TokenAuthenticationFilter.java index fbeed0e8..1c551a18 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/auth/common/filter/TokenAuthenticationFilter.java +++ b/core/core-api/src/main/java/cmc/mellyserver/auth/common/filter/TokenAuthenticationFilter.java @@ -1,10 +1,7 @@ package cmc.mellyserver.auth.common.filter; import java.io.IOException; -import java.util.Objects; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.data.redis.core.ValueOperations; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.util.StringUtils; @@ -12,7 +9,6 @@ import cmc.mellyserver.auth.common.util.HeaderUtil; import cmc.mellyserver.auth.token.TokenProvider; -import cmc.mellyserver.support.exception.LogoutOrWithdrawException; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; @@ -26,8 +22,6 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter { private final TokenProvider tokenProvider; - private final RedisTemplate redisTemplate; - @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { @@ -36,8 +30,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse if (StringUtils.hasText(accessToken) && tokenProvider.validateToken(accessToken)) { - // checkLogoutOrWithdrawUser(accessToken); - Authentication authentication = tokenProvider.getAuthentication(accessToken); SecurityContextHolder.getContext().setAuthentication(authentication); @@ -45,14 +37,4 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse filterChain.doFilter(request, response); } - - private void checkLogoutOrWithdrawUser(String accessToken) { - - ValueOperations valueOperations = redisTemplate.opsForValue(); - - if (Objects.nonNull(valueOperations.get(accessToken))) { - throw new LogoutOrWithdrawException("already Logout or withdraw user"); - } - } - } \ No newline at end of file diff --git a/core/core-api/src/main/java/cmc/mellyserver/auth/config/SecurityConfig.java b/core/core-api/src/main/java/cmc/mellyserver/auth/config/SecurityConfig.java index 5780a5b4..f0ef9026 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/auth/config/SecurityConfig.java +++ b/core/core-api/src/main/java/cmc/mellyserver/auth/config/SecurityConfig.java @@ -2,7 +2,6 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; @@ -28,9 +27,7 @@ public class SecurityConfig { private final JwtTokenProvider jwtTokenProvider; - - private final RedisTemplate redisTemplate; - + private final RestAuthenticationEntryPoint authenticationEntryPoint; private final TokenAccessDeniedHandler accessDeniedHandler; @@ -40,7 +37,7 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { - TokenAuthenticationFilter authenticationFilter = new TokenAuthenticationFilter(jwtTokenProvider, redisTemplate); + TokenAuthenticationFilter authenticationFilter = new TokenAuthenticationFilter(jwtTokenProvider); httpSecurity.csrf(CsrfConfigurer::disable) .cors(CorsConfigurer::disable) diff --git a/core/core-api/src/main/java/cmc/mellyserver/auth/service/AuthService.java b/core/core-api/src/main/java/cmc/mellyserver/auth/service/AuthService.java index bb3da6cf..060e3789 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/auth/service/AuthService.java +++ b/core/core-api/src/main/java/cmc/mellyserver/auth/service/AuthService.java @@ -1,5 +1,7 @@ package cmc.mellyserver.auth.service; +import java.util.Objects; + import org.springframework.context.ApplicationEventPublisher; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; @@ -16,7 +18,7 @@ import cmc.mellyserver.dbcore.user.User; import cmc.mellyserver.domain.user.UserReader; import cmc.mellyserver.domain.user.UserWriter; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -49,11 +51,6 @@ public TokenResponseDto signup(AuthSignupRequestDto authSignupRequestDto) { return TokenResponseDto.of(tokenDto.accessToken(), tokenDto.refreshToken().token()); } - /* - 로그인 요청이 몰리는 상황에서 TPS를 올릴 수 있는 방법들을 고민했습니다. - - 1. email 컬럼에 대한 인덱스를 생성해서 DB 랜덤 I/O 시간 단축 - - 2. password 비교하는 과정에서 encoder의 암호화 강도가 높아서 CPU 사용량과 처리시간 증가, EC2의 CPU 스펙에 맞춰서 암호화 강도 조절 - */ @Transactional public TokenResponseDto login(AuthLoginRequestDto authLoginRequestDto) { @@ -66,7 +63,6 @@ public TokenResponseDto login(AuthLoginRequestDto authLoginRequestDto) { return TokenResponseDto.of(tokenDto.accessToken(), tokenDto.refreshToken().token()); } - // Refresh Token Rotation (RTR) 전략 적용 public TokenResponseDto reIssueAccessTokenAndRefreshToken(final String token) { Long userId = tokenService.extractUserId(token); @@ -100,22 +96,26 @@ public void withdraw(final Long userId, final String accessToken) { public void checkDuplicatedNickname(final String nickname) { if (userReader.existsByNickname(nickname)) { - throw new BusinessException(ErrorCode.DUPLICATE_NICKNAME); + throw new CommonException(ErrorCode.DUPLICATE_NICKNAME); } } public void checkDuplicatedEmail(final String email) { - if (userReader.findByEmail(email).isPresent()) { - throw new BusinessException(ErrorCode.DUPLICATE_EMAIL); + if (Objects.nonNull(userReader.findByEmail(email))) { + throw new CommonException(ErrorCode.DUPLICATE_EMAIL); } } @Transactional public void updateForgetPassword(ChangePasswordRequest requestDto) { - User user = userReader.findByEmail(requestDto.email()) - .orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); + User user = userReader.findByEmail(requestDto.email()); + + if (Objects.isNull(user)) { + throw new CommonException(ErrorCode.USER_NOT_FOUND); + } + user.changePassword(requestDto.passwordAfter()); } @@ -128,21 +128,25 @@ public void changePassword(final Long userId, ChangePasswordRequest requestDto) String passwordAfter = passwordEncoder.encode(requestDto.passwordAfter()); if (!userReader.existsByEmailAndPassword(user.getEmail(), passwordBefore)) { - throw new BusinessException(ErrorCode.BEFORE_PASSWORD_NOT_EXIST); + throw new CommonException(ErrorCode.BEFORE_PASSWORD_NOT_EXIST); } user.changePassword(passwordAfter); } private User checkEmail(final String email) { - return userReader.findByEmail(email).orElseThrow(() -> { - throw new BusinessException(ErrorCode.INVALID_EMAIL); - }); + User byEmail = userReader.findByEmail(email); + + if (Objects.isNull(byEmail)) { + throw new CommonException(ErrorCode.INVALID_EMAIL); + } + + return byEmail; } private void checkPassword(final String password, final String originPassword) { if (!passwordEncoder.matches(password, originPassword)) { - throw new BusinessException(ErrorCode.INVALID_PASSWORD); + throw new CommonException(ErrorCode.INVALID_PASSWORD); } } @@ -150,7 +154,7 @@ private void checkAbnormalUserAccess(final String token, final Long userId, fina if (!refreshToken.refreshToken().equals(token)) { tokenService.removeRefreshToken(userId); - throw new BusinessException(ErrorCode.ABNORMAL_ACCESS); + throw new CommonException(ErrorCode.ABNORMAL_ACCESS); } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/auth/token/TokenService.java b/core/core-api/src/main/java/cmc/mellyserver/auth/token/TokenService.java index 4a61dbdd..0d08c262 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/auth/token/TokenService.java +++ b/core/core-api/src/main/java/cmc/mellyserver/auth/token/TokenService.java @@ -4,7 +4,7 @@ import cmc.mellyserver.auth.service.dto.response.RefreshTokenDto; import cmc.mellyserver.dbcore.user.User; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -26,7 +26,7 @@ public TokenDto createToken(User user) { public RefreshToken findRefreshToken(Long userId) { return authTokenDao.findRefreshToken(userId).orElseThrow(() -> { - throw new BusinessException(ErrorCode.RELOGIN_REQUIRED); + throw new CommonException(ErrorCode.RELOGIN_REQUIRED); }); } diff --git a/core/core-api/src/main/java/cmc/mellyserver/common/aspect/lock/LockMessage.java b/core/core-api/src/main/java/cmc/mellyserver/common/aspect/lock/LockMessage.java index a4153276..f9b350c3 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/common/aspect/lock/LockMessage.java +++ b/core/core-api/src/main/java/cmc/mellyserver/common/aspect/lock/LockMessage.java @@ -2,7 +2,6 @@ public abstract class LockMessage { - // Optimistic Lock public static final String OPTIMISTIC_LOCK_AOP_ENTRY = "Optimistic Lock AOP 진입"; public static final String OPTIMISTIC_LOCK_RETRY = "optimistic Lock acquire fail, retry start"; diff --git a/core/core-api/src/main/java/cmc/mellyserver/common/aspect/lock/OptimisticLockAspect.java b/core/core-api/src/main/java/cmc/mellyserver/common/aspect/lock/OptimisticLockAspect.java index 5c5a2aec..9e904175 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/common/aspect/lock/OptimisticLockAspect.java +++ b/core/core-api/src/main/java/cmc/mellyserver/common/aspect/lock/OptimisticLockAspect.java @@ -10,23 +10,14 @@ import org.aspectj.lang.reflect.MethodSignature; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; -import org.springframework.dao.CannotAcquireLockException; import org.springframework.dao.OptimisticLockingFailureException; import org.springframework.stereotype.Component; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -/* -트랜잭션이 커밋될때 낙관적 락을 위한 버전 체크가 발생합니다. 이때 버전 충돌이 발생하면 예외가 반환됩니다. -해당 AOP 어드바이저는 OptimisticLockingFailureException을 캐치해서 트랜잭션을 재시도 해야 합니다. -따라서 트랜잭션보다 외부에 AOP를 생성하는 방법을 적용했습니다. - -AOP는 Order의 숫자가 작을수록 우선순위가 높습니다. @Transactional은 default가 LOWEST_PRECEDENCE으로 가장 우선순위가 낮습니다. -따라서 LOWEST_PRECEDENCE보다 한 단계 우선하도록 LOWEST_PRECEDENCE-1을 적용했습니다. - */ @Slf4j @Aspect @Component @@ -49,13 +40,13 @@ public Object lock(final ProceedingJoinPoint joinPoint) throws Throwable { for (int i = 0; i < retryCount; i++) { try { return joinPoint.proceed(); - } catch (OptimisticLockingFailureException | CannotAcquireLockException ex) { + } catch (OptimisticLockingFailureException e) { log.info(OPTIMISTIC_LOCK_RETRY); Thread.sleep(waitTime); } } log.error(OPTIMISTIC_LOCK_ACQUIRE_FAIL); - throw new BusinessException(ErrorCode.SERVER_ERROR); + throw new CommonException(ErrorCode.SERVER_ERROR); } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/config/async/AsyncConfig.java b/core/core-api/src/main/java/cmc/mellyserver/config/async/AsyncConfig.java index eb8a18de..9ab95846 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/config/async/AsyncConfig.java +++ b/core/core-api/src/main/java/cmc/mellyserver/config/async/AsyncConfig.java @@ -3,8 +3,8 @@ import static cmc.mellyserver.config.async.ExecutorConstants.*; import java.util.concurrent.Executor; -import java.util.concurrent.ThreadPoolExecutor; +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; @@ -30,7 +30,7 @@ public ThreadPoolTaskExecutor imageUploadTaskExecutor() { executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(5); executor.setThreadNamePrefix(IMAGE_EXECUTOR_PREFIX); - executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); + executor.initialize(); return executor; } @@ -43,7 +43,6 @@ public ThreadPoolTaskExecutor notificationTaskExecutor() { executor.setQueueCapacity(1000); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(5); - executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); executor.setThreadNamePrefix(NOTIFICATION_EXECUTOR_PREFIX); executor.initialize(); return executor; @@ -58,7 +57,6 @@ public ThreadPoolTaskExecutor sendEmailTaskExecutor() { executor.setQueueCapacity(1000); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(5); - executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); executor.setThreadNamePrefix(SEND_EMAIL_EXECUTOR_PREFIX); executor.initialize(); return executor; @@ -72,9 +70,13 @@ public Executor getAsyncExecutor() { executor.setQueueCapacity(1000); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(5); - executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setThreadNamePrefix(ASYNC_DEFAULT_EXECUTOR_PREFIX); executor.initialize(); return executor; } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return new AsyncExceptionHandler(); + } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/config/async/AsyncExceptionHandler.java b/core/core-api/src/main/java/cmc/mellyserver/config/async/AsyncExceptionHandler.java new file mode 100644 index 00000000..a750d315 --- /dev/null +++ b/core/core-api/src/main/java/cmc/mellyserver/config/async/AsyncExceptionHandler.java @@ -0,0 +1,16 @@ +package cmc.mellyserver.config.async; + +import java.lang.reflect.Method; + +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler { + + @Override + public void handleUncaughtException(Throwable ex, Method method, Object... params) { + log.error(ex.getMessage()); + } +} diff --git a/core/core-api/src/main/java/cmc/mellyserver/config/cache/CacheConfig.java b/core/core-api/src/main/java/cmc/mellyserver/config/cache/CacheConfig.java index ccf4824a..ae0d5d03 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/config/cache/CacheConfig.java +++ b/core/core-api/src/main/java/cmc/mellyserver/config/cache/CacheConfig.java @@ -26,13 +26,14 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; @EnableCaching @Configuration public class CacheConfig { - private static final Duration COMMAND_TIMEOUT = Duration.ofMillis(200); + private static final Duration COMMAND_TIMEOUT = Duration.ofMillis(300); @Value("${spring.redis.cache.host}") private String cacheHost; @@ -45,20 +46,26 @@ RedisConnectionFactory redisCacheConnectionFactory() { RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); redisStandaloneConfiguration.setHostName(cacheHost); redisStandaloneConfiguration.setPort(cachePort); - LettuceClientConfiguration lettuceClientConfiguration = LettuceClientConfiguration.builder() .commandTimeout(COMMAND_TIMEOUT).build(); - return new LettuceConnectionFactory(redisStandaloneConfiguration, lettuceClientConfiguration); } - /* - 캐시 TTL 시간 설정 기준 - - USER 프로필 캐시는 조회에 비해 변경 가능성이 적고 TTL로 1일을 설정했습니다. - - SCRAP 캐시는 변경 가능성이 높지만 개인화된 데이터이고 TTL로 1일을 설정했습니다. - - MEMORY 상세 페이지 캐시는 메모리 이외에도 그룹 정보, 장소 정보들이 혼합되기 때문에 TTL을 10분으로 짧게 설정했습니다. - - GROUP 상세 페이지 캐시는 그룹 이외에도 유저 정보가 혼합되기 때문에 TTL을 10분으로 짧게 설정했습니다. - */ + @Bean + public ObjectMapper objectMapper() { + + BasicPolymorphicTypeValidator typeValidator = BasicPolymorphicTypeValidator + .builder() + .allowIfSubType(Object.class) + .build(); + + return new ObjectMapper() + .registerModule(new JavaTimeModule()) + .activateDefaultTyping(typeValidator, ObjectMapper.DefaultTyping.NON_FINAL) + .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + } + @Bean public CacheManager customCacheManager(CircuitBreakerFactory circuitBreakerFactory) { @@ -70,8 +77,8 @@ public CacheManager customCacheManager(CircuitBreakerFactory circuitBreakerFacto /* Cache TTL 설정 */ Map redisCacheConfigMap = new ConcurrentHashMap<>(); - redisCacheConfigMap.put(CacheNames.USER, defaultConfig.entryTtl(Duration.ofDays(1))); - redisCacheConfigMap.put(CacheNames.SCRAP, defaultConfig.entryTtl(Duration.ofDays(1))); + redisCacheConfigMap.put(CacheNames.USER, defaultConfig.entryTtl(Duration.ofHours(1))); + redisCacheConfigMap.put(CacheNames.SCRAP, defaultConfig.entryTtl(Duration.ofHours(1))); redisCacheConfigMap.put(CacheNames.MEMORY, defaultConfig.entryTtl(Duration.ofMinutes(10))); redisCacheConfigMap.put(CacheNames.GROUP, defaultConfig.entryTtl(Duration.ofMinutes(10))); @@ -81,19 +88,4 @@ public CacheManager customCacheManager(CircuitBreakerFactory circuitBreakerFacto CircuitBreaker circuitBreaker = circuitBreakerFactory.create(CACHE_CIRCUIT); return new CustomCacheManager(redisCacheManager, circuitBreaker); } - - /* - 설정 종류 - - JavaTimeModule : Java 8의 date/time을 사용해서 string으로 직렬화 - - SerializationFeature.WRITE_DATES_AS_TIMESTAMP : 해당 속성을 true 시 Long 타입 직렬화, false는 String으로 직렬화 - - DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES : 역직렬화시 클래스 변수에 매핑되지 않는 값이 있을때 예외 발생 여부 - */ - @Bean - public ObjectMapper objectMapper() { - - return new ObjectMapper() - .registerModule(new JavaTimeModule()) - .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); - } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/config/cache/CustomCache.java b/core/core-api/src/main/java/cmc/mellyserver/config/cache/CustomCache.java index 7261933c..283ad255 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/config/cache/CustomCache.java +++ b/core/core-api/src/main/java/cmc/mellyserver/config/cache/CustomCache.java @@ -30,19 +30,11 @@ public Object getNativeCache() { return globalCache.getNativeCache(); } - /* - 1. 로컬 캐시를 조회 - 2. 로컬 캐시에 데이터 없으면 글로벌 캐시 조회 하고, 로컬 캐시 업데이트 - 3. 만약 글로벌 캐시에도 없으면 - */ @Override public ValueWrapper get(Object key) { return circuitBreaker.run(() -> globalCache.get(key), ((throwable) -> fallback())); } - /* - Cache가 ValueWrapper로 null을 반환하면 캐싱된 데이터가 없다고 판단 후, 실제 로직을 통해 DB 쿼리를 진행합니다. - */ private ValueWrapper fallback() { log.error("글로벌 캐시 다운, Fallback 메서드 실행"); return null; diff --git a/core/core-api/src/main/java/cmc/mellyserver/config/cache/CustomCacheManager.java b/core/core-api/src/main/java/cmc/mellyserver/config/cache/CustomCacheManager.java index a347b4a1..7f370cca 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/config/cache/CustomCacheManager.java +++ b/core/core-api/src/main/java/cmc/mellyserver/config/cache/CustomCacheManager.java @@ -12,8 +12,7 @@ public class CustomCacheManager implements CacheManager { private final RedisCacheManager globalCacheManager; private final CircuitBreaker circuitBreaker; - public CustomCacheManager(RedisCacheManager globalCacheManager, - CircuitBreaker circuitBreaker) { + public CustomCacheManager(RedisCacheManager globalCacheManager, CircuitBreaker circuitBreaker) { this.globalCacheManager = globalCacheManager; this.circuitBreaker = circuitBreaker; } diff --git a/core/core-api/src/main/java/cmc/mellyserver/controller/comment/CommentController.java b/core/core-api/src/main/java/cmc/mellyserver/controller/comment/CommentController.java index fbcb17df..15fd3477 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/controller/comment/CommentController.java +++ b/core/core-api/src/main/java/cmc/mellyserver/controller/comment/CommentController.java @@ -35,7 +35,7 @@ public class CommentController { public ResponseEntity> removeCommentLike(@CurrentUser LoginUser loginUser, @PathVariable Long commentId) { - commentLikeService.deleteCommentLike(loginUser.getId(), commentId); + commentLikeService.delete(loginUser.getId(), commentId); return ApiResponse.success(SuccessCode.DELETE_SUCCESS); } @@ -43,7 +43,7 @@ public ResponseEntity> removeCommentLike(@CurrentUser LoginUse public ResponseEntity> saveCommentLike(@CurrentUser LoginUser loginUser, @PathVariable Long commentId) { - commentLikeService.saveCommentLike(loginUser.getId(), commentId); + commentLikeService.save(loginUser.getId(), commentId); return ApiResponse.success(SuccessCode.INSERT_SUCCESS); } diff --git a/core/core-api/src/main/java/cmc/mellyserver/controller/exception/GlobalExceptionHandler.java b/core/core-api/src/main/java/cmc/mellyserver/controller/exception/GlobalExceptionHandler.java index 7fb0dfcf..c9958b8a 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/controller/exception/GlobalExceptionHandler.java +++ b/core/core-api/src/main/java/cmc/mellyserver/controller/exception/GlobalExceptionHandler.java @@ -18,7 +18,7 @@ import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.JsonProcessingException; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import cmc.mellyserver.support.response.ErrorResponse; import io.github.resilience4j.circuitbreaker.CallNotPermittedException; @@ -57,9 +57,8 @@ public ResponseEntity handleBindException(BindException e) { return new ResponseEntity<>(response, HTTP_STATUS_OK); } - // 비즈니스 예외 일괄 처리 - @ExceptionHandler(BusinessException.class) - protected ResponseEntity handleBusinessException(BusinessException e) { + @ExceptionHandler(CommonException.class) + protected ResponseEntity handleBusinessException(CommonException e) { ErrorCode errorCode = e.getErrorCode(); ErrorResponse response = ErrorResponse.of(errorCode); return new ResponseEntity<>(response, HTTP_STATUS_OK); @@ -72,13 +71,6 @@ protected ResponseEntity handleIOException(IOException ex) { return new ResponseEntity<>(response, HTTP_STATUS_OK); } - @ExceptionHandler(NullPointerException.class) - protected ResponseEntity handleNullPointerException(NullPointerException e) { - log.error("handleNullPointerException", e); - final ErrorResponse response = ErrorResponse.of(ErrorCode.NULL_POINT_ERROR, e.getMessage()); - return new ResponseEntity<>(response, HTTP_STATUS_OK); - } - @ExceptionHandler(NoHandlerFoundException.class) protected ResponseEntity handleNoHandlerFoundExceptionException(NoHandlerFoundException e) { log.error("handleNoHandlerFoundExceptionException", e); diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeReader.java b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeReader.java index 23840ac6..29d62091 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeReader.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeReader.java @@ -4,7 +4,7 @@ import cmc.mellyserver.dbcore.comment.commenlike.CommentLike; import cmc.mellyserver.dbcore.comment.commenlike.CommentLikeRepository; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -16,7 +16,7 @@ public class CommentLikeReader { public CommentLike find(final Long userId, final Long commentId) { return commentLikeRepository.findByUserIdAndCommentId(userId, commentId) - .orElseThrow(() -> new BusinessException( + .orElseThrow(() -> new CommonException( ErrorCode.NOT_EXIST_SCRAP)); } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeService.java b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeService.java index d22658f7..de356e58 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeService.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeService.java @@ -20,7 +20,7 @@ public class CommentLikeService { private final CommentReader commentReader; @Transactional - public void saveCommentLike(final Long userId, final Long commentId) { + public void save(final Long userId, final Long commentId) { Comment comment = commentReader.findByIdWithLock(commentId); commentLikeValidator.validateDuplicatedLike(commentId, userId); @@ -29,7 +29,7 @@ public void saveCommentLike(final Long userId, final Long commentId) { } @Transactional - public void deleteCommentLike(final Long userId, final Long commentId) { + public void delete(final Long userId, final Long commentId) { Comment comment = commentReader.findByIdWithLock(commentId); comment.unLike(); diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeValidator.java b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeValidator.java index ae63de3b..361f4b7d 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeValidator.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentLikeValidator.java @@ -3,7 +3,7 @@ import org.springframework.stereotype.Component; import cmc.mellyserver.dbcore.comment.commenlike.CommentLikeRepository; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -15,7 +15,7 @@ public class CommentLikeValidator { public void validateDuplicatedLike(final Long commentId, final Long userId) { commentLikeRepository.findByUserIdAndCommentId(commentId, userId).ifPresent(commentLike -> { - throw new BusinessException(ErrorCode.DUPLICATED_COMMENT_LIKE); + throw new CommonException(ErrorCode.DUPLICATED_COMMENT_LIKE); }); } diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentReader.java b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentReader.java index cea1f8b2..20742cff 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentReader.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentReader.java @@ -19,7 +19,7 @@ import cmc.mellyserver.domain.comment.dto.response.CommentResponseDto; import cmc.mellyserver.domain.comment.query.CommentQueryRepository; import cmc.mellyserver.domain.user.UserReader; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -37,7 +37,7 @@ public class CommentReader { public Comment findById(final Long commentId) { return commentRepository.findById(commentId).orElseThrow(() -> { - throw new BusinessException(ErrorCode.NO_SUCH_COMMENT); + throw new CommonException(ErrorCode.NO_SUCH_COMMENT); }); } diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentWriter.java b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentWriter.java index e6014697..7b2cdda4 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentWriter.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/comment/CommentWriter.java @@ -11,7 +11,7 @@ import cmc.mellyserver.domain.comment.dto.request.CommentRequestDto; import cmc.mellyserver.domain.memory.MemoryReader; import cmc.mellyserver.domain.user.UserReader; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -66,7 +66,7 @@ private Comment findRoot(Long rootId) { private void checkAuthority(Long userId, Comment comment) { if (!comment.getUser().getId().equals(userId)) { - throw new BusinessException(ErrorCode.NOT_VALID_ERROR); + throw new CommonException(ErrorCode.NOT_VALID_ERROR); } } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupReader.java b/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupReader.java index 457d4d94..fceeef97 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupReader.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupReader.java @@ -11,7 +11,7 @@ import cmc.mellyserver.domain.group.dto.response.UserJoinedGroupsResponse; import cmc.mellyserver.domain.group.query.UserGroupQueryRepository; import cmc.mellyserver.domain.group.query.dto.UserJoinedGroupsResponseDto; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -24,7 +24,7 @@ public class GroupReader { private final UserGroupQueryRepository userGroupQueryRepository; public UserGroup read(Long groupId) { - return groupRepository.findById(groupId).orElseThrow(() -> new BusinessException(ErrorCode.NO_SUCH_GROUP)); + return groupRepository.findById(groupId).orElseThrow(() -> new CommonException(ErrorCode.NO_SUCH_GROUP)); } public UserGroup readWithLock(Long groupId) { diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupService.java b/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupService.java index f657d43c..b32deedd 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupService.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupService.java @@ -69,11 +69,12 @@ public void joinGroup(Long userId, Long groupId) { groupAndUserWriter.save(GroupAndUser.of(userId, userGroup)); } + @OptimisticLock @CacheEvict(cacheNames = CacheNames.GROUP, key = "#updateGroupRequestDto.groupId") @Transactional public void updateGroup(UpdateGroupRequestDto updateGroupRequestDto) { - UserGroup userGroup = groupReader.read(updateGroupRequestDto.getGroupId()); + UserGroup userGroup = groupReader.readWithLock(updateGroupRequestDto.getGroupId()); userGroup.update(updateGroupRequestDto.getGroupName(), updateGroupRequestDto.getGroupType(), updateGroupRequestDto.getGroupIcon()); } diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupValidator.java b/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupValidator.java index 652a8962..cff55bc2 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupValidator.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/group/GroupValidator.java @@ -3,7 +3,7 @@ import org.springframework.stereotype.Component; import cmc.mellyserver.dbcore.group.UserGroup; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -17,19 +17,19 @@ public class GroupValidator { public void isDuplicatedJoin(Long userId, Long groupId) { if (groupAndUserReader.findByUserIdAndGroupId(userId, groupId).isPresent()) { - throw new BusinessException(ErrorCode.DUPLICATED_GROUP); + throw new CommonException(ErrorCode.DUPLICATED_GROUP); } } public void isMaximumGroupMember(Long groupId) { if (groupAndUserReader.countGroupMembers(groupId) > GROUP_MEMBER_MAX_COUNT) { - throw new BusinessException(ErrorCode.PARTICIPATE_GROUP_NOT_POSSIBLE); + throw new CommonException(ErrorCode.PARTICIPATE_GROUP_NOT_POSSIBLE); } } public void checkRemoveAuthority(Long userId, UserGroup userGroup) { if (!userGroup.checkAuthority(userId)) { - throw new BusinessException(ErrorCode.NO_AUTHORITY_TO_REMOVE); + throw new CommonException(ErrorCode.NO_AUTHORITY_TO_REMOVE); } } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/memory/MemoryReader.java b/core/core-api/src/main/java/cmc/mellyserver/domain/memory/MemoryReader.java index 5b87cb89..b408bd66 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/memory/MemoryReader.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/memory/MemoryReader.java @@ -10,7 +10,7 @@ import cmc.mellyserver.dbcore.memory.memory.MemoryRepository; import cmc.mellyserver.domain.memory.dto.response.MemoryListResponse; import cmc.mellyserver.domain.memory.query.MemoryQueryRepository; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -23,7 +23,7 @@ public class MemoryReader { private final MemoryQueryRepository memoryQueryRepository; public Memory read(Long memoryId) { - return memoryRepository.findById(memoryId).orElseThrow(() -> new BusinessException(ErrorCode.NO_SUCH_MEMORY)); + return memoryRepository.findById(memoryId).orElseThrow(() -> new CommonException(ErrorCode.NO_SUCH_MEMORY)); } public HashMap countMemoryInPlace(Long userId, Long placeId) { diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/memory/MemoryWriter.java b/core/core-api/src/main/java/cmc/mellyserver/domain/memory/MemoryWriter.java index f42e4334..fdb94eb5 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/memory/MemoryWriter.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/memory/MemoryWriter.java @@ -6,14 +6,13 @@ import java.util.Collections; import java.util.List; import java.util.Objects; -import java.util.stream.Collectors; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import cmc.mellyserver.FileDto; -import cmc.mellyserver.FileService; +import cmc.mellyserver.FileUploader; import cmc.mellyserver.common.aspect.place.CheckPlaceExist; import cmc.mellyserver.dbcore.memory.memory.Memory; import cmc.mellyserver.dbcore.memory.memory.MemoryImage; @@ -23,7 +22,7 @@ import cmc.mellyserver.domain.memory.dto.request.CreateMemoryRequestDto; import cmc.mellyserver.domain.memory.dto.request.UpdateMemoryRequestDto; import cmc.mellyserver.domain.place.PlaceReader; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import lombok.RequiredArgsConstructor; @Component @@ -36,7 +35,7 @@ public class MemoryWriter { private final PlaceReader placeReader; - private final FileService fileService; + private final FileUploader fileUploader; private final ThreadPoolTaskExecutor imageUploadTaskExecutor; @@ -44,14 +43,21 @@ public class MemoryWriter { public Long save(CreateMemoryRequestDto createMemoryRequestDto) { Memory memory = createMemoryRequestDto.toMemory(); + addPlace(createMemoryRequestDto.getPosition(), memory); addKeywords(createMemoryRequestDto.getKeywordIds(), memory); + Memory savedMemory = memoryRepository.save(memory); - imageUploadTaskExecutor.execute(() -> addMemoryImages(memory.getId(), createMemoryRequestDto.getUserId(), - createMemoryRequestDto.getMultipartFiles())); + + addImages(memory.getId(), createMemoryRequestDto.getUserId(), createMemoryRequestDto.getMultipartFiles()); + return savedMemory.getId(); } + private void addImages(Long id, Long userId, List multipartFiles) { + + } + public void update(UpdateMemoryRequestDto updateDto) { Memory memory = memoryReader.read(updateDto.getMemoryId()); @@ -63,12 +69,12 @@ public void update(UpdateMemoryRequestDto updateDto) { } private List updateImages(List deleteImages, List newImages, Long userId) { - fileService.deleteFiles(deleteImages); + fileUploader.deleteFiles(deleteImages); return saveImages(userId, newImages); } private List saveImages(Long userId, List newImages) { - return fileService.saveFiles(userId, extractFileDtos(newImages)); + return fileUploader.saveFiles(userId, extractFileDtos(newImages)); } private List extractFileDtos(List newImages) { @@ -103,9 +109,14 @@ private void addMemoryImages(Long userId, Long memoryId, List ima return; } - List multipartFileNames = fileService.saveFiles(userId, fileList); - Memory memory = memoryRepository.findById(memoryId).orElseThrow(() -> new BusinessException(NO_SUCH_MEMORY)); - memory.setMemoryImages(multipartFileNames.stream().map(MemoryImage::new).collect(Collectors.toList())); + List multipartFileNames = fileUploader.saveFiles(userId, fileList); + Memory memory = memoryRepository.findById(memoryId).orElseThrow(() -> new CommonException(NO_SUCH_MEMORY)); + List memoryImages = transferToMemoryImages(multipartFileNames); + memory.addImages(memoryImages); + } + + private List transferToMemoryImages(List multipartFileNames) { + return multipartFileNames.stream().map(MemoryImage::new).toList(); } private List extractImageData(List multipartFiles) { diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/notification/NotificationReader.java b/core/core-api/src/main/java/cmc/mellyserver/domain/notification/NotificationReader.java index 514912bc..01194ebc 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/notification/NotificationReader.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/notification/NotificationReader.java @@ -8,7 +8,7 @@ import cmc.mellyserver.controller.notification.dto.response.NotificationResponse; import cmc.mellyserver.dbcore.notification.Notification; import cmc.mellyserver.dbcore.notification.NotificationRepository; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -20,7 +20,7 @@ public class NotificationReader { public Notification findById(Long notificationId) { return notificationRepository.findById(notificationId) - .orElseThrow(() -> new BusinessException(ErrorCode.NO_SUCH_NOTIFICATION)); + .orElseThrow(() -> new CommonException(ErrorCode.NO_SUCH_NOTIFICATION)); } public List getNotificationList(Long userId) { diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/place/PlaceReader.java b/core/core-api/src/main/java/cmc/mellyserver/domain/place/PlaceReader.java index f9bacc67..e9a970e0 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/place/PlaceReader.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/place/PlaceReader.java @@ -12,7 +12,7 @@ import cmc.mellyserver.domain.memory.query.dto.FindPlaceByMemoryTitleResponseDto; import cmc.mellyserver.domain.place.query.PlaceQueryRepository; import cmc.mellyserver.domain.scrap.dto.MarkedPlaceResponseDto; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -26,13 +26,13 @@ public class PlaceReader { public Place read(Long placeId) { return placeRepository.findById(placeId).orElseThrow(() -> { - throw new BusinessException(ErrorCode.NO_SUCH_PLACE); + throw new CommonException(ErrorCode.NO_SUCH_PLACE); }); } public Place read(Position position) { return placeRepository.findByPosition(position) - .orElseThrow(() -> new BusinessException(ErrorCode.NO_SUCH_PLACE)); + .orElseThrow(() -> new CommonException(ErrorCode.NO_SUCH_PLACE)); } public List placeUserMemoryExist(Long userId, GroupType groupType) { diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/scrap/PlaceScrapService.java b/core/core-api/src/main/java/cmc/mellyserver/domain/scrap/PlaceScrapService.java index 3d71f19e..b09db044 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/scrap/PlaceScrapService.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/scrap/PlaceScrapService.java @@ -33,40 +33,37 @@ public class PlaceScrapService { private final PlaceReader placeReader; - private final PlaceScrapReader placeScrapReader; + private final PlaceScrapReader scrapReader; - private final PlaceScrapWriter placeScrapWriter; + private final PlaceScrapWriter scrapWriter; - private final PlaceScrapValidator placeScrapValidator; + private final PlaceScrapValidator scrapValidator; public ScrapedPlaceListResponse findScrapedPlace(Long lastId, Pageable pageable, Long userId, ScrapType scrapType) { - Slice places = placeScrapReader.getUserScrapedPlaces(lastId, pageable, userId, - scrapType); + Slice places = scrapReader.getUserScrapedPlaces(lastId, pageable, userId, scrapType); return ScrapedPlaceListResponse.of(places.getContent(), places.hasNext()); } @Cacheable(cacheNames = CacheNames.SCRAP, key = "#userId") public List countByPlaceScrapType(Long userId) { - return placeScrapReader.getScrapedPlaceGrouping(userId); + return scrapReader.getScrapedPlaceGrouping(userId); } @CheckPlaceExist @CacheEvict(cacheNames = CacheNames.SCRAP, key = "#userId") @Transactional public void createScrap(Long userId, CreatePlaceScrapRequestDto createPlaceScrapRequestDto) { - Place place = placeReader.read(createPlaceScrapRequestDto.getPosition()); User user = userReader.findById(userId); - placeScrapValidator.validateDuplicatedScrap(user.getId(), place.getId()); - placeScrapWriter.save(PlaceScrap.createScrap(user, place, createPlaceScrapRequestDto.getScrapType())); + scrapValidator.validateDuplicatedScrap(user.getId(), place.getId()); + scrapWriter.save(PlaceScrap.createScrap(user, place, createPlaceScrapRequestDto.getScrapType())); } @CacheEvict(cacheNames = CacheNames.SCRAP, key = "#userId") @Transactional public void removeScrap(Long userId, Position position) { - Place place = placeReader.read(position); - placeScrapValidator.validateExistedScrap(userId, place.getId()); - placeScrapWriter.deleteByUserIdAndPlacePosition(userId, position); + scrapValidator.validateExistedScrap(userId, place.getId()); + scrapWriter.deleteByUserIdAndPlacePosition(userId, position); } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/scrap/PlaceScrapValidator.java b/core/core-api/src/main/java/cmc/mellyserver/domain/scrap/PlaceScrapValidator.java index 9b8313ef..ed696bcb 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/scrap/PlaceScrapValidator.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/scrap/PlaceScrapValidator.java @@ -3,7 +3,7 @@ import org.springframework.stereotype.Component; import cmc.mellyserver.dbcore.scrap.PlaceScrapRepository; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -13,18 +13,19 @@ public class PlaceScrapValidator { private final PlaceScrapRepository placeScrapRepository; - public void validateDuplicatedScrap(final Long userId, final Long placeId) { - boolean isDuplicated = placeScrapRepository.existsByUserIdAndPlaceId(userId, placeId); - if (isDuplicated) { - throw new BusinessException(ErrorCode.DUPLICATE_SCRAP); + public void validateDuplicatedScrap(Long userId, Long placeId) { + if (checkDuplicatedScrap(userId, placeId)) { + throw new CommonException(ErrorCode.DUPLICATE_SCRAP); } } - public void validateExistedScrap(final Long userId, final Long placeId) { - - boolean isDuplicated = placeScrapRepository.existsByUserIdAndPlaceId(userId, placeId); - if (!isDuplicated) { - throw new BusinessException(ErrorCode.NOT_EXIST_SCRAP); + public void validateExistedScrap(Long userId, Long placeId) { + if (!checkDuplicatedScrap(userId, placeId)) { + throw new CommonException(ErrorCode.NOT_EXIST_SCRAP); } } + + private boolean checkDuplicatedScrap(Long userId, Long placeId) { + return placeScrapRepository.existsByUserIdAndPlaceId(userId, placeId); + } } diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/user/ProfileImageUploader.java b/core/core-api/src/main/java/cmc/mellyserver/domain/user/ProfileImageUploader.java index 619c0f50..ccf9188a 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/user/ProfileImageUploader.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/user/ProfileImageUploader.java @@ -7,7 +7,7 @@ import org.springframework.web.multipart.MultipartFile; import cmc.mellyserver.FileDto; -import cmc.mellyserver.FileService; +import cmc.mellyserver.FileUploader; import cmc.mellyserver.dbcore.user.User; import lombok.RequiredArgsConstructor; @@ -15,7 +15,7 @@ @RequiredArgsConstructor public class ProfileImageUploader { - private final FileService fileService; + private final FileUploader fileService; public void update(User user, MultipartFile profileImage, boolean isDeleted) throws IOException { diff --git a/core/core-api/src/main/java/cmc/mellyserver/domain/user/UserReader.java b/core/core-api/src/main/java/cmc/mellyserver/domain/user/UserReader.java index 10370814..cb12a195 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/domain/user/UserReader.java +++ b/core/core-api/src/main/java/cmc/mellyserver/domain/user/UserReader.java @@ -1,13 +1,12 @@ package cmc.mellyserver.domain.user; import java.util.List; -import java.util.Optional; import org.springframework.stereotype.Component; import cmc.mellyserver.dbcore.user.User; import cmc.mellyserver.dbcore.user.UserRepository; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import lombok.RequiredArgsConstructor; @@ -19,7 +18,7 @@ public class UserReader { public User findById(Long id) { - return userRepository.findById(id).orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); + return userRepository.findById(id).orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); } public List findByIds(List userIds) { @@ -34,7 +33,7 @@ public User findBySocialId(String socialId) { return userRepository.findBySocialId(socialId); } - public Optional findByEmail(String email) { + public User findByEmail(String email) { return userRepository.findByEmail(email); } diff --git a/core/core-api/src/main/java/cmc/mellyserver/support/exception/BusinessException.java b/core/core-api/src/main/java/cmc/mellyserver/support/exception/CommonException.java similarity index 68% rename from core/core-api/src/main/java/cmc/mellyserver/support/exception/BusinessException.java rename to core/core-api/src/main/java/cmc/mellyserver/support/exception/CommonException.java index 379dd9d9..6eefe1a2 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/support/exception/BusinessException.java +++ b/core/core-api/src/main/java/cmc/mellyserver/support/exception/CommonException.java @@ -1,10 +1,10 @@ package cmc.mellyserver.support.exception; -public class BusinessException extends RuntimeException { +public class CommonException extends RuntimeException { private final ErrorCode errorCode; - public BusinessException(ErrorCode errorCode) { + public CommonException(ErrorCode errorCode) { super(errorCode.getMessage()); this.errorCode = errorCode; } diff --git a/core/core-api/src/main/java/cmc/mellyserver/support/exception/ErrorCode.java b/core/core-api/src/main/java/cmc/mellyserver/support/exception/ErrorCode.java index 3bbc9f86..8aa86cf5 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/support/exception/ErrorCode.java +++ b/core/core-api/src/main/java/cmc/mellyserver/support/exception/ErrorCode.java @@ -41,17 +41,12 @@ public enum ErrorCode { // 서버로 요청한 리소스가 존재하지 않음 NOT_FOUND_ERROR(NOT_FOUND.value(), "COMMON-011", "Not Found Exception"), - // NULL Point Exception 발생 - NULL_POINT_ERROR(NOT_FOUND.value(), "COMMON-012", "Null Point Exception"), - // @RequestBody 및 @RequestParam, @PathVariable 값이 유효하지 않음 NOT_VALID_ERROR(NOT_FOUND.value(), "COMMON-013", "handle Validation Exception"), // @RequestBody 및 @RequestParam, @PathVariable 값이 유효하지 않음 NOT_VALID_HEADER_ERROR(NOT_FOUND.value(), "COMMON-014", "Header에 데이터가 존재하지 않는 경우 "), - // 분산락 획득에 실패한 경우 - DISTRIBUTED_LOCK_ACQUIRED_FAIL(INTERNAL_SERVER_ERROR.value(), "COMMON-015", "분산락 획득에 실패했습니다"), /* * Business Error */ @@ -110,5 +105,4 @@ public enum ErrorCode { this.code = code; this.message = message; } - } diff --git a/core/core-api/src/main/java/cmc/mellyserver/support/health/HealthController.java b/core/core-api/src/main/java/cmc/mellyserver/support/health/HealthController.java new file mode 100644 index 00000000..d240f0c8 --- /dev/null +++ b/core/core-api/src/main/java/cmc/mellyserver/support/health/HealthController.java @@ -0,0 +1,13 @@ +package cmc.mellyserver.support.health; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HealthController { + + @GetMapping("/health") + public String healthCheck() { + return "ON"; + } +} diff --git a/core/core-api/src/main/java/cmc/mellyserver/support/response/ApiResponse.java b/core/core-api/src/main/java/cmc/mellyserver/support/response/ApiResponse.java index 23cbf8aa..db3c4b1c 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/support/response/ApiResponse.java +++ b/core/core-api/src/main/java/cmc/mellyserver/support/response/ApiResponse.java @@ -27,4 +27,4 @@ public static ResponseEntity> success(final SuccessCode succe .body(new ApiResponse<>(successCode.getStatus(), successCode.getMessage(), null)); } -} +} \ No newline at end of file diff --git a/core/core-api/src/main/java/cmc/mellyserver/support/response/ErrorResponse.java b/core/core-api/src/main/java/cmc/mellyserver/support/response/ErrorResponse.java index 38961fee..bd6e83c8 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/support/response/ErrorResponse.java +++ b/core/core-api/src/main/java/cmc/mellyserver/support/response/ErrorResponse.java @@ -94,4 +94,4 @@ private static List of(final BindingResult bindingResult) { } -} +} \ No newline at end of file diff --git a/core/core-api/src/main/java/cmc/mellyserver/support/response/SuccessCode.java b/core/core-api/src/main/java/cmc/mellyserver/support/response/SuccessCode.java index 3037a725..739f08ac 100644 --- a/core/core-api/src/main/java/cmc/mellyserver/support/response/SuccessCode.java +++ b/core/core-api/src/main/java/cmc/mellyserver/support/response/SuccessCode.java @@ -5,8 +5,8 @@ @Getter public enum SuccessCode { - SELECT_SUCCESS(200, "SELECT SUCCESS"), INSERT_SUCCESS(201, "INSERT SUCCESS"), DELETE_SUCCESS(200, "DELETE SUCCESS"), - UPDATE_SUCCESS(200, "UPDATE SUCCESS"); + SELECT_SUCCESS(200, "SELECT SUCCESS"), INSERT_SUCCESS(201, "INSERT SUCCESS"), DELETE_SUCCESS(204, "DELETE SUCCESS"), + UPDATE_SUCCESS(204, "UPDATE SUCCESS"); private final int status; @@ -17,4 +17,4 @@ public enum SuccessCode { this.message = message; } -} \ No newline at end of file +} diff --git a/core/core-api/src/test/java/cmc/mellyserver/common/mock/MockFileService.java b/core/core-api/src/test/java/cmc/mellyserver/common/mock/MockFileService.java index 4c291657..0fe3f3e8 100644 --- a/core/core-api/src/test/java/cmc/mellyserver/common/mock/MockFileService.java +++ b/core/core-api/src/test/java/cmc/mellyserver/common/mock/MockFileService.java @@ -6,13 +6,13 @@ import org.springframework.stereotype.Component; import cmc.mellyserver.FileDto; -import cmc.mellyserver.FileService; +import cmc.mellyserver.FileUploader; import lombok.extern.slf4j.Slf4j; @Slf4j @Component @Profile("test") -public class MockFileService implements FileService { +public class MockFileService implements FileUploader { @Override public List saveFiles(Long userId, List multipartFiles) { diff --git a/core/core-api/src/test/java/cmc/mellyserver/domain/group/integration/UserGroupServiceTest.java b/core/core-api/src/test/java/cmc/mellyserver/domain/group/integration/UserGroupServiceTest.java index 2293d2f1..348fd3c7 100644 --- a/core/core-api/src/test/java/cmc/mellyserver/domain/group/integration/UserGroupServiceTest.java +++ b/core/core-api/src/test/java/cmc/mellyserver/domain/group/integration/UserGroupServiceTest.java @@ -23,7 +23,7 @@ import cmc.mellyserver.domain.group.dto.response.UserJoinedGroupsResponse; import cmc.mellyserver.domain.group.query.dto.GroupResponseDto; import cmc.mellyserver.support.IntegrationTestSupport; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import fixtures.GroupFixtures; @@ -163,7 +163,7 @@ public class UserGroupServiceTest extends IntegrationTestSupport { // when Assertions.assertThatThrownBy(() -> groupService.removeGroup(머식.getId(), 친구들.getId())) - .isInstanceOf(BusinessException.class).hasMessage(ErrorCode.NO_AUTHORITY_TO_REMOVE.getMessage()); + .isInstanceOf(CommonException.class).hasMessage(ErrorCode.NO_AUTHORITY_TO_REMOVE.getMessage()); } @@ -202,7 +202,7 @@ public class UserGroupServiceTest extends IntegrationTestSupport { // // Assertions.assertThatThrownBy(() -> { // groupService.joinGroup(마지막_회원.getId(), 친구들.getId()); - // }).isInstanceOf(BusinessException.class).hasMessage(ErrorCode.PARTICIPATE_GROUP_NOT_POSSIBLE.getMessage()); + // }).isInstanceOf(CommonException.class).hasMessage(ErrorCode.PARTICIPATE_GROUP_NOT_POSSIBLE.getMessage()); // } @DisplayName("그룹을_탈퇴한다") diff --git a/core/core-api/src/test/java/cmc/mellyserver/domain/memory/integration/MemoryServiceTest.java b/core/core-api/src/test/java/cmc/mellyserver/domain/memory/integration/MemoryServiceTest.java index 4f1fc03d..2aa49d83 100644 --- a/core/core-api/src/test/java/cmc/mellyserver/domain/memory/integration/MemoryServiceTest.java +++ b/core/core-api/src/test/java/cmc/mellyserver/domain/memory/integration/MemoryServiceTest.java @@ -20,7 +20,7 @@ import cmc.mellyserver.domain.memory.MemoryService; import cmc.mellyserver.domain.memory.dto.request.CreateMemoryRequestDto; import cmc.mellyserver.support.IntegrationTestSupport; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import fixtures.MemoryFixtures; @@ -87,7 +87,7 @@ void memory_not_exist_exception() { // when & then assertThatThrownBy(() -> memoryService.removeMemory(-1L)) - .isInstanceOf(BusinessException.class) + .isInstanceOf(CommonException.class) .hasMessage(ErrorCode.NO_SUCH_MEMORY.getMessage()); } } diff --git a/core/core-api/src/test/java/cmc/mellyserver/domain/notification/integration/NotificationServiceTest.java b/core/core-api/src/test/java/cmc/mellyserver/domain/notification/integration/NotificationServiceTest.java index 736f0552..2d96394e 100644 --- a/core/core-api/src/test/java/cmc/mellyserver/domain/notification/integration/NotificationServiceTest.java +++ b/core/core-api/src/test/java/cmc/mellyserver/domain/notification/integration/NotificationServiceTest.java @@ -18,7 +18,7 @@ import cmc.mellyserver.domain.notification.NotificationService; import cmc.mellyserver.domain.notification.dto.response.NotificationOnOffResponseDto; import cmc.mellyserver.support.IntegrationTestSupport; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import fixtures.MemoryFixtures; @@ -79,7 +79,7 @@ public class NotificationServiceTest extends IntegrationTestSupport { assertThatThrownBy(() -> { notificationService.createNotification("메세지 본문", NotificationType.COMMENT_ENROLL, 모카.getId(), -1L); }) - .isInstanceOf(BusinessException.class) + .isInstanceOf(CommonException.class) .hasMessage(ErrorCode.NO_SUCH_MEMORY.getMessage()); } diff --git a/core/core-api/src/test/java/cmc/mellyserver/domain/place/integration/PlaceServiceTest.java b/core/core-api/src/test/java/cmc/mellyserver/domain/place/integration/PlaceServiceTest.java index d31a8865..caa980f8 100644 --- a/core/core-api/src/test/java/cmc/mellyserver/domain/place/integration/PlaceServiceTest.java +++ b/core/core-api/src/test/java/cmc/mellyserver/domain/place/integration/PlaceServiceTest.java @@ -27,7 +27,7 @@ import cmc.mellyserver.domain.scrap.dto.MarkedPlaceResponseDto; import cmc.mellyserver.domain.scrap.dto.PlaceResponseDto; import cmc.mellyserver.support.IntegrationTestSupport; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import fixtures.MemoryFixtures; @@ -133,7 +133,7 @@ class 장소_ID로_조회했을때 { // when & then assertThatThrownBy(() -> placeService.findByPlaceId(모카.getId(), -1L) - ).isInstanceOf(BusinessException.class).hasMessage(ErrorCode.NO_SUCH_PLACE.getMessage()); + ).isInstanceOf(CommonException.class).hasMessage(ErrorCode.NO_SUCH_PLACE.getMessage()); } } @@ -185,7 +185,7 @@ class 장소_좌표로_조회했을때 { // when & then assertThatThrownBy(() -> placeService.findByPosition(모카.getId(), new Position(1.000, 1.000)) - ).isInstanceOf(BusinessException.class).hasMessage(ErrorCode.NO_SUCH_PLACE.getMessage()); + ).isInstanceOf(CommonException.class).hasMessage(ErrorCode.NO_SUCH_PLACE.getMessage()); } } diff --git a/core/core-api/src/test/java/cmc/mellyserver/domain/scrap/integration/PlaceScrapServiceTest.java b/core/core-api/src/test/java/cmc/mellyserver/domain/scrap/integration/PlaceScrapServiceTest.java index aba60fe4..cbc54df1 100644 --- a/core/core-api/src/test/java/cmc/mellyserver/domain/scrap/integration/PlaceScrapServiceTest.java +++ b/core/core-api/src/test/java/cmc/mellyserver/domain/scrap/integration/PlaceScrapServiceTest.java @@ -23,7 +23,7 @@ import cmc.mellyserver.domain.scrap.dto.request.CreatePlaceScrapRequestDto; import cmc.mellyserver.domain.scrap.dto.response.ScrapedPlaceListResponse; import cmc.mellyserver.support.IntegrationTestSupport; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import fixtures.PlaceFixtures; import fixtures.UserFixtures; @@ -84,7 +84,7 @@ class 스크랩을_추가할때 { // then assertThatThrownBy(() -> placeScrapService.createScrap(모카.getId(), createPlaceScrapRequestDto)) - .isInstanceOf(BusinessException.class) + .isInstanceOf(CommonException.class) .hasMessage(ErrorCode.DUPLICATE_SCRAP.getMessage()); } @@ -144,7 +144,7 @@ class 스크랩을_삭제하려고_할때 { // Then assertThatThrownBy(() -> placeScrapService.removeScrap(모카.getId(), 스타벅스.getPosition())) - .isInstanceOf(BusinessException.class) + .isInstanceOf(CommonException.class) .hasMessage(ErrorCode.NOT_EXIST_SCRAP.getMessage()); } } diff --git a/core/core-api/src/test/java/cmc/mellyserver/domain/scrap/integration/PlaceScrapValidatorTest.java b/core/core-api/src/test/java/cmc/mellyserver/domain/scrap/integration/PlaceScrapValidatorTest.java index 7132cfc7..143648a6 100644 --- a/core/core-api/src/test/java/cmc/mellyserver/domain/scrap/integration/PlaceScrapValidatorTest.java +++ b/core/core-api/src/test/java/cmc/mellyserver/domain/scrap/integration/PlaceScrapValidatorTest.java @@ -15,7 +15,7 @@ import cmc.mellyserver.dbcore.user.UserRepository; import cmc.mellyserver.domain.scrap.PlaceScrapValidator; import cmc.mellyserver.support.IntegrationTestSupport; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; import fixtures.PlaceFixtures; import fixtures.UserFixtures; @@ -47,7 +47,7 @@ public class PlaceScrapValidatorTest extends IntegrationTestSupport { // then assertThatThrownBy(() -> placeScrapValidator.validateDuplicatedScrap(모카.getId(), 스타벅스.getId())) - .isInstanceOf(BusinessException.class) + .isInstanceOf(CommonException.class) .hasMessage(ErrorCode.DUPLICATE_SCRAP.getMessage()); } @@ -61,7 +61,7 @@ public class PlaceScrapValidatorTest extends IntegrationTestSupport { // when & then assertThatThrownBy(() -> placeScrapValidator.validateExistedScrap(모카.getId(), 스타벅스.getId())) - .isInstanceOf(BusinessException.class) + .isInstanceOf(CommonException.class) .hasMessage(ErrorCode.NOT_EXIST_SCRAP.getMessage()); } } diff --git a/core/core-api/src/test/java/cmc/mellyserver/domain/user/repository/UserRepositoryTest.java b/core/core-api/src/test/java/cmc/mellyserver/domain/user/repository/UserRepositoryTest.java index 015e510f..079f0f7e 100644 --- a/core/core-api/src/test/java/cmc/mellyserver/domain/user/repository/UserRepositoryTest.java +++ b/core/core-api/src/test/java/cmc/mellyserver/domain/user/repository/UserRepositoryTest.java @@ -9,7 +9,7 @@ import cmc.mellyserver.dbcore.user.UserRepository; import cmc.mellyserver.support.RepositoryTestSupport; -import cmc.mellyserver.support.exception.BusinessException; +import cmc.mellyserver.support.exception.CommonException; import cmc.mellyserver.support.exception.ErrorCode; public class UserRepositoryTest extends RepositoryTestSupport { @@ -37,7 +37,7 @@ public class UserRepositoryTest extends RepositoryTestSupport { // when & then assertThatThrownBy(() -> { - userRepository.findById(0L).orElseThrow(() -> new BusinessException(ErrorCode.USER_NOT_FOUND)); - }).isInstanceOf(BusinessException.class).hasMessage(ErrorCode.USER_NOT_FOUND.getMessage()); + userRepository.findById(0L).orElseThrow(() -> new CommonException(ErrorCode.USER_NOT_FOUND)); + }).isInstanceOf(CommonException.class).hasMessage(ErrorCode.USER_NOT_FOUND.getMessage()); } } diff --git a/infra/file/src/main/java/cmc/mellyserver/FileService.java b/infra/file/src/main/java/cmc/mellyserver/FileUploader.java similarity index 90% rename from infra/file/src/main/java/cmc/mellyserver/FileService.java rename to infra/file/src/main/java/cmc/mellyserver/FileUploader.java index d6715df9..52c3e2e3 100644 --- a/infra/file/src/main/java/cmc/mellyserver/FileService.java +++ b/infra/file/src/main/java/cmc/mellyserver/FileUploader.java @@ -3,7 +3,7 @@ import java.io.IOException; import java.util.List; -public interface FileService { +public interface FileUploader { List saveFiles(Long userId, List multipartFiles); diff --git a/infra/file/src/main/java/cmc/mellyserver/aws/S3StorageService.java b/infra/file/src/main/java/cmc/mellyserver/aws/S3StorageService.java index 8dca95b1..2794cb11 100644 --- a/infra/file/src/main/java/cmc/mellyserver/aws/S3StorageService.java +++ b/infra/file/src/main/java/cmc/mellyserver/aws/S3StorageService.java @@ -17,13 +17,13 @@ import com.amazonaws.services.s3.model.PutObjectRequest; import cmc.mellyserver.FileDto; -import cmc.mellyserver.FileService; +import cmc.mellyserver.FileUploader; import lombok.RequiredArgsConstructor; @Component @RequiredArgsConstructor @Profile(value = {"local", "prod"}) -class S3StorageService implements FileService { +class S3StorageService implements FileUploader { private final AmazonS3 amazonS3Client; @Value("${cloud.aws.s3.bucket}") diff --git a/settings.gradle b/settings.gradle index f231ad6f..cb87c2d8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,7 +9,6 @@ pluginManagement { rootProject.name = "mellyServer" - include ':storage:db-core' include ':storage:db-redis' include ':core:core-api' diff --git a/storage/db-core/src/main/java/cmc/mellyserver/dbcore/comment/comment/Comment.java b/storage/db-core/src/main/java/cmc/mellyserver/dbcore/comment/comment/Comment.java index b3d3eeb9..32c156f1 100644 --- a/storage/db-core/src/main/java/cmc/mellyserver/dbcore/comment/comment/Comment.java +++ b/storage/db-core/src/main/java/cmc/mellyserver/dbcore/comment/comment/Comment.java @@ -58,7 +58,7 @@ public class Comment extends JpaBaseEntity { @OneToMany(mappedBy = "root", orphanRemoval = true) private List children = new ArrayList<>(); - + @Column(name = "like_count") private int likeCount; @@ -105,6 +105,9 @@ public void addLike() { } public void unLike() { + if (likeCount == 0) { + throw new IllegalArgumentException("좋아요를 취소할 수 없습니다"); + } this.likeCount -= 1; } diff --git a/storage/db-core/src/main/java/cmc/mellyserver/dbcore/memory/memory/Memory.java b/storage/db-core/src/main/java/cmc/mellyserver/dbcore/memory/memory/Memory.java index 5d2034d5..5b5d8f88 100644 --- a/storage/db-core/src/main/java/cmc/mellyserver/dbcore/memory/memory/Memory.java +++ b/storage/db-core/src/main/java/cmc/mellyserver/dbcore/memory/memory/Memory.java @@ -112,8 +112,8 @@ public void update(String title, String content, Long groupId, OpenType openType this.stars = stars; } - public void setMemoryImages(List memoryImages) { - this.memoryImages = memoryImages; + public void addImages(List images) { + this.memoryImages = images; memoryImages.forEach(image -> image.addMemory(this)); } diff --git a/storage/db-core/src/main/java/cmc/mellyserver/dbcore/user/User.java b/storage/db-core/src/main/java/cmc/mellyserver/dbcore/user/User.java index 4963fe17..d1c89999 100644 --- a/storage/db-core/src/main/java/cmc/mellyserver/dbcore/user/User.java +++ b/storage/db-core/src/main/java/cmc/mellyserver/dbcore/user/User.java @@ -135,10 +135,6 @@ public void changeAppPushStatus(boolean enableAppPush) { this.enableAppPush = enableAppPush; } - public void changeCommentLikePushStatus(boolean enableCommentLikePush) { - this.enableCommentLikePush = enableCommentLikePush; - } - public void changeCommentPushStatus(boolean enableCommentPush) { this.enableCommentPush = enableCommentPush; } diff --git a/storage/db-core/src/main/java/cmc/mellyserver/dbcore/user/UserRepository.java b/storage/db-core/src/main/java/cmc/mellyserver/dbcore/user/UserRepository.java index 4676b0db..cf7621ab 100644 --- a/storage/db-core/src/main/java/cmc/mellyserver/dbcore/user/UserRepository.java +++ b/storage/db-core/src/main/java/cmc/mellyserver/dbcore/user/UserRepository.java @@ -1,7 +1,6 @@ package cmc.mellyserver.dbcore.user; import java.util.List; -import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; @@ -9,7 +8,7 @@ public interface UserRepository extends JpaRepository { User findBySocialId(String socialId); - Optional findByEmail(String email); + User findByEmail(String email); boolean existsByEmail(String email);