From 9bc449e88995182ee6bf018d8b95efb8a76102f3 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 2 Oct 2024 16:59:29 +0900 Subject: [PATCH 01/38] =?UTF-8?q?refactor=20:=20=EC=97=91=EC=84=B8?= =?UTF-8?q?=EC=8A=A4=20=ED=86=A0=ED=81=B0=20=EB=B0=9C=EA=B8=89=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=EC=9D=98=20=EB=B9=84=EC=A6=88?= =?UTF-8?q?=EB=8B=88=EC=8A=A4=EB=A1=9C=EC=A7=81=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=EB=8B=A8=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/space/space_spring/domain/.DS_Store | Bin 6148 -> 6148 bytes .../auth/service/AuthService.java | 2 +- .../jwt/controller/JwtController.java | 12 +---- .../jwt/model}/JwtLoginProvider.java | 3 +- .../jwt/model/TokenResolver.java | 42 ++++++++++++++++ .../jwt/repository/JwtRepository.java | 10 +++- .../authorization/jwt/service/JwtService.java | 47 +++++++----------- .../space_spring/entity/TokenStorage.java | 2 +- .../jwtLogin/JwtLoginAuthInterceptor.java | 2 +- .../jwtSocket/JwtChannelInterceptor.java | 2 +- 10 files changed, 75 insertions(+), 47 deletions(-) rename src/main/java/space/space_spring/{jwt => domain/authorization/jwt/model}/JwtLoginProvider.java (97%) create mode 100644 src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java diff --git a/src/main/java/space/space_spring/domain/.DS_Store b/src/main/java/space/space_spring/domain/.DS_Store index cf1810f3a12ab491bfe87f5bb0b434060947e4bc..33136f01813a20ce3759383589b4a92cf60b3b8c 100644 GIT binary patch delta 278 zcmZoMXfc=|#>B)qu~2NHo+2aD!~pA!7aABR8;Gz>?3b=jDlaZb%E?b+U|`shRFIQd zTw-8wjgg6&g_Vt+gPnt$BQ`iAzdX1kv81%vDX}OT#0$yK&q;!@6O+O+Q_JH8M4a>U zN)j{kQj5SEGE-84N@Bt@^HTE5o$^cbQi{QPgCPfYER$-0@HgP#NF&y5Ga cGf(Ch(G>y7f^;-MXt3tZAtD=?CpNGE096b~TmS$7 delta 68 zcmZoMXfc=|#>CJzu~2NHo+2aT!~knX#?9}TBw05bFefo>X6NAN07`FGWd6=PnO{Vg WlaYae;Q$abOt#^X-W(&cgc$%{7Z6zh diff --git a/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java b/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java index 25484a2d..2c9c0a00 100644 --- a/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java +++ b/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java @@ -12,7 +12,7 @@ import space.space_spring.entity.TokenStorage; import space.space_spring.entity.User; import space.space_spring.exception.CustomException; -import space.space_spring.jwt.JwtLoginProvider; +import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; import space.space_spring.util.user.UserUtils; import static space.space_spring.entity.enumStatus.UserSignupType.LOCAL; diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/controller/JwtController.java b/src/main/java/space/space_spring/domain/authorization/jwt/controller/JwtController.java index b2cd2d93..85fff086 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/controller/JwtController.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/controller/JwtController.java @@ -26,19 +26,9 @@ public class JwtController { */ @PostMapping("/new-token") public BaseResponse updateAccessToken(HttpServletRequest request, HttpServletResponse response) throws IOException { - // access token, refresh token 파싱 - TokenPairDTO tokenPairDTO = jwtService.resolveTokenPair(request); - // access token 로부터 user find - User userByAccessToken = jwtService.getUserByAccessToken(tokenPairDTO.getAccessToken()); + TokenPairDTO newTokenPairDTO = jwtService.updateAccessToken(request); - // refresh token 유효성 검사 - jwtService.validateRefreshToken(userByAccessToken, tokenPairDTO.getRefreshToken()); - - // access token, refresh token 새로 발급 - TokenPairDTO newTokenPairDTO = jwtService.updateTokenPair(userByAccessToken); - - // response header에 새로 발급한 token pair set response.setHeader("Authorization-refresh", "Bearer " + newTokenPairDTO.getRefreshToken()); response.setHeader("Authorization", "Bearer " + newTokenPairDTO.getAccessToken()); diff --git a/src/main/java/space/space_spring/jwt/JwtLoginProvider.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java similarity index 97% rename from src/main/java/space/space_spring/jwt/JwtLoginProvider.java rename to src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java index 998b42c5..86313905 100644 --- a/src/main/java/space/space_spring/jwt/JwtLoginProvider.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java @@ -1,10 +1,9 @@ -package space.space_spring.jwt; +package space.space_spring.domain.authorization.jwt.model; import io.jsonwebtoken.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import space.space_spring.domain.authorization.jwt.model.TokenType; import space.space_spring.entity.User; import space.space_spring.exception.CustomException; import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java new file mode 100644 index 00000000..b5e04609 --- /dev/null +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java @@ -0,0 +1,42 @@ +package space.space_spring.domain.authorization.jwt.model; + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.HttpHeaders; +import org.springframework.stereotype.Component; +import space.space_spring.exception.jwt.bad_request.JwtNoTokenException; +import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; + +import static space.space_spring.response.status.BaseExceptionResponseStatus.TOKEN_NOT_FOUND; +import static space.space_spring.response.status.BaseExceptionResponseStatus.UNSUPPORTED_TOKEN_TYPE; + +@Component +public class TokenResolver { + + private static final String JWT_TOKEN_PREFIX = "Bearer "; + + public static TokenPairDTO resolveTokenPair(HttpServletRequest request) { + // TODO 1. access token 파싱 + String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION); + validateToken(accessToken); + + // TODO 2. refresh token 파싱 + String refreshToken = request.getHeader("Authorization-refresh"); + validateToken(refreshToken); + + // TODO 3. return + return TokenPairDTO.builder() + .accessToken(accessToken.substring(JWT_TOKEN_PREFIX.length())) + .refreshToken(refreshToken.substring(JWT_TOKEN_PREFIX.length())) + .build(); + } + + private static void validateToken(String token) { + if (token == null) { + throw new JwtNoTokenException(TOKEN_NOT_FOUND); + } + if (!token.startsWith(JWT_TOKEN_PREFIX)) { + throw new JwtUnsupportedTokenException(UNSUPPORTED_TOKEN_TYPE); + } + } + +} diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java b/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java index dad962d3..57a7d26a 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java @@ -1,7 +1,11 @@ package space.space_spring.domain.authorization.jwt.repository; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; +import org.springframework.transaction.annotation.Transactional; import space.space_spring.entity.TokenStorage; import space.space_spring.entity.User; @@ -11,5 +15,9 @@ public interface JwtRepository extends JpaRepository { Optional findByUser(User user); - void deleteByUser(User user); + + @Transactional + @Modifying + @Query("DELETE FROM TokenStorage t WHERE t.user = :user") + void deleteByUser(@Param("user") User user); } diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index 1b3c65af..9c5ca408 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -2,9 +2,9 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; -import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import space.space_spring.domain.authorization.jwt.model.TokenResolver; import space.space_spring.domain.authorization.jwt.repository.JwtRepository; import space.space_spring.domain.user.repository.UserRepository; import space.space_spring.domain.authorization.jwt.model.TokenPairDTO; @@ -12,51 +12,39 @@ import space.space_spring.entity.TokenStorage; import space.space_spring.entity.User; import space.space_spring.exception.CustomException; -import space.space_spring.exception.jwt.bad_request.JwtNoTokenException; -import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; import space.space_spring.exception.jwt.unauthorized.JwtUnauthorizedTokenException; -import space.space_spring.jwt.JwtLoginProvider; +import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; import static space.space_spring.response.status.BaseExceptionResponseStatus.*; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class JwtService { private final JwtRepository jwtRepository; private final JwtLoginProvider jwtLoginProvider; private final UserRepository userRepository; - private static final String JWT_TOKEN_PREFIX = "Bearer "; + @Transactional + public TokenPairDTO updateAccessToken(HttpServletRequest request) { + // request에서 기존의 TokenPair를 찾아와서 + TokenPairDTO oldTokenPair = TokenResolver.resolveTokenPair(request); + // 여기서 User 찾고 + User userByAccessToken = getUserByAccessToken(oldTokenPair.getAccessToken()); - public TokenPairDTO resolveTokenPair(HttpServletRequest request) { - // TODO 1. access token 파싱 - String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION); - validateToken(accessToken); + // 이 User로 refresh token의 유효성 검사 진행하고 + validateRefreshToken(userByAccessToken, oldTokenPair.getRefreshToken()); - // TODO 2. refresh token 파싱 - String refreshToken = request.getHeader("Authorization-refresh"); - validateToken(refreshToken); + // access, refresh 새로 발급 + TokenPairDTO tokenPairDTO = updateTokenPair(userByAccessToken); - // TODO 3. return - return TokenPairDTO.builder() - .accessToken(accessToken.substring(JWT_TOKEN_PREFIX.length())) - .refreshToken(refreshToken.substring(JWT_TOKEN_PREFIX.length())) - .build(); + return tokenPairDTO; } - private void validateToken(String token) { - if (token == null) { - throw new JwtNoTokenException(TOKEN_NOT_FOUND); - } - if (!token.startsWith(JWT_TOKEN_PREFIX)) { - throw new JwtUnsupportedTokenException(UNSUPPORTED_TOKEN_TYPE); - } - } - - public User getUserByAccessToken(String accessToken) { + private User getUserByAccessToken(String accessToken) { Long userIdFromToken = jwtLoginProvider.getUserIdFromAccessToken(accessToken); return userRepository.findByUserId(userIdFromToken) @@ -64,7 +52,7 @@ public User getUserByAccessToken(String accessToken) { } @Transactional - public void validateRefreshToken(User user, String refreshToken) { + protected void validateRefreshToken(User user, String refreshToken) { TokenStorage tokenStorage = jwtRepository.findByUser(user) .orElseThrow(() -> { @@ -91,7 +79,7 @@ public void validateRefreshToken(User user, String refreshToken) { } @Transactional - public TokenPairDTO updateTokenPair(User user) { + protected TokenPairDTO updateTokenPair(User user) { // TODO 1. new access token, refresh token 발급 String newAccessToken = jwtLoginProvider.generateToken(user, TokenType.ACCESS); String newRefreshToken = jwtLoginProvider.generateToken(user, TokenType.REFRESH); @@ -127,4 +115,5 @@ public void updateRefreshToken(User user, String refreshToken) { tokenStorage.updateTokenValue(refreshToken); } + } diff --git a/src/main/java/space/space_spring/entity/TokenStorage.java b/src/main/java/space/space_spring/entity/TokenStorage.java index 5519d8e2..84d388b0 100644 --- a/src/main/java/space/space_spring/entity/TokenStorage.java +++ b/src/main/java/space/space_spring/entity/TokenStorage.java @@ -18,7 +18,7 @@ public class TokenStorage { @Column(name = "token_storage_id") private Long tokenStorageId; - @OneToOne + @OneToOne(orphanRemoval = true) // @Column(name = "user_id") private User user; diff --git a/src/main/java/space/space_spring/interceptor/jwtLogin/JwtLoginAuthInterceptor.java b/src/main/java/space/space_spring/interceptor/jwtLogin/JwtLoginAuthInterceptor.java index 03bcfd59..db9fc283 100644 --- a/src/main/java/space/space_spring/interceptor/jwtLogin/JwtLoginAuthInterceptor.java +++ b/src/main/java/space/space_spring/interceptor/jwtLogin/JwtLoginAuthInterceptor.java @@ -10,7 +10,7 @@ import space.space_spring.exception.jwt.bad_request.JwtNoTokenException; import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; -import space.space_spring.jwt.JwtLoginProvider; +import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; import static space.space_spring.response.status.BaseExceptionResponseStatus.*; diff --git a/src/main/java/space/space_spring/interceptor/jwtSocket/JwtChannelInterceptor.java b/src/main/java/space/space_spring/interceptor/jwtSocket/JwtChannelInterceptor.java index 3c137e09..5ae95aea 100644 --- a/src/main/java/space/space_spring/interceptor/jwtSocket/JwtChannelInterceptor.java +++ b/src/main/java/space/space_spring/interceptor/jwtSocket/JwtChannelInterceptor.java @@ -12,7 +12,7 @@ import space.space_spring.exception.jwt.bad_request.JwtNoTokenException; import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; -import space.space_spring.jwt.JwtLoginProvider; +import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; import static space.space_spring.response.status.BaseExceptionResponseStatus.*; From a3fd022d59e2b513b8963603b244cd607eb6348c Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Mon, 7 Oct 2024 14:22:22 +0900 Subject: [PATCH 02/38] =?UTF-8?q?test=20:=20TokenResolver=20=EC=8A=A4?= =?UTF-8?q?=ED=94=84=EB=A7=81=20=EB=B9=88=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwt/model/TokenResolver.java | 4 +- .../authorization/jwt/service/JwtService.java | 3 +- .../jwt/model/JwtLoginProviderTest.java | 7 ++ .../jwt/model/TokenResolverTest.java | 97 +++++++++++++++++++ .../jwt/service/JwtServiceTest.java | 7 ++ 5 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java create mode 100644 src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java create mode 100644 src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java index b5e04609..4fe0b66d 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java @@ -14,7 +14,7 @@ public class TokenResolver { private static final String JWT_TOKEN_PREFIX = "Bearer "; - public static TokenPairDTO resolveTokenPair(HttpServletRequest request) { + public TokenPairDTO resolveTokenPair(HttpServletRequest request) { // TODO 1. access token 파싱 String accessToken = request.getHeader(HttpHeaders.AUTHORIZATION); validateToken(accessToken); @@ -30,7 +30,7 @@ public static TokenPairDTO resolveTokenPair(HttpServletRequest request) { .build(); } - private static void validateToken(String token) { + private void validateToken(String token) { if (token == null) { throw new JwtNoTokenException(TOKEN_NOT_FOUND); } diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index 9c5ca408..ed4651ac 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -26,11 +26,12 @@ public class JwtService { private final JwtRepository jwtRepository; private final JwtLoginProvider jwtLoginProvider; private final UserRepository userRepository; + private final TokenResolver tokenResolver; @Transactional public TokenPairDTO updateAccessToken(HttpServletRequest request) { // request에서 기존의 TokenPair를 찾아와서 - TokenPairDTO oldTokenPair = TokenResolver.resolveTokenPair(request); + TokenPairDTO oldTokenPair = tokenResolver.resolveTokenPair(request); // 여기서 User 찾고 User userByAccessToken = getUserByAccessToken(oldTokenPair.getAccessToken()); diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java new file mode 100644 index 00000000..fb25065e --- /dev/null +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java @@ -0,0 +1,7 @@ +package space.space_spring.domain.authorization.jwt.model; + +import static org.junit.jupiter.api.Assertions.*; + +class JwtLoginProviderTest { + +} \ No newline at end of file diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java new file mode 100644 index 00000000..7c6a3875 --- /dev/null +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java @@ -0,0 +1,97 @@ +package space.space_spring.domain.authorization.jwt.model; + +import jakarta.servlet.http.HttpServletRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import space.space_spring.exception.jwt.bad_request.JwtNoTokenException; +import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.*; + +@ExtendWith(SpringExtension.class) +@TestConfiguration +class TokenResolverTestConfig { // 테스트 전용 설정 클래스 + + @Bean + public TokenResolver tokenResolver() { + return new TokenResolver(); // 직접 TokenResolver 빈 생성 + } +} + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = TokenResolverTestConfig.class) +class TokenResolverTest { + + private static final String JWT_TOKEN_PREFIX = "Bearer "; + + @Autowired + private TokenResolver tokenResolver; + + @Test + @DisplayName("request header로부터 access token, refresh token을 rosolve한다.") + void resolveTokenPair() throws Exception { + //given + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", JWT_TOKEN_PREFIX + "accessToken"); + request.addHeader("Authorization-refresh", JWT_TOKEN_PREFIX + "refreshToken"); + + //when + TokenPairDTO tokenPairDTO = tokenResolver.resolveTokenPair(request); + + //then + assertThat(tokenPairDTO.getAccessToken()).isEqualTo("accessToken"); + assertThat(tokenPairDTO.getRefreshToken()).isEqualTo("refreshToken"); + } + + @Test + @DisplayName("access token값이 null 일 경우 예외를 던진다.") + void validateToken1() throws Exception { + //given + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization-refresh", JWT_TOKEN_PREFIX + "refreshToken"); + + //when //then + assertThatThrownBy(() -> tokenResolver.resolveTokenPair(request)) + .isInstanceOf(JwtNoTokenException.class) + .hasMessage("토큰이 HTTP Header에 없습니다."); + } + + @Test + @DisplayName("refresh token값이 null 일 경우 예외를 던진다.") + void validateToken2() throws Exception { + //given + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", JWT_TOKEN_PREFIX + "accessToken"); + + //when //then + assertThatThrownBy(() -> tokenResolver.resolveTokenPair(request)) + .isInstanceOf(JwtNoTokenException.class) + .hasMessage("토큰이 HTTP Header에 없습니다."); + } + + @Test + @DisplayName("토큰값의 prefix가 잘못된 경우 예외를 던진다.") + void validateToken3() throws Exception { + //given + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", "wrong prefix " + "accessToken"); + request.addHeader("Authorization-refresh", "wrong prefix " + "refreshToken"); + + //when //then + assertThatThrownBy(() -> tokenResolver.resolveTokenPair(request)) + .isInstanceOf(JwtUnsupportedTokenException.class) + .hasMessage("지원되지 않는 토큰 형식입니다."); + } +} \ No newline at end of file diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java new file mode 100644 index 00000000..e5e71196 --- /dev/null +++ b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java @@ -0,0 +1,7 @@ +package space.space_spring.domain.authorization.jwt.service; + +import static org.junit.jupiter.api.Assertions.*; + +class JwtServiceTest { + +} \ No newline at end of file From 8c1b862f825b72540bc1eac4b70c061851d4275f Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Mon, 7 Oct 2024 16:58:46 +0900 Subject: [PATCH 03/38] =?UTF-8?q?refactor=20:=20refreshtoken=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20JwtProvider=20=EB=82=B4?= =?UTF-8?q?=EB=B6=80=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwt/model/JwtLoginProvider.java | 34 +++++++++++++++++ .../jwt/repository/JwtRepository.java | 6 +++ .../authorization/jwt/service/JwtService.java | 37 ++----------------- .../space_spring/entity/TokenStorage.java | 3 -- .../java/space/space_spring/entity/User.java | 2 + .../jwt/model/JwtLoginProviderTest.java | 14 +++++++ .../jwt/model/TokenResolverTest.java | 2 +- 7 files changed, 60 insertions(+), 38 deletions(-) diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java index 86313905..d7c1d224 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java @@ -1,14 +1,19 @@ package space.space_spring.domain.authorization.jwt.model; import io.jsonwebtoken.*; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import space.space_spring.domain.authorization.jwt.repository.JwtRepository; +import space.space_spring.entity.TokenStorage; import space.space_spring.entity.User; import space.space_spring.exception.CustomException; import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; +import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; import space.space_spring.exception.jwt.unauthorized.JwtInvalidTokenException; import space.space_spring.exception.jwt.unauthorized.JwtMalformedTokenException; +import space.space_spring.exception.jwt.unauthorized.JwtUnauthorizedTokenException; import java.util.Date; @@ -16,6 +21,7 @@ @Slf4j @Component +@RequiredArgsConstructor public class JwtLoginProvider { @Value("${secret.jwt.access-secret-key}") private String ACCESS_SECRET_KEY; @@ -29,6 +35,8 @@ public class JwtLoginProvider { @Value("${secret.jwt.refresh-expired-in}") private Long REFRESH_EXPIRED_IN; + private final JwtRepository jwtRepository; + public String generateToken(User user, TokenType tokenType) { // Claims claims = Jwts.claims().setSubject(jwtPayloadDto.getUserId().toString()); @@ -115,4 +123,30 @@ public Long getUserIdFromAccessToken(String token) { throw e; } } + + public void validateRefreshToken(User user, String refreshToken) { + TokenStorage tokenStorage = jwtRepository.findByUser(user) + .orElseThrow(() -> + { + // db에서 row delete 하는 코드 추가 + jwtRepository.deleteByUser(user); + throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); + }); + + // TODO 1. refresh token의 만료시간 체크 + if (isExpiredToken(refreshToken, TokenType.REFRESH)) { + // refresh token이 만료된 경우 -> 예외 발생 -> 유저의 재 로그인 유도 + // db에서 row delete 하는 코드 추가 + jwtRepository.deleteByUser(user); + throw new JwtExpiredTokenException(EXPIRED_REFRESH_TOKEN); + } + + // TODO 2. refresh token이 db에 실제로 존재하는지 체크 + if (!tokenStorage.checkTokenValue(refreshToken)) { + // refresh token이 db에 존재하지 않느 경우 -> 유효하지 않은 refresh token이므로 예외 발생 + // db에서 row delete 하는 코드 추가 + jwtRepository.deleteByUser(user); + throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); + } + } } diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java b/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java index 57a7d26a..443e6356 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java @@ -20,4 +20,10 @@ public interface JwtRepository extends JpaRepository { @Modifying @Query("DELETE FROM TokenStorage t WHERE t.user = :user") void deleteByUser(@Param("user") User user); + + @Transactional + default void deleteAndFlushByUser(User user) { + deleteByUser(user); + flush(); // JPA가 즉시 반영하도록 강제 플러시 + } } diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index ed4651ac..258db50f 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -4,17 +4,14 @@ import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import space.space_spring.domain.authorization.jwt.model.TokenResolver; +import space.space_spring.domain.authorization.jwt.model.*; import space.space_spring.domain.authorization.jwt.repository.JwtRepository; import space.space_spring.domain.user.repository.UserRepository; -import space.space_spring.domain.authorization.jwt.model.TokenPairDTO; -import space.space_spring.domain.authorization.jwt.model.TokenType; import space.space_spring.entity.TokenStorage; import space.space_spring.entity.User; import space.space_spring.exception.CustomException; import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; import space.space_spring.exception.jwt.unauthorized.JwtUnauthorizedTokenException; -import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; import static space.space_spring.response.status.BaseExceptionResponseStatus.*; @@ -37,7 +34,7 @@ public TokenPairDTO updateAccessToken(HttpServletRequest request) { User userByAccessToken = getUserByAccessToken(oldTokenPair.getAccessToken()); // 이 User로 refresh token의 유효성 검사 진행하고 - validateRefreshToken(userByAccessToken, oldTokenPair.getRefreshToken()); + jwtLoginProvider.validateRefreshToken(userByAccessToken, oldTokenPair.getRefreshToken()); // access, refresh 새로 발급 TokenPairDTO tokenPairDTO = updateTokenPair(userByAccessToken); @@ -52,35 +49,7 @@ private User getUserByAccessToken(String accessToken) { .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); } - @Transactional - protected void validateRefreshToken(User user, String refreshToken) { - TokenStorage tokenStorage = jwtRepository.findByUser(user) - .orElseThrow(() -> - { - // db에서 row delete 하는 코드 추가 - jwtRepository.deleteByUser(user); - throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); - }); - - // TODO 1. refresh token의 만료시간 체크 - if (jwtLoginProvider.isExpiredToken(refreshToken, TokenType.REFRESH)) { - // refresh token이 만료된 경우 -> 예외 발생 -> 유저의 재 로그인 유도 - // db에서 row delete 하는 코드 추가 - jwtRepository.deleteByUser(user); - throw new JwtExpiredTokenException(EXPIRED_REFRESH_TOKEN); - } - - // TODO 2. refresh token이 db에 실제로 존재하는지 체크 - if (!tokenStorage.checkTokenValue(refreshToken)) { - // refresh token이 db에 존재하지 않느 경우 -> 유효하지 않은 refresh token이므로 예외 발생 - // db에서 row delete 하는 코드 추가 - jwtRepository.deleteByUser(user); - throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); - } - } - - @Transactional - protected TokenPairDTO updateTokenPair(User user) { + private TokenPairDTO updateTokenPair(User user) { // TODO 1. new access token, refresh token 발급 String newAccessToken = jwtLoginProvider.generateToken(user, TokenType.ACCESS); String newRefreshToken = jwtLoginProvider.generateToken(user, TokenType.REFRESH); diff --git a/src/main/java/space/space_spring/entity/TokenStorage.java b/src/main/java/space/space_spring/entity/TokenStorage.java index 84d388b0..1175aaf5 100644 --- a/src/main/java/space/space_spring/entity/TokenStorage.java +++ b/src/main/java/space/space_spring/entity/TokenStorage.java @@ -9,9 +9,6 @@ @Entity @Table(name = "Token_Storage") @Getter -@Builder -@NoArgsConstructor -@AllArgsConstructor public class TokenStorage { @Id @GeneratedValue diff --git a/src/main/java/space/space_spring/entity/User.java b/src/main/java/space/space_spring/entity/User.java index 9bddd8b2..c25d702c 100644 --- a/src/main/java/space/space_spring/entity/User.java +++ b/src/main/java/space/space_spring/entity/User.java @@ -3,11 +3,13 @@ import jakarta.annotation.Nullable; import jakarta.persistence.*; import lombok.Getter; +import lombok.NoArgsConstructor; import space.space_spring.entity.enumStatus.UserSignupType; @Entity @Table(name = "Users") @Getter +@NoArgsConstructor public class User extends BaseEntity { @Id @GeneratedValue diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java index fb25065e..6f38e281 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java @@ -1,7 +1,21 @@ package space.space_spring.domain.authorization.jwt.model; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.*; class JwtLoginProviderTest { + @Test + @DisplayName("") + void test() throws Exception { + //given + + //when + + //then + } + + } \ No newline at end of file diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java index 7c6a3875..bd224b4c 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java @@ -25,7 +25,7 @@ class TokenResolverTestConfig { // 테스트 전용 설정 클래스 @Bean - public TokenResolver tokenResolver() { + TokenResolver tokenResolver() { return new TokenResolver(); // 직접 TokenResolver 빈 생성 } } From 02103dbb86eb00dd537e9c1a0aa82c0f8b26576e Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Tue, 29 Oct 2024 01:29:10 +0900 Subject: [PATCH 04/38] =?UTF-8?q?refactor=20:=20JwtService=20=EB=8B=A8?= =?UTF-8?q?=EC=9D=98=20private=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EB=93=A4=EC=9D=84=20=EA=B0=9D=EC=B2=B4=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes .../java/space/space_spring/domain/.DS_Store | Bin 6148 -> 6148 bytes .../domain/authorization/.DS_Store | Bin 0 -> 6148 bytes .../jwt/model/JwtLoginProvider.java | 25 ---------- .../authorization/jwt/model/TokenUpdater.java | 28 ++++++++++++ .../jwt/model/TokenValidator.java | 34 ++++++++++++++ .../authorization/jwt/service/JwtService.java | 43 +++++++++++------- .../space_spring/entity/TokenStorage.java | 1 + .../jwt/model/TokenResolverTest.java | 1 + 9 files changed, 90 insertions(+), 42 deletions(-) create mode 100644 .DS_Store create mode 100644 src/main/java/space/space_spring/domain/authorization/.DS_Store create mode 100644 src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java create mode 100644 src/main/java/space/space_spring/domain/authorization/jwt/model/TokenValidator.java diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5c4e2b02f428daec48439f3ec895f1f4d5017d16 GIT binary patch literal 6148 zcmeHK%}T>S5T3CS0;2RNh_EM*g zB+s7Fh*oq<56SbNygYY(Rb7_zbv=hIe}BC^`nY~OOa03q{hOPX8$O*Ol?HTAceF^V z?p__Vo^DN|=4o^sYg%4aw-vX&-FmctA@y9G0cXG&a0Z+KVE}iwNWQ1&voqifI0N4d z$oUX31PjAPF&-V5VhaGwV2%P^dI`x1hJ|6H2oHoc6{x9fEe2~k?7`v+!$wiliLLoy ztNhixaIB8~LkuS_6n%CEoPm^qfi8z~|DWTN>231U6kj<5&cHuofU|O1PViE8w{E?j x+_eE?h9M$xjVKW4$xi?la*iBEr}~5Fh${>mMcGB{F&*eX0+A4(oPl3p;1iLJK*In4 literal 0 HcmV?d00001 diff --git a/src/main/java/space/space_spring/domain/.DS_Store b/src/main/java/space/space_spring/domain/.DS_Store index 33136f01813a20ce3759383589b4a92cf60b3b8c..1741fef24d2e7ffa310198ae93e1f5c36797994e 100644 GIT binary patch delta 291 zcmZoMXfc=|#>B!ku~2NHo+2aH#(>?7iw&5W7`Z0DW0IS!#q>xZC*3eOIX}060Sq#q zgCs<9^Icq$a`KaaVjM4LST58JI_3zKNWm&0P>_La%moIZYTbGkhEj%NhE#?kR7=e7 z0?mcXA={<;rXd1k7pgqMN^J6|HXi_Lg@MgF%xf7pvvcrs0E1w&BJ+3V$^0UY9E=PM NOdutjBSh9P0|3|%N~Qn+ delta 76 zcmZoMXfc=|#>B)qu~2NHo+2aD#(>?7lMO^zCO5N6Pu602H2DlG|7H;mVU~#vH#f6$ f@N)pwZWiSD&ODi4#F2vm2pAa{ST;w9tYHQKE)Ek( diff --git a/src/main/java/space/space_spring/domain/authorization/.DS_Store b/src/main/java/space/space_spring/domain/authorization/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a9267028d891cc26f92accd816345daf8e67d9ff GIT binary patch literal 6148 zcmeHKJxc>Y5S>jTL<9}kSSa2fPz)A!a*1bQC79AeO#%iD6BEcvrONC`rBjg zaR2O;>y){py#J$rJP2zie2XgG&@D}7*uB6LveT%T+rj2ne#q?U;{0Jpm}y?fYu+2P zDo~V`=#*NEbaPwqhRlM`uu*U41@fT<>H8#=^isRGX+cmQ(#sB?AdJf z6+!Dw0aL&fC>7xELxRSbDi(tN(}B((0f043d&AiO`U4Z50H%tCAZB1rQh}1{^oZf~ zaKw6SPY-HjXO<%M=X!R*YEQiZ{@_VLssjFjXuBF$1$70WX7f JrogW%@Ck4Ef3g4o literal 0 HcmV?d00001 diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java index d7c1d224..dd7d9389 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java @@ -124,29 +124,4 @@ public Long getUserIdFromAccessToken(String token) { } } - public void validateRefreshToken(User user, String refreshToken) { - TokenStorage tokenStorage = jwtRepository.findByUser(user) - .orElseThrow(() -> - { - // db에서 row delete 하는 코드 추가 - jwtRepository.deleteByUser(user); - throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); - }); - - // TODO 1. refresh token의 만료시간 체크 - if (isExpiredToken(refreshToken, TokenType.REFRESH)) { - // refresh token이 만료된 경우 -> 예외 발생 -> 유저의 재 로그인 유도 - // db에서 row delete 하는 코드 추가 - jwtRepository.deleteByUser(user); - throw new JwtExpiredTokenException(EXPIRED_REFRESH_TOKEN); - } - - // TODO 2. refresh token이 db에 실제로 존재하는지 체크 - if (!tokenStorage.checkTokenValue(refreshToken)) { - // refresh token이 db에 존재하지 않느 경우 -> 유효하지 않은 refresh token이므로 예외 발생 - // db에서 row delete 하는 코드 추가 - jwtRepository.deleteByUser(user); - throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); - } - } } diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java new file mode 100644 index 00000000..be43ec51 --- /dev/null +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java @@ -0,0 +1,28 @@ +package space.space_spring.domain.authorization.jwt.model; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import space.space_spring.entity.TokenStorage; +import space.space_spring.entity.User; + +@Component +@RequiredArgsConstructor +public class TokenUpdater { + + private final JwtLoginProvider jwtLoginProvider; + + public TokenPairDTO updateTokenPair(User user, TokenStorage tokenStorage) { + // new access token, new refresh token 발급 받아서 + String newAccessToken = jwtLoginProvider.generateToken(user, TokenType.ACCESS); + String newRefreshToken = jwtLoginProvider.generateToken(user, TokenType.REFRESH); + + // tokenStorage update 하고 + tokenStorage.updateTokenValue(newRefreshToken); + + return TokenPairDTO.builder() + .accessToken(newAccessToken) + .refreshToken(newRefreshToken) + .build(); + } + +} diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenValidator.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenValidator.java new file mode 100644 index 00000000..ffa74f55 --- /dev/null +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenValidator.java @@ -0,0 +1,34 @@ +package space.space_spring.domain.authorization.jwt.model; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; +import space.space_spring.entity.TokenStorage; +import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; +import space.space_spring.exception.jwt.unauthorized.JwtUnauthorizedTokenException; + +import static space.space_spring.response.status.BaseExceptionResponseStatus.EXPIRED_REFRESH_TOKEN; +import static space.space_spring.response.status.BaseExceptionResponseStatus.TOKEN_MISMATCH; + +@Component +@RequiredArgsConstructor +public class TokenValidator { + + private final JwtLoginProvider jwtLoginProvider; + + public void validateRefreshToken(String refreshToken, TokenStorage tokenStorage) { + // TODO 1. refresh token의 만료시간 체크 + if (jwtLoginProvider.isExpiredToken(refreshToken, TokenType.REFRESH)) { + // refresh token이 만료된 경우 -> 예외 발생 -> 유저의 재 로그인 유도 + // db에서 row delete 하는 코드 추가 + throw new JwtExpiredTokenException(EXPIRED_REFRESH_TOKEN); + } + + // TODO 2. refresh token이 db에 실제로 존재하는지 체크 + if (!tokenStorage.checkTokenValue(refreshToken)) { + // refresh token이 db에 존재하지 않느 경우 -> 유효하지 않은 refresh token이므로 예외 발생 + // db에서 row delete 하는 코드 추가 + throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); + } + } + +} diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index 258db50f..7b432e98 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -24,6 +24,8 @@ public class JwtService { private final JwtLoginProvider jwtLoginProvider; private final UserRepository userRepository; private final TokenResolver tokenResolver; + private final TokenValidator tokenValidator; + private final TokenUpdater tokenUpdater; @Transactional public TokenPairDTO updateAccessToken(HttpServletRequest request) { @@ -31,15 +33,13 @@ public TokenPairDTO updateAccessToken(HttpServletRequest request) { TokenPairDTO oldTokenPair = tokenResolver.resolveTokenPair(request); // 여기서 User 찾고 - User userByAccessToken = getUserByAccessToken(oldTokenPair.getAccessToken()); + User user = getUserByAccessToken(oldTokenPair.getAccessToken()); // 이 User로 refresh token의 유효성 검사 진행하고 - jwtLoginProvider.validateRefreshToken(userByAccessToken, oldTokenPair.getRefreshToken()); + validateRefreshToken(user, oldTokenPair.getRefreshToken()); // access, refresh 새로 발급 - TokenPairDTO tokenPairDTO = updateTokenPair(userByAccessToken); - - return tokenPairDTO; + return updateTokenPair(user); } private User getUserByAccessToken(String accessToken) { @@ -49,22 +49,31 @@ private User getUserByAccessToken(String accessToken) { .orElseThrow(() -> new CustomException(USER_NOT_FOUND)); } - private TokenPairDTO updateTokenPair(User user) { - // TODO 1. new access token, refresh token 발급 - String newAccessToken = jwtLoginProvider.generateToken(user, TokenType.ACCESS); - String newRefreshToken = jwtLoginProvider.generateToken(user, TokenType.REFRESH); + private void validateRefreshToken(User user, String refreshToken) { + TokenStorage tokenStorage = jwtRepository.findByUser(user) + .orElseThrow(() -> + { + // db에서 row delete 하는 코드 추가 + jwtRepository.deleteByUser(user); + throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); + }); + + try { + tokenValidator.validateRefreshToken(refreshToken, tokenStorage); + } catch (JwtExpiredTokenException e) { + jwtRepository.deleteByUser(user); + throw e; + } catch (JwtUnauthorizedTokenException e) { + jwtRepository.deleteByUser(user); + throw e; + } + } - // TODO 2. db의 refresh token update + private TokenPairDTO updateTokenPair(User user) { TokenStorage tokenStorage = jwtRepository.findByUser(user) .orElseThrow(() -> new JwtUnauthorizedTokenException(TOKEN_MISMATCH)); - tokenStorage.updateTokenValue(newRefreshToken); - - // TODO 3. return - return TokenPairDTO.builder() - .accessToken(newAccessToken) - .refreshToken(newRefreshToken) - .build(); + return tokenUpdater.updateTokenPair(user, tokenStorage); } public TokenPairDTO provideJwtToOAuthUser(User userByOAuthInfo) { diff --git a/src/main/java/space/space_spring/entity/TokenStorage.java b/src/main/java/space/space_spring/entity/TokenStorage.java index 1175aaf5..6c5ffcc6 100644 --- a/src/main/java/space/space_spring/entity/TokenStorage.java +++ b/src/main/java/space/space_spring/entity/TokenStorage.java @@ -9,6 +9,7 @@ @Entity @Table(name = "Token_Storage") @Getter +@Builder public class TokenStorage { @Id @GeneratedValue diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java index bd224b4c..185830bb 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java @@ -9,6 +9,7 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.ContextConfiguration; From d7b9c79e13cbdd7419c9894b2c87da503e9d9854 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Tue, 29 Oct 2024 23:10:46 +0900 Subject: [PATCH 05/38] =?UTF-8?q?refactor=20:=20JwtLoginProvider=EC=9D=98?= =?UTF-8?q?=20Repository=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=B0=8F=20generateToken=20=EB=A9=94=EC=84=9C?= =?UTF-8?q?=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 --- .../auth/service/AuthService.java | 4 +-- .../jwt/model/JwtLoginProvider.java | 23 +++++--------- .../authorization/jwt/model/TokenUpdater.java | 4 +-- .../authorization/jwt/service/JwtService.java | 9 ++---- .../jwt/model/JwtLoginProviderTest.java | 30 +++++++++++++++++++ 5 files changed, 45 insertions(+), 25 deletions(-) diff --git a/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java b/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java index 2c9c0a00..9d702884 100644 --- a/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java +++ b/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java @@ -40,8 +40,8 @@ public PostLoginDto login(PostLoginDto.Request request) { validatePassword(userByEmail, request.getPassword()); // TODO 3. JWT 발급 -> access token, refresh token 2개 발급 - String accessToken = jwtLoginProvider.generateToken(userByEmail, TokenType.ACCESS); - String refreshToken = jwtLoginProvider.generateToken(userByEmail, TokenType.REFRESH); + String accessToken = jwtLoginProvider.generateToken(userByEmail.getUserId(), TokenType.ACCESS); + String refreshToken = jwtLoginProvider.generateToken(userByEmail.getUserId(), TokenType.REFRESH); // TODO 4. refresh token db에 저장 TokenStorage tokenStorage = TokenStorage.builder() diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java index dd7d9389..5a2ba195 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java @@ -1,19 +1,16 @@ package space.space_spring.domain.authorization.jwt.model; import io.jsonwebtoken.*; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; -import space.space_spring.domain.authorization.jwt.repository.JwtRepository; -import space.space_spring.entity.TokenStorage; -import space.space_spring.entity.User; import space.space_spring.exception.CustomException; import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; -import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; import space.space_spring.exception.jwt.unauthorized.JwtInvalidTokenException; import space.space_spring.exception.jwt.unauthorized.JwtMalformedTokenException; -import space.space_spring.exception.jwt.unauthorized.JwtUnauthorizedTokenException; import java.util.Date; @@ -21,30 +18,26 @@ @Slf4j @Component -@RequiredArgsConstructor +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class JwtLoginProvider { @Value("${secret.jwt.access-secret-key}") - private String ACCESS_SECRET_KEY; + protected String ACCESS_SECRET_KEY; @Value("${secret.jwt.refresh-secret-key}") - private String REFRESH_SECRET_KEY; + protected String REFRESH_SECRET_KEY; @Value("${secret.jwt.access-expired-in}") - private Long ACCESS_EXPIRED_IN; + protected Long ACCESS_EXPIRED_IN; @Value("${secret.jwt.refresh-expired-in}") - private Long REFRESH_EXPIRED_IN; + protected Long REFRESH_EXPIRED_IN; - private final JwtRepository jwtRepository; - - public String generateToken(User user, TokenType tokenType) { + public String generateToken(Long userId, TokenType tokenType) { // Claims claims = Jwts.claims().setSubject(jwtPayloadDto.getUserId().toString()); Date now = new Date(); Date expiration = setExpiration(now, tokenType); - Long userId = user.getUserId(); - return makeToken(tokenType, userId, now, expiration); } diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java index be43ec51..f1967d07 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java @@ -13,8 +13,8 @@ public class TokenUpdater { public TokenPairDTO updateTokenPair(User user, TokenStorage tokenStorage) { // new access token, new refresh token 발급 받아서 - String newAccessToken = jwtLoginProvider.generateToken(user, TokenType.ACCESS); - String newRefreshToken = jwtLoginProvider.generateToken(user, TokenType.REFRESH); + String newAccessToken = jwtLoginProvider.generateToken(user.getUserId(), TokenType.ACCESS); + String newRefreshToken = jwtLoginProvider.generateToken(user.getUserId(), TokenType.REFRESH); // tokenStorage update 하고 tokenStorage.updateTokenValue(newRefreshToken); diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index 7b432e98..0be718b1 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -21,8 +21,8 @@ public class JwtService { private final JwtRepository jwtRepository; - private final JwtLoginProvider jwtLoginProvider; private final UserRepository userRepository; + private final JwtLoginProvider jwtLoginProvider; private final TokenResolver tokenResolver; private final TokenValidator tokenValidator; private final TokenUpdater tokenUpdater; @@ -60,9 +60,6 @@ private void validateRefreshToken(User user, String refreshToken) { try { tokenValidator.validateRefreshToken(refreshToken, tokenStorage); - } catch (JwtExpiredTokenException e) { - jwtRepository.deleteByUser(user); - throw e; } catch (JwtUnauthorizedTokenException e) { jwtRepository.deleteByUser(user); throw e; @@ -77,8 +74,8 @@ private TokenPairDTO updateTokenPair(User user) { } public TokenPairDTO provideJwtToOAuthUser(User userByOAuthInfo) { - String accessToken = jwtLoginProvider.generateToken(userByOAuthInfo, TokenType.ACCESS); - String refreshToken = jwtLoginProvider.generateToken(userByOAuthInfo, TokenType.REFRESH); + String accessToken = jwtLoginProvider.generateToken(userByOAuthInfo.getUserId(), TokenType.ACCESS); + String refreshToken = jwtLoginProvider.generateToken(userByOAuthInfo.getUserId(), TokenType.REFRESH); return TokenPairDTO.builder() .accessToken(accessToken) diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java index 6f38e281..0a595b2f 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java @@ -1,12 +1,42 @@ package space.space_spring.domain.authorization.jwt.model; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jws; +import io.jsonwebtoken.Jwts; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; class JwtLoginProviderTest { + @Test + @DisplayName("userId를 인자로 넘기면, userId값을 payload에 가지고 있는 access token을 만들어 줍니다.") + void generateToken() throws Exception { + //given + Long userId = 1L; + JwtLoginProvider jwtLoginProvider = new JwtLoginProvider(); + + jwtLoginProvider.ACCESS_SECRET_KEY = "Kv7yGnLFcgfx7F9MyrBuBp4hbhtsAiY17Mo7TlUpDQU"; + jwtLoginProvider.REFRESH_SECRET_KEY = "UvfDATy9MEEg3rWvxrQ0JBc5gC4MFyxDS6VXLCcjou4"; + jwtLoginProvider.ACCESS_EXPIRED_IN = 3600000L; // 1시간 + jwtLoginProvider.REFRESH_EXPIRED_IN = 604800000L; // 7일 + + //when + String accessToken = jwtLoginProvider.generateToken(userId, TokenType.ACCESS); + + //then + Jws claims = Jwts.parserBuilder() + .setSigningKey(jwtLoginProvider.ACCESS_SECRET_KEY) + .build() + .parseClaimsJws(accessToken); + + Long extractedUserId = claims.getBody().get("userId", Long.class); + + assertThat(extractedUserId).isEqualTo(userId); + } + @Test @DisplayName("") void test() throws Exception { From 707ae080b48b5fbeaf5abf367d7a74c2152084ce Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 30 Oct 2024 01:39:49 +0900 Subject: [PATCH 06/38] =?UTF-8?q?test=20:=20JwtLoginProvider=20test=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=9E=91=EC=84=B1=20&=20test=20yml=20reba?= =?UTF-8?q?se=20=EC=A7=80=EC=A0=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwt/model/JwtLoginProvider.java | 10 +- .../jwt/model/JwtLoginProviderTest.java | 126 ++++++++++++++++-- 2 files changed, 123 insertions(+), 13 deletions(-) diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java index 5a2ba195..81b6c7ce 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProvider.java @@ -2,6 +2,7 @@ import io.jsonwebtoken.*; import lombok.AccessLevel; +import lombok.Getter; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -19,18 +20,19 @@ @Slf4j @Component @NoArgsConstructor(access = AccessLevel.PROTECTED) +@Getter public class JwtLoginProvider { @Value("${secret.jwt.access-secret-key}") - protected String ACCESS_SECRET_KEY; + private String ACCESS_SECRET_KEY; @Value("${secret.jwt.refresh-secret-key}") - protected String REFRESH_SECRET_KEY; + private String REFRESH_SECRET_KEY; @Value("${secret.jwt.access-expired-in}") - protected Long ACCESS_EXPIRED_IN; + private Long ACCESS_EXPIRED_IN; @Value("${secret.jwt.refresh-expired-in}") - protected Long REFRESH_EXPIRED_IN; + private Long REFRESH_EXPIRED_IN; public String generateToken(Long userId, TokenType tokenType) { // Claims claims = Jwts.claims().setSubject(jwtPayloadDto.getUserId().toString()); diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java index 0a595b2f..10e6bd1a 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java @@ -3,32 +3,46 @@ import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jws; import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import space.space_spring.config.WebSocketConfig; + +import java.util.Date; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; +@SpringJUnitConfig(JwtLoginProvider.class) +@TestPropertySource(properties = { // 테스트용 프로퍼티 소스(환경 설정) 지정 + "secret.jwt.access-secret-key=accessSecretKeyaccessSecretKeyaccessSecretKey", + "secret.jwt.refresh-secret-key=refreshSecretKeyrefreshSecretKeyrefreshSecretKey", + "secret.jwt.access-expired-in=3600000", + "secret.jwt.refresh-expired-in=604800000" +}) class JwtLoginProviderTest { + @Autowired + private JwtLoginProvider jwtLoginProvider; + @Test @DisplayName("userId를 인자로 넘기면, userId값을 payload에 가지고 있는 access token을 만들어 줍니다.") void generateToken() throws Exception { //given Long userId = 1L; - JwtLoginProvider jwtLoginProvider = new JwtLoginProvider(); - - jwtLoginProvider.ACCESS_SECRET_KEY = "Kv7yGnLFcgfx7F9MyrBuBp4hbhtsAiY17Mo7TlUpDQU"; - jwtLoginProvider.REFRESH_SECRET_KEY = "UvfDATy9MEEg3rWvxrQ0JBc5gC4MFyxDS6VXLCcjou4"; - jwtLoginProvider.ACCESS_EXPIRED_IN = 3600000L; // 1시간 - jwtLoginProvider.REFRESH_EXPIRED_IN = 604800000L; // 7일 //when String accessToken = jwtLoginProvider.generateToken(userId, TokenType.ACCESS); //then Jws claims = Jwts.parserBuilder() - .setSigningKey(jwtLoginProvider.ACCESS_SECRET_KEY) + .setSigningKey(jwtLoginProvider.getACCESS_SECRET_KEY()) .build() .parseClaimsJws(accessToken); @@ -38,14 +52,108 @@ void generateToken() throws Exception { } @Test - @DisplayName("") - void test() throws Exception { + @DisplayName("인자로 받은 access token의 유효기간이 끝나지 않았다면, false를 return 한다.") + void isExpiredToken1() throws Exception { + //given + Date now = new Date(); + String accessToken = Jwts.builder() + .setExpiration(new Date(now.getTime() + 360000L)) // 현 시점부터 1시간 동안이 유효기간 + .signWith(SignatureAlgorithm.HS256, "accessSecretKeyaccessSecretKeyaccessSecretKey") + .compact(); + + //when + boolean expiredToken = jwtLoginProvider.isExpiredToken(accessToken, TokenType.ACCESS); + + //then + assertThat(expiredToken).isFalse(); + } + + @Test + @DisplayName("인자로 받은 access token의 유효기간이 끝났다면, true를 return 한다.") + void isExpiredToken2() throws Exception { //given + Date now = new Date(); + String accessToken = Jwts.builder() + .setExpiration(new Date(now.getTime())) // 생성하자마자 유효기간 끝 + .signWith(SignatureAlgorithm.HS256, "accessSecretKeyaccessSecretKeyaccessSecretKey") + .compact(); //when + boolean expiredToken = jwtLoginProvider.isExpiredToken(accessToken, TokenType.ACCESS); //then + assertThat(expiredToken).isTrue(); } + @Test + @DisplayName("인자로 받은 refresh token의 유효기간이 끝나지 않았다면, false를 return 한다.") + void isExpiredToken3() throws Exception { + //given + Date now = new Date(); + String refreshToken = Jwts.builder() + .setExpiration(new Date(now.getTime() + 360000L)) // 현 시점부터 1시간 동안이 유효기간 + .signWith(SignatureAlgorithm.HS256, "refreshSecretKeyrefreshSecretKeyrefreshSecretKey") + .compact(); + + //when + boolean expiredToken = jwtLoginProvider.isExpiredToken(refreshToken, TokenType.REFRESH); + //then + assertThat(expiredToken).isFalse(); + } + + @Test + @DisplayName("인자로 받은 refresh token의 유효기간이 끝났다면, true를 return 한다.") + void isExpiredToken4() throws Exception { + //given + Date now = new Date(); + String refreshToken = Jwts.builder() + .setExpiration(new Date(now.getTime())) // 생성하자마자 유효기간 끝 + .signWith(SignatureAlgorithm.HS256, "refreshSecretKeyrefreshSecretKeyrefreshSecretKey") + .compact(); + + //when + boolean expiredToken = jwtLoginProvider.isExpiredToken(refreshToken, TokenType.REFRESH); + + //then + assertThat(expiredToken).isTrue(); + } + + @Test + @DisplayName("만료되지 않은 access token의 payload에 담긴 userId 값을 return 한다.") + void getUserIdFromAccessToken1() throws Exception { + //given + Long userId = 1L; + Date now = new Date(); + String accessToken = Jwts.builder() + .setExpiration(new Date(now.getTime() + 360000L)) // 현 시점부터 1시간 동안이 유효기간 + .claim("userId", userId) + .signWith(SignatureAlgorithm.HS256, "accessSecretKeyaccessSecretKeyaccessSecretKey") + .compact(); + + //when + Long userIdFromAccessToken = jwtLoginProvider.getUserIdFromAccessToken(accessToken); + + //then + assertThat(userIdFromAccessToken).isEqualTo(userId); + } + + @Test + @DisplayName("만료된 access token의 payload에 담긴 userId 값을 return 한다.") + void getUserIdFromAccessToken2() throws Exception { + //given + Long userId = 1L; + Date now = new Date(); + String accessToken = Jwts.builder() + .setExpiration(new Date(now.getTime())) // 생성하자마자 유효기간 끝 + .claim("userId", userId) + .signWith(SignatureAlgorithm.HS256, "accessSecretKeyaccessSecretKeyaccessSecretKey") + .compact(); + + //when + Long userIdFromAccessToken = jwtLoginProvider.getUserIdFromAccessToken(accessToken); + + //then + assertThat(userIdFromAccessToken).isEqualTo(userId); + } } \ No newline at end of file From 84b4dbc70a3b34a83c2686cec6484dba3880fc7e Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 30 Oct 2024 01:40:51 +0900 Subject: [PATCH 07/38] =?UTF-8?q?allow=20empty=20=EC=A7=80=EC=A0=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From 20dc6d58699962303c23d5ccebf8217ae28ad5e8 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 30 Oct 2024 02:08:35 +0900 Subject: [PATCH 08/38] =?UTF-8?q?refactor=20:=20TokenResolverTest=20?= =?UTF-8?q?=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 --- .../jwt/model/TokenResolver.java | 3 +++ .../jwt/model/TokenResolverTest.java | 23 +++++++------------ .../jwt/model/TokenValidatorTest.java | 22 ++++++++++++++++++ 3 files changed, 33 insertions(+), 15 deletions(-) create mode 100644 src/test/java/space/space_spring/domain/authorization/jwt/model/TokenValidatorTest.java diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java index 4fe0b66d..b657ece2 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java @@ -1,6 +1,8 @@ package space.space_spring.domain.authorization.jwt.model; import jakarta.servlet.http.HttpServletRequest; +import lombok.AccessLevel; +import lombok.NoArgsConstructor; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Component; import space.space_spring.exception.jwt.bad_request.JwtNoTokenException; @@ -10,6 +12,7 @@ import static space.space_spring.response.status.BaseExceptionResponseStatus.UNSUPPORTED_TOKEN_TYPE; @Component +@NoArgsConstructor(access = AccessLevel.PROTECTED) public class TokenResolver { private static final String JWT_TOKEN_PREFIX = "Bearer "; diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java index 185830bb..c62e71d5 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java @@ -21,29 +21,16 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.*; -@ExtendWith(SpringExtension.class) -@TestConfiguration -class TokenResolverTestConfig { // 테스트 전용 설정 클래스 - - @Bean - TokenResolver tokenResolver() { - return new TokenResolver(); // 직접 TokenResolver 빈 생성 - } -} - -@ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = TokenResolverTestConfig.class) class TokenResolverTest { private static final String JWT_TOKEN_PREFIX = "Bearer "; - @Autowired - private TokenResolver tokenResolver; - @Test @DisplayName("request header로부터 access token, refresh token을 rosolve한다.") void resolveTokenPair() throws Exception { //given + TokenResolver tokenResolver = new TokenResolver(); + MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization", JWT_TOKEN_PREFIX + "accessToken"); request.addHeader("Authorization-refresh", JWT_TOKEN_PREFIX + "refreshToken"); @@ -60,6 +47,8 @@ void resolveTokenPair() throws Exception { @DisplayName("access token값이 null 일 경우 예외를 던진다.") void validateToken1() throws Exception { //given + TokenResolver tokenResolver = new TokenResolver(); + MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization-refresh", JWT_TOKEN_PREFIX + "refreshToken"); @@ -73,6 +62,8 @@ void validateToken1() throws Exception { @DisplayName("refresh token값이 null 일 경우 예외를 던진다.") void validateToken2() throws Exception { //given + TokenResolver tokenResolver = new TokenResolver(); + MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization", JWT_TOKEN_PREFIX + "accessToken"); @@ -86,6 +77,8 @@ void validateToken2() throws Exception { @DisplayName("토큰값의 prefix가 잘못된 경우 예외를 던진다.") void validateToken3() throws Exception { //given + TokenResolver tokenResolver = new TokenResolver(); + MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization", "wrong prefix " + "accessToken"); request.addHeader("Authorization-refresh", "wrong prefix " + "refreshToken"); diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenValidatorTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenValidatorTest.java new file mode 100644 index 00000000..273c7e47 --- /dev/null +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenValidatorTest.java @@ -0,0 +1,22 @@ +package space.space_spring.domain.authorization.jwt.model; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class TokenValidatorTest { + + @Test + @DisplayName("") + void test() throws Exception { + //given + + + //when + + //then + } + + +} \ No newline at end of file From d8da2bf9d1f0efec12ac371be7bdaed1e63e8858 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 30 Oct 2024 02:26:27 +0900 Subject: [PATCH 09/38] =?UTF-8?q?refactor=20:=20TokenValidator,=20TokenUpd?= =?UTF-8?q?ater=20=EA=B0=9D=EC=B2=B4=20=EC=82=AD=EC=A0=9C=20->=20=ED=95=B4?= =?UTF-8?q?=EB=8B=B9=20=EB=A1=9C=EC=A7=81=20JwtService=EC=9D=98=20private?= =?UTF-8?q?=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../authorization/jwt/model/TokenUpdater.java | 28 --------------- .../jwt/model/TokenValidator.java | 34 ------------------ .../authorization/jwt/service/JwtService.java | 32 ++++++++++++----- .../jwt/model/TokenValidatorTest.java | 22 ------------ .../jwt/service/JwtServiceTest.java | 36 +++++++++++++++++++ 5 files changed, 60 insertions(+), 92 deletions(-) delete mode 100644 src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java delete mode 100644 src/main/java/space/space_spring/domain/authorization/jwt/model/TokenValidator.java delete mode 100644 src/test/java/space/space_spring/domain/authorization/jwt/model/TokenValidatorTest.java diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java deleted file mode 100644 index f1967d07..00000000 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenUpdater.java +++ /dev/null @@ -1,28 +0,0 @@ -package space.space_spring.domain.authorization.jwt.model; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import space.space_spring.entity.TokenStorage; -import space.space_spring.entity.User; - -@Component -@RequiredArgsConstructor -public class TokenUpdater { - - private final JwtLoginProvider jwtLoginProvider; - - public TokenPairDTO updateTokenPair(User user, TokenStorage tokenStorage) { - // new access token, new refresh token 발급 받아서 - String newAccessToken = jwtLoginProvider.generateToken(user.getUserId(), TokenType.ACCESS); - String newRefreshToken = jwtLoginProvider.generateToken(user.getUserId(), TokenType.REFRESH); - - // tokenStorage update 하고 - tokenStorage.updateTokenValue(newRefreshToken); - - return TokenPairDTO.builder() - .accessToken(newAccessToken) - .refreshToken(newRefreshToken) - .build(); - } - -} diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenValidator.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenValidator.java deleted file mode 100644 index ffa74f55..00000000 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenValidator.java +++ /dev/null @@ -1,34 +0,0 @@ -package space.space_spring.domain.authorization.jwt.model; - -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Component; -import space.space_spring.entity.TokenStorage; -import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; -import space.space_spring.exception.jwt.unauthorized.JwtUnauthorizedTokenException; - -import static space.space_spring.response.status.BaseExceptionResponseStatus.EXPIRED_REFRESH_TOKEN; -import static space.space_spring.response.status.BaseExceptionResponseStatus.TOKEN_MISMATCH; - -@Component -@RequiredArgsConstructor -public class TokenValidator { - - private final JwtLoginProvider jwtLoginProvider; - - public void validateRefreshToken(String refreshToken, TokenStorage tokenStorage) { - // TODO 1. refresh token의 만료시간 체크 - if (jwtLoginProvider.isExpiredToken(refreshToken, TokenType.REFRESH)) { - // refresh token이 만료된 경우 -> 예외 발생 -> 유저의 재 로그인 유도 - // db에서 row delete 하는 코드 추가 - throw new JwtExpiredTokenException(EXPIRED_REFRESH_TOKEN); - } - - // TODO 2. refresh token이 db에 실제로 존재하는지 체크 - if (!tokenStorage.checkTokenValue(refreshToken)) { - // refresh token이 db에 존재하지 않느 경우 -> 유효하지 않은 refresh token이므로 예외 발생 - // db에서 row delete 하는 코드 추가 - throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); - } - } - -} diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index 0be718b1..6de88eb4 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -24,8 +24,6 @@ public class JwtService { private final UserRepository userRepository; private final JwtLoginProvider jwtLoginProvider; private final TokenResolver tokenResolver; - private final TokenValidator tokenValidator; - private final TokenUpdater tokenUpdater; @Transactional public TokenPairDTO updateAccessToken(HttpServletRequest request) { @@ -58,11 +56,18 @@ private void validateRefreshToken(User user, String refreshToken) { throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); }); - try { - tokenValidator.validateRefreshToken(refreshToken, tokenStorage); - } catch (JwtUnauthorizedTokenException e) { - jwtRepository.deleteByUser(user); - throw e; + // TODO 1. refresh token의 만료시간 체크 + if (jwtLoginProvider.isExpiredToken(refreshToken, TokenType.REFRESH)) { + // refresh token이 만료된 경우 -> 예외 발생 -> 유저의 재 로그인 유도 + // db에서 row delete 하는 코드 추가 + throw new JwtExpiredTokenException(EXPIRED_REFRESH_TOKEN); + } + + // TODO 2. refresh token이 db에 실제로 존재하는지 체크 + if (!tokenStorage.checkTokenValue(refreshToken)) { + // refresh token이 db에 존재하지 않느 경우 -> 유효하지 않은 refresh token이므로 예외 발생 + // db에서 row delete 하는 코드 추가 + throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); } } @@ -70,7 +75,18 @@ private TokenPairDTO updateTokenPair(User user) { TokenStorage tokenStorage = jwtRepository.findByUser(user) .orElseThrow(() -> new JwtUnauthorizedTokenException(TOKEN_MISMATCH)); - return tokenUpdater.updateTokenPair(user, tokenStorage); + // new access token, new refresh token 발급 받아서 + String newAccessToken = jwtLoginProvider.generateToken(user.getUserId(), TokenType.ACCESS); + String newRefreshToken = jwtLoginProvider.generateToken(user.getUserId(), TokenType.REFRESH); + + // tokenStorage update 하고 + tokenStorage.updateTokenValue(newRefreshToken); + + return TokenPairDTO.builder() + .accessToken(newAccessToken) + .refreshToken(newRefreshToken) + .build(); + } public TokenPairDTO provideJwtToOAuthUser(User userByOAuthInfo) { diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenValidatorTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenValidatorTest.java deleted file mode 100644 index 273c7e47..00000000 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenValidatorTest.java +++ /dev/null @@ -1,22 +0,0 @@ -package space.space_spring.domain.authorization.jwt.model; - -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class TokenValidatorTest { - - @Test - @DisplayName("") - void test() throws Exception { - //given - - - //when - - //then - } - - -} \ No newline at end of file diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java index e5e71196..b46f7640 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java @@ -1,7 +1,43 @@ package space.space_spring.domain.authorization.jwt.service; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; +import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; +import space.space_spring.domain.authorization.jwt.model.TokenResolver; +import space.space_spring.domain.authorization.jwt.repository.JwtRepository; +import space.space_spring.domain.user.repository.UserRepository; + import static org.junit.jupiter.api.Assertions.*; +@SpringJUnitConfig(classes = {JwtService.class, JwtRepository.class, UserRepository.class, JwtLoginProvider.class, TokenResolver.class}) class JwtServiceTest { + @Autowired + private JwtService jwtService; + + @Autowired + private JwtRepository jwtRepository; + + @Autowired + private UserRepository userRepository; + + @Autowired + private JwtLoginProvider jwtLoginProvider; + + @Autowired + private TokenResolver tokenResolver; + + @Test + @DisplayName("") + void test() throws Exception { + //given + + //when + + //then + } + + } \ No newline at end of file From 0da099c1f5da7944f97810190a9a19385017c8cf Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 30 Oct 2024 03:27:00 +0900 Subject: [PATCH 10/38] =?UTF-8?q?test=20:=20jwtService=20test=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jwt/controller/JwtController.java | 2 +- .../authorization/jwt/service/JwtService.java | 2 +- .../space_spring/entity/TokenStorage.java | 15 +++- .../java/space/space_spring/entity/User.java | 16 ++++ .../jwt/service/JwtServiceTest.java | 74 ++++++++++++++++++- src/test/resources/application-test.yml | 17 +++++ 6 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 src/test/resources/application-test.yml diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/controller/JwtController.java b/src/main/java/space/space_spring/domain/authorization/jwt/controller/JwtController.java index 85fff086..8a597dbc 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/controller/JwtController.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/controller/JwtController.java @@ -27,7 +27,7 @@ public class JwtController { @PostMapping("/new-token") public BaseResponse updateAccessToken(HttpServletRequest request, HttpServletResponse response) throws IOException { - TokenPairDTO newTokenPairDTO = jwtService.updateAccessToken(request); + TokenPairDTO newTokenPairDTO = jwtService.updateTokenPair(request); response.setHeader("Authorization-refresh", "Bearer " + newTokenPairDTO.getRefreshToken()); response.setHeader("Authorization", "Bearer " + newTokenPairDTO.getAccessToken()); diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index 6de88eb4..daaff4d2 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -26,7 +26,7 @@ public class JwtService { private final TokenResolver tokenResolver; @Transactional - public TokenPairDTO updateAccessToken(HttpServletRequest request) { + public TokenPairDTO updateTokenPair(HttpServletRequest request) { // request에서 기존의 TokenPair를 찾아와서 TokenPairDTO oldTokenPair = tokenResolver.resolveTokenPair(request); diff --git a/src/main/java/space/space_spring/entity/TokenStorage.java b/src/main/java/space/space_spring/entity/TokenStorage.java index 6c5ffcc6..b0edd35a 100644 --- a/src/main/java/space/space_spring/entity/TokenStorage.java +++ b/src/main/java/space/space_spring/entity/TokenStorage.java @@ -9,7 +9,7 @@ @Entity @Table(name = "Token_Storage") @Getter -@Builder +@NoArgsConstructor public class TokenStorage { @Id @GeneratedValue @@ -31,4 +31,17 @@ public boolean checkTokenValue(String tokenValue) { return this.tokenValue.equals(tokenValue); } + @Builder + private TokenStorage(User user, String tokenValue) { + this.user = user; + this.tokenValue = tokenValue; + } + + public static TokenStorage create(User user, String tokenValue) { + return TokenStorage.builder() + .user(user) + .tokenValue(tokenValue) + .build(); + } + } diff --git a/src/main/java/space/space_spring/entity/User.java b/src/main/java/space/space_spring/entity/User.java index c25d702c..ee6a88b1 100644 --- a/src/main/java/space/space_spring/entity/User.java +++ b/src/main/java/space/space_spring/entity/User.java @@ -2,6 +2,7 @@ import jakarta.annotation.Nullable; import jakarta.persistence.*; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import space.space_spring.entity.enumStatus.UserSignupType; @@ -36,6 +37,21 @@ public void saveUser(String email, String password, String userName, UserSignupT initializeBaseEntityFields(); } + @Builder + private User(String email, String password, String userName, UserSignupType signupType) { + this.email = email; + this.password = password; + this.userName = userName; + this.signupType = signupType.getSignupType(); + } + public static User create(String email, String password, String userName, UserSignupType signupType) { + return User.builder() + .email(email) + .password(password) + .userName(userName) + .signupType(signupType) + .build(); + } } diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java index b46f7640..dde0173d 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java @@ -1,17 +1,44 @@ package space.space_spring.domain.authorization.jwt.service; +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; +import space.space_spring.domain.authorization.jwt.model.TokenPairDTO; import space.space_spring.domain.authorization.jwt.model.TokenResolver; import space.space_spring.domain.authorization.jwt.repository.JwtRepository; import space.space_spring.domain.user.repository.UserRepository; +import space.space_spring.entity.TokenStorage; +import space.space_spring.entity.User; +import space.space_spring.entity.enumStatus.UserSignupType; +import java.util.Date; + +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.*; -@SpringJUnitConfig(classes = {JwtService.class, JwtRepository.class, UserRepository.class, JwtLoginProvider.class, TokenResolver.class}) +@DataJpaTest +@Import({JwtService.class, JwtLoginProvider.class, TokenResolver.class}) +@ActiveProfiles("test") +@TestPropertySource(properties = { + "secret.jwt.access-secret-key=accessSecretKeyaccessSecretKeyaccessSecretKey", + "secret.jwt.refresh-secret-key=refreshSecretKeyrefreshSecretKeyrefreshSecretKey", + "secret.jwt.access-expired-in=3600000", + "secret.jwt.refresh-expired-in=604800000" +}) +@EnableJpaRepositories(basePackageClasses = {UserRepository.class, JwtRepository.class}) +@EntityScan(basePackageClasses = {User.class, TokenStorage.class}) class JwtServiceTest { @Autowired @@ -29,14 +56,55 @@ class JwtServiceTest { @Autowired private TokenResolver tokenResolver; + private static final String JWT_TOKEN_PREFIX = "Bearer "; + @Test - @DisplayName("") - void test() throws Exception { + @DisplayName("request의 refresh token이 유효한 토큰인 경우, 새로운 token pair를 발급하고 db의 token을 update 한다.") + void updateTokenPair() throws Exception { //given + User user = User.create("email", "password", "name", UserSignupType.LOCAL); + User savedUser = userRepository.save(user); + Long userId = savedUser.getUserId(); + + Date now = new Date(); + String accessToken = Jwts.builder() + .setExpiration(new Date(now.getTime())) // 현 시점부터 1시간 동안이 유효기간 + .claim("userId", userId) + .signWith(SignatureAlgorithm.HS256, "accessSecretKeyaccessSecretKeyaccessSecretKey") + .compact(); + + String refreshToken = Jwts.builder() + .setExpiration(new Date(now.getTime() + 360000L)) // 생성하자마자 유효기간 끝 + .signWith(SignatureAlgorithm.HS256, "refreshSecretKeyrefreshSecretKeyrefreshSecretKey") + .compact(); + + TokenStorage tokenStorage = TokenStorage.create(savedUser, refreshToken); + jwtRepository.save(tokenStorage); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", JWT_TOKEN_PREFIX + accessToken); + request.addHeader("Authorization-refresh", JWT_TOKEN_PREFIX + refreshToken); //when + TokenPairDTO tokenPairDTO = jwtService.updateTokenPair(request); //then + String newAccessToken = tokenPairDTO.getAccessToken(); + String newRefreshToken = tokenPairDTO.getRefreshToken(); + + // 새로운 액세스 토큰 검증 + Claims accessTokenClaims = Jwts.parser() + .setSigningKey(jwtLoginProvider.getACCESS_SECRET_KEY()) + .parseClaimsJws(newAccessToken) + .getBody(); + + assertThat(accessTokenClaims.get("userId", Long.class)).isEqualTo(userId); + + // 토큰 저장소에 저장된 리프레시 토큰이 업데이트되었는지 확인 + TokenStorage updatedTokenStorage = jwtRepository.findByUser(savedUser) + .orElseThrow(() -> new Exception("TokenStorage not found")); + + assertThat(updatedTokenStorage.getTokenValue()).isEqualTo(newRefreshToken); } diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml new file mode 100644 index 00000000..cb798131 --- /dev/null +++ b/src/test/resources/application-test.yml @@ -0,0 +1,17 @@ +spring: + datasource: + url: jdbc:h2:mem:~/space_spring + driver-class-name: org.h2.Driver + username: sa + password: + jpa: + hibernate: + ddl-auto: create + show-sql: true + properties: + hibernate: + format_sql: true + + sql: + init: + mode: never # sql initialization 을 사용하지 않겠다 \ No newline at end of file From 631e28f6e88dd7a76ea177cc92e0cdf8eeae2df2 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 30 Oct 2024 17:42:36 +0900 Subject: [PATCH 11/38] =?UTF-8?q?jwtService=20test=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=9E=91=EC=84=B1=20=EB=B0=8F=20jwtService=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20transaction=20=EA=B4=80=EB=A0=A8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../space_spring/SpaceSpringApplication.java | 1 - .../jwt/repository/JwtRepository.java | 7 +- .../authorization/jwt/service/JwtService.java | 14 ++- .../jwt/service/JwtServiceTest.java | 95 ++++++++++++++++++- src/test/resources/application-test.yml | 10 +- 5 files changed, 112 insertions(+), 15 deletions(-) diff --git a/src/main/java/space/space_spring/SpaceSpringApplication.java b/src/main/java/space/space_spring/SpaceSpringApplication.java index 6b2a19cf..7333c784 100644 --- a/src/main/java/space/space_spring/SpaceSpringApplication.java +++ b/src/main/java/space/space_spring/SpaceSpringApplication.java @@ -2,7 +2,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; -import org.springframework.transaction.annotation.EnableTransactionManagement; @SpringBootApplication public class SpaceSpringApplication { diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java b/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java index 443e6356..69b4e12e 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java @@ -16,14 +16,9 @@ public interface JwtRepository extends JpaRepository { Optional findByUser(User user); - @Transactional @Modifying + @Transactional @Query("DELETE FROM TokenStorage t WHERE t.user = :user") void deleteByUser(@Param("user") User user); - @Transactional - default void deleteAndFlushByUser(User user) { - deleteByUser(user); - flush(); // JPA가 즉시 반영하도록 강제 플러시 - } } diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index daaff4d2..1f8004e4 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -3,6 +3,7 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import space.space_spring.domain.authorization.jwt.model.*; import space.space_spring.domain.authorization.jwt.repository.JwtRepository; @@ -60,17 +61,26 @@ private void validateRefreshToken(User user, String refreshToken) { if (jwtLoginProvider.isExpiredToken(refreshToken, TokenType.REFRESH)) { // refresh token이 만료된 경우 -> 예외 발생 -> 유저의 재 로그인 유도 // db에서 row delete 하는 코드 추가 + deleteTokenStorage(user); + throw new JwtExpiredTokenException(EXPIRED_REFRESH_TOKEN); } - // TODO 2. refresh token이 db에 실제로 존재하는지 체크 + // TODO 2. refresh token이 db에 존재하는 token 값과 일치하는지 확인 if (!tokenStorage.checkTokenValue(refreshToken)) { - // refresh token이 db에 존재하지 않느 경우 -> 유효하지 않은 refresh token이므로 예외 발생 + // refresh token이 db에 존재하는 token 값과 일치하지 않는 경우 -> 유효하지 않은 refresh token이므로 예외 발생 // db에서 row delete 하는 코드 추가 + deleteTokenStorage(user); + throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); } } + @Transactional(propagation = Propagation.REQUIRES_NEW) + public void deleteTokenStorage(User user) { + jwtRepository.deleteByUser(user); + } + private TokenPairDTO updateTokenPair(User user) { TokenStorage tokenStorage = jwtRepository.findByUser(user) .orElseThrow(() -> new JwtUnauthorizedTokenException(TOKEN_MISMATCH)); diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java index dde0173d..fc5fdee5 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java @@ -22,10 +22,14 @@ import space.space_spring.entity.TokenStorage; import space.space_spring.entity.User; import space.space_spring.entity.enumStatus.UserSignupType; +import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; +import space.space_spring.exception.jwt.unauthorized.JwtUnauthorizedTokenException; import java.util.Date; +import java.util.Optional; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.*; @DataJpaTest @@ -60,7 +64,7 @@ class JwtServiceTest { @Test @DisplayName("request의 refresh token이 유효한 토큰인 경우, 새로운 token pair를 발급하고 db의 token을 update 한다.") - void updateTokenPair() throws Exception { + void updateTokenPair1() throws Exception { //given User user = User.create("email", "password", "name", UserSignupType.LOCAL); User savedUser = userRepository.save(user); @@ -68,13 +72,13 @@ void updateTokenPair() throws Exception { Date now = new Date(); String accessToken = Jwts.builder() - .setExpiration(new Date(now.getTime())) // 현 시점부터 1시간 동안이 유효기간 + .setExpiration(new Date(now.getTime())) // 생성하자마자 유효기간 끝 .claim("userId", userId) .signWith(SignatureAlgorithm.HS256, "accessSecretKeyaccessSecretKeyaccessSecretKey") .compact(); String refreshToken = Jwts.builder() - .setExpiration(new Date(now.getTime() + 360000L)) // 생성하자마자 유효기간 끝 + .setExpiration(new Date(now.getTime() + 360000L)) // 현 시점부터 1시간 동안이 유효기간 .signWith(SignatureAlgorithm.HS256, "refreshSecretKeyrefreshSecretKeyrefreshSecretKey") .compact(); @@ -92,7 +96,6 @@ void updateTokenPair() throws Exception { String newAccessToken = tokenPairDTO.getAccessToken(); String newRefreshToken = tokenPairDTO.getRefreshToken(); - // 새로운 액세스 토큰 검증 Claims accessTokenClaims = Jwts.parser() .setSigningKey(jwtLoginProvider.getACCESS_SECRET_KEY()) .parseClaimsJws(newAccessToken) @@ -100,11 +103,93 @@ void updateTokenPair() throws Exception { assertThat(accessTokenClaims.get("userId", Long.class)).isEqualTo(userId); - // 토큰 저장소에 저장된 리프레시 토큰이 업데이트되었는지 확인 TokenStorage updatedTokenStorage = jwtRepository.findByUser(savedUser) .orElseThrow(() -> new Exception("TokenStorage not found")); assertThat(updatedTokenStorage.getTokenValue()).isEqualTo(newRefreshToken); + + System.out.println("old access token = " + accessToken); + System.out.println("new access token = " + newAccessToken); + System.out.println("old refresh token = " + refreshToken); + System.out.println("new refresh token = " + newRefreshToken); + + } + + @Test + @DisplayName("request의 refresh token의 유효기간이 지났을 경우, 에러를 발생시키고 db의 token을 지운다.") + void updateTokenPair2() throws Exception { + //given + User user = User.create("email", "password", "name", UserSignupType.LOCAL); + User savedUser = userRepository.save(user); + Long userId = savedUser.getUserId(); + + Date now = new Date(); + String accessToken = Jwts.builder() + .setExpiration(new Date(now.getTime())) // 생성하자마자 유효기간 끝 + .claim("userId", userId) + .signWith(SignatureAlgorithm.HS256, "accessSecretKeyaccessSecretKeyaccessSecretKey") + .compact(); + + String refreshToken = Jwts.builder() + .setExpiration(new Date(now.getTime())) // 생성하자마자 유효기간 끝 + .signWith(SignatureAlgorithm.HS256, "refreshSecretKeyrefreshSecretKeyrefreshSecretKey") + .compact(); + + TokenStorage tokenStorage = TokenStorage.create(savedUser, refreshToken); + jwtRepository.save(tokenStorage); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", JWT_TOKEN_PREFIX + accessToken); + request.addHeader("Authorization-refresh", JWT_TOKEN_PREFIX + refreshToken); + + //when //then + assertThatThrownBy(() -> jwtService.updateTokenPair(request)) + .isInstanceOf(JwtExpiredTokenException.class) + .hasMessage("만료된 refresh token 입니다. 다시 로그인해야합니다."); + + Optional byUser = jwtRepository.findByUser(user); + assertThat(byUser).isEmpty(); + } + + @Test + @DisplayName("request의 refresh token이 db에 저장된 token 값과 다를 경우, 에러를 발생시키고 db의 token을 지운다.") + void updateTokenPair3() throws Exception { + //given + User user = User.create("email", "password", "name", UserSignupType.LOCAL); + User savedUser = userRepository.save(user); + Long userId = savedUser.getUserId(); + + Date now = new Date(); + String accessToken = Jwts.builder() + .setExpiration(new Date(now.getTime())) // 생성하자마자 유효기간 끝 + .claim("userId", userId) + .signWith(SignatureAlgorithm.HS256, "accessSecretKeyaccessSecretKeyaccessSecretKey") + .compact(); + + String refreshToken = Jwts.builder() + .setExpiration(new Date(now.getTime() + 360000L)) // 현 시점부터 1시간 동안이 유효기간 + .signWith(SignatureAlgorithm.HS256, "refreshSecretKeyrefreshSecretKeyrefreshSecretKey") + .compact(); + + String anotherRefreshToken = "anotherRefreshToken"; + + TokenStorage tokenStorage = TokenStorage.create(savedUser, anotherRefreshToken); + jwtRepository.save(tokenStorage); + + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Authorization", JWT_TOKEN_PREFIX + accessToken); + request.addHeader("Authorization-refresh", JWT_TOKEN_PREFIX + refreshToken); + + //when //then + assertThatThrownBy(() -> jwtService.updateTokenPair(request)) + .isInstanceOf(JwtUnauthorizedTokenException.class) + .hasMessage("저장된 refresh token 과 전달받은 refresh token 이 일치하지 않습니다. 다시 로그인해야합니다."); + + Optional byUser = jwtRepository.findByUser(user); + assertThat(byUser).isEmpty(); + + System.out.println("refresh token = " + refreshToken); + System.out.println("another refresh token = " + anotherRefreshToken); } diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index cb798131..42c9af63 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -1,4 +1,8 @@ spring: + h2: + console: + enabled: true + path: /h2-console datasource: url: jdbc:h2:mem:~/space_spring driver-class-name: org.h2.Driver @@ -14,4 +18,8 @@ spring: sql: init: - mode: never # sql initialization 을 사용하지 않겠다 \ No newline at end of file + mode: never # sql initialization 을 사용하지 않겠다 + + +server: + port: 8080 \ No newline at end of file From 85ca82f603c0533cff2b019d570f65b7dbbbf7b1 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Tue, 10 Sep 2024 15:53:12 +0900 Subject: [PATCH 12/38] =?UTF-8?q?refactor:=20entity=EC=97=90=EC=84=9C=20re?= =?UTF-8?q?quest=20dto=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/space/space_spring/entity/ChatRoom.java | 8 ++------ .../space/space_spring/entity/document/ChatMessage.java | 9 ++++----- .../java/space/space_spring/service/ChatRoomService.java | 2 +- .../java/space/space_spring/service/ChattingService.java | 6 ++++-- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/space/space_spring/entity/ChatRoom.java b/src/main/java/space/space_spring/entity/ChatRoom.java index 0f3104da..57dd9c24 100644 --- a/src/main/java/space/space_spring/entity/ChatRoom.java +++ b/src/main/java/space/space_spring/entity/ChatRoom.java @@ -7,10 +7,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.hibernate.annotations.Comment; -import space.space_spring.dto.chat.request.CreateChatRoomRequest; - -import java.time.LocalDateTime; -import java.time.ZoneId; @Entity @Getter @@ -40,10 +36,10 @@ public class ChatRoom extends BaseEntity{ @Column(name = "chat_room_img") private String img; - public static ChatRoom of(Space space, CreateChatRoomRequest createChatRoomRequest, String chatRoomImgUrl) { + public static ChatRoom of(Space space, String chatRoomName, String chatRoomImgUrl) { return ChatRoom.builder() .space(space) - .name(createChatRoomRequest.getName()) + .name(chatRoomName) .img(chatRoomImgUrl) .build(); } diff --git a/src/main/java/space/space_spring/entity/document/ChatMessage.java b/src/main/java/space/space_spring/entity/document/ChatMessage.java index d55a8128..00643a0c 100644 --- a/src/main/java/space/space_spring/entity/document/ChatMessage.java +++ b/src/main/java/space/space_spring/entity/document/ChatMessage.java @@ -5,7 +5,6 @@ import org.springframework.data.annotation.Id; import org.springframework.data.annotation.TypeAlias; import org.springframework.data.mongodb.core.mapping.Document; -import space.space_spring.dto.chat.request.ChatMessageRequest; import space.space_spring.entity.enumStatus.ChatMessageType; import java.time.LocalDateTime; @@ -36,15 +35,15 @@ public class ChatMessage { private LocalDateTime createdAt; - public static ChatMessage of(ChatMessageRequest chatMessageRequest, Long chatRoomId, Long senderId, String senderName, String senderImg) { + public static ChatMessage of(HashMap content, Long chatRoomId, Long spaceId, Long senderId, String senderName, String senderImg, ChatMessageType messageType) { return ChatMessage.builder() - .content(chatMessageRequest.getContent()) + .content(content) .chatRoomId(chatRoomId) - .spaceId(chatMessageRequest.getSpaceId()) + .spaceId(spaceId) .senderId(senderId) .senderName(senderName) .senderImg(senderImg) - .messageType(chatMessageRequest.getMessageType()) + .messageType(messageType) .createdAt(LocalDateTime.now(ZoneId.of("Asia/Seoul"))) .build(); } diff --git a/src/main/java/space/space_spring/service/ChatRoomService.java b/src/main/java/space/space_spring/service/ChatRoomService.java index 3b3ccebc..cdf9a7e2 100644 --- a/src/main/java/space/space_spring/service/ChatRoomService.java +++ b/src/main/java/space/space_spring/service/ChatRoomService.java @@ -110,7 +110,7 @@ public CreateChatRoomResponse createChatRoom(Long userId, Long spaceId, CreateCh Space spaceBySpaceId = spaceUtils.findSpaceBySpaceId(spaceId); // TODO 3: chatRoom 생성 및 저장 - ChatRoom chatRoom = chatRoomDao.save(ChatRoom.of(spaceBySpaceId, createChatRoomRequest, chatRoomImgUrl)); + ChatRoom chatRoom = chatRoomDao.save(ChatRoom.of(spaceBySpaceId, createChatRoomRequest.getName(), chatRoomImgUrl)); // TODO 4: user_chatRoom 매핑 정보 저장 UserChatRoom userChatRoom = userChatRoomDao.save(UserChatRoom.of(chatRoom, userByUserId, LocalDateTime.now())); diff --git a/src/main/java/space/space_spring/service/ChattingService.java b/src/main/java/space/space_spring/service/ChattingService.java index 72b0e836..01f37b2f 100644 --- a/src/main/java/space/space_spring/service/ChattingService.java +++ b/src/main/java/space/space_spring/service/ChattingService.java @@ -58,11 +58,13 @@ public ChatMessageResponse sendChatMessage(Long senderId, ChatMessageRequest cha // TODO 4: DB에 메시지 저장 ChatMessage message = chattingDao.insert(ChatMessage.of( - chatMessageRequest, + chatMessageRequest.getContent(), chatRoomId, + chatMessageRequest.getSpaceId(), senderId, senderName, - senderProfileImg + senderProfileImg, + chatMessageRequest.getMessageType() )); return ChatMessageResponse.of(message); From e0c2acee2cefa6055a546dd8792048d758f249e0 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Tue, 10 Sep 2024 15:53:52 +0900 Subject: [PATCH 13/38] =?UTF-8?q?refactor:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20=EB=A9=94=EC=86=8C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/space/space_spring/dao/chat/ChatRoomDao.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/space/space_spring/dao/chat/ChatRoomDao.java b/src/main/java/space/space_spring/dao/chat/ChatRoomDao.java index 9c6ab523..e66f7798 100644 --- a/src/main/java/space/space_spring/dao/chat/ChatRoomDao.java +++ b/src/main/java/space/space_spring/dao/chat/ChatRoomDao.java @@ -4,11 +4,7 @@ import org.springframework.stereotype.Repository; import space.space_spring.dao.chat.custom.ChatRoomDaoCustom; import space.space_spring.entity.ChatRoom; -import space.space_spring.entity.Space; - -import java.util.List; @Repository public interface ChatRoomDao extends JpaRepository, ChatRoomDaoCustom { - List findBySpace(Space space); } From 553f03603ccb82ab9bc7eb85cf32f09c174ca963 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Tue, 10 Sep 2024 16:03:55 +0900 Subject: [PATCH 14/38] =?UTF-8?q?feat:=20repository=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=8F?= =?UTF-8?q?=20=EC=98=81=EC=86=8D=EC=84=B1=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../space/space_spring/entity/ChatRoom.java | 2 +- .../space_spring/entity/UserChatRoom.java | 2 +- .../repository/ChatRoomDaoTest.java | 102 ++++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 src/test/java/space/space_spring/repository/ChatRoomDaoTest.java diff --git a/src/main/java/space/space_spring/entity/ChatRoom.java b/src/main/java/space/space_spring/entity/ChatRoom.java index 57dd9c24..754d42df 100644 --- a/src/main/java/space/space_spring/entity/ChatRoom.java +++ b/src/main/java/space/space_spring/entity/ChatRoom.java @@ -23,7 +23,7 @@ public class ChatRoom extends BaseEntity{ private Long id; @Comment("채팅방이 속한 스페이스 ID") - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "space_id") private Space space; diff --git a/src/main/java/space/space_spring/entity/UserChatRoom.java b/src/main/java/space/space_spring/entity/UserChatRoom.java index 4b36bbfc..20ddb513 100644 --- a/src/main/java/space/space_spring/entity/UserChatRoom.java +++ b/src/main/java/space/space_spring/entity/UserChatRoom.java @@ -30,7 +30,7 @@ public class UserChatRoom extends BaseEntity{ private ChatRoom chatRoom; @Comment("사용자 ID") - @ManyToOne(fetch = FetchType.LAZY) + @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL) @JoinColumn(name = "user_id") private User user; diff --git a/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java b/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java new file mode 100644 index 00000000..d718f333 --- /dev/null +++ b/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java @@ -0,0 +1,102 @@ +package space.space_spring.repository; + +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import space.space_spring.config.QueryDslConfig; +import space.space_spring.dao.chat.ChatRoomDao; +import space.space_spring.dao.chat.UserChatRoomDao; +import space.space_spring.entity.ChatRoom; +import space.space_spring.entity.Space; +import space.space_spring.entity.User; +import space.space_spring.entity.UserChatRoom; +import space.space_spring.entity.enumStatus.UserSignupType; + +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.*; + +@DataJpaTest +@Import({QueryDslConfig.class, QueryDslConfig.class}) +public class ChatRoomDaoTest { + + @Autowired + private ChatRoomDao chatRoomDao; + + @Autowired + private UserChatRoomDao userChatRoomDao; + + private Space testSpace; + + private ChatRoom testChatRoom1; + + private ChatRoom testChatRoom2; + + private User testUser; + + @BeforeEach + void 테스트_셋업() { + testUser = new User(); + + testUser.saveUser("testUser@test.com", "Asdf1234!", "testUser", UserSignupType.LOCAL); + + testSpace = new Space(); + + // testSpace에 속한 채팅방 생성 + testChatRoom1 = ChatRoom.of(testSpace, "testChatRoom1", ""); + testChatRoom2 = ChatRoom.of(testSpace, "testChatRoom2", ""); + } + + @Test + @DisplayName("채팅방_저장_테스트") + void 채팅방_저장_테스트() { + // given + + // when + ChatRoom savedTestChatRoom1 = chatRoomDao.save(testChatRoom1); + ChatRoom savedTestChatRoom2 = chatRoomDao.save(testChatRoom2); + + // then + assertThat(savedTestChatRoom1.getName()).isEqualTo(testChatRoom1.getName()); + assertThat(savedTestChatRoom2.getName()).isEqualTo(testChatRoom2.getName()); + } + + @Test + @DisplayName("id로_채팅방_조회_테스트") + void id로_채팅방_조회_테스트() { + // given + ChatRoom savedTestChatRoom1 = chatRoomDao.save(testChatRoom1); + ChatRoom savedTestChatRoom2 = chatRoomDao.save(testChatRoom2); + Long testChatRoom1Id = savedTestChatRoom1.getId(); + Long testChatRoom2Id = savedTestChatRoom2.getId(); + + // when + Optional chatRoom1byId = chatRoomDao.findById(testChatRoom1Id); + Optional chatRoom2byId = chatRoomDao.findById(testChatRoom2Id); + + // then + chatRoom1byId.ifPresent(chatRoom -> assertThat(chatRoom.getId()).isEqualTo(testChatRoom1Id)); + chatRoom2byId.ifPresent(chatRoom -> assertThat(chatRoom.getId()).isEqualTo(testChatRoom2Id)); + } + + @Test + @DisplayName("유저와_스페이스로_채팅방_조회_테스트") + void 유저와_스페이스로_채팅방_조회_테스트() { + // given + ChatRoom savedTestChatRoom1 = chatRoomDao.save(testChatRoom1); + ChatRoom savedTestChatRoom2 = chatRoomDao.save(testChatRoom2); + UserChatRoom userChatRoom1 = UserChatRoom.of(savedTestChatRoom1, testUser, LocalDateTime.now()); + UserChatRoom userChatRoom2 = UserChatRoom.of(savedTestChatRoom2, testUser, LocalDateTime.now()); + userChatRoomDao.save(userChatRoom1); + userChatRoomDao.save(userChatRoom2); + + // when + List chatRoomListByUser = chatRoomDao.findByUserAndSpace(testUser, testSpace); + + // then + assertThat(chatRoomListByUser.size()).isEqualTo(2); + } +} From bdd63978078807fca5cf90ad08a487c69315725c Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Tue, 10 Sep 2024 17:11:32 +0900 Subject: [PATCH 15/38] =?UTF-8?q?refactor:=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=8C=80=EC=83=81=20name=20->=20id=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/space/space_spring/repository/ChatRoomDaoTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java b/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java index d718f333..1a02b7c6 100644 --- a/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java +++ b/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java @@ -45,7 +45,7 @@ public class ChatRoomDaoTest { testSpace = new Space(); - // testSpace에 속한 채팅방 생성 + // testSpace에 속한 chatRoom 엔티티 생성 testChatRoom1 = ChatRoom.of(testSpace, "testChatRoom1", ""); testChatRoom2 = ChatRoom.of(testSpace, "testChatRoom2", ""); } @@ -60,8 +60,8 @@ public class ChatRoomDaoTest { ChatRoom savedTestChatRoom2 = chatRoomDao.save(testChatRoom2); // then - assertThat(savedTestChatRoom1.getName()).isEqualTo(testChatRoom1.getName()); - assertThat(savedTestChatRoom2.getName()).isEqualTo(testChatRoom2.getName()); + assertThat(savedTestChatRoom1.getId()).isEqualTo(testChatRoom1.getId()); + assertThat(savedTestChatRoom2.getId()).isEqualTo(testChatRoom2.getId()); } @Test From 28809905d98b32701ce391df6fb07e35c9d95ab8 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Tue, 10 Sep 2024 17:24:42 +0900 Subject: [PATCH 16/38] =?UTF-8?q?feat:=20UserChatRoomDao=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/UserChatRoomDaoTest.java | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 src/test/java/space/space_spring/repository/UserChatRoomDaoTest.java diff --git a/src/test/java/space/space_spring/repository/UserChatRoomDaoTest.java b/src/test/java/space/space_spring/repository/UserChatRoomDaoTest.java new file mode 100644 index 00000000..3d3ddad1 --- /dev/null +++ b/src/test/java/space/space_spring/repository/UserChatRoomDaoTest.java @@ -0,0 +1,107 @@ +package space.space_spring.repository; + +import org.junit.jupiter.api.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; +import space.space_spring.config.QueryDslConfig; +import space.space_spring.dao.chat.ChatRoomDao; +import space.space_spring.dao.chat.UserChatRoomDao; +import space.space_spring.entity.ChatRoom; +import space.space_spring.entity.Space; +import space.space_spring.entity.User; +import space.space_spring.entity.UserChatRoom; +import space.space_spring.entity.enumStatus.UserSignupType; + +import java.time.LocalDateTime; +import java.util.List; + +import static org.assertj.core.api.Assertions.*; + +@DataJpaTest +@Import({QueryDslConfig.class, QueryDslConfig.class}) +@TestMethodOrder(value = MethodOrderer.OrderAnnotation.class) +public class UserChatRoomDaoTest { + + @Autowired + private UserChatRoomDao userChatRoomDao; + + @Autowired + private ChatRoomDao chatRoomDao; + + private User testUser1; + + private User testUser2; + + private UserChatRoom testUserChatRoom1; + + private UserChatRoom testUserChatRoom2; + + private ChatRoom testChatRoom; + + @BeforeEach + void 테스트_셋업() { + testUser1 = new User(); + testUser2 = new User(); + + testUser1.saveUser("testUser1@test.com", "Asdf1234!", "testUser1", UserSignupType.LOCAL); + testUser2.saveUser("testUser2@test.com", "Asdf1234!", "testUser2", UserSignupType.LOCAL); + + Space testSpace = new Space(); + + // testSpace에 속한 채팅방 생성 및 저장 + testChatRoom = ChatRoom.of(testSpace, "testChatRoom", ""); + chatRoomDao.save(testChatRoom); + + // testChatRoom에 대한 testUserChatRoom 엔티티 생성 + testUserChatRoom1 = UserChatRoom.of(testChatRoom, testUser1, LocalDateTime.now()); + testUserChatRoom2 = UserChatRoom.of(testChatRoom, testUser2, LocalDateTime.now()); + } + + @Test + @DisplayName("유저채팅방_저장_테스트") + void 유저채팅방_저장_테스트() { + // given + + // when + UserChatRoom savedTestUserChatRoom1 = userChatRoomDao.save(testUserChatRoom1); + UserChatRoom savedTestUserChatRoom2 = userChatRoomDao.save(testUserChatRoom2); + + // then + assertThat(savedTestUserChatRoom1.getId()).isEqualTo(testUserChatRoom1.getId()); + assertThat(savedTestUserChatRoom2.getId()).isEqualTo(testUserChatRoom2.getId()); + + assertThat(savedTestUserChatRoom1.getUser().getUserId()).isEqualTo(testUser1.getUserId()); + assertThat(savedTestUserChatRoom2.getUser().getUserId()).isEqualTo(testUser2.getUserId()); + } + + @Test + @DisplayName("채팅방으로_유저채팅방_조회_테스트") + void 채팅방으로_유저채팅방_저장_테스트() { + // given + userChatRoomDao.save(testUserChatRoom1); + userChatRoomDao.save(testUserChatRoom2); + + // when + List userChatRoomList = userChatRoomDao.findByChatRoom(testChatRoom); + + // then + assertThat(userChatRoomList.size()).isEqualTo(2); + } + + @Test + @DisplayName("유저와_채팅방으로_유저채팅방_저장_테스트") + void 유저와_채팅방으로_유저채팅방_저장_테스트() { + // given + userChatRoomDao.save(testUserChatRoom1); + userChatRoomDao.save(testUserChatRoom2); + + // when + UserChatRoom userChatRoom1 = userChatRoomDao.findByUserAndChatRoom(testUser1, testChatRoom); + UserChatRoom userChatRoom2 = userChatRoomDao.findByUserAndChatRoom(testUser2, testChatRoom); + + // then + assertThat(userChatRoom1.getId()).isEqualTo(testUserChatRoom1.getId()); + assertThat(userChatRoom2.getId()).isEqualTo(testUserChatRoom2.getId()); + } +} From 2b0c13313c569384704a9bd40ec57d94b34f3cd3 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Wed, 11 Sep 2024 13:43:14 +0900 Subject: [PATCH 17/38] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=B3=80=EC=88=98=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../space/space_spring/repository/ChatRoomDaoTest.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java b/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java index 1a02b7c6..4748b831 100644 --- a/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java +++ b/src/test/java/space/space_spring/repository/ChatRoomDaoTest.java @@ -70,16 +70,14 @@ public class ChatRoomDaoTest { // given ChatRoom savedTestChatRoom1 = chatRoomDao.save(testChatRoom1); ChatRoom savedTestChatRoom2 = chatRoomDao.save(testChatRoom2); - Long testChatRoom1Id = savedTestChatRoom1.getId(); - Long testChatRoom2Id = savedTestChatRoom2.getId(); // when - Optional chatRoom1byId = chatRoomDao.findById(testChatRoom1Id); - Optional chatRoom2byId = chatRoomDao.findById(testChatRoom2Id); + Optional chatRoom1byId = chatRoomDao.findById(savedTestChatRoom1.getId()); + Optional chatRoom2byId = chatRoomDao.findById(savedTestChatRoom2.getId()); // then - chatRoom1byId.ifPresent(chatRoom -> assertThat(chatRoom.getId()).isEqualTo(testChatRoom1Id)); - chatRoom2byId.ifPresent(chatRoom -> assertThat(chatRoom.getId()).isEqualTo(testChatRoom2Id)); + chatRoom1byId.ifPresent(chatRoom -> assertThat(chatRoom.getId()).isEqualTo(savedTestChatRoom1.getId())); + chatRoom2byId.ifPresent(chatRoom -> assertThat(chatRoom.getId()).isEqualTo(savedTestChatRoom2.getId())); } @Test From 7aba3e0b54d1a9370ab2991ab6d96a838c67ba10 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Wed, 11 Sep 2024 13:44:14 +0900 Subject: [PATCH 18/38] =?UTF-8?q?fix:=20=EC=B1=84=ED=8C=85=EB=B0=A9=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=EC=8B=9C=20=EB=A9=A4=EB=B2=84=20=EA=B0=81?= =?UTF-8?q?=EA=B0=81=EC=97=90=20=EB=8C=80=ED=95=9C=20userChatRoom=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/space/space_spring/service/ChatRoomService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/space/space_spring/service/ChatRoomService.java b/src/main/java/space/space_spring/service/ChatRoomService.java index cdf9a7e2..831a421c 100644 --- a/src/main/java/space/space_spring/service/ChatRoomService.java +++ b/src/main/java/space/space_spring/service/ChatRoomService.java @@ -113,7 +113,11 @@ public CreateChatRoomResponse createChatRoom(Long userId, Long spaceId, CreateCh ChatRoom chatRoom = chatRoomDao.save(ChatRoom.of(spaceBySpaceId, createChatRoomRequest.getName(), chatRoomImgUrl)); // TODO 4: user_chatRoom 매핑 정보 저장 - UserChatRoom userChatRoom = userChatRoomDao.save(UserChatRoom.of(chatRoom, userByUserId, LocalDateTime.now())); + userChatRoomDao.save(UserChatRoom.of(chatRoom, userByUserId, LocalDateTime.now())); + for (Long id : createChatRoomRequest.getMemberList()) { + User user = userUtils.findUserByUserId(id); + userChatRoomDao.save(UserChatRoom.of(chatRoom, user, LocalDateTime.now())); + } // TODO 5: chatroom id 반환 return CreateChatRoomResponse.of(chatRoom.getId()); From e9267b80cf0b6bc544b9be0a767e4628d204cc91 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Thu, 12 Sep 2024 14:38:22 +0900 Subject: [PATCH 19/38] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=ED=8C=8C=EB=9D=BC=EB=AF=B8=ED=84=B0=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/space/space_spring/controller/ChatRoomController.java | 2 +- src/main/java/space/space_spring/service/ChatRoomService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/space/space_spring/controller/ChatRoomController.java b/src/main/java/space/space_spring/controller/ChatRoomController.java index aeccf610..9434092e 100644 --- a/src/main/java/space/space_spring/controller/ChatRoomController.java +++ b/src/main/java/space/space_spring/controller/ChatRoomController.java @@ -71,7 +71,7 @@ public BaseResponse updateLastReadTime( @JwtLoginAuth Long userId, @PathVariable Long spaceId, @PathVariable Long chatRoomId) { - return new BaseResponse<>(chatRoomService.updateLastReadTime(userId, spaceId, chatRoomId)); + return new BaseResponse<>(chatRoomService.updateLastReadTime(userId, chatRoomId)); } /** diff --git a/src/main/java/space/space_spring/service/ChatRoomService.java b/src/main/java/space/space_spring/service/ChatRoomService.java index 831a421c..24b17393 100644 --- a/src/main/java/space/space_spring/service/ChatRoomService.java +++ b/src/main/java/space/space_spring/service/ChatRoomService.java @@ -156,7 +156,7 @@ public ReadChatRoomMemberResponse readChatRoomMembers(Long spaceId, Long chatRoo } @Transactional - public ChatSuccessResponse updateLastReadTime(Long userId, Long spaceId, Long chatRoomId) { + public ChatSuccessResponse updateLastReadTime(Long userId, Long chatRoomId) { User userByUserId = userUtils.findUserByUserId(userId); ChatRoom chatRoomByChatRoomId = chatRoomDao.findById(chatRoomId) .orElseThrow(() -> new CustomException(CHATROOM_NOT_EXIST)); From 83d30271b43f221f4f7ee194f3e7cdfcba25c5e0 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Thu, 12 Sep 2024 14:51:34 +0900 Subject: [PATCH 20/38] =?UTF-8?q?feat:=20ChatRoomService=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ChatRoomServiceTest.java | 326 ++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 src/test/java/space/space_spring/service/ChatRoomServiceTest.java diff --git a/src/test/java/space/space_spring/service/ChatRoomServiceTest.java b/src/test/java/space/space_spring/service/ChatRoomServiceTest.java new file mode 100644 index 00000000..ff3b8ac5 --- /dev/null +++ b/src/test/java/space/space_spring/service/ChatRoomServiceTest.java @@ -0,0 +1,326 @@ +package space.space_spring.service; + +import org.junit.jupiter.api.*; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.util.ReflectionTestUtils; +import space.space_spring.dao.UserSpaceDao; +import space.space_spring.dao.chat.ChatRoomDao; +import space.space_spring.dao.chat.ChattingDao; +import space.space_spring.dao.chat.UserChatRoomDao; +import space.space_spring.dto.chat.request.CreateChatRoomRequest; +import space.space_spring.dto.chat.request.JoinChatRoomRequest; +import space.space_spring.dto.chat.response.ChatSuccessResponse; +import space.space_spring.dto.chat.response.CreateChatRoomResponse; +import space.space_spring.dto.chat.response.ReadChatRoomMemberResponse; +import space.space_spring.dto.chat.response.ReadChatRoomResponse; +import space.space_spring.entity.*; +import space.space_spring.entity.enumStatus.UserSignupType; +import space.space_spring.entity.enumStatus.UserSpaceAuth; +import space.space_spring.util.space.SpaceUtils; +import space.space_spring.util.user.UserUtils; + +import java.nio.charset.StandardCharsets; +import java.time.LocalDateTime; +import java.util.List; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class ChatRoomServiceTest { + + @InjectMocks + private ChatRoomService chatRoomService; + + @Mock + private ChatRoomDao chatRoomDao; + + @Mock + private UserUtils userUtils; + + @Mock + private SpaceUtils spaceUtils; + + @Mock + private UserSpaceDao userSpaceDao; + + @Mock + private ChattingDao chattingDao; + + @Mock + private UserChatRoomDao userChatRoomDao; + + private User user1; + + private User user2; + + private User user3; + + private Space testSpace; + + private UserSpace testUserSpace1; + + private UserSpace testUserSpace2; + + private UserSpace testUserSpace3; + + private ChatRoom chatRoom1; + + private ChatRoom chatRoom2; + + private UserChatRoom userChatRoom1; + + private UserChatRoom userChatRoom2; + + private UserChatRoom userChatRoom1ByUser2; + + private UserChatRoom userChatRoom1ByUser3; + + private CreateChatRoomRequest createChatRoomRequest1; + + private CreateChatRoomRequest createChatRoomRequest2; + + private JoinChatRoomRequest joinChatRoomRequest; + + @BeforeEach + void 채팅방_테스트_설정() { + /** + * <관리자인 user1은 chatRoom1, chatRoom2 생성> + * + */ + user1 = new User(); + user1.saveUser("user1@test.com", "Asdf1234!", "user1", UserSignupType.LOCAL); + ReflectionTestUtils.setField(user1, "userId", 0L); + lenient().when(userUtils.findUserByUserId(0L)).thenReturn(user1); + + user2 = new User(); + user2.saveUser("user2@test.com", "Asdf1234!", "user2", UserSignupType.LOCAL); + ReflectionTestUtils.setField(user2, "userId", 1L); + lenient().when(userUtils.findUserByUserId(1L)).thenReturn(user2); + + user3 = new User(); + user3.saveUser("user3@test.com", "Asdf1234!", "user3", UserSignupType.LOCAL); + ReflectionTestUtils.setField(user3, "userId", 2L); + lenient().when(userUtils.findUserByUserId(2L)).thenReturn(user3); + + testSpace = new Space(); + testSpace.saveSpace("testSpace", ""); + ReflectionTestUtils.setField(testSpace, "spaceId", 0L); + lenient().when(spaceUtils.findSpaceBySpaceId(0L)).thenReturn(testSpace); + + testUserSpace1 = new UserSpace(); + testUserSpace2 = new UserSpace(); + testUserSpace3 = new UserSpace(); + testUserSpace1.createUserSpace(user1, testSpace, UserSpaceAuth.MANAGER); + testUserSpace2.createUserSpace(user2, testSpace, UserSpaceAuth.NORMAL); + testUserSpace3.createUserSpace(user3, testSpace, UserSpaceAuth.NORMAL); + + lenient().when(chatRoomDao.save(any(ChatRoom.class))).thenAnswer(invocationOnMock -> { + ChatRoom savedChatRoom = invocationOnMock.getArgument(0); + if ("chatRoom1".equals(savedChatRoom.getName())) { + chatRoom1 = savedChatRoom; + ReflectionTestUtils.setField(chatRoom1, "id", 0L); + ReflectionTestUtils.setField(chatRoom1, "status", "ACTIVE"); + ReflectionTestUtils.setField(chatRoom1, "createdAt", LocalDateTime.now()); + return chatRoom1; + } else if ("chatRoom2".equals(savedChatRoom.getName())) { + chatRoom2 = savedChatRoom; + ReflectionTestUtils.setField(chatRoom2, "id", 1L); + ReflectionTestUtils.setField(chatRoom2, "status", "ACTIVE"); + ReflectionTestUtils.setField(chatRoom2, "createdAt", LocalDateTime.now()); + return chatRoom2; + } + return null; + }); + + // chatRoom1, chatRoom2 생성 시 사용할 request + MockMultipartFile mockImgFile = new MockMultipartFile("mockImgFile", "test.png", "png", "test file".getBytes(StandardCharsets.UTF_8) ); + createChatRoomRequest1 = new CreateChatRoomRequest(); + createChatRoomRequest1.setName("chatRoom1"); + createChatRoomRequest1.setImg(mockImgFile); + createChatRoomRequest1.setMemberList(List.of(1L)); + + createChatRoomRequest2 = new CreateChatRoomRequest(); + createChatRoomRequest2.setName("chatRoom2"); + createChatRoomRequest2.setImg(mockImgFile); + createChatRoomRequest2.setMemberList(List.of()); + + // user3 초대 시 사용할 request + joinChatRoomRequest = new JoinChatRoomRequest(); + ReflectionTestUtils.setField(joinChatRoomRequest, "memberList", List.of(2L)); + + lenient().when(userChatRoomDao.save(any(UserChatRoom.class))).thenAnswer(invocationOnMock -> { + UserChatRoom savedChatRoom = invocationOnMock.getArgument(0); + if ("chatRoom1".equals(savedChatRoom.getChatRoom().getName())) { + if ("user1".equals(savedChatRoom.getUser().getUserName())) { + userChatRoom1 = savedChatRoom; + ReflectionTestUtils.setField(userChatRoom1, "id", 0L); + ReflectionTestUtils.setField(userChatRoom1, "status", "ACTIVE"); + ReflectionTestUtils.setField(userChatRoom1, "createdAt", LocalDateTime.now()); + return userChatRoom1; + } else if ("user2".equals(savedChatRoom.getUser().getUserName())) { + userChatRoom1ByUser2 = savedChatRoom; + ReflectionTestUtils.setField(userChatRoom1ByUser2, "id", 1L); + ReflectionTestUtils.setField(userChatRoom1ByUser2, "status", "ACTIVE"); + ReflectionTestUtils.setField(userChatRoom1ByUser2, "createdAt", LocalDateTime.now()); + return userChatRoom1ByUser2; + } else { + userChatRoom1ByUser3 = savedChatRoom; + ReflectionTestUtils.setField(userChatRoom1ByUser3, "id", 2L); + ReflectionTestUtils.setField(userChatRoom1ByUser3, "status", "ACTIVE"); + ReflectionTestUtils.setField(userChatRoom1ByUser3, "createdAt", LocalDateTime.now()); + return userChatRoom1ByUser3; + } + } else if ("chatRoom2".equals(savedChatRoom.getChatRoom().getName())) { + userChatRoom2 = savedChatRoom; + ReflectionTestUtils.setField(userChatRoom2, "id", 3L); + ReflectionTestUtils.setField(userChatRoom2, "status", "ACTIVE"); + ReflectionTestUtils.setField(userChatRoom2, "createdAt", LocalDateTime.now()); + return userChatRoom2; + } + return null; + }); + } + + @Test + @DisplayName("특정_스페이스_내의_채팅방_생성_테스트") + void 특정_스페이스_내의_채팅방_생성_테스트() { + // given + + // when + CreateChatRoomResponse createdChatRoom1 = chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); + CreateChatRoomResponse createdChatRoom2 = chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest2, ""); + + // then + assertThat(createdChatRoom1.getChatRoomId()).isEqualTo(0L); + assertThat(createdChatRoom2.getChatRoomId()).isEqualTo(1L); + } + + @Test + @DisplayName("특정_스페이스_내의_전체_채팅방_조회_테스트") + void 특정_스페이스_내의_전체_채팅방_조회_테스트() { + // given + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest2, ""); + + lenient().when(chattingDao.findTopByChatRoomIdOrderByCreatedAtDesc(chatRoom1.getId())).thenReturn(null); // 마지막 메시지가 없다고 가정 + lenient().when(chattingDao.countByChatRoomIdAndCreatedAtBetween(chatRoom1.getId(), LocalDateTime.now(), LocalDateTime.now())).thenReturn(0); + when(chatRoomDao.findByUserAndSpace(user1, testSpace)).thenReturn(List.of(chatRoom1, chatRoom2)); + when(userChatRoomDao.findByUserAndChatRoom(user1, chatRoom1)).thenReturn(userChatRoom1); + + lenient().when(chattingDao.findTopByChatRoomIdOrderByCreatedAtDesc(chatRoom2.getId())).thenReturn(null); // 마지막 메시지가 없다고 가정 + lenient().when(chattingDao.countByChatRoomIdAndCreatedAtBetween(chatRoom2.getId(), LocalDateTime.now(), LocalDateTime.now())).thenReturn(0); + when(userChatRoomDao.findByUserAndChatRoom(user1, chatRoom2)).thenReturn(userChatRoom2); + + // when + ReadChatRoomResponse readChatRoomResponse = chatRoomService.readChatRooms(user1.getUserId(), testSpace.getSpaceId()); + + // then + assertThat(readChatRoomResponse.getChatRoomList().size()).isEqualTo(2); + } + + @Test + @DisplayName("특정_채팅방의_전체_멤버_조회_테스트") + void 특정_채팅방의_전체_멤버_조회_테스트() { + // given + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest2, ""); + + when(chatRoomDao.findById(chatRoom1.getId())).thenReturn(Optional.ofNullable(chatRoom1)); + when(userChatRoomDao.findByChatRoom(chatRoom1)).thenReturn(List.of(userChatRoom1, userChatRoom1ByUser2)); + when(userSpaceDao.findUserSpaceByUserAndSpace(user1, testSpace)).thenReturn(Optional.ofNullable(testUserSpace1)); + + when(chatRoomDao.findById(chatRoom2.getId())).thenReturn(Optional.ofNullable(chatRoom2)); + when(userChatRoomDao.findByChatRoom(chatRoom2)).thenReturn(List.of(userChatRoom2)); + when(userSpaceDao.findUserSpaceByUserAndSpace(user2, testSpace)).thenReturn(Optional.ofNullable(testUserSpace2)); + + // when + ReadChatRoomMemberResponse readChatRoomMemberResponse1 = chatRoomService.readChatRoomMembers(testSpace.getSpaceId(), chatRoom1.getId()); + ReadChatRoomMemberResponse readChatRoomMemberResponse2 = chatRoomService.readChatRoomMembers(testSpace.getSpaceId(), chatRoom2.getId()); + + // then + assertThat(readChatRoomMemberResponse1.getUserList().size()).isEqualTo(2); + assertThat(readChatRoomMemberResponse1.getUserList().get(0).getUserId()).isEqualTo(0L); + assertThat(readChatRoomMemberResponse1.getUserList().get(1).getUserId()).isEqualTo(1L); + assertThat(readChatRoomMemberResponse2.getUserList().size()).isEqualTo(1); + assertThat(readChatRoomMemberResponse2.getUserList().get(0).getUserId()).isEqualTo(0L); + } + + @Test + @DisplayName("특정_채팅방으로의_멤버_초대_테스트") + void 특정_채팅방으로의_멤버_초대_테스트() { + // given + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); + when(chatRoomDao.findById(chatRoom1.getId())).thenReturn(Optional.ofNullable(chatRoom1)); + when(userChatRoomDao.findByChatRoom(chatRoom1)).thenReturn(List.of(userChatRoom1, userChatRoom1ByUser2)); + + // when + ChatSuccessResponse chatSuccessResponse = chatRoomService.joinChatRoom(chatRoom1.getId(), joinChatRoomRequest); + + // then + assertThat(chatSuccessResponse.isSuccess()).isEqualTo(true); + } + + @Test + @DisplayName("특정_채팅방에서_특정_유저가_마지막으로_읽은_시간_수정_테스트") + void 특정_채팅방에서_특정_유저가_마지막으로_읽은_시간_수정_테스트() { + // given + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); + when(chatRoomDao.findById(chatRoom1.getId())).thenReturn(Optional.ofNullable(chatRoom1)); + when(userChatRoomDao.findByUserAndChatRoom(user1, chatRoom1)).thenReturn(userChatRoom1); + + // when + ChatSuccessResponse chatSuccessResponse = chatRoomService.updateLastReadTime(user1.getUserId(), chatRoom1.getId()); + + // then + assertThat(chatSuccessResponse.isSuccess()).isEqualTo(true); + } + + @Test + @DisplayName("특정_채팅방_이름_수정_테스트") + void 특정_채팅방_이름_수정_테스트() { + // given + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); + when(chatRoomDao.findById(chatRoom1.getId())).thenReturn(Optional.ofNullable(chatRoom1)); + + // when + ChatSuccessResponse chatSuccessResponse = chatRoomService.modifyChatRoomName(chatRoom1.getId(), "newChatRoom1"); + + // then + assertThat(chatSuccessResponse.isSuccess()).isEqualTo(true); + } + + @Test + @DisplayName("특정_채팅방_나가기_테스트") + void 특정_채팅방_나가기_테스트() { + // given + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); + when(chatRoomDao.findById(chatRoom1.getId())).thenReturn(Optional.ofNullable(chatRoom1)); + when(userChatRoomDao.findByUserAndChatRoom(user2, chatRoom1)).thenReturn(userChatRoom1ByUser2); + + // when + ChatSuccessResponse chatSuccessResponse = chatRoomService.exitChatRoom(user2.getUserId(), chatRoom1.getId()); + + // then + assertThat(chatSuccessResponse.isSuccess()).isEqualTo(true); + } + + @Test + @DisplayName("특정_채팅방_삭제_테스트") + void 특정_채팅방_삭제_테스트() { + // given + chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); + when(chatRoomDao.findById(chatRoom1.getId())).thenReturn(Optional.ofNullable(chatRoom1)); + + // when + ChatSuccessResponse chatSuccessResponse = chatRoomService.deleteChatRoom(chatRoom1.getId()); + + // then + assertThat(chatSuccessResponse.isSuccess()).isEqualTo(true); + } +} From cc8da46fa312e9a206c9ccef0c4ef6e7f3dc2135 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Thu, 12 Sep 2024 15:47:33 +0900 Subject: [PATCH 21/38] =?UTF-8?q?refactor:=20=ED=97=AC=ED=8D=BC=20?= =?UTF-8?q?=EB=A9=94=EC=86=8C=EB=93=9C=EB=A5=BC=20=ED=86=B5=ED=95=9C=20?= =?UTF-8?q?=EC=B1=85=EC=9E=84=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/ChatRoomServiceTest.java | 100 ++++++++++-------- 1 file changed, 56 insertions(+), 44 deletions(-) diff --git a/src/test/java/space/space_spring/service/ChatRoomServiceTest.java b/src/test/java/space/space_spring/service/ChatRoomServiceTest.java index ff3b8ac5..6b39b9f8 100644 --- a/src/test/java/space/space_spring/service/ChatRoomServiceTest.java +++ b/src/test/java/space/space_spring/service/ChatRoomServiceTest.java @@ -25,6 +25,7 @@ import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; +import java.time.ZoneId; import java.util.List; import java.util.Optional; @@ -87,26 +88,17 @@ class ChatRoomServiceTest { private JoinChatRoomRequest joinChatRoomRequest; + private LocalDateTime mockTime; + @BeforeEach void 채팅방_테스트_설정() { /** * <관리자인 user1은 chatRoom1, chatRoom2 생성> * */ - user1 = new User(); - user1.saveUser("user1@test.com", "Asdf1234!", "user1", UserSignupType.LOCAL); - ReflectionTestUtils.setField(user1, "userId", 0L); - lenient().when(userUtils.findUserByUserId(0L)).thenReturn(user1); - - user2 = new User(); - user2.saveUser("user2@test.com", "Asdf1234!", "user2", UserSignupType.LOCAL); - ReflectionTestUtils.setField(user2, "userId", 1L); - lenient().when(userUtils.findUserByUserId(1L)).thenReturn(user2); - - user3 = new User(); - user3.saveUser("user3@test.com", "Asdf1234!", "user3", UserSignupType.LOCAL); - ReflectionTestUtils.setField(user3, "userId", 2L); - lenient().when(userUtils.findUserByUserId(2L)).thenReturn(user3); + user1 = createUser("user1@test.com", 0L); + user2 = createUser("user2@test.com", 1L); + user3 = createUser("user3@test.com", 2L); testSpace = new Space(); testSpace.saveSpace("testSpace", ""); @@ -116,23 +108,19 @@ class ChatRoomServiceTest { testUserSpace1 = new UserSpace(); testUserSpace2 = new UserSpace(); testUserSpace3 = new UserSpace(); - testUserSpace1.createUserSpace(user1, testSpace, UserSpaceAuth.MANAGER); - testUserSpace2.createUserSpace(user2, testSpace, UserSpaceAuth.NORMAL); + testUserSpace1.createUserSpace(this.user1, testSpace, UserSpaceAuth.MANAGER); + testUserSpace2.createUserSpace(this.user2, testSpace, UserSpaceAuth.NORMAL); testUserSpace3.createUserSpace(user3, testSpace, UserSpaceAuth.NORMAL); + mockTime = LocalDateTime.now(); + lenient().when(chatRoomDao.save(any(ChatRoom.class))).thenAnswer(invocationOnMock -> { ChatRoom savedChatRoom = invocationOnMock.getArgument(0); if ("chatRoom1".equals(savedChatRoom.getName())) { - chatRoom1 = savedChatRoom; - ReflectionTestUtils.setField(chatRoom1, "id", 0L); - ReflectionTestUtils.setField(chatRoom1, "status", "ACTIVE"); - ReflectionTestUtils.setField(chatRoom1, "createdAt", LocalDateTime.now()); + chatRoom1 = createChatRoom("chatRoom1", 0L); return chatRoom1; } else if ("chatRoom2".equals(savedChatRoom.getName())) { - chatRoom2 = savedChatRoom; - ReflectionTestUtils.setField(chatRoom2, "id", 1L); - ReflectionTestUtils.setField(chatRoom2, "status", "ACTIVE"); - ReflectionTestUtils.setField(chatRoom2, "createdAt", LocalDateTime.now()); + chatRoom2 = createChatRoom("chatRoom2", 1L); return chatRoom2; } return null; @@ -158,29 +146,17 @@ class ChatRoomServiceTest { UserChatRoom savedChatRoom = invocationOnMock.getArgument(0); if ("chatRoom1".equals(savedChatRoom.getChatRoom().getName())) { if ("user1".equals(savedChatRoom.getUser().getUserName())) { - userChatRoom1 = savedChatRoom; - ReflectionTestUtils.setField(userChatRoom1, "id", 0L); - ReflectionTestUtils.setField(userChatRoom1, "status", "ACTIVE"); - ReflectionTestUtils.setField(userChatRoom1, "createdAt", LocalDateTime.now()); + userChatRoom1 = createUserChatRoom(0L, chatRoom1, user1); return userChatRoom1; } else if ("user2".equals(savedChatRoom.getUser().getUserName())) { - userChatRoom1ByUser2 = savedChatRoom; - ReflectionTestUtils.setField(userChatRoom1ByUser2, "id", 1L); - ReflectionTestUtils.setField(userChatRoom1ByUser2, "status", "ACTIVE"); - ReflectionTestUtils.setField(userChatRoom1ByUser2, "createdAt", LocalDateTime.now()); + userChatRoom1ByUser2 = createUserChatRoom(1L, chatRoom1, user2); return userChatRoom1ByUser2; } else { - userChatRoom1ByUser3 = savedChatRoom; - ReflectionTestUtils.setField(userChatRoom1ByUser3, "id", 2L); - ReflectionTestUtils.setField(userChatRoom1ByUser3, "status", "ACTIVE"); - ReflectionTestUtils.setField(userChatRoom1ByUser3, "createdAt", LocalDateTime.now()); + userChatRoom1ByUser3 = createUserChatRoom(2L, chatRoom1, user3); return userChatRoom1ByUser3; } } else if ("chatRoom2".equals(savedChatRoom.getChatRoom().getName())) { - userChatRoom2 = savedChatRoom; - ReflectionTestUtils.setField(userChatRoom2, "id", 3L); - ReflectionTestUtils.setField(userChatRoom2, "status", "ACTIVE"); - ReflectionTestUtils.setField(userChatRoom2, "createdAt", LocalDateTime.now()); + userChatRoom2 = createUserChatRoom(3L, chatRoom2, user1); return userChatRoom2; } return null; @@ -208,13 +184,13 @@ class ChatRoomServiceTest { chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest1, ""); chatRoomService.createChatRoom(user1.getUserId(), testSpace.getSpaceId(), createChatRoomRequest2, ""); - lenient().when(chattingDao.findTopByChatRoomIdOrderByCreatedAtDesc(chatRoom1.getId())).thenReturn(null); // 마지막 메시지가 없다고 가정 - lenient().when(chattingDao.countByChatRoomIdAndCreatedAtBetween(chatRoom1.getId(), LocalDateTime.now(), LocalDateTime.now())).thenReturn(0); + when(chattingDao.findTopByChatRoomIdOrderByCreatedAtDesc(chatRoom1.getId())).thenReturn(null); // 마지막 메시지가 없다고 가정 + when(chattingDao.countByChatRoomIdAndCreatedAtBetween(chatRoom1.getId(), convertToKoreaTime(mockTime), convertToKoreaTime(mockTime))).thenReturn(0); when(chatRoomDao.findByUserAndSpace(user1, testSpace)).thenReturn(List.of(chatRoom1, chatRoom2)); when(userChatRoomDao.findByUserAndChatRoom(user1, chatRoom1)).thenReturn(userChatRoom1); - lenient().when(chattingDao.findTopByChatRoomIdOrderByCreatedAtDesc(chatRoom2.getId())).thenReturn(null); // 마지막 메시지가 없다고 가정 - lenient().when(chattingDao.countByChatRoomIdAndCreatedAtBetween(chatRoom2.getId(), LocalDateTime.now(), LocalDateTime.now())).thenReturn(0); + when(chattingDao.findTopByChatRoomIdOrderByCreatedAtDesc(chatRoom2.getId())).thenReturn(null); // 마지막 메시지가 없다고 가정 + when(chattingDao.countByChatRoomIdAndCreatedAtBetween(chatRoom2.getId(), convertToKoreaTime(mockTime), convertToKoreaTime(mockTime))).thenReturn(0); when(userChatRoomDao.findByUserAndChatRoom(user1, chatRoom2)).thenReturn(userChatRoom2); // when @@ -222,6 +198,8 @@ class ChatRoomServiceTest { // then assertThat(readChatRoomResponse.getChatRoomList().size()).isEqualTo(2); + assertThat(readChatRoomResponse.getChatRoomList().get(0).getName()).isEqualTo("chatRoom1"); + assertThat(readChatRoomResponse.getChatRoomList().get(1).getName()).isEqualTo("chatRoom2"); } @Test @@ -323,4 +301,38 @@ class ChatRoomServiceTest { // then assertThat(chatSuccessResponse.isSuccess()).isEqualTo(true); } + + private User createUser(String email, Long userId) { + User user = new User(); + user.saveUser(email, "Asdf1234!", email.split("@")[0], UserSignupType.LOCAL); + ReflectionTestUtils.setField(user, "userId", userId); + lenient().when(userUtils.findUserByUserId(userId)).thenReturn(user); + return user; + } + + private ChatRoom createChatRoom(String name, Long id) { + ChatRoom chatRoom = new ChatRoom(); + ReflectionTestUtils.setField(chatRoom, "id", id); + ReflectionTestUtils.setField(chatRoom, "status", "ACTIVE"); + ReflectionTestUtils.setField(chatRoom, "createdAt", mockTime); + ReflectionTestUtils.setField(chatRoom, "name", name); + return chatRoom; + } + + private UserChatRoom createUserChatRoom(Long id, ChatRoom chatRoom, User user) { + UserChatRoom userChatRoom = new UserChatRoom(); + ReflectionTestUtils.setField(userChatRoom, "id", id); + ReflectionTestUtils.setField(userChatRoom, "status", "ACTIVE"); + ReflectionTestUtils.setField(userChatRoom, "createdAt", mockTime); + ReflectionTestUtils.setField(userChatRoom, "chatRoom", chatRoom); + ReflectionTestUtils.setField(userChatRoom, "user", user); + ReflectionTestUtils.setField(userChatRoom, "lastReadTime", mockTime); + return userChatRoom; + } + + private LocalDateTime convertToKoreaTime(LocalDateTime time) { + return time.atZone(ZoneId.of("UTC")) + .withZoneSameInstant(ZoneId.of("Asia/Seoul")) + .toLocalDateTime(); + } } From e52eac007b3704f9a5487cb4c1231dd15315b5dc Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Fri, 13 Sep 2024 09:02:41 +0900 Subject: [PATCH 22/38] =?UTF-8?q?refactor:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=A3=BC=EC=9E=85=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/space/space_spring/controller/ChatRoomController.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/space/space_spring/controller/ChatRoomController.java b/src/main/java/space/space_spring/controller/ChatRoomController.java index 9434092e..50392f3d 100644 --- a/src/main/java/space/space_spring/controller/ChatRoomController.java +++ b/src/main/java/space/space_spring/controller/ChatRoomController.java @@ -16,7 +16,6 @@ import space.space_spring.response.BaseResponse; import space.space_spring.service.ChatRoomService; import space.space_spring.service.S3Uploader; -import space.space_spring.util.userSpace.UserSpaceUtils; import java.io.IOException; @@ -30,7 +29,6 @@ public class ChatRoomController { private final ChatRoomService chatRoomService; private final S3Uploader s3Uploader; - private final UserSpaceUtils userSpaceUtils; /** * 모든 채팅방 정보 조회 From f64d602cb8ec76ced237cf034b700424b5a7dd68 Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Fri, 13 Sep 2024 18:30:06 +0900 Subject: [PATCH 23/38] =?UTF-8?q?refactor:=20=EC=83=9D=EC=84=B1=EC=9E=90?= =?UTF-8?q?=20builder=20=ED=8C=A8=ED=84=B4=EC=9C=BC=EB=A1=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat/request/CreateChatRoomRequest.java | 4 ++-- .../dto/chat/request/JoinChatRoomRequest.java | 6 +++++ .../service/ChatRoomServiceTest.java | 22 ++++++++++--------- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/main/java/space/space_spring/dto/chat/request/CreateChatRoomRequest.java b/src/main/java/space/space_spring/dto/chat/request/CreateChatRoomRequest.java index c492d0b9..e8143551 100644 --- a/src/main/java/space/space_spring/dto/chat/request/CreateChatRoomRequest.java +++ b/src/main/java/space/space_spring/dto/chat/request/CreateChatRoomRequest.java @@ -4,8 +4,8 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import lombok.Builder; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import org.springframework.web.multipart.MultipartFile; @@ -13,7 +13,7 @@ @Getter @Setter -@NoArgsConstructor +@Builder public class CreateChatRoomRequest { @Size(min = 2, max = 15, message = "채팅방 이름은 2자 이상, 15자 이내의 문자열이어야 합니다.") diff --git a/src/main/java/space/space_spring/dto/chat/request/JoinChatRoomRequest.java b/src/main/java/space/space_spring/dto/chat/request/JoinChatRoomRequest.java index 63d41259..5b6e3d53 100644 --- a/src/main/java/space/space_spring/dto/chat/request/JoinChatRoomRequest.java +++ b/src/main/java/space/space_spring/dto/chat/request/JoinChatRoomRequest.java @@ -1,11 +1,17 @@ package space.space_spring.dto.chat.request; import jakarta.validation.constraints.NotEmpty; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; import java.util.List; @Getter +@Builder +@NoArgsConstructor /* controller단 테스트 위해 적용*/ +@AllArgsConstructor public class JoinChatRoomRequest { @NotEmpty(message = "1명 이상의 멤버를 초대해야 합니다.") diff --git a/src/test/java/space/space_spring/service/ChatRoomServiceTest.java b/src/test/java/space/space_spring/service/ChatRoomServiceTest.java index 6b39b9f8..97facaf5 100644 --- a/src/test/java/space/space_spring/service/ChatRoomServiceTest.java +++ b/src/test/java/space/space_spring/service/ChatRoomServiceTest.java @@ -128,19 +128,21 @@ class ChatRoomServiceTest { // chatRoom1, chatRoom2 생성 시 사용할 request MockMultipartFile mockImgFile = new MockMultipartFile("mockImgFile", "test.png", "png", "test file".getBytes(StandardCharsets.UTF_8) ); - createChatRoomRequest1 = new CreateChatRoomRequest(); - createChatRoomRequest1.setName("chatRoom1"); - createChatRoomRequest1.setImg(mockImgFile); - createChatRoomRequest1.setMemberList(List.of(1L)); - createChatRoomRequest2 = new CreateChatRoomRequest(); - createChatRoomRequest2.setName("chatRoom2"); - createChatRoomRequest2.setImg(mockImgFile); - createChatRoomRequest2.setMemberList(List.of()); + createChatRoomRequest1 = CreateChatRoomRequest.builder() + .name("chatRoom1") + .img(mockImgFile) + .memberList(List.of(1L)) + .build(); + + createChatRoomRequest2 = CreateChatRoomRequest.builder() + .name("chatRoom2") + .img(mockImgFile) + .memberList(List.of()) + .build(); // user3 초대 시 사용할 request - joinChatRoomRequest = new JoinChatRoomRequest(); - ReflectionTestUtils.setField(joinChatRoomRequest, "memberList", List.of(2L)); + joinChatRoomRequest = JoinChatRoomRequest.builder().memberList(List.of(2L)).build(); lenient().when(userChatRoomDao.save(any(UserChatRoom.class))).thenAnswer(invocationOnMock -> { UserChatRoom savedChatRoom = invocationOnMock.getArgument(0); From 674a3b89a9f531fa04a7019a400c6222c233365b Mon Sep 17 00:00:00 2001 From: hyunn522 Date: Fri, 13 Sep 2024 18:30:42 +0900 Subject: [PATCH 24/38] =?UTF-8?q?feat:=20ChatRoomController=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/ChatRoomControllerTest.java | 250 ++++++++++++++++++ 1 file changed, 250 insertions(+) create mode 100644 src/test/java/space/space_spring/controller/ChatRoomControllerTest.java diff --git a/src/test/java/space/space_spring/controller/ChatRoomControllerTest.java b/src/test/java/space/space_spring/controller/ChatRoomControllerTest.java new file mode 100644 index 00000000..6d1c244b --- /dev/null +++ b/src/test/java/space/space_spring/controller/ChatRoomControllerTest.java @@ -0,0 +1,250 @@ +package space.space_spring.controller; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.test.web.servlet.MockMvc; +import space.space_spring.argumentResolver.jwtLogin.JwtLoginAuthHandlerArgumentResolver; +import space.space_spring.argumentResolver.userSpace.UserSpaceAuthHandlerArgumentResolver; +import space.space_spring.argumentResolver.userSpace.UserSpaceIdHandlerArgumentResolver; +import space.space_spring.config.SecurityConfig; +import space.space_spring.dto.chat.request.CreateChatRoomRequest; +import space.space_spring.dto.chat.request.JoinChatRoomRequest; +import space.space_spring.dto.chat.response.*; +import space.space_spring.dto.userSpace.UserInfoInSpace; +import space.space_spring.interceptor.UserSpaceValidationInterceptor; +import space.space_spring.interceptor.jwtLogin.JwtLoginAuthInterceptor; +import space.space_spring.service.ChatRoomService; +import space.space_spring.service.S3Uploader; + +import java.nio.charset.StandardCharsets; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; + +@WebMvcTest(ChatRoomController.class) +@MockBean(JpaMetamodelMappingContext.class) +@Import(SecurityConfig.class) +@AutoConfigureMockMvc(addFilters = false) // security config ignore +public class ChatRoomControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private ChatRoomService chatRoomService; + + @MockBean + private S3Uploader s3Uploader; + + @MockBean + private JwtLoginAuthHandlerArgumentResolver jwtLoginAuthHandlerArgumentResolver; + + @MockBean + private UserSpaceIdHandlerArgumentResolver userSpaceIdHandlerArgumentResolver; + + @MockBean + private UserSpaceAuthHandlerArgumentResolver userSpaceAuthHandlerArgumentResolver; + + @MockBean + private JwtLoginAuthInterceptor jwtLoginAuthInterceptor; + + @MockBean + private UserSpaceValidationInterceptor userSpaceValidationInterceptor; + + private static Long userId; + + private static Long spaceId; + + private static Long chatRoomId; + + private static Long userSpaceId; + + private static MockMultipartFile mockImgFile; + + private ChatSuccessResponse commonResponse; + + @BeforeEach + void 채팅방_테스트_설정() throws Exception { + userId = 0L; + spaceId = 1L; + userSpaceId = 2L; + chatRoomId = 3L; + + given(userSpaceValidationInterceptor.preHandle(any(), any(), any())) + .willReturn(true); + + given(jwtLoginAuthInterceptor.preHandle(any(), any(), any())) + .willReturn(true); + + given(jwtLoginAuthHandlerArgumentResolver.resolveArgument(any(), any(), any(), any())) + .willReturn(userId); + + given(userSpaceIdHandlerArgumentResolver.resolveArgument(any(), any(), any(), any())) + .willReturn(userSpaceId); + + given(userSpaceAuthHandlerArgumentResolver.resolveArgument(any(), any(), any(), any())) + .willReturn("manager"); + + mockImgFile = new MockMultipartFile("img", "test.png", "png", "test file".getBytes(StandardCharsets.UTF_8)); + + commonResponse = ChatSuccessResponse.builder().build(); + } + + @Test + @DisplayName("모든_채팅방_조회_테스트") + void 모든_채팅방_조회_테스트() throws Exception { + // given + ReadChatRoomResponse response = ReadChatRoomResponse.of(List.of(new ChatRoomResponse[]{})); + given(chatRoomService.readChatRooms(userId, spaceId)) + .willReturn(response); + + // when & then + mockMvc.perform(get("/space/{spaceId}/chat/chatroom", spaceId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + } + + @Test + @DisplayName("채팅방_생성_테스트") + void 채팅방_생성_테스트() throws Exception { + // given +// CreateChatRoomRequest request = new CreateChatRoomRequest(); + CreateChatRoomRequest request = CreateChatRoomRequest.builder() + .name("testChatRoom") + .img(mockImgFile) + .memberList(List.of(4L)) + .build(); +// request.setName("testChatRoom"); +// request.setImg(mockImgFile); +// request.setMemberList(List.of(4L)); + + CreateChatRoomResponse response = CreateChatRoomResponse.of(chatRoomId); + given(chatRoomService.createChatRoom(userId, spaceId, request, "asdf")) + .willReturn(response); + + // when & then + mockMvc.perform(multipart("/space/{spaceId}/chat/chatroom", spaceId) + .file(mockImgFile) + .param("name", request.getName()) + .param("memberList", request.getMemberList().stream() + .map(String::valueOf) + .toArray(String[]::new)) + .param("userSpaceAuth", "manager") + .contentType(MediaType.MULTIPART_FORM_DATA)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + } + + @Test + @DisplayName("특정_채팅방의_모든_유저_정보_조회_테스트") + void 특정_채팅방의_모든_유저_정보_조회_테스트() throws Exception { + // given + ReadChatRoomMemberResponse response = ReadChatRoomMemberResponse.of(List.of(new UserInfoInSpace[]{})); + given(chatRoomService.readChatRoomMembers(userId, spaceId)) + .willReturn(response); + + // when & then + mockMvc.perform(get("/space/{spaceId}/chat/{chatRoomId}/member", spaceId, chatRoomId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + } + + @Test + @DisplayName("특정_채팅방에_유저_초대_테스트") + void 특정_채팅방에_유저_초대_테스트() throws Exception { + // given + JoinChatRoomRequest request = JoinChatRoomRequest.builder().memberList(List.of(1L)).build(); + String content = objectMapper.writeValueAsString(request); + + given(chatRoomService.joinChatRoom(chatRoomId, request)) + .willReturn(commonResponse); + + // when & then + mockMvc.perform(post("/space/{spaceId}/chat/{chatRoomId}/member", spaceId, chatRoomId) + .param("userSpaceAuth", "manager") + .contentType(MediaType.APPLICATION_JSON) + .content(content)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + } + + @Test + @DisplayName("특정_유저가_채팅방에서_떠난_시간_저장_테스트") + void 특정_유저가_채팅방에서_떠난_시간_저장_테스트() throws Exception { + // given + given(chatRoomService.updateLastReadTime(userId, chatRoomId)) + .willReturn(commonResponse); + + // when & then + mockMvc.perform(post("/space/{spaceId}/chat/{chatRoomId}/leave", spaceId, chatRoomId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + } + + @Test + @DisplayName("특정_채팅방의_이름_수정_테스트") + void 특정_채팅방의_이름_수정_테스트() throws Exception { + // given + given(chatRoomService.modifyChatRoomName(chatRoomId, "newChatRoom")) + .willReturn(commonResponse); + + // when & then + mockMvc.perform(post("/space/{spaceId}/chat/{chatRoomId}/setting", spaceId, chatRoomId) + .param("name", "newChatRoom") + .param("userSpaceAuth", "manager")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + } + + @Test + @DisplayName("특정_채팅방에서_나가기_테스트") + void 특정_채팅방에서_나가기_테스트() throws Exception { + // given + given(chatRoomService.exitChatRoom(userId, chatRoomId)) + .willReturn(commonResponse); + + // when & then + mockMvc.perform(post("/space/{spaceId}/chat/{chatRoomId}/exit", spaceId, chatRoomId)) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + } + + @Test + @DisplayName("특정_채팅방_삭제_테스트") + void 특정_채팅방_삭제_테스트() throws Exception { + // given + given(chatRoomService.deleteChatRoom(chatRoomId)) + .willReturn(commonResponse); + + // when & then + mockMvc.perform(post("/space/{spaceId}/chat/{chatRoomId}/delete", spaceId, chatRoomId) + .param("userSpaceAuth", "manager")) + .andDo(print()) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.message").exists()); + } +} From 59ad8df19f13121dc4d119d59a75ee69478142cd Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Fri, 27 Sep 2024 18:00:49 +0900 Subject: [PATCH 25/38] [refactoring] add Todo comment --- .../space/space_spring/service/VoiceRoomService.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/space/space_spring/service/VoiceRoomService.java b/src/main/java/space/space_spring/service/VoiceRoomService.java index c831ef89..6b94bcb5 100644 --- a/src/main/java/space/space_spring/service/VoiceRoomService.java +++ b/src/main/java/space/space_spring/service/VoiceRoomService.java @@ -116,7 +116,10 @@ public List getVoiceRoomInfoListConcurrency(long //해당 space VoiceRoom 가져오기 (VoiceRoom List) //Todo 가져오기에 limit 적용 + //todo 일급 객체 `voiceRoomEntityList`로 변경 List voiceRoomDataList = findBySpaceId(spaceId); + //todo voiceRoomEntityList 객체에 책임 위임 + //todo RoomDtoList 일급 객체 생성 List roomDtoList = RoomDto.convertRoomDtoListByVoiceRoom(voiceRoomDataList); //VoiceRoom과 Room mapping //#1 Response 받아오기 @@ -131,6 +134,8 @@ public List getVoiceRoomInfoListConcurrency(long for(RoomDto roomDto : roomDtoList){ roomDto.setActiveRoom(roomResponses); } + //ToDo setRoomDto 함수를 RoomDtoList 객체로 이동 + //todo 책임을 위임해도 이 병렬처리 코드가 잘 동작할까? List> roomDtoFutureList = roomDtoList.stream() .map(r->CompletableFuture.runAsync(()->setRoomDto(r,roomResponses,req),taskExecutor) //.exceptionally(ex->{throws ex;}) @@ -155,7 +160,7 @@ public List getVoiceRoomInfoListConcurrency(long } //return null; } - + //todo 해당 함수의 책임을 RoomDto에게 위임 private void setRoomDto(RoomDto roomDto,List roomResponses,GetVoiceRoomList.Request req){ roomDto.setActiveRoom(roomResponses); @@ -217,7 +222,7 @@ public boolean updateVoiceRoom(List updateRoomList){ //Todo 입력된 order가 유효한지 확인 필요 - + //Todo 병렬적으로 update하도록 수정 for(PatchVoiceRoom.UpdateRoom updateRoom : updateRoomList){ VoiceRoom voiceRoom = voiceRoomRepository.findById(updateRoom.getRoomId()).get(); String newName =updateRoom.getName(); From 4230e3f9c9958461d2744aa9cce8af1c64f7adb1 Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:54:36 +0900 Subject: [PATCH 26/38] [refactoring] change setActive func --- .../dto/VoiceRoom/VoiceRoomDtoList.java | 113 ++++++++++++++++++ .../dto/VoiceRoom/VoiceRoomEntityList.java | 22 ++++ 2 files changed, 135 insertions(+) create mode 100644 src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java create mode 100644 src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomEntityList.java diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java new file mode 100644 index 00000000..80b5c293 --- /dev/null +++ b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java @@ -0,0 +1,113 @@ +package space.space_spring.dto.VoiceRoom; + +import livekit.LivekitModels; +import lombok.RequiredArgsConstructor; +import org.springframework.core.task.TaskExecutor; +import org.springframework.stereotype.Service; +import space.space_spring.controller.VoiceRoomController; +import space.space_spring.dao.UserDao; +import space.space_spring.dao.UserSpaceDao; +import space.space_spring.dao.VoiceRoomRepository; +import space.space_spring.entity.Space; +import space.space_spring.entity.User; +import space.space_spring.util.LiveKitUtils; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; +@Service +@RequiredArgsConstructor +public class VoiceRoomDtoList { + private List roomDtoList; + private final LiveKitUtils liveKitUtils; + private final VoiceRoomRepository voiceRoomRepository; + private final UserSpaceDao userSpaceDao; + private final UserDao userDao; + private final TaskExecutor taskExecutor; + public void RoomDtoList(List roomDtos){ + this.roomDtoList=roomDtos; + } + + public void setActiveRoom(){ + //#1 Response 받아오기 + + List roomResponsesTemp = liveKitUtils.getRoomList(); + + //불변 list로 변환 + List roomResponses = Collections.unmodifiableList(roomResponsesTemp); + /** + * 병렬 처리 적용대상 1 + */ + //#2 Room과 mapping 시키기 + for(RoomDto roomDto : roomDtoList){ + roomDto.setActiveRoom(roomResponses); + } + //ToDo setRoomDto 함수를 RoomDtoList 객체로 이동 + //todo 책임을 위임해도 이 병렬처리 코드가 잘 동작할까? + List> roomDtoFutureList = roomDtoList.stream() + .map(r->CompletableFuture.runAsync(()->setRoomDto(r,roomResponses,req),taskExecutor) + //.exceptionally(ex->{throws ex;}) + ) + .collect(Collectors.toList()); + + + // 모든 Future의 완료를 기다림 + CompletableFuture allOf = CompletableFuture.allOf( + roomDtoFutureList.toArray(new CompletableFuture[0])); + + // 결과 수집 및 출력 + allOf.join(); + //ToDo Response로 convert + //#1 Active/inActive 분리 + } + + public void setRoomDto (RoomDto roomDto,List roomResponses,GetVoiceRoomList.Request req){ + roomDto.setActiveRoom(roomResponses); + + if(!req.isShowParticipant()){ + return; + } + + if(roomDto.getNumParticipants()==0){ + //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 + System.out.print("\n[DEBUG]Participant Number : 0\n"); + roomDto.setParticipantDTOList(Collections.emptyList()); + return; + } + //participantDto List 가져오기 + List participantDtoList = getParticipantDtoListById(roomDto.getId()); + + //RoomDto에 값 집어넣기 + //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 + if(participantDtoList==null||participantDtoList.isEmpty()){ + System.out.print("\n\n[DEBUG]participant response is empty or null"+participantDtoList.toString()+ + "participant number is \n\n"); + roomDto.setParticipantDTOList(Collections.emptyList()); + }else { + roomDto.setParticipantDTOList(participantDtoList); + } + + } + + private List getParticipantDtoListById(long voiceRoomId){ + Space space = voiceRoomRepository.findById(voiceRoomId).getSpace(); + List participantDtoList = liveKitUtils.getParticipantInfo(String.valueOf(voiceRoomId)); + if(participantDtoList==null||participantDtoList.isEmpty()){ + return Collections.emptyList(); + } + for(ParticipantDto participantDto: participantDtoList){ + //profileIamge 집어넣기 + participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); + //userSpaceId 집어 넣기 + User user = userDao.findUserByUserId(participantDto.getId()); + participantDto.setUserSpaceId(userSpaceDao.findUserSpaceByUserAndSpace(user,space).get().getUserSpaceId()); + } + return participantDtoList; + } + private String findProfileImageByUserId(Long userSpaceId){ + return userSpaceDao.findProfileImageById(userSpaceId).orElse(""); + } + + +} diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomEntityList.java b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomEntityList.java new file mode 100644 index 00000000..11a30826 --- /dev/null +++ b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomEntityList.java @@ -0,0 +1,22 @@ +package space.space_spring.dto.VoiceRoom; + +import space.space_spring.entity.VoiceRoom; + +import java.util.List; +import java.util.stream.Collectors; + +public class VoiceRoomEntityList { + + private List voiceRoomEntityList; + + public void VoiceRoomList(List voiceRoomEntityList) { + this.voiceRoomEntityList = voiceRoomEntityList; + } + + public List convertRoomDto(){ + if(this.voiceRoomEntityList==null||this.voiceRoomEntityList.isEmpty()){return null;} + return this.voiceRoomEntityList.stream() + .map(RoomDto::convertRoom) + .collect(Collectors.toList()); + } +} \ No newline at end of file From 35fa9732dc82c4ef0ade2f3b1e220f5c8f10b35f Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:57:16 +0900 Subject: [PATCH 27/38] [feat] ask roomList By roomNameList --- src/main/java/space/space_spring/util/LiveKitUtils.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main/java/space/space_spring/util/LiveKitUtils.java b/src/main/java/space/space_spring/util/LiveKitUtils.java index 8984ec69..f9c36e88 100644 --- a/src/main/java/space/space_spring/util/LiveKitUtils.java +++ b/src/main/java/space/space_spring/util/LiveKitUtils.java @@ -28,13 +28,13 @@ public class LiveKitUtils { private final RestTemplate restTemplate; - public List getRoomList() { + public List getRoomList(List roomNameList) { String liveKitHost = hostUrl; System.out.print("[liveKit Url]:"+hostUrl); RoomServiceClient roomServiceClient = RoomServiceClient.createClient(liveKitHost, apiKey, apiSecretKey); try { - Response> response = roomServiceClient.listRooms().execute(); + Response> response = roomServiceClient.listRooms(roomNameList).execute(); System.out.print(response.body()); //response.body().get(0). @@ -48,6 +48,10 @@ public List getRoomList() { } + public List getRoomList(){ + return getRoomList(null); + } + public List getParticipantInfo(String roomName) { String liveKitHost = hostUrl; RoomServiceClient roomServiceClient = RoomServiceClient.createClient(liveKitHost, apiKey, apiSecretKey); From 30764d9194fdfc8ab76596e412d5d97e498f6bf1 Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Tue, 1 Oct 2024 12:58:26 +0900 Subject: [PATCH 28/38] [refactoring] add convert func in RoomDto --- .../space_spring/dto/VoiceRoom/RoomDto.java | 18 +- .../dto/VoiceRoom/VoiceRoomDtoList.java | 167 +++++++++--------- 2 files changed, 101 insertions(+), 84 deletions(-) diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java b/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java index 5183274a..32621f0a 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java @@ -99,10 +99,7 @@ public void setActiveRoom(List liveKitRoomList){ boolean find = false; for(LivekitModels.Room resRoom : liveKitRoomList){ if(String.valueOf(this.id).equals( resRoom.getName() )){ - this.numParticipants = resRoom.getNumParticipants(); - this.sid = resRoom.getSid(); - this.metadata = resRoom.getMetadata(); - this.startTime= resRoom.getCreationTime(); + setActiveRoom(resRoom,true); find = true; break; } @@ -111,6 +108,19 @@ public void setActiveRoom(List liveKitRoomList){ if(!find){this.numParticipants=0;} //return this; } + + public void setActiveRoom(LivekitModels.Room resRoom,boolean checkId){ + if(checkId || String.valueOf(this.id).equals( resRoom.getName() )){ + this.numParticipants = resRoom.getNumParticipants(); + this.sid = resRoom.getSid(); + this.metadata = resRoom.getMetadata(); + this.startTime= resRoom.getCreationTime(); + + } + } + public void setActiveRoom(LivekitModels.Room resRoom){ + setActiveRoom(resRoom,false); + } private static boolean EqualRoomIdByNameTag(String roomName,long Id){ return roomName.endsWith("#"+String.valueOf(Id)); } diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java index 80b5c293..32637ba9 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java @@ -14,100 +14,107 @@ import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class VoiceRoomDtoList { private List roomDtoList; - private final LiveKitUtils liveKitUtils; - private final VoiceRoomRepository voiceRoomRepository; - private final UserSpaceDao userSpaceDao; - private final UserDao userDao; - private final TaskExecutor taskExecutor; +// private final LiveKitUtils liveKitUtils; +// private final VoiceRoomRepository voiceRoomRepository; +// private final UserSpaceDao userSpaceDao; +// private final UserDao userDao; +// private final TaskExecutor taskExecutor; public void RoomDtoList(List roomDtos){ this.roomDtoList=roomDtos; } - public void setActiveRoom(){ - //#1 Response 받아오기 - - List roomResponsesTemp = liveKitUtils.getRoomList(); - - //불변 list로 변환 - List roomResponses = Collections.unmodifiableList(roomResponsesTemp); - /** - * 병렬 처리 적용대상 1 - */ - //#2 Room과 mapping 시키기 - for(RoomDto roomDto : roomDtoList){ - roomDto.setActiveRoom(roomResponses); + public void setActiveRoom(Map roomResponse){ + for(RoomDto room : this.roomDtoList){ + LivekitModels.Room resRoom= roomResponse.get(room.getId()); + room.setActiveRoom(resRoom); } - //ToDo setRoomDto 함수를 RoomDtoList 객체로 이동 - //todo 책임을 위임해도 이 병렬처리 코드가 잘 동작할까? - List> roomDtoFutureList = roomDtoList.stream() - .map(r->CompletableFuture.runAsync(()->setRoomDto(r,roomResponses,req),taskExecutor) - //.exceptionally(ex->{throws ex;}) - ) - .collect(Collectors.toList()); - - // 모든 Future의 완료를 기다림 - CompletableFuture allOf = CompletableFuture.allOf( - roomDtoFutureList.toArray(new CompletableFuture[0])); - - // 결과 수집 및 출력 - allOf.join(); - //ToDo Response로 convert - //#1 Active/inActive 분리 } - public void setRoomDto (RoomDto roomDto,List roomResponses,GetVoiceRoomList.Request req){ - roomDto.setActiveRoom(roomResponses); - - if(!req.isShowParticipant()){ - return; - } - - if(roomDto.getNumParticipants()==0){ - //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 - System.out.print("\n[DEBUG]Participant Number : 0\n"); - roomDto.setParticipantDTOList(Collections.emptyList()); - return; - } - //participantDto List 가져오기 - List participantDtoList = getParticipantDtoListById(roomDto.getId()); - - //RoomDto에 값 집어넣기 - //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 - if(participantDtoList==null||participantDtoList.isEmpty()){ - System.out.print("\n\n[DEBUG]participant response is empty or null"+participantDtoList.toString()+ - "participant number is \n\n"); - roomDto.setParticipantDTOList(Collections.emptyList()); - }else { - roomDto.setParticipantDTOList(participantDtoList); - } - - } - - private List getParticipantDtoListById(long voiceRoomId){ - Space space = voiceRoomRepository.findById(voiceRoomId).getSpace(); - List participantDtoList = liveKitUtils.getParticipantInfo(String.valueOf(voiceRoomId)); - if(participantDtoList==null||participantDtoList.isEmpty()){ - return Collections.emptyList(); - } - for(ParticipantDto participantDto: participantDtoList){ - //profileIamge 집어넣기 - participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); - //userSpaceId 집어 넣기 - User user = userDao.findUserByUserId(participantDto.getId()); - participantDto.setUserSpaceId(userSpaceDao.findUserSpaceByUserAndSpace(user,space).get().getUserSpaceId()); - } - return participantDtoList; - } - private String findProfileImageByUserId(Long userSpaceId){ - return userSpaceDao.findProfileImageById(userSpaceId).orElse(""); - } +// public void setActiveRoom(List roomResponsesTemp){ +// //#1 Response 받아오기 +// +// //불변 list로 변환 +// List roomResponses = Collections.unmodifiableList(roomResponsesTemp); +// /** +// * 병렬 처리 적용대상 1 +// */ +// //#2 Room과 mapping 시키기 +// for(RoomDto roomDto : roomDtoList){ +// roomDto.setActiveRoom(roomResponses); +// } +// //ToDo setRoomDto 함수를 RoomDtoList 객체로 이동 +// //todo 책임을 위임해도 이 병렬처리 코드가 잘 동작할까? +// List> roomDtoFutureList = roomDtoList.stream() +// .map(r->CompletableFuture.runAsync(()->setRoomDto(r,roomResponses,req),taskExecutor) +// //.exceptionally(ex->{throws ex;}) +// ) +// .collect(Collectors.toList()); +// +// +// // 모든 Future의 완료를 기다림 +// CompletableFuture allOf = CompletableFuture.allOf( +// roomDtoFutureList.toArray(new CompletableFuture[0])); +// +// // 결과 수집 및 출력 +// allOf.join(); +// //ToDo Response로 convert +// //#1 Active/inActive 분리 +// } + +// public void setRoomDto (RoomDto roomDto,List roomResponses,GetVoiceRoomList.Request req){ +// roomDto.setActiveRoom(roomResponses); +// +// if(!req.isShowParticipant()){ +// return; +// } +// +// if(roomDto.getNumParticipants()==0){ +// //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 +// System.out.print("\n[DEBUG]Participant Number : 0\n"); +// roomDto.setParticipantDTOList(Collections.emptyList()); +// return; +// } +// //participantDto List 가져오기 +// List participantDtoList = getParticipantDtoListById(roomDto.getId()); +// +// //RoomDto에 값 집어넣기 +// //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 +// if(participantDtoList==null||participantDtoList.isEmpty()){ +// System.out.print("\n\n[DEBUG]participant response is empty or null"+participantDtoList.toString()+ +// "participant number is \n\n"); +// roomDto.setParticipantDTOList(Collections.emptyList()); +// }else { +// roomDto.setParticipantDTOList(participantDtoList); +// } +// +// } +// +// private List getParticipantDtoListById(long voiceRoomId){ +// Space space = voiceRoomRepository.findById(voiceRoomId).getSpace(); +// List participantDtoList = liveKitUtils.getParticipantInfo(String.valueOf(voiceRoomId)); +// if(participantDtoList==null||participantDtoList.isEmpty()){ +// return Collections.emptyList(); +// } +// for(ParticipantDto participantDto: participantDtoList){ +// //profileIamge 집어넣기 +// participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); +// //userSpaceId 집어 넣기 +// User user = userDao.findUserByUserId(participantDto.getId()); +// participantDto.setUserSpaceId(userSpaceDao.findUserSpaceByUserAndSpace(user,space).get().getUserSpaceId()); +// } +// return participantDtoList; +// } +// private String findProfileImageByUserId(Long userSpaceId){ +// return userSpaceDao.findProfileImageById(userSpaceId).orElse(""); +// } } From e4b967f27363cccbb94b6b733110c9c7729987bd Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 30 Oct 2024 21:19:11 +0900 Subject: [PATCH 29/38] =?UTF-8?q?conflict=20=ED=95=B4=EA=B2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/VoiceRoom/GetVoiceRoomList.java | 2 + .../space_spring/dto/VoiceRoom/RoomDto.java | 2 + .../dto/VoiceRoom/VoiceRoomDtoList.java | 49 +++++++++++- .../space/space_spring/entity/VoiceRoom.java | 14 ++++ .../service/VoiceRoomService.java | 80 ++++++++++--------- 5 files changed, 108 insertions(+), 39 deletions(-) diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/GetVoiceRoomList.java b/src/main/java/space/space_spring/dto/VoiceRoom/GetVoiceRoomList.java index e512885d..13edb903 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/GetVoiceRoomList.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/GetVoiceRoomList.java @@ -52,6 +52,7 @@ public static VoiceRoomInfo convertRoomDto(RoomDto roomDto){ ) .build(); } + //Todo VoiceRoomDto로 이전예정 public static List convertRoomDtoList(List roomDtoList,Integer limit){ if(roomDtoList==null||roomDtoList.isEmpty()){return null;} Stream sortedStream = roomDtoList.stream() @@ -65,6 +66,7 @@ public static List convertRoomDtoList(List roomDtoList,I .collect(Collectors.toList()); } + //Todo VoiceRoomDto로 이전예정 public static List convertRoomDtoList(List roomDtoList) { return convertRoomDtoList(roomDtoList, null); } diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java b/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java index 32621f0a..c7aadd5f 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java @@ -49,6 +49,7 @@ public static RoomDto convertRoom(LivekitModels.Room room){ .build(); } + //Todo VoiceRoomDtoList 로 이전 예정 public static List convertRoomDtoListByVoiceRoom(List voiceRoomList){ if(voiceRoomList==null||voiceRoomList.isEmpty()){return null;} return voiceRoomList.stream() @@ -110,6 +111,7 @@ public void setActiveRoom(List liveKitRoomList){ } public void setActiveRoom(LivekitModels.Room resRoom,boolean checkId){ + //null에 대한 예외 처리 if(checkId || String.valueOf(this.id).equals( resRoom.getName() )){ this.numParticipants = resRoom.getNumParticipants(); this.sid = resRoom.getSid(); diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java index 32637ba9..58633d49 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java @@ -10,13 +10,17 @@ import space.space_spring.dao.VoiceRoomRepository; import space.space_spring.entity.Space; import space.space_spring.entity.User; +import space.space_spring.entity.VoiceRoom; import space.space_spring.util.LiveKitUtils; import java.util.Collections; +import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +import java.util.stream.Stream; + @Service @RequiredArgsConstructor public class VoiceRoomDtoList { @@ -26,17 +30,56 @@ public class VoiceRoomDtoList { // private final UserSpaceDao userSpaceDao; // private final UserDao userDao; // private final TaskExecutor taskExecutor; - public void RoomDtoList(List roomDtos){ + public VoiceRoomDtoList(List roomDtos){ this.roomDtoList=roomDtos; } - public void setActiveRoom(Map roomResponse){ + public static VoiceRoomDtoList from(List voiceRoomEntityList){ + List roomDtos = convertRoomDtoListByVoiceRoom(voiceRoomEntityList); + return new VoiceRoomDtoList(roomDtos); + } + + public static List convertRoomDtoListByVoiceRoom(List voiceRoomList){ + if(voiceRoomList==null||voiceRoomList.isEmpty()){return null;} + return voiceRoomList.stream() + .map(RoomDto::convertRoom) + .collect(Collectors.toList()); + } + + private void setActiveRoom(Map roomResponse){ for(RoomDto room : this.roomDtoList){ - LivekitModels.Room resRoom= roomResponse.get(room.getId()); + LivekitModels.Room resRoom= roomResponse.get(String.valueOf(room.getId())); + if(resRoom==null){continue;} room.setActiveRoom(resRoom); } } + public void setActiveRoom(List roomResponse){ + Map roomResMap=roomResponse.stream() + .collect(Collectors.toMap( + res->res.getName(), + res->res, + (oldVal,newVal)->newVal + )); + roomResMap = Collections.unmodifiableMap(roomResMap); + setActiveRoom(roomResMap); + } + + public List convertVoicRoomInfoList(Integer limit){ + if(this.roomDtoList==null||this.roomDtoList.isEmpty()){return null;} + Stream sortedStream = this.roomDtoList.stream() + .sorted(Comparator + .comparing((RoomDto r) -> r.getNumParticipants() == 0) // Active rooms first + .thenComparing(RoomDto::getOrder)) ;// Then by order + System.out.print("limit input:"+limit); + Stream processedStream = (limit != null) ? sortedStream.limit(limit) : sortedStream; + + return processedStream.map(GetVoiceRoomList.VoiceRoomInfo::convertRoomDto) + .collect(Collectors.toList()); + } + public List convertVoicRoomInfoList() { + return convertVoicRoomInfoList( null); + } // public void setActiveRoom(List roomResponsesTemp){ // //#1 Response 받아오기 diff --git a/src/main/java/space/space_spring/entity/VoiceRoom.java b/src/main/java/space/space_spring/entity/VoiceRoom.java index aa93d303..2472dd92 100644 --- a/src/main/java/space/space_spring/entity/VoiceRoom.java +++ b/src/main/java/space/space_spring/entity/VoiceRoom.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import space.space_spring.dto.VoiceRoom.GetVoiceRoomList; +import space.space_spring.dto.VoiceRoom.RoomDto; @Entity @Table(name = "VoiceRoom") @@ -52,4 +53,17 @@ public void update(String name,Integer order){ } this.onUpdate(); } + + public RoomDto convertRoomDto(){ + return RoomDto.builder() + .name(this.getName()) + //.createdAt(voiceRoom.) + .id(this.getVoiceRoomId()) + .order(this.getOrder()) + .sid(null) + .metadata(null) + //.startTime() + .participantDTOList(null) + .build(); + } } diff --git a/src/main/java/space/space_spring/service/VoiceRoomService.java b/src/main/java/space/space_spring/service/VoiceRoomService.java index 6b94bcb5..780b46b2 100644 --- a/src/main/java/space/space_spring/service/VoiceRoomService.java +++ b/src/main/java/space/space_spring/service/VoiceRoomService.java @@ -18,6 +18,10 @@ import java.util.Collections; import java.util.List; + +import java.util.Map; +import java.util.Optional; + import java.util.concurrent.CompletableFuture; import java.util.function.Function; import java.util.stream.Collectors; @@ -121,12 +125,16 @@ public List getVoiceRoomInfoListConcurrency(long //todo voiceRoomEntityList 객체에 책임 위임 //todo RoomDtoList 일급 객체 생성 List roomDtoList = RoomDto.convertRoomDtoListByVoiceRoom(voiceRoomDataList); + //VoiceRoom과 Room mapping //#1 Response 받아오기 List roomResponsesTemp = liveKitUtils.getRoomList(); //불변 list로 변환 List roomResponses = Collections.unmodifiableList(roomResponsesTemp); + VoiceRoomDtoList voiceRoomDtoList=VoiceRoomDtoList.from(voiceRoomDataList); + voiceRoomDtoList.setActiveRoom(roomResponsesTemp); + /** * 병렬 처리 적용대상 1 */ @@ -154,9 +162,11 @@ public List getVoiceRoomInfoListConcurrency(long //#2 convert if(limit==null||limit<=0) { - return GetVoiceRoomList.VoiceRoomInfo.convertRoomDtoList(roomDtoList); + return voiceRoomDtoList.convertVoicRoomInfoList(); + //return GetVoiceRoomList.VoiceRoomInfo.convertRoomDtoList(roomDtoList); }else{ - return GetVoiceRoomList.VoiceRoomInfo.convertRoomDtoList(roomDtoList,limit); + return voiceRoomDtoList.convertVoicRoomInfoList(limit); + //return GetVoiceRoomList.VoiceRoomInfo.convertRoomDtoList(roomDtoList,limit); } //return null; } @@ -191,32 +201,32 @@ private void setRoomDto(RoomDto roomDto,List roomResponses,G - private Function setActiveParticipant= roomDto->{ - - if(roomDto.getNumParticipants()==0){ - //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 - System.out.print("\n[DEBUG]Participant Number : 0\n"); - roomDto.setParticipantDTOList(Collections.emptyList()); - - } - //participantDto List 가져오기 - List participantDtoList = this.getParticipantDtoListById(roomDto.getId()); -// for(ParticipantDto participantDto: participantDtoList){ -// //Todo profileIamge 집어넣기 -// participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); -// } - //RoomDto에 값 집어넣기 - //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 - if(participantDtoList==null||participantDtoList.isEmpty()){ - System.out.print("\n\n[DEBUG]participant response is empty or null"+participantDtoList.toString()+ - "participant number is \n\n"); - roomDto.setParticipantDTOList(Collections.emptyList()); - }else { - roomDto.setParticipantDTOList(participantDtoList); - } - return roomDto; - - }; +// private Function setActiveParticipant= roomDto->{ +// +// if(roomDto.getNumParticipants()==0){ +// //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 +// System.out.print("\n[DEBUG]Participant Number : 0\n"); +// roomDto.setParticipantDTOList(Collections.emptyList()); +// +// } +// //participantDto List 가져오기 +// List participantDtoList = this.getParticipantDtoListById(roomDto.getId()); +//// for(ParticipantDto participantDto: participantDtoList){ +//// //Todo profileIamge 집어넣기 +//// participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); +//// } +// //RoomDto에 값 집어넣기 +// //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 +// if(participantDtoList==null||participantDtoList.isEmpty()){ +// System.out.print("\n\n[DEBUG]participant response is empty or null"+participantDtoList.toString()+ +// "participant number is \n\n"); +// roomDto.setParticipantDTOList(Collections.emptyList()); +// }else { +// roomDto.setParticipantDTOList(participantDtoList); +// } +// return roomDto; +// +// }; public boolean updateVoiceRoom(List updateRoomList){ @@ -240,8 +250,6 @@ public void deleteVoiceRoom(long voiceRoomId){ VoiceRoom voiceRoom = voiceRoomRepository.findById(voiceRoomId); voiceRoom.updateInactive(); voiceRoomRepository.save(voiceRoom); - - } private String findProfileImageByUserId(Long userSpaceId){ @@ -293,12 +301,12 @@ public List getParticipantInfoListById(long //liveKitUtils.getParticipantInfo(findNameTagById(voiceRoomId)) ); } - private String findNameTagById(long id){ - VoiceRoom voiceRoom =voiceRoomRepository.findById(id); - //null pointer error 처리 - String name = voiceRoom.getName(); - return name+" #"+String.valueOf(id); - } +// private String findNameTagById(long id){ +// VoiceRoom voiceRoom =voiceRoomRepository.findById(id); +// //null pointer error 처리 +// String name = voiceRoom.getName(); +// return name+" #"+String.valueOf(id); +// } public String getToken(long spaceId,long userId,long userSpaceId,long voiceRoomId){ String userName=userSpaceDao.findUserNameById(userSpaceId); From 62ebbb5e6999eb0a66e09c9c8ac4c5f402fde6c8 Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Wed, 2 Oct 2024 17:05:14 +0900 Subject: [PATCH 30/38] [refactoring] delete not used import & func --- .../dto/VoiceRoom/VoiceRoomDtoList.java | 98 +------------------ .../service/VoiceRoomService.java | 6 +- 2 files changed, 5 insertions(+), 99 deletions(-) diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java index 58633d49..708ce962 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java @@ -1,35 +1,19 @@ package space.space_spring.dto.VoiceRoom; import livekit.LivekitModels; -import lombok.RequiredArgsConstructor; -import org.springframework.core.task.TaskExecutor; -import org.springframework.stereotype.Service; -import space.space_spring.controller.VoiceRoomController; -import space.space_spring.dao.UserDao; -import space.space_spring.dao.UserSpaceDao; -import space.space_spring.dao.VoiceRoomRepository; -import space.space_spring.entity.Space; -import space.space_spring.entity.User; import space.space_spring.entity.VoiceRoom; -import space.space_spring.util.LiveKitUtils; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; -import java.util.concurrent.CompletableFuture; + import java.util.stream.Collectors; import java.util.stream.Stream; -@Service -@RequiredArgsConstructor public class VoiceRoomDtoList { private List roomDtoList; -// private final LiveKitUtils liveKitUtils; -// private final VoiceRoomRepository voiceRoomRepository; -// private final UserSpaceDao userSpaceDao; -// private final UserDao userDao; -// private final TaskExecutor taskExecutor; + public VoiceRoomDtoList(List roomDtos){ this.roomDtoList=roomDtos; } @@ -81,83 +65,5 @@ public List convertVoicRoomInfoList() { return convertVoicRoomInfoList( null); } -// public void setActiveRoom(List roomResponsesTemp){ -// //#1 Response 받아오기 -// -// //불변 list로 변환 -// List roomResponses = Collections.unmodifiableList(roomResponsesTemp); -// /** -// * 병렬 처리 적용대상 1 -// */ -// //#2 Room과 mapping 시키기 -// for(RoomDto roomDto : roomDtoList){ -// roomDto.setActiveRoom(roomResponses); -// } -// //ToDo setRoomDto 함수를 RoomDtoList 객체로 이동 -// //todo 책임을 위임해도 이 병렬처리 코드가 잘 동작할까? -// List> roomDtoFutureList = roomDtoList.stream() -// .map(r->CompletableFuture.runAsync(()->setRoomDto(r,roomResponses,req),taskExecutor) -// //.exceptionally(ex->{throws ex;}) -// ) -// .collect(Collectors.toList()); -// -// -// // 모든 Future의 완료를 기다림 -// CompletableFuture allOf = CompletableFuture.allOf( -// roomDtoFutureList.toArray(new CompletableFuture[0])); -// -// // 결과 수집 및 출력 -// allOf.join(); -// //ToDo Response로 convert -// //#1 Active/inActive 분리 -// } - -// public void setRoomDto (RoomDto roomDto,List roomResponses,GetVoiceRoomList.Request req){ -// roomDto.setActiveRoom(roomResponses); -// -// if(!req.isShowParticipant()){ -// return; -// } -// -// if(roomDto.getNumParticipants()==0){ -// //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 -// System.out.print("\n[DEBUG]Participant Number : 0\n"); -// roomDto.setParticipantDTOList(Collections.emptyList()); -// return; -// } -// //participantDto List 가져오기 -// List participantDtoList = getParticipantDtoListById(roomDto.getId()); -// -// //RoomDto에 값 집어넣기 -// //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 -// if(participantDtoList==null||participantDtoList.isEmpty()){ -// System.out.print("\n\n[DEBUG]participant response is empty or null"+participantDtoList.toString()+ -// "participant number is \n\n"); -// roomDto.setParticipantDTOList(Collections.emptyList()); -// }else { -// roomDto.setParticipantDTOList(participantDtoList); -// } -// -// } -// -// private List getParticipantDtoListById(long voiceRoomId){ -// Space space = voiceRoomRepository.findById(voiceRoomId).getSpace(); -// List participantDtoList = liveKitUtils.getParticipantInfo(String.valueOf(voiceRoomId)); -// if(participantDtoList==null||participantDtoList.isEmpty()){ -// return Collections.emptyList(); -// } -// for(ParticipantDto participantDto: participantDtoList){ -// //profileIamge 집어넣기 -// participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); -// //userSpaceId 집어 넣기 -// User user = userDao.findUserByUserId(participantDto.getId()); -// participantDto.setUserSpaceId(userSpaceDao.findUserSpaceByUserAndSpace(user,space).get().getUserSpaceId()); -// } -// return participantDtoList; -// } -// private String findProfileImageByUserId(Long userSpaceId){ -// return userSpaceDao.findProfileImageById(userSpaceId).orElse(""); -// } - } diff --git a/src/main/java/space/space_spring/service/VoiceRoomService.java b/src/main/java/space/space_spring/service/VoiceRoomService.java index 780b46b2..6d4e89d2 100644 --- a/src/main/java/space/space_spring/service/VoiceRoomService.java +++ b/src/main/java/space/space_spring/service/VoiceRoomService.java @@ -132,16 +132,16 @@ public List getVoiceRoomInfoListConcurrency(long //불변 list로 변환 List roomResponses = Collections.unmodifiableList(roomResponsesTemp); + VoiceRoomDtoList voiceRoomDtoList=VoiceRoomDtoList.from(voiceRoomDataList); voiceRoomDtoList.setActiveRoom(roomResponsesTemp); - /** - * 병렬 처리 적용대상 1 - */ + //Todo 대체됨. 관련 함수 삭제 예정 //#2 Room과 mapping 시키기 for(RoomDto roomDto : roomDtoList){ roomDto.setActiveRoom(roomResponses); } + //ToDo setRoomDto 함수를 RoomDtoList 객체로 이동 //todo 책임을 위임해도 이 병렬처리 코드가 잘 동작할까? List> roomDtoFutureList = roomDtoList.stream() From f864830de8b3880b934c84853f9522a27e1961bd Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Sat, 5 Oct 2024 00:31:16 +0900 Subject: [PATCH 31/38] [refactoring] Remove unused function in voiceRoom module --- .../controller/VoiceRoomController.java | 18 +-- .../dto/VoiceRoom/GetVoiceRoomList.java | 18 --- .../space_spring/dto/VoiceRoom/RoomDto.java | 11 +- .../service/VoiceRoomService.java | 114 +----------------- .../concurrency/completableFutureTest.java | 11 ++ 5 files changed, 18 insertions(+), 154 deletions(-) diff --git a/src/main/java/space/space_spring/controller/VoiceRoomController.java b/src/main/java/space/space_spring/controller/VoiceRoomController.java index c2aad928..5b7dd483 100644 --- a/src/main/java/space/space_spring/controller/VoiceRoomController.java +++ b/src/main/java/space/space_spring/controller/VoiceRoomController.java @@ -85,26 +85,16 @@ public BaseResponse getRoomListNonConCurrent( @JwtLoginAuth Long userId, //@RequestBody GetVoiceRoomList.Request voiceRoomList, @RequestParam(required = false,defaultValue = "0") Integer limit, - @RequestParam(required = false,defaultValue = "false") Boolean showParticipant, - @PathVariable("version") Integer version){ + @RequestParam(required = false,defaultValue = "false") Boolean showParticipant + ){ boolean showParticipantValue = (showParticipant != null) ? showParticipant : false; GetVoiceRoomList.Request voiceRoomList=new GetVoiceRoomList.Request(limit, showParticipant); List roomInfoList; - if(version==null){ - version =1; - } - if(version==1){ - roomInfoList= voiceRoomService.getVoiceRoomInfoListConcurrency(spaceId,voiceRoomList); - } - if(version==2){ - roomInfoList = voiceRoomService.getVoiceRoomInfoList(spaceId,voiceRoomList); - } - else{ - roomInfoList= voiceRoomService.getVoiceRoomInfoListConcurrency(spaceId,voiceRoomList); - } + + roomInfoList= voiceRoomService.getVoiceRoomInfoListConcurrency(spaceId,voiceRoomList); return new BaseResponse(new GetVoiceRoomList.Response(roomInfoList)); } diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/GetVoiceRoomList.java b/src/main/java/space/space_spring/dto/VoiceRoom/GetVoiceRoomList.java index 13edb903..40661862 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/GetVoiceRoomList.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/GetVoiceRoomList.java @@ -52,23 +52,5 @@ public static VoiceRoomInfo convertRoomDto(RoomDto roomDto){ ) .build(); } - //Todo VoiceRoomDto로 이전예정 - public static List convertRoomDtoList(List roomDtoList,Integer limit){ - if(roomDtoList==null||roomDtoList.isEmpty()){return null;} - Stream sortedStream = roomDtoList.stream() - .sorted(Comparator - .comparing((RoomDto r) -> r.getNumParticipants() == 0) // Active rooms first - .thenComparing(RoomDto::getOrder)) ;// Then by order - System.out.print("limit input:"+limit); - Stream processedStream = (limit != null) ? sortedStream.limit(limit) : sortedStream; - - return processedStream.map(VoiceRoomInfo::convertRoomDto) - .collect(Collectors.toList()); - - } - //Todo VoiceRoomDto로 이전예정 - public static List convertRoomDtoList(List roomDtoList) { - return convertRoomDtoList(roomDtoList, null); - } } } diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java b/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java index c7aadd5f..9e0a530c 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/RoomDto.java @@ -56,16 +56,7 @@ public static List convertRoomDtoListByVoiceRoom(List voiceR .map(RoomDto::convertRoom) .collect(Collectors.toList()); } -// public static Room convertRoom(LiveKitSession session){ -// return Room.builder() -// .name(session.) -// .numParticipants(room.getNumParticipants()) -// .creationTime(room.getCreationTime()) -// .sid(room.getSid()) -// .metadata(room.getMetadata()) -// .participantList(null) -// .build(); -// } + public static RoomDto convertRoom(VoiceRoom voiceRoom){ if(voiceRoom==null){return null;} return RoomDto.builder() diff --git a/src/main/java/space/space_spring/service/VoiceRoomService.java b/src/main/java/space/space_spring/service/VoiceRoomService.java index 6d4e89d2..629b080a 100644 --- a/src/main/java/space/space_spring/service/VoiceRoomService.java +++ b/src/main/java/space/space_spring/service/VoiceRoomService.java @@ -53,61 +53,6 @@ public Long createVoiceRoom(long spaceId,PostVoiceRoomDto.Request req){ return voiceRoomDao.createVoiceRoom(name, order, targetSpace); } - public List getVoiceRoomInfoList(long spaceId,GetVoiceRoomList.Request req){ - Integer limit = req.getLimit(); - boolean showParticipant =req.isShowParticipant(); - - - //해당 space VoiceRoom 가져오기 (VoiceRoom List) - //Todo 가져오기에 limit 적용 - List voiceRoomDataList = findBySpaceId(spaceId); - List roomDtoList = RoomDto.convertRoomDtoListByVoiceRoom(voiceRoomDataList); - //VoiceRoom과 Room mapping - //#1 Response 받아오기 - List roomResponses = liveKitUtils.getRoomList(); - //#2 Room과 mapping 시키기 - for(RoomDto roomDto : roomDtoList){ - roomDto.setActiveRoom(roomResponses); - } - //participant mapping - if (showParticipant) { - for(RoomDto roomDto : roomDtoList) { - if(roomDto.getNumParticipants()==0){ - //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 - System.out.print("\n[DEBUG]Participant Number : 0\n"); - roomDto.setParticipantDTOList(Collections.emptyList()); - continue; - } - //participantDto List 가져오기 - List participantDtoList = getParticipantDtoListById(roomDto.getId()); - for(ParticipantDto participantDto: participantDtoList){ - //Todo profileIamge 집어넣기 - participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); - } - //RoomDto에 값 집어넣기 - //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 - if(participantDtoList==null||participantDtoList.isEmpty()){ - System.out.print("\n\n[DEBUG]participant response is empty or null"+participantDtoList.toString()+ - "participant number is \n\n"); - roomDto.setParticipantDTOList(Collections.emptyList()); - }else { - roomDto.setParticipantDTOList(participantDtoList); - } - } - } - //ToDo Response로 convert - //#1 Active/inActive 분리 - - //#2 convert - if(limit==null||limit<=0) { - return GetVoiceRoomList.VoiceRoomInfo.convertRoomDtoList(roomDtoList); - }else{ - return GetVoiceRoomList.VoiceRoomInfo.convertRoomDtoList(roomDtoList,limit); - } - //return null; - } - - /** @@ -136,11 +81,6 @@ public List getVoiceRoomInfoListConcurrency(long VoiceRoomDtoList voiceRoomDtoList=VoiceRoomDtoList.from(voiceRoomDataList); voiceRoomDtoList.setActiveRoom(roomResponsesTemp); - //Todo 대체됨. 관련 함수 삭제 예정 - //#2 Room과 mapping 시키기 - for(RoomDto roomDto : roomDtoList){ - roomDto.setActiveRoom(roomResponses); - } //ToDo setRoomDto 함수를 RoomDtoList 객체로 이동 //todo 책임을 위임해도 이 병렬처리 코드가 잘 동작할까? @@ -170,6 +110,7 @@ public List getVoiceRoomInfoListConcurrency(long } //return null; } + //todo 해당 함수의 책임을 RoomDto에게 위임 private void setRoomDto(RoomDto roomDto,List roomResponses,GetVoiceRoomList.Request req){ roomDto.setActiveRoom(roomResponses); @@ -200,34 +141,6 @@ private void setRoomDto(RoomDto roomDto,List roomResponses,G } - -// private Function setActiveParticipant= roomDto->{ -// -// if(roomDto.getNumParticipants()==0){ -// //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 -// System.out.print("\n[DEBUG]Participant Number : 0\n"); -// roomDto.setParticipantDTOList(Collections.emptyList()); -// -// } -// //participantDto List 가져오기 -// List participantDtoList = this.getParticipantDtoListById(roomDto.getId()); -//// for(ParticipantDto participantDto: participantDtoList){ -//// //Todo profileIamge 집어넣기 -//// participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); -//// } -// //RoomDto에 값 집어넣기 -// //showParticipant = ture 일때, 참가자가 없으면 빈문자열[] 출력 -// if(participantDtoList==null||participantDtoList.isEmpty()){ -// System.out.print("\n\n[DEBUG]participant response is empty or null"+participantDtoList.toString()+ -// "participant number is \n\n"); -// roomDto.setParticipantDTOList(Collections.emptyList()); -// }else { -// roomDto.setParticipantDTOList(participantDtoList); -// } -// return roomDto; -// -// }; - public boolean updateVoiceRoom(List updateRoomList){ //Todo 입력된 order가 유효한지 확인 필요 @@ -276,24 +189,7 @@ private List getParticipantDtoListById(long voiceRoomId){ } return participantDtoList; } -// -// private static List getParticipantDtoListById(long voiceRoomId){ -// -// -// Space space = voiceRoomRepository.findById(voiceRoomId).getSpace(); -// List participantDtoList = liveKitUtils.getParticipantInfo(String.valueOf(voiceRoomId)); -// if(participantDtoList==null||participantDtoList.isEmpty()){ -// return Collections.emptyList(); -// } -// for(ParticipantDto participantDto: participantDtoList){ -// //profileIamge 집어넣기 -// participantDto.setProfileImage(findProfileImageByUserId(participantDto.getUserSpaceId())); -// //userSpaceId 집어 넣기 -// User user = userDao.findUserByUserId(participantDto.getId()); -// participantDto.setUserSpaceId(userSpaceDao.findUserSpaceByUserAndSpace(user,space).get().getUserSpaceId()); -// } -// return participantDtoList; -// } + public List getParticipantInfoListById(long voiceRoomId){ return GetParticipantList.ParticipantInfo.convertParticipantDtoList( @@ -301,12 +197,6 @@ public List getParticipantInfoListById(long //liveKitUtils.getParticipantInfo(findNameTagById(voiceRoomId)) ); } -// private String findNameTagById(long id){ -// VoiceRoom voiceRoom =voiceRoomRepository.findById(id); -// //null pointer error 처리 -// String name = voiceRoom.getName(); -// return name+" #"+String.valueOf(id); -// } public String getToken(long spaceId,long userId,long userSpaceId,long voiceRoomId){ String userName=userSpaceDao.findUserNameById(userSpaceId); diff --git a/src/test/java/space/space_spring/concurrency/completableFutureTest.java b/src/test/java/space/space_spring/concurrency/completableFutureTest.java index fadcb118..db951e46 100644 --- a/src/test/java/space/space_spring/concurrency/completableFutureTest.java +++ b/src/test/java/space/space_spring/concurrency/completableFutureTest.java @@ -81,6 +81,17 @@ public static List> processStringsAsync(List .collect(Collectors.toList()); } + @Test + void supplyAsyncb() throws ExecutionException, InterruptedException { + + CompletableFuture future = CompletableFuture.supplyAsync(() -> { + System.out.println("Thread task start"); + return "Thread: " + Thread.currentThread().getName(); + }); + + //System.out.println(future.get()); + System.out.println("Thread: " + Thread.currentThread().getName()); + } From c5dd1ba3b5bed7c265ef392c958eabc152d61c70 Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:27:10 +0900 Subject: [PATCH 32/38] [test] voice room service test : create voice room --- .../dto/VoiceRoom/PostVoiceRoomDto.java | 2 + .../VoiceRoom/VoiceRoomServiceTest.java | 143 ++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 src/test/java/space/space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java b/src/main/java/space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java index a3c0dc41..833df893 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java @@ -2,10 +2,12 @@ import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Getter; public class PostVoiceRoomDto { @Getter + @Builder public static class Request{ @NotNull(message = "name is mandatory") private String name; diff --git a/src/test/java/space/space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java b/src/test/java/space/space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java new file mode 100644 index 00000000..91f95083 --- /dev/null +++ b/src/test/java/space/space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java @@ -0,0 +1,143 @@ +package space.space_spring.domain.VoiceRoom; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito.*; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; +import space.space_spring.dao.UserDao; +import space.space_spring.dao.UserSpaceDao; +import space.space_spring.dao.VoiceRoomDao; +import space.space_spring.dao.VoiceRoomRepository; +import space.space_spring.dto.VoiceRoom.PostVoiceRoomDto; +import space.space_spring.entity.*; +import space.space_spring.entity.enumStatus.UserSignupType; +import space.space_spring.service.VoiceRoomService; +import space.space_spring.util.LiveKitUtils; +import space.space_spring.util.space.SpaceUtils; + + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class VoiceRoomServiceTest { + @InjectMocks + private VoiceRoomService voiceRoomService; + + @Mock + private VoiceRoomRepository voiceRoomRepository; + + @Mock + private VoiceRoomDao voiceRoomDao; + + @Mock + // 삭제 예정 + private SpaceUtils spaceUtils; + + @Mock + private LiveKitUtils liveKitUtils; + + @Mock + private UserDao userDao; + + @Mock + private UserSpaceDao userSpaceDao; + + + private User user1; + private User user2; + private User user3; + private User user4; + private User user5; + private User user6; + private User user7; + private Space testSpace; + private PayRequest testPayRequest_user1; + private PayRequest testPayRequest_user2; + private PayRequestTarget testPayRequestTarget_user1; + private PayRequestTarget testPayRequestTarget_user2; + private PayRequestTarget testPayRequestTarget_user3; + private PayRequestTarget testPayRequestTarget_user4; + + @BeforeEach + public void 테스트_셋업() { + /** + * : user2, 3은 정산 완료 X & user4는 정산 완료 + * : user1은 정산 완료 + */ + user1 = new User(); + user1.saveUser("test1@test.com", "abcDEF123!@", "user1", UserSignupType.LOCAL); + + user2 = new User(); + user2.saveUser("test2@test.com", "abcDEF123!@", "user2", UserSignupType.LOCAL); + + user3 = new User(); + user3.saveUser("test3@test.com", "abcDEF123!@", "user3", UserSignupType.LOCAL); + + user4 = new User(); + user4.saveUser("test4@test.com", "abcDEF123!@", "user4", UserSignupType.LOCAL); + + testSpace = new Space(); + testSpace.saveSpace("testSpace", "test_profile_img_url"); + + testPayRequest_user1 = new PayRequest(); + testPayRequest_user1.savePayRequest(user1, testSpace, 30000, "우리은행", "111-111-111", 0, false); + + testPayRequestTarget_user2 = new PayRequestTarget(); + testPayRequestTarget_user2.savePayRequestTarget(testPayRequest_user1, user2.getUserId(), 10000, false); + + testPayRequestTarget_user3 = new PayRequestTarget(); + testPayRequestTarget_user3.savePayRequestTarget(testPayRequest_user1, user3.getUserId(), 10000, false); + + testPayRequestTarget_user4 = new PayRequestTarget(); + testPayRequestTarget_user4.savePayRequestTarget(testPayRequest_user1, user4.getUserId(), 10000, true); + + testPayRequest_user2 = new PayRequest(); + testPayRequest_user2.savePayRequest(user2, testSpace, 10000, "국민은행", "111-111-111", 0, true); + + testPayRequestTarget_user1 = new PayRequestTarget(); + testPayRequestTarget_user1.savePayRequestTarget(testPayRequest_user2, user1.getUserId(), 10000, true); + + /** + * 추가로 user5,6,7 생성 + */ + user5 = new User(); + user6 = new User(); + user7 = new User(); + user5.saveUser("test5@test.com", "abcDEF123!@", "user5", UserSignupType.LOCAL); + user6.saveUser("test6@test.com", "abcDEF123!@", "user6", UserSignupType.LOCAL); + user7.saveUser("test7@test.com", "abcDEF123!@", "user7", UserSignupType.LOCAL); + + } + + @Test + @DisplayName("create VoiceRoom test") + void voiceRoom_create_test(){ + //given + int spaceOrder =1; + String voiceRoomName = "voiceRoom"; + Long spaceId = 2L; + //when + //when(testSpace.getSpaceId()).thenReturn(1L); + //testSpace. + ReflectionTestUtils.setField(testSpace,"spaceId",spaceId); + when(spaceUtils.findSpaceBySpaceId(testSpace.getSpaceId())).thenReturn(testSpace); + when(voiceRoomRepository.findMaxOrderBySpace(testSpace)).thenReturn(spaceOrder); + when(voiceRoomDao.createVoiceRoom(voiceRoomName,spaceOrder+1,testSpace)).thenReturn(1L); + + + PostVoiceRoomDto.Request request = PostVoiceRoomDto.Request.builder().name(voiceRoomName).build(); + Long voiceRoomId = voiceRoomService.createVoiceRoom(testSpace.getSpaceId(),request); + + //then + assertThat(voiceRoomId).isEqualTo(1L); + + } +} From 789e0fd675157de86c638de6d9ccfbd139ee8da7 Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Mon, 7 Oct 2024 03:32:35 +0900 Subject: [PATCH 33/38] [fix] PostVoiceRoom.Request refactoring --- .../space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java | 5 ++++- .../space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java | 6 ++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java b/src/main/java/space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java index 833df893..0395b5c6 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/PostVoiceRoomDto.java @@ -4,10 +4,13 @@ import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; public class PostVoiceRoomDto { @Getter - @Builder + //@Builder + @AllArgsConstructor + @NoArgsConstructor public static class Request{ @NotNull(message = "name is mandatory") private String name; diff --git a/src/test/java/space/space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java b/src/test/java/space/space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java index 91f95083..b7c88409 100644 --- a/src/test/java/space/space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java +++ b/src/test/java/space/space_spring/domain/VoiceRoom/VoiceRoomServiceTest.java @@ -9,7 +9,6 @@ import org.mockito.Mockito.*; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; -import space.space_spring.dao.UserDao; import space.space_spring.dao.UserSpaceDao; import space.space_spring.dao.VoiceRoomDao; import space.space_spring.dao.VoiceRoomRepository; @@ -44,8 +43,7 @@ public class VoiceRoomServiceTest { @Mock private LiveKitUtils liveKitUtils; - @Mock - private UserDao userDao; + @Mock private UserSpaceDao userSpaceDao; @@ -133,7 +131,7 @@ void voiceRoom_create_test(){ when(voiceRoomDao.createVoiceRoom(voiceRoomName,spaceOrder+1,testSpace)).thenReturn(1L); - PostVoiceRoomDto.Request request = PostVoiceRoomDto.Request.builder().name(voiceRoomName).build(); + PostVoiceRoomDto.Request request = new PostVoiceRoomDto.Request(voiceRoomName); Long voiceRoomId = voiceRoomService.createVoiceRoom(testSpace.getSpaceId(),request); //then From c3f45662673473c6a2d1a862a91eb8548d05dc8c Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Mon, 7 Oct 2024 03:33:32 +0900 Subject: [PATCH 34/38] [refactoring] add id base dao in voiceRoom and UserSpace --- .../space_spring/dao/UserSpaceRepository.java | 16 ++++++++++++++++ .../space_spring/dao/VoiceRoomRepository.java | 6 ++++++ .../space_spring/service/VoiceRoomService.java | 16 +++++++++------- 3 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 src/main/java/space/space_spring/dao/UserSpaceRepository.java diff --git a/src/main/java/space/space_spring/dao/UserSpaceRepository.java b/src/main/java/space/space_spring/dao/UserSpaceRepository.java new file mode 100644 index 00000000..6e3383c9 --- /dev/null +++ b/src/main/java/space/space_spring/dao/UserSpaceRepository.java @@ -0,0 +1,16 @@ +package space.space_spring.dao; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import space.space_spring.entity.UserSpace; +import space.space_spring.entity.VoiceRoom; + +import java.util.List; +import java.util.Optional; + +public interface UserSpaceRepository extends JpaRepository { + @Query("SELECT r FROM UserSpace r WHERE r.user.userId = :userId AND r.space.spaceId = :spaceId AND r.status = 'ACTIVE'") + Optional findUserSpaceByUserAndSpace(@Param("userId") Long userId, @Param("spaceId") Long spaceId); + +} diff --git a/src/main/java/space/space_spring/dao/VoiceRoomRepository.java b/src/main/java/space/space_spring/dao/VoiceRoomRepository.java index d3cea243..fc169ff7 100644 --- a/src/main/java/space/space_spring/dao/VoiceRoomRepository.java +++ b/src/main/java/space/space_spring/dao/VoiceRoomRepository.java @@ -16,10 +16,16 @@ public interface VoiceRoomRepository extends JpaRepository { List findBySpace(@Param("space")Space space); @Query("SELECT MAX(r.order) FROM VoiceRoom r WHERE r.space = :space AND r.status = 'ACTIVE'") Integer findMaxOrderBySpace(@Param("space") Space space); + + @Query("SELECT MAX(r.order) FROM VoiceRoom r WHERE r.space.id = :spaceId AND r.status = 'ACTIVE'") + Integer findMaxOrderBySpaceId(@Param("spaceId") Long spaceId); @Query("SELECT CASE WHEN COUNT(v) > 0 THEN true ELSE false END FROM VoiceRoom v WHERE v.voiceRoomId = :id AND v.status = 'ACTIVE'") boolean existsByVoiceRoomId(@Param("id")long voiceRoomId); @Query("SELECT CASE WHEN COUNT(v) > 0 THEN true ELSE false END FROM VoiceRoom v WHERE v.name = :voiceRoomName AND v.status = 'ACTIVE'") boolean existsByName(@Param("voiceRoomName") String voiceRoomName); @Query("SELECT v FROM VoiceRoom v WHERE v.voiceRoomId = :id AND v.status = 'ACTIVE'") VoiceRoom findById(@Param("id") long Id); + + @Query("SELECT v FROM VoiceRoom v WHERE v.space.id = :spaceId AND v.status = 'ACTIVE'") + List findActiveVoiceRoomsBySpaceId(@Param("spaceId") Long spaceId); } diff --git a/src/main/java/space/space_spring/service/VoiceRoomService.java b/src/main/java/space/space_spring/service/VoiceRoomService.java index 629b080a..9e187eba 100644 --- a/src/main/java/space/space_spring/service/VoiceRoomService.java +++ b/src/main/java/space/space_spring/service/VoiceRoomService.java @@ -42,6 +42,7 @@ public class VoiceRoomService { public Long createVoiceRoom(long spaceId,PostVoiceRoomDto.Request req){ Space targetSpace = spaceUtils.findSpaceBySpaceId(spaceId); Integer orderInt = voiceRoomRepository.findMaxOrderBySpace(targetSpace); + //Space currentSpace=voiceRoomRepository.findActiveVoiceRoomsBySpaceId(spaceId); int order; if(orderInt==null||orderInt==0){ order=1; @@ -66,7 +67,8 @@ public List getVoiceRoomInfoListConcurrency(long //해당 space VoiceRoom 가져오기 (VoiceRoom List) //Todo 가져오기에 limit 적용 //todo 일급 객체 `voiceRoomEntityList`로 변경 - List voiceRoomDataList = findBySpaceId(spaceId); + //List voiceRoomDataList = findBySpaceId(spaceId); + List voiceRoomDataList = voiceRoomRepository.findActiveVoiceRoomsBySpaceId(spaceId); //todo voiceRoomEntityList 객체에 책임 위임 //todo RoomDtoList 일급 객체 생성 List roomDtoList = RoomDto.convertRoomDtoListByVoiceRoom(voiceRoomDataList); @@ -168,12 +170,12 @@ public void deleteVoiceRoom(long voiceRoomId){ private String findProfileImageByUserId(Long userSpaceId){ return userSpaceDao.findProfileImageById(userSpaceId).orElse(""); } - public List findBySpaceId(long spaceId){ - return findBySpace(spaceUtils.findSpaceBySpaceId(spaceId)); - } - private List findBySpace(Space space){ - return voiceRoomRepository.findBySpace(space); - } +// public List findBySpaceId(long spaceId){ +// return findBySpace(spaceUtils.findSpaceBySpaceId(spaceId)); +// } +// private List findBySpace(Space space){ +// return voiceRoomRepository.findBySpace(space); +// } private List getParticipantDtoListById(long voiceRoomId){ Space space = voiceRoomRepository.findById(voiceRoomId).getSpace(); List participantDtoList = liveKitUtils.getParticipantInfo(String.valueOf(voiceRoomId)); From 7216a72389ccbd848315167190cbce064483f7a5 Mon Sep 17 00:00:00 2001 From: kim_sang_ june <79149384+drbug2000@users.noreply.github.com> Date: Tue, 8 Oct 2024 20:37:44 +0900 Subject: [PATCH 35/38] [refactoring] rename VoicRoomDtoList->VoiceRoomListDto --- .../{VoiceRoomDtoList.java => VoiceRoomListDto.java} | 8 ++++---- .../java/space/space_spring/service/VoiceRoomService.java | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) rename src/main/java/space/space_spring/dto/VoiceRoom/{VoiceRoomDtoList.java => VoiceRoomListDto.java} (92%) diff --git a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomListDto.java similarity index 92% rename from src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java rename to src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomListDto.java index 708ce962..ffc5ad9e 100644 --- a/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomDtoList.java +++ b/src/main/java/space/space_spring/dto/VoiceRoom/VoiceRoomListDto.java @@ -11,16 +11,16 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -public class VoiceRoomDtoList { +public class VoiceRoomListDto { private List roomDtoList; - public VoiceRoomDtoList(List roomDtos){ + public VoiceRoomListDto(List roomDtos){ this.roomDtoList=roomDtos; } - public static VoiceRoomDtoList from(List voiceRoomEntityList){ + public static VoiceRoomListDto from(List voiceRoomEntityList){ List roomDtos = convertRoomDtoListByVoiceRoom(voiceRoomEntityList); - return new VoiceRoomDtoList(roomDtos); + return new VoiceRoomListDto(roomDtos); } public static List convertRoomDtoListByVoiceRoom(List voiceRoomList){ diff --git a/src/main/java/space/space_spring/service/VoiceRoomService.java b/src/main/java/space/space_spring/service/VoiceRoomService.java index 9e187eba..b3e49928 100644 --- a/src/main/java/space/space_spring/service/VoiceRoomService.java +++ b/src/main/java/space/space_spring/service/VoiceRoomService.java @@ -80,8 +80,8 @@ public List getVoiceRoomInfoListConcurrency(long //불변 list로 변환 List roomResponses = Collections.unmodifiableList(roomResponsesTemp); - VoiceRoomDtoList voiceRoomDtoList=VoiceRoomDtoList.from(voiceRoomDataList); - voiceRoomDtoList.setActiveRoom(roomResponsesTemp); + VoiceRoomListDto voiceRoomListDto = VoiceRoomListDto.from(voiceRoomDataList); + voiceRoomListDto.setActiveRoom(roomResponsesTemp); //ToDo setRoomDto 함수를 RoomDtoList 객체로 이동 @@ -104,10 +104,10 @@ public List getVoiceRoomInfoListConcurrency(long //#2 convert if(limit==null||limit<=0) { - return voiceRoomDtoList.convertVoicRoomInfoList(); + return voiceRoomListDto.convertVoicRoomInfoList(); //return GetVoiceRoomList.VoiceRoomInfo.convertRoomDtoList(roomDtoList); }else{ - return voiceRoomDtoList.convertVoicRoomInfoList(limit); + return voiceRoomListDto.convertVoicRoomInfoList(limit); //return GetVoiceRoomList.VoiceRoomInfo.convertRoomDtoList(roomDtoList,limit); } //return null; From 2fc6cde7ee79381e0fe3818cf9951cde3d515c80 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Wed, 30 Oct 2024 21:04:08 +0900 Subject: [PATCH 36/38] =?UTF-8?q?refactor=20:=20JwtServiceTest=20=EC=95=88?= =?UTF-8?q?=EC=93=B0=EB=8A=94=20import=20=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 --- .../domain/authorization/jwt/service/JwtServiceTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java index fc5fdee5..d4b8c64a 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java @@ -13,7 +13,6 @@ import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; import space.space_spring.domain.authorization.jwt.model.TokenPairDTO; import space.space_spring.domain.authorization.jwt.model.TokenResolver; @@ -30,7 +29,6 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.*; @DataJpaTest @Import({JwtService.class, JwtLoginProvider.class, TokenResolver.class}) From ebe40c9e35310223733096da920533d4052fd1f7 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Fri, 1 Nov 2024 16:15:25 +0900 Subject: [PATCH 37/38] =?UTF-8?q?refactor=20:=20TokenResolver=20->=20JwtLo?= =?UTF-8?q?ginTokenResolver=20=EA=B0=9D=EC=B2=B4=20=EC=9D=B4=EB=A6=84=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 --- ...solver.java => JwtLoginTokenResolver.java} | 2 +- .../authorization/jwt/service/JwtService.java | 2 +- .../jwt/model/JwtLoginProviderTest.java | 5 ----- ...st.java => JwtLoginTokenResolverTest.java} | 22 +++++-------------- .../jwt/service/JwtServiceTest.java | 6 ++--- 5 files changed, 10 insertions(+), 27 deletions(-) rename src/main/java/space/space_spring/domain/authorization/jwt/model/{TokenResolver.java => JwtLoginTokenResolver.java} (97%) rename src/test/java/space/space_spring/domain/authorization/jwt/model/{TokenResolverTest.java => JwtLoginTokenResolverTest.java} (75%) diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginTokenResolver.java similarity index 97% rename from src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java rename to src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginTokenResolver.java index b657ece2..56381bc5 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/model/TokenResolver.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/model/JwtLoginTokenResolver.java @@ -13,7 +13,7 @@ @Component @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class TokenResolver { +public class JwtLoginTokenResolver { private static final String JWT_TOKEN_PREFIX = "Bearer "; diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index 1f8004e4..df928df1 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -24,7 +24,7 @@ public class JwtService { private final JwtRepository jwtRepository; private final UserRepository userRepository; private final JwtLoginProvider jwtLoginProvider; - private final TokenResolver tokenResolver; + private final JwtLoginTokenResolver tokenResolver; @Transactional public TokenPairDTO updateTokenPair(HttpServletRequest request) { diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java index 10e6bd1a..053dc66b 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginProviderTest.java @@ -7,17 +7,12 @@ import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.SpringJUnitConfig; -import space.space_spring.config.WebSocketConfig; import java.util.Date; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; @SpringJUnitConfig(JwtLoginProvider.class) @TestPropertySource(properties = { // 테스트용 프로퍼티 소스(환경 설정) 지정 diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginTokenResolverTest.java similarity index 75% rename from src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java rename to src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginTokenResolverTest.java index c62e71d5..ad6e8b14 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/model/TokenResolverTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/model/JwtLoginTokenResolverTest.java @@ -1,27 +1,15 @@ package space.space_spring.domain.authorization.jwt.model; -import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.context.TestConfiguration; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit.jupiter.SpringExtension; import space.space_spring.exception.jwt.bad_request.JwtNoTokenException; import space.space_spring.exception.jwt.bad_request.JwtUnsupportedTokenException; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.*; -class TokenResolverTest { +class JwtLoginTokenResolverTest { private static final String JWT_TOKEN_PREFIX = "Bearer "; @@ -29,7 +17,7 @@ class TokenResolverTest { @DisplayName("request header로부터 access token, refresh token을 rosolve한다.") void resolveTokenPair() throws Exception { //given - TokenResolver tokenResolver = new TokenResolver(); + JwtLoginTokenResolver tokenResolver = new JwtLoginTokenResolver(); MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization", JWT_TOKEN_PREFIX + "accessToken"); @@ -47,7 +35,7 @@ void resolveTokenPair() throws Exception { @DisplayName("access token값이 null 일 경우 예외를 던진다.") void validateToken1() throws Exception { //given - TokenResolver tokenResolver = new TokenResolver(); + JwtLoginTokenResolver tokenResolver = new JwtLoginTokenResolver(); MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization-refresh", JWT_TOKEN_PREFIX + "refreshToken"); @@ -62,7 +50,7 @@ void validateToken1() throws Exception { @DisplayName("refresh token값이 null 일 경우 예외를 던진다.") void validateToken2() throws Exception { //given - TokenResolver tokenResolver = new TokenResolver(); + JwtLoginTokenResolver tokenResolver = new JwtLoginTokenResolver(); MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization", JWT_TOKEN_PREFIX + "accessToken"); @@ -77,7 +65,7 @@ void validateToken2() throws Exception { @DisplayName("토큰값의 prefix가 잘못된 경우 예외를 던진다.") void validateToken3() throws Exception { //given - TokenResolver tokenResolver = new TokenResolver(); + JwtLoginTokenResolver tokenResolver = new JwtLoginTokenResolver(); MockHttpServletRequest request = new MockHttpServletRequest(); request.addHeader("Authorization", "wrong prefix " + "accessToken"); diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java index d4b8c64a..7f767f39 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java @@ -15,7 +15,7 @@ import org.springframework.test.context.TestPropertySource; import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; import space.space_spring.domain.authorization.jwt.model.TokenPairDTO; -import space.space_spring.domain.authorization.jwt.model.TokenResolver; +import space.space_spring.domain.authorization.jwt.model.JwtLoginTokenResolver; import space.space_spring.domain.authorization.jwt.repository.JwtRepository; import space.space_spring.domain.user.repository.UserRepository; import space.space_spring.entity.TokenStorage; @@ -31,7 +31,7 @@ import static org.assertj.core.api.Assertions.assertThatThrownBy; @DataJpaTest -@Import({JwtService.class, JwtLoginProvider.class, TokenResolver.class}) +@Import({JwtService.class, JwtLoginProvider.class, JwtLoginTokenResolver.class}) @ActiveProfiles("test") @TestPropertySource(properties = { "secret.jwt.access-secret-key=accessSecretKeyaccessSecretKeyaccessSecretKey", @@ -56,7 +56,7 @@ class JwtServiceTest { private JwtLoginProvider jwtLoginProvider; @Autowired - private TokenResolver tokenResolver; + private JwtLoginTokenResolver tokenResolver; private static final String JWT_TOKEN_PREFIX = "Bearer "; From 8eaab2e0fb927e541ff46c5a2357b2e9d79f309d Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sat, 2 Nov 2024 16:19:05 +0900 Subject: [PATCH 38/38] =?UTF-8?q?refactor=20:=20TokenStorage=20->=20Refres?= =?UTF-8?q?hTokenStorage=20=EC=97=94=ED=8B=B0=ED=8B=B0=20=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../auth/service/AuthService.java | 4 ++-- .../jwt/repository/JwtRepository.java | 8 ++++---- .../authorization/jwt/service/JwtService.java | 14 ++++++------- ...nStorage.java => RefreshTokenStorage.java} | 9 ++++----- .../jwt/service/JwtServiceTest.java | 20 +++++++++---------- 5 files changed, 27 insertions(+), 28 deletions(-) rename src/main/java/space/space_spring/entity/{TokenStorage.java => RefreshTokenStorage.java} (79%) diff --git a/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java b/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java index 9d702884..87fb127f 100644 --- a/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java +++ b/src/main/java/space/space_spring/domain/authorization/auth/service/AuthService.java @@ -9,7 +9,7 @@ import space.space_spring.domain.authorization.jwt.model.TokenType; import space.space_spring.domain.authorization.jwt.repository.JwtRepository; import space.space_spring.domain.user.model.PostLoginDto; -import space.space_spring.entity.TokenStorage; +import space.space_spring.entity.RefreshTokenStorage; import space.space_spring.entity.User; import space.space_spring.exception.CustomException; import space.space_spring.domain.authorization.jwt.model.JwtLoginProvider; @@ -44,7 +44,7 @@ public PostLoginDto login(PostLoginDto.Request request) { String refreshToken = jwtLoginProvider.generateToken(userByEmail.getUserId(), TokenType.REFRESH); // TODO 4. refresh token db에 저장 - TokenStorage tokenStorage = TokenStorage.builder() + RefreshTokenStorage tokenStorage = RefreshTokenStorage.builder() .user(userByEmail) .tokenValue(refreshToken) .build(); diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java b/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java index 69b4e12e..85654bcf 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/repository/JwtRepository.java @@ -6,19 +6,19 @@ import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; -import space.space_spring.entity.TokenStorage; +import space.space_spring.entity.RefreshTokenStorage; import space.space_spring.entity.User; import java.util.Optional; @Repository -public interface JwtRepository extends JpaRepository { +public interface JwtRepository extends JpaRepository { - Optional findByUser(User user); + Optional findByUser(User user); @Modifying @Transactional - @Query("DELETE FROM TokenStorage t WHERE t.user = :user") + @Query("DELETE FROM RefreshTokenStorage t WHERE t.user = :user") void deleteByUser(@Param("user") User user); } diff --git a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java index df928df1..9a2ba721 100644 --- a/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java +++ b/src/main/java/space/space_spring/domain/authorization/jwt/service/JwtService.java @@ -8,7 +8,7 @@ import space.space_spring.domain.authorization.jwt.model.*; import space.space_spring.domain.authorization.jwt.repository.JwtRepository; import space.space_spring.domain.user.repository.UserRepository; -import space.space_spring.entity.TokenStorage; +import space.space_spring.entity.RefreshTokenStorage; import space.space_spring.entity.User; import space.space_spring.exception.CustomException; import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; @@ -49,7 +49,7 @@ private User getUserByAccessToken(String accessToken) { } private void validateRefreshToken(User user, String refreshToken) { - TokenStorage tokenStorage = jwtRepository.findByUser(user) + RefreshTokenStorage tokenStorage = jwtRepository.findByUser(user) .orElseThrow(() -> { // db에서 row delete 하는 코드 추가 @@ -61,7 +61,7 @@ private void validateRefreshToken(User user, String refreshToken) { if (jwtLoginProvider.isExpiredToken(refreshToken, TokenType.REFRESH)) { // refresh token이 만료된 경우 -> 예외 발생 -> 유저의 재 로그인 유도 // db에서 row delete 하는 코드 추가 - deleteTokenStorage(user); + deleteRefreshTokenStorage(user); throw new JwtExpiredTokenException(EXPIRED_REFRESH_TOKEN); } @@ -70,19 +70,19 @@ private void validateRefreshToken(User user, String refreshToken) { if (!tokenStorage.checkTokenValue(refreshToken)) { // refresh token이 db에 존재하는 token 값과 일치하지 않는 경우 -> 유효하지 않은 refresh token이므로 예외 발생 // db에서 row delete 하는 코드 추가 - deleteTokenStorage(user); + deleteRefreshTokenStorage(user); throw new JwtUnauthorizedTokenException(TOKEN_MISMATCH); } } @Transactional(propagation = Propagation.REQUIRES_NEW) - public void deleteTokenStorage(User user) { + public void deleteRefreshTokenStorage(User user) { jwtRepository.deleteByUser(user); } private TokenPairDTO updateTokenPair(User user) { - TokenStorage tokenStorage = jwtRepository.findByUser(user) + RefreshTokenStorage tokenStorage = jwtRepository.findByUser(user) .orElseThrow(() -> new JwtUnauthorizedTokenException(TOKEN_MISMATCH)); // new access token, new refresh token 발급 받아서 @@ -111,7 +111,7 @@ public TokenPairDTO provideJwtToOAuthUser(User userByOAuthInfo) { @Transactional public void updateRefreshToken(User user, String refreshToken) { - TokenStorage tokenStorage = jwtRepository.findByUser(user) + RefreshTokenStorage tokenStorage = jwtRepository.findByUser(user) .orElseThrow(() -> new JwtUnauthorizedTokenException(TOKEN_MISMATCH)); tokenStorage.updateTokenValue(refreshToken); diff --git a/src/main/java/space/space_spring/entity/TokenStorage.java b/src/main/java/space/space_spring/entity/RefreshTokenStorage.java similarity index 79% rename from src/main/java/space/space_spring/entity/TokenStorage.java rename to src/main/java/space/space_spring/entity/RefreshTokenStorage.java index b0edd35a..d79f3bef 100644 --- a/src/main/java/space/space_spring/entity/TokenStorage.java +++ b/src/main/java/space/space_spring/entity/RefreshTokenStorage.java @@ -1,7 +1,6 @@ package space.space_spring.entity; import jakarta.persistence.*; -import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -10,7 +9,7 @@ @Table(name = "Token_Storage") @Getter @NoArgsConstructor -public class TokenStorage { +public class RefreshTokenStorage { @Id @GeneratedValue @Column(name = "token_storage_id") @@ -32,13 +31,13 @@ public boolean checkTokenValue(String tokenValue) { } @Builder - private TokenStorage(User user, String tokenValue) { + private RefreshTokenStorage(User user, String tokenValue) { this.user = user; this.tokenValue = tokenValue; } - public static TokenStorage create(User user, String tokenValue) { - return TokenStorage.builder() + public static RefreshTokenStorage create(User user, String tokenValue) { + return RefreshTokenStorage.builder() .user(user) .tokenValue(tokenValue) .build(); diff --git a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java index 7f767f39..8c1fe0fb 100644 --- a/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java +++ b/src/test/java/space/space_spring/domain/authorization/jwt/service/JwtServiceTest.java @@ -18,7 +18,7 @@ import space.space_spring.domain.authorization.jwt.model.JwtLoginTokenResolver; import space.space_spring.domain.authorization.jwt.repository.JwtRepository; import space.space_spring.domain.user.repository.UserRepository; -import space.space_spring.entity.TokenStorage; +import space.space_spring.entity.RefreshTokenStorage; import space.space_spring.entity.User; import space.space_spring.entity.enumStatus.UserSignupType; import space.space_spring.exception.jwt.unauthorized.JwtExpiredTokenException; @@ -40,7 +40,7 @@ "secret.jwt.refresh-expired-in=604800000" }) @EnableJpaRepositories(basePackageClasses = {UserRepository.class, JwtRepository.class}) -@EntityScan(basePackageClasses = {User.class, TokenStorage.class}) +@EntityScan(basePackageClasses = {User.class, RefreshTokenStorage.class}) class JwtServiceTest { @Autowired @@ -80,7 +80,7 @@ void updateTokenPair1() throws Exception { .signWith(SignatureAlgorithm.HS256, "refreshSecretKeyrefreshSecretKeyrefreshSecretKey") .compact(); - TokenStorage tokenStorage = TokenStorage.create(savedUser, refreshToken); + RefreshTokenStorage tokenStorage = RefreshTokenStorage.create(savedUser, refreshToken); jwtRepository.save(tokenStorage); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -101,10 +101,10 @@ void updateTokenPair1() throws Exception { assertThat(accessTokenClaims.get("userId", Long.class)).isEqualTo(userId); - TokenStorage updatedTokenStorage = jwtRepository.findByUser(savedUser) - .orElseThrow(() -> new Exception("TokenStorage not found")); + RefreshTokenStorage updatedRefreshTokenStorage = jwtRepository.findByUser(savedUser) + .orElseThrow(() -> new Exception("RefreshTokenStorage not found")); - assertThat(updatedTokenStorage.getTokenValue()).isEqualTo(newRefreshToken); + assertThat(updatedRefreshTokenStorage.getTokenValue()).isEqualTo(newRefreshToken); System.out.println("old access token = " + accessToken); System.out.println("new access token = " + newAccessToken); @@ -133,7 +133,7 @@ void updateTokenPair2() throws Exception { .signWith(SignatureAlgorithm.HS256, "refreshSecretKeyrefreshSecretKeyrefreshSecretKey") .compact(); - TokenStorage tokenStorage = TokenStorage.create(savedUser, refreshToken); + RefreshTokenStorage tokenStorage = RefreshTokenStorage.create(savedUser, refreshToken); jwtRepository.save(tokenStorage); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -145,7 +145,7 @@ void updateTokenPair2() throws Exception { .isInstanceOf(JwtExpiredTokenException.class) .hasMessage("만료된 refresh token 입니다. 다시 로그인해야합니다."); - Optional byUser = jwtRepository.findByUser(user); + Optional byUser = jwtRepository.findByUser(user); assertThat(byUser).isEmpty(); } @@ -171,7 +171,7 @@ void updateTokenPair3() throws Exception { String anotherRefreshToken = "anotherRefreshToken"; - TokenStorage tokenStorage = TokenStorage.create(savedUser, anotherRefreshToken); + RefreshTokenStorage tokenStorage = RefreshTokenStorage.create(savedUser, anotherRefreshToken); jwtRepository.save(tokenStorage); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -183,7 +183,7 @@ void updateTokenPair3() throws Exception { .isInstanceOf(JwtUnauthorizedTokenException.class) .hasMessage("저장된 refresh token 과 전달받은 refresh token 이 일치하지 않습니다. 다시 로그인해야합니다."); - Optional byUser = jwtRepository.findByUser(user); + Optional byUser = jwtRepository.findByUser(user); assertThat(byUser).isEmpty(); System.out.println("refresh token = " + refreshToken);