From a0ccc91959d6c7265b223d14e8c8709666a41e62 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Fri, 27 Jun 2025 11:08:00 +0900 Subject: [PATCH 01/17] =?UTF-8?q?[refactor]=20:=20=ED=9A=8C=EC=9B=90?= =?UTF-8?q?=EA=B0=80=EC=9E=85=20api=20request=20dto=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=88=98=EC=A0=95=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - nickname 필드값 bean validation 수정 - 테스트 코드의 메서드 네이밍 간결하게 수정 --- .../in/web/request/UserSignupRequest.java | 9 ++--- ...est.java => UserSignupControllerTest.java} | 39 ++++++++++++++----- 2 files changed, 32 insertions(+), 16 deletions(-) rename src/test/java/konkuk/thip/user/adapter/in/web/{UserCommandControllerTest.java => UserSignupControllerTest.java} (82%) diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/request/UserSignupRequest.java b/src/main/java/konkuk/thip/user/adapter/in/web/request/UserSignupRequest.java index 96c9725a3..720435b7e 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/request/UserSignupRequest.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/request/UserSignupRequest.java @@ -1,17 +1,14 @@ package konkuk.thip.user.adapter.in.web.request; -import jakarta.validation.constraints.Email; -import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.*; import konkuk.thip.user.application.port.in.dto.UserSignupCommand; -import org.hibernate.validator.constraints.Length; public record UserSignupRequest( @NotNull(message = "aliasId는 필수입니다.") Long aliasId, - @NotBlank(message = "닉네임은 공백일 수 없습니다.") - @Length(max = 10, message = "닉네임은 최대 10자 입니다.") + @Pattern(regexp = "[가-힣a-zA-Z0-9]+", message = "닉네임은 한글, 영어, 숫자로만 구성되어야 합니다.(공백불가)") + @Size(max = 10, message = "닉네임은 최대 10자 입니다.") String nickname, @NotBlank(message = "이메일은 공백일 수 없습니다.") diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserCommandControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java similarity index 82% rename from src/test/java/konkuk/thip/user/adapter/in/web/UserCommandControllerTest.java rename to src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java index fe6ef27c2..6d0a6223b 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserCommandControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java @@ -27,7 +27,7 @@ @SpringBootTest @ActiveProfiles("test") @AutoConfigureMockMvc -class UserCommandControllerTest { +class UserSignupControllerTest { @Autowired private MockMvc mockMvc; @@ -54,7 +54,7 @@ void signup_success() throws Exception { UserSignupRequest request = new UserSignupRequest( aliasJpaEntity.getAliasId(), - "테스트 유저", + "테스트유저", "test@test.com" ); @@ -80,7 +80,7 @@ void signup_success() throws Exception { @Test @DisplayName("[칭호id]값이 null일 경우, 400 error가 발생한다.") - void signup_whenAliasIdNull_thenBadRequest() throws Exception { + void signup_alias_id_null() throws Exception { //given: aliasId null UserSignupRequest request = new UserSignupRequest( null, @@ -99,7 +99,7 @@ void signup_whenAliasIdNull_thenBadRequest() throws Exception { @Test @DisplayName("[닉네임]값이 공백일 경우, 400 error가 발생한다.") - void signup_whenNicknameBlank_thenBadRequest() throws Exception { + void signup_nickname_blank() throws Exception { //given: nickname blank UserSignupRequest request = new UserSignupRequest( 1L, @@ -113,16 +113,35 @@ void signup_whenNicknameBlank_thenBadRequest() throws Exception { .content(objectMapper.writeValueAsString(request))) .andExpect(status().isBadRequest()) .andExpect(jsonPath("$.code").value(API_INVALID_PARAM.getCode())) - .andExpect(jsonPath("$.message", containsString("닉네임은 공백일 수 없습니다."))); + .andExpect(jsonPath("$.message", containsString("닉네임은 한글, 영어, 숫자로만 구성되어야 합니다.(공백불가)"))); + } + + @Test + @DisplayName("[닉네임]값이 한글, 영어, 숫자 외의 문자를 포함할 경우, 400 error가 발생한다.") + void signup_nickname_invalid_pattern() throws Exception { + //given: nickname with invalid characters + UserSignupRequest request = new UserSignupRequest( + 1L, + "닉네임!!", + "test@test.com" + ); + + //when //then + mockMvc.perform(post("/users/signup") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(API_INVALID_PARAM.getCode())) + .andExpect(jsonPath("$.message", containsString("닉네임은 한글, 영어, 숫자로만 구성되어야 합니다.(공백불가)"))); } @Test @DisplayName("[닉네임]값이 11자 이상일 경우, 400 error가 발생한다.") - void signup_whenNicknameTooLong_thenBadRequest() throws Exception { - //given: nickname blank + void signup_nickname_too_long() throws Exception { + //given: 11글자 nickname UserSignupRequest request = new UserSignupRequest( 1L, - "11자_닉네임_입니다", + "11글자닉네임입니다아", "test@test.com" ); @@ -137,7 +156,7 @@ void signup_whenNicknameTooLong_thenBadRequest() throws Exception { @Test @DisplayName("[이메일]값이 공백일 경우, 400 error가 발생한다.") - void signup_whenEmailBlank_thenBadRequest() throws Exception { + void signup_email_blank() throws Exception { //given UserSignupRequest request = new UserSignupRequest( 1L, @@ -156,7 +175,7 @@ void signup_whenEmailBlank_thenBadRequest() throws Exception { @Test @DisplayName("[이메일]값이 유효한 이메일 형식이 아닐 경우, 400 error가 발생한다.") - void signup_whenEmailInvalidFormat_thenBadRequest() throws Exception { + void signup_email_invalid_format() throws Exception { //given UserSignupRequest request = new UserSignupRequest( 1L, From 290e7c6e4a38d57f3dd83a9bea17f7064fb3664a Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Fri, 27 Jun 2025 11:18:15 +0900 Subject: [PATCH 02/17] =?UTF-8?q?[refactor]=20:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=A9=94=EC=84=9C=EB=93=9C=EC=97=90=20DB=20clear?= =?UTF-8?q?=20=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 각각 테스트 메서드 종료 후 DB를 clear 해주는 @BeforeEach 메서드 추가 - 테스트 클래스에 @Transactional 을 명시하는 방법도 있지만, 명시적으로 DB 클리어를 보여주기 위해 @BeforeEach 메서드 사용을 채택하였음 --- .../thip/user/adapter/in/web/UserSignupControllerTest.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java index 6d0a6223b..5ab0bd72c 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java @@ -7,6 +7,7 @@ import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.UserJpaRepository; +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; @@ -41,6 +42,12 @@ class UserSignupControllerTest { @Autowired private UserJpaRepository userJpaRepository; + @BeforeEach + void tearDown() { + userJpaRepository.deleteAll(); + aliasJpaRepository.deleteAll(); + } + @Test @DisplayName("[칭호id, 닉네임, 이메일] 정보를 바탕으로 회원가입을 진행한다.") void signup_success() throws Exception { From fe71388a9a19676d283e00872fb363a1d645334b Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Fri, 27 Jun 2025 11:19:09 +0900 Subject: [PATCH 03/17] =?UTF-8?q?[feat]=20:=20=EB=8B=89=EB=84=A4=EC=9E=84?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20=EA=B2=80=EC=82=AC=20api=20controller?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/adapter/in/web/UserCommandController.java | 12 +++++++++++- .../in/web/request/VerifyNicknameRequest.java | 11 +++++++++++ .../in/web/response/VerifyNicknameResponse.java | 7 +++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/main/java/konkuk/thip/user/adapter/in/web/request/VerifyNicknameRequest.java create mode 100644 src/main/java/konkuk/thip/user/adapter/in/web/response/VerifyNicknameResponse.java diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/UserCommandController.java b/src/main/java/konkuk/thip/user/adapter/in/web/UserCommandController.java index e799f0509..10f8fb4c5 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/UserCommandController.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/UserCommandController.java @@ -2,9 +2,11 @@ import konkuk.thip.common.dto.BaseResponse; import konkuk.thip.user.adapter.in.web.request.UserSignupRequest; +import konkuk.thip.user.adapter.in.web.request.VerifyNicknameRequest; import konkuk.thip.user.adapter.in.web.response.UserSignupResponse; +import konkuk.thip.user.adapter.in.web.response.VerifyNicknameResponse; import konkuk.thip.user.application.port.in.UserSignupUseCase; -import konkuk.thip.user.application.port.in.dto.UserSignupCommand; +import konkuk.thip.user.application.port.in.VerifyNicknameUseCase; import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; @@ -16,6 +18,7 @@ public class UserCommandController { private final UserSignupUseCase userSignupUseCase; + private final VerifyNicknameUseCase verifyNicknameUseCase; @PostMapping("/users/signup") public BaseResponse signup(@Validated @RequestBody UserSignupRequest request) { @@ -23,4 +26,11 @@ public BaseResponse signup(@Validated @RequestBody UserSignu userSignupUseCase.signup(request.toCommand())) ); } + + @PostMapping("/users/nickname") + public BaseResponse verifyNickname(@Validated @RequestBody VerifyNicknameRequest request) { + return BaseResponse.ok(VerifyNicknameResponse.of( + verifyNicknameUseCase.isNicknameUnique(request.nickname())) + ); + } } diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/request/VerifyNicknameRequest.java b/src/main/java/konkuk/thip/user/adapter/in/web/request/VerifyNicknameRequest.java new file mode 100644 index 000000000..b552614d9 --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/in/web/request/VerifyNicknameRequest.java @@ -0,0 +1,11 @@ +package konkuk.thip.user.adapter.in.web.request; + +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; + +public record VerifyNicknameRequest( + @Pattern(regexp = "[가-힣a-zA-Z0-9]+", message = "닉네임은 한글, 영어, 숫자로만 구성되어야 합니다.(공백불가)") + @Size(max = 10, message = "닉네임은 최대 10자 입니다.") + String nickname +) { +} diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/response/VerifyNicknameResponse.java b/src/main/java/konkuk/thip/user/adapter/in/web/response/VerifyNicknameResponse.java new file mode 100644 index 000000000..b6ef18cb5 --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/in/web/response/VerifyNicknameResponse.java @@ -0,0 +1,7 @@ +package konkuk.thip.user.adapter.in.web.response; + +public record VerifyNicknameResponse(boolean isVerified) { + public static VerifyNicknameResponse of(boolean isVerified) { + return new VerifyNicknameResponse(isVerified); + } +} From 8e02a9bd2e1281007a1935d50784db94645ab9fa Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Fri, 27 Jun 2025 11:19:24 +0900 Subject: [PATCH 04/17] =?UTF-8?q?[feat]=20:=20=EB=8B=89=EB=84=A4=EC=9E=84?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20=EA=B2=80=EC=82=AC=20api=20use=20case?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../port/in/VerifyNicknameUseCase.java | 6 ++++++ .../service/VerifyNicknameService.java | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) create mode 100644 src/main/java/konkuk/thip/user/application/port/in/VerifyNicknameUseCase.java create mode 100644 src/main/java/konkuk/thip/user/application/service/VerifyNicknameService.java diff --git a/src/main/java/konkuk/thip/user/application/port/in/VerifyNicknameUseCase.java b/src/main/java/konkuk/thip/user/application/port/in/VerifyNicknameUseCase.java new file mode 100644 index 000000000..3cca5a9f3 --- /dev/null +++ b/src/main/java/konkuk/thip/user/application/port/in/VerifyNicknameUseCase.java @@ -0,0 +1,6 @@ +package konkuk.thip.user.application.port.in; + +public interface VerifyNicknameUseCase { + + boolean isNicknameUnique(String nickname); +} diff --git a/src/main/java/konkuk/thip/user/application/service/VerifyNicknameService.java b/src/main/java/konkuk/thip/user/application/service/VerifyNicknameService.java new file mode 100644 index 000000000..f8cae39a1 --- /dev/null +++ b/src/main/java/konkuk/thip/user/application/service/VerifyNicknameService.java @@ -0,0 +1,18 @@ +package konkuk.thip.user.application.service; + +import konkuk.thip.user.application.port.in.VerifyNicknameUseCase; +import konkuk.thip.user.application.port.out.UserQueryPort; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class VerifyNicknameService implements VerifyNicknameUseCase { + + private final UserQueryPort userQueryPort; + + @Override + public boolean isNicknameUnique(String nickname) { + return !userQueryPort.existsByNickname(nickname); + } +} From f665e7aefbdd2a6d3c7bddd9999024b5c63eaebd Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Fri, 27 Jun 2025 11:19:45 +0900 Subject: [PATCH 05/17] =?UTF-8?q?[feat]=20:=20=EB=8B=89=EB=84=A4=EC=9E=84?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20=EA=B2=80=EC=82=AC=20=EC=98=81=EC=86=8D?= =?UTF-8?q?=EC=84=B1=20=EC=96=B4=EB=8C=91=ED=84=B0=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/out/persistence/UserJpaRepository.java | 4 +++- .../out/persistence/UserQueryPersistenceAdapter.java | 6 +++++- .../adapter/out/persistence/UserRepositoryCustom.java | 5 +++++ .../out/persistence/UserRepositoryCustomImpl.java | 11 +++++++++++ .../thip/user/application/port/out/UserQueryPort.java | 1 + 5 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustom.java create mode 100644 src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustomImpl.java diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserJpaRepository.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserJpaRepository.java index feeb4f1a8..41d61a491 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserJpaRepository.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserJpaRepository.java @@ -3,5 +3,7 @@ import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; -public interface UserJpaRepository extends JpaRepository { +public interface UserJpaRepository extends JpaRepository, UserRepositoryCustom { + + boolean existsByNickname(String nickname); } diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryPersistenceAdapter.java index ad2450362..039015537 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryPersistenceAdapter.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryPersistenceAdapter.java @@ -9,7 +9,11 @@ @RequiredArgsConstructor public class UserQueryPersistenceAdapter implements UserQueryPort { - private final UserJpaRepository jpaRepository; + private final UserJpaRepository userJpaRepository; private final UserMapper userMapper; + @Override + public boolean existsByNickname(String nickname) { + return userJpaRepository.existsByNickname(nickname); + } } diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustom.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustom.java new file mode 100644 index 000000000..11c30268a --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustom.java @@ -0,0 +1,5 @@ +package konkuk.thip.user.adapter.out.persistence; + +public interface UserRepositoryCustom { + +} diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustomImpl.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustomImpl.java new file mode 100644 index 000000000..7991e25e5 --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustomImpl.java @@ -0,0 +1,11 @@ +package konkuk.thip.user.adapter.out.persistence; + +import org.springframework.stereotype.Repository; + +@Repository +public class UserRepositoryCustomImpl implements UserRepositoryCustom { + + /** + * QueryDsl 을 활용한 복잡한 조회 로직 구현 + */ +} diff --git a/src/main/java/konkuk/thip/user/application/port/out/UserQueryPort.java b/src/main/java/konkuk/thip/user/application/port/out/UserQueryPort.java index 448131481..3d2de47c0 100644 --- a/src/main/java/konkuk/thip/user/application/port/out/UserQueryPort.java +++ b/src/main/java/konkuk/thip/user/application/port/out/UserQueryPort.java @@ -2,4 +2,5 @@ public interface UserQueryPort { + boolean existsByNickname(String nickname); } From cfd2d7f67cbaa8cd1da575017eb5de52da88dfa9 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Fri, 27 Jun 2025 11:20:27 +0900 Subject: [PATCH 06/17] =?UTF-8?q?[test]=20:=20=EB=8B=89=EB=84=A4=EC=9E=84?= =?UTF-8?q?=20=EC=A4=91=EB=B3=B5=20=EA=B2=80=EC=82=AC=20api=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C,?= =?UTF-8?q?=20controller=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../in/web/VerifyNicknameControllerTest.java | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java new file mode 100644 index 000000000..bf704f212 --- /dev/null +++ b/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java @@ -0,0 +1,157 @@ +package konkuk.thip.user.adapter.in.web; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import konkuk.thip.user.adapter.in.web.request.VerifyNicknameRequest; +import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; +import konkuk.thip.user.adapter.out.jpa.UserRole; +import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; +import konkuk.thip.user.adapter.out.persistence.UserJpaRepository; +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.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import static konkuk.thip.common.exception.code.ErrorCode.API_INVALID_PARAM; +import static konkuk.thip.user.adapter.out.jpa.UserRole.USER; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@ActiveProfiles("test") +@AutoConfigureMockMvc +class VerifyNicknameControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private UserJpaRepository userJpaRepository; + + @Autowired + private AliasJpaRepository aliasJpaRepository; + + @BeforeEach + void tearDown() { + userJpaRepository.deleteAll(); + aliasJpaRepository.deleteAll(); + } + + @Test + @DisplayName("[닉네임]값이 unique 할 경우, true를 반환한다.") + void verify_nickname_true() throws Exception { + //given + VerifyNicknameRequest request = new VerifyNicknameRequest("테스트유저"); + + //when + ResultActions result = mockMvc.perform(post("/users/nickname") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))); + + //then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.data.isVerified").exists()); + + String json = result.andReturn().getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(json); + boolean isVerified = jsonNode.path("data").path("isVerified").asBoolean(); + + assertThat(isVerified).isTrue(); + } + + @Test + @DisplayName("[닉네임]값이 이미 DB에 존재하는 경우, false를 반환한다.") + void verify_nickname_false() throws Exception { + //given: DB에 "테스트유저" 생성 + AliasJpaEntity aliasJpaEntity = AliasJpaEntity.builder() + .value("칭호") + .color("blue") + .imageUrl("http://image.url") + .build(); + aliasJpaRepository.save(aliasJpaEntity); + + UserJpaEntity userJpaEntity = UserJpaEntity.builder() + .email("test@test.com") + .nickname("테스트유저") + .imageUrl("http://image.url") + .role(USER) + .aliasForUserJpaEntity(aliasJpaEntity) + .build(); + userJpaRepository.save(userJpaEntity); + + VerifyNicknameRequest request = new VerifyNicknameRequest("테스트유저"); + + //when + ResultActions result = mockMvc.perform(post("/users/nickname") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))); + + //then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.data.isVerified").exists()); + + String json = result.andReturn().getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(json); + boolean isVerified = jsonNode.path("data").path("isVerified").asBoolean(); + + assertThat(isVerified).isFalse(); + } + + @Test + @DisplayName("[닉네임]값이 공백일 경우, 400 error가 발생한다.") + void nickname_blank() throws Exception { + //given: nickname blank + VerifyNicknameRequest request = new VerifyNicknameRequest(""); + + //when //then + mockMvc.perform(post("/users/nickname") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(API_INVALID_PARAM.getCode())) + .andExpect(jsonPath("$.message", containsString("닉네임은 한글, 영어, 숫자로만 구성되어야 합니다.(공백불가)"))); + } + + @Test + @DisplayName("[닉네임]값이 한글, 영어, 숫자 외의 문자를 포함할 경우, 400 error가 발생한다.") + void nickname_invalid_pattern() throws Exception { + //given: nickname with invalid characters + VerifyNicknameRequest request = new VerifyNicknameRequest("닉네임!!"); + + //when //then + mockMvc.perform(post("/users/nickname") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(API_INVALID_PARAM.getCode())) + .andExpect(jsonPath("$.message", containsString("닉네임은 한글, 영어, 숫자로만 구성되어야 합니다.(공백불가)"))); + } + + @Test + @DisplayName("[닉네임]값이 11자 이상일 경우, 400 error가 발생한다.") + void nickname_too_long() throws Exception { + //given: 11글자 nickname + VerifyNicknameRequest request = new VerifyNicknameRequest("11글자닉네임입니다아"); + + //when //then + mockMvc.perform(post("/users/nickname") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value(API_INVALID_PARAM.getCode())) + .andExpect(jsonPath("$.message", containsString("닉네임은 최대 10자 입니다."))); + } +} From 1fa761ce4a4e39825210affd964062647b1643d8 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sat, 28 Jun 2025 02:36:01 +0900 Subject: [PATCH 07/17] =?UTF-8?q?[refactor]=20:=20tearDown=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=EB=A5=BC=20@AfterEach=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../thip/user/adapter/in/web/UserSignupControllerTest.java | 3 ++- .../user/adapter/in/web/VerifyNicknameControllerTest.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java index 5ab0bd72c..685818a1d 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java @@ -7,6 +7,7 @@ import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.UserJpaRepository; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -42,7 +43,7 @@ class UserSignupControllerTest { @Autowired private UserJpaRepository userJpaRepository; - @BeforeEach + @AfterEach void tearDown() { userJpaRepository.deleteAll(); aliasJpaRepository.deleteAll(); diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java index bf704f212..8075eb26e 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java @@ -5,9 +5,9 @@ import konkuk.thip.user.adapter.in.web.request.VerifyNicknameRequest; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; -import konkuk.thip.user.adapter.out.jpa.UserRole; import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.UserJpaRepository; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -44,7 +44,7 @@ class VerifyNicknameControllerTest { @Autowired private AliasJpaRepository aliasJpaRepository; - @BeforeEach + @AfterEach void tearDown() { userJpaRepository.deleteAll(); aliasJpaRepository.deleteAll(); From 67819df4fd16f4985461391a8986d842b167a6d0 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sat, 28 Jun 2025 02:37:46 +0900 Subject: [PATCH 08/17] =?UTF-8?q?[feat]=20:=20querydsl=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=A3=BC=EC=9E=85=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 28 ++++++++++++++++++- .../konkuk/thip/config/QuerydslConfig.java | 19 +++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 src/main/java/konkuk/thip/config/QuerydslConfig.java diff --git a/build.gradle b/build.gradle index 9dc25e2af..5d3b82f80 100644 --- a/build.gradle +++ b/build.gradle @@ -24,21 +24,47 @@ repositories { } dependencies { + // Spring Boot 스타터 implementation 'org.springframework.boot:spring-boot-starter-data-jpa' // implementation 'org.springframework.boot:spring-boot-starter-security' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-redis' implementation 'org.springframework.boot:spring-boot-starter-validation' + + // Lombok compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + // Runtime DB 드라이버 runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' - annotationProcessor 'org.projectlombok:lombok' + + // Test testImplementation 'org.assertj:assertj-core:3.24.2' testImplementation 'org.springframework.boot:spring-boot-starter-test' // testImplementation 'org.springframework.security:spring-security-test' testImplementation 'com.h2database:h2:2.1.214' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // Querydsl + implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' + annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" + annotationProcessor "jakarta.annotation:jakarta.annotation-api" + annotationProcessor "jakarta.persistence:jakarta.persistence-api" +} + +def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile + +tasks.withType(JavaCompile).configureEach { + options.generatedSourceOutputDirectory.set(querydslDir) +} + +sourceSets { + main.java.srcDirs += [ querydslDir ] +} + +clean.doLast { + file(querydslDir).deleteDir() } tasks.named('test') { diff --git a/src/main/java/konkuk/thip/config/QuerydslConfig.java b/src/main/java/konkuk/thip/config/QuerydslConfig.java new file mode 100644 index 000000000..6e1a55ebd --- /dev/null +++ b/src/main/java/konkuk/thip/config/QuerydslConfig.java @@ -0,0 +1,19 @@ +package konkuk.thip.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class QuerydslConfig { + + @PersistenceContext + private EntityManager entityManager; + + @Bean + public JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(entityManager); + } +} From d37adb319fa9565872a707e24b1cef4f4d76ea1e Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sat, 28 Jun 2025 02:39:11 +0900 Subject: [PATCH 09/17] =?UTF-8?q?[refactor]=20:=20querydsl=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=EC=84=B1=20=EC=A3=BC=EC=9E=85=EC=97=90=20=EB=94=B0?= =?UTF-8?q?=EB=A5=B8=20=EA=B8=B0=EC=A1=B4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DataJpaTest 는 Jpa 관련 빈들만 로드하므로, 컴포넌트 스캔 대상이 아닌 JPAQueryFactory를 수동으로 주입하도록 코드 수정 --- .../thip/config/TestQuerydslConfig.java | 19 +++++++++++++++++++ .../adapter/out/jpa/FeedJpaEntityTest.java | 2 ++ .../adapter/out/jpa/RecordJpaEntityTest.java | 2 ++ .../adapter/out/jpa/RoomJpaEntityTest.java | 2 ++ .../adapter/out/jpa/VoteJpaEntityTest.java | 2 ++ .../adapter/out/jpa/UserJpaEntityTest.java | 2 ++ 6 files changed, 29 insertions(+) create mode 100644 src/test/java/konkuk/thip/config/TestQuerydslConfig.java diff --git a/src/test/java/konkuk/thip/config/TestQuerydslConfig.java b/src/test/java/konkuk/thip/config/TestQuerydslConfig.java new file mode 100644 index 000000000..70c4d5b51 --- /dev/null +++ b/src/test/java/konkuk/thip/config/TestQuerydslConfig.java @@ -0,0 +1,19 @@ +package konkuk.thip.config; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; + +@TestConfiguration +public class TestQuerydslConfig { + + @PersistenceContext + EntityManager em; + + @Bean + JPAQueryFactory jpaQueryFactory() { + return new JPAQueryFactory(em); + } +} diff --git a/src/test/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntityTest.java b/src/test/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntityTest.java index 2b1d18198..3eef4a2bf 100644 --- a/src/test/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntityTest.java +++ b/src/test/java/konkuk/thip/feed/adapter/out/jpa/FeedJpaEntityTest.java @@ -14,12 +14,14 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest @ActiveProfiles("test") +@Import(konkuk.thip.config.TestQuerydslConfig.class) // DataJpaTest 이므로 JPA 제외 빈 추가로 import class FeedJpaEntityTest { @PersistenceContext diff --git a/src/test/java/konkuk/thip/room/adapter/out/jpa/RecordJpaEntityTest.java b/src/test/java/konkuk/thip/room/adapter/out/jpa/RecordJpaEntityTest.java index a69653bfe..cdfee771e 100644 --- a/src/test/java/konkuk/thip/room/adapter/out/jpa/RecordJpaEntityTest.java +++ b/src/test/java/konkuk/thip/room/adapter/out/jpa/RecordJpaEntityTest.java @@ -16,6 +16,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; import java.time.LocalDate; @@ -24,6 +25,7 @@ @DataJpaTest @ActiveProfiles("test") +@Import(konkuk.thip.config.TestQuerydslConfig.class) // DataJpaTest 이므로 JPA 제외 빈 추가로 import class RecordJpaEntityTest { @Autowired diff --git a/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java b/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java index 302a5d683..ecb06c6a3 100644 --- a/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java +++ b/src/test/java/konkuk/thip/room/adapter/out/jpa/RoomJpaEntityTest.java @@ -12,12 +12,14 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; import java.time.LocalDate; @DataJpaTest @ActiveProfiles("test") +@Import(konkuk.thip.config.TestQuerydslConfig.class) // DataJpaTest 이므로 JPA 제외 빈 추가로 import class RoomJpaEntityTest { @PersistenceContext private EntityManager em; diff --git a/src/test/java/konkuk/thip/room/adapter/out/jpa/VoteJpaEntityTest.java b/src/test/java/konkuk/thip/room/adapter/out/jpa/VoteJpaEntityTest.java index 8c626f0e3..e28fee521 100644 --- a/src/test/java/konkuk/thip/room/adapter/out/jpa/VoteJpaEntityTest.java +++ b/src/test/java/konkuk/thip/room/adapter/out/jpa/VoteJpaEntityTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; import java.time.LocalDate; @@ -25,6 +26,7 @@ @DataJpaTest @ActiveProfiles("test") +@Import(konkuk.thip.config.TestQuerydslConfig.class) // DataJpaTest 이므로 JPA 제외 빈 추가로 import class VoteJpaEntityTest { @PersistenceContext diff --git a/src/test/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntityTest.java b/src/test/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntityTest.java index afbe8ab44..fc2056ac3 100644 --- a/src/test/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntityTest.java +++ b/src/test/java/konkuk/thip/user/adapter/out/jpa/UserJpaEntityTest.java @@ -8,12 +8,14 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.context.annotation.Import; import org.springframework.test.context.ActiveProfiles; import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest @ActiveProfiles("test") +@Import(konkuk.thip.config.TestQuerydslConfig.class) // DataJpaTest 이므로 JPA 제외 빈 추가로 import class UserJpaEntityTest { @PersistenceContext From c86919990c6053e9c50ecd004153714e1b005934 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sat, 28 Jun 2025 02:39:56 +0900 Subject: [PATCH 10/17] =?UTF-8?q?[feat]=20:=20=EC=B9=AD=ED=98=B8=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20view=20api=20controller=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../adapter/in/web/UserQueryController.java | 12 ++++++++ .../web/response/ShowAliasChoiceResponse.java | 29 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 src/main/java/konkuk/thip/user/adapter/in/web/response/ShowAliasChoiceResponse.java diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java b/src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java index a7d51c3cc..5b986533e 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java @@ -1,10 +1,22 @@ package konkuk.thip.user.adapter.in.web; +import konkuk.thip.common.dto.BaseResponse; +import konkuk.thip.user.adapter.in.web.response.ShowAliasChoiceResponse; +import konkuk.thip.user.application.port.in.ShowAliasChoiceViewUseCase; import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor public class UserQueryController { + private final ShowAliasChoiceViewUseCase showAliasChoiceViewUseCase; + + @GetMapping("/users/alias") + public BaseResponse showAliasChoiceView() { + return BaseResponse.ok(ShowAliasChoiceResponse.of( + showAliasChoiceViewUseCase.getAllAliasesAndCategories() + )); + } } diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/response/ShowAliasChoiceResponse.java b/src/main/java/konkuk/thip/user/adapter/in/web/response/ShowAliasChoiceResponse.java new file mode 100644 index 000000000..30df2d7ac --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/in/web/response/ShowAliasChoiceResponse.java @@ -0,0 +1,29 @@ +package konkuk.thip.user.adapter.in.web.response; + +import konkuk.thip.user.application.port.in.dto.AliasChoiceViewResult; + +import java.util.List; + +public record ShowAliasChoiceResponse(List aliasChoices) { + + public static ShowAliasChoiceResponse of(AliasChoiceViewResult result) { + List choices = result.aliasChoices().stream() + .map(ac -> new AliasChoice( + ac.aliasId(), + ac.aliasName(), + ac.categoryName(), + ac.imageUrl(), + ac.color() + )) + .toList(); + return new ShowAliasChoiceResponse(choices); + } + + public record AliasChoice( + Long aliasId, + String aliasName, + String categoryName, + String imageUrl, + String color + ) {} +} From a74ee80e85f074943de8bc44282f985ee282eed3 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sat, 28 Jun 2025 02:40:22 +0900 Subject: [PATCH 11/17] =?UTF-8?q?[feat]=20:=20=EC=B9=AD=ED=98=B8=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20view=20api=20use=20case=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../port/in/ShowAliasChoiceViewUseCase.java | 8 ++++++++ .../port/in/dto/AliasChoiceViewResult.java | 14 ++++++++++++++ .../application/port/in/dto/DummyResult.java | 10 ---------- .../service/ShowAliasChoiceViewService.java | 19 +++++++++++++++++++ 4 files changed, 41 insertions(+), 10 deletions(-) create mode 100644 src/main/java/konkuk/thip/user/application/port/in/ShowAliasChoiceViewUseCase.java create mode 100644 src/main/java/konkuk/thip/user/application/port/in/dto/AliasChoiceViewResult.java delete mode 100644 src/main/java/konkuk/thip/user/application/port/in/dto/DummyResult.java create mode 100644 src/main/java/konkuk/thip/user/application/service/ShowAliasChoiceViewService.java diff --git a/src/main/java/konkuk/thip/user/application/port/in/ShowAliasChoiceViewUseCase.java b/src/main/java/konkuk/thip/user/application/port/in/ShowAliasChoiceViewUseCase.java new file mode 100644 index 000000000..994a6cf31 --- /dev/null +++ b/src/main/java/konkuk/thip/user/application/port/in/ShowAliasChoiceViewUseCase.java @@ -0,0 +1,8 @@ +package konkuk.thip.user.application.port.in; + +import konkuk.thip.user.application.port.in.dto.AliasChoiceViewResult; + +public interface ShowAliasChoiceViewUseCase { + + AliasChoiceViewResult getAllAliasesAndCategories(); +} diff --git a/src/main/java/konkuk/thip/user/application/port/in/dto/AliasChoiceViewResult.java b/src/main/java/konkuk/thip/user/application/port/in/dto/AliasChoiceViewResult.java new file mode 100644 index 000000000..3df6ca89e --- /dev/null +++ b/src/main/java/konkuk/thip/user/application/port/in/dto/AliasChoiceViewResult.java @@ -0,0 +1,14 @@ +package konkuk.thip.user.application.port.in.dto; + +import java.util.List; + +public record AliasChoiceViewResult(List aliasChoices) { + + public record AliasChoice( + Long aliasId, + String aliasName, + String categoryName, + String imageUrl, + String color + ) {} +} diff --git a/src/main/java/konkuk/thip/user/application/port/in/dto/DummyResult.java b/src/main/java/konkuk/thip/user/application/port/in/dto/DummyResult.java deleted file mode 100644 index 452d64a2e..000000000 --- a/src/main/java/konkuk/thip/user/application/port/in/dto/DummyResult.java +++ /dev/null @@ -1,10 +0,0 @@ -package konkuk.thip.user.application.port.in.dto; - -import lombok.Builder; -import lombok.Getter; - -@Getter -@Builder -public class DummyResult { - -} diff --git a/src/main/java/konkuk/thip/user/application/service/ShowAliasChoiceViewService.java b/src/main/java/konkuk/thip/user/application/service/ShowAliasChoiceViewService.java new file mode 100644 index 000000000..bc96d2749 --- /dev/null +++ b/src/main/java/konkuk/thip/user/application/service/ShowAliasChoiceViewService.java @@ -0,0 +1,19 @@ +package konkuk.thip.user.application.service; + +import konkuk.thip.user.application.port.in.ShowAliasChoiceViewUseCase; +import konkuk.thip.user.application.port.in.dto.AliasChoiceViewResult; +import konkuk.thip.user.application.port.out.AliasQueryPort; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class ShowAliasChoiceViewService implements ShowAliasChoiceViewUseCase { + + private final AliasQueryPort aliasQueryPort; + + @Override + public AliasChoiceViewResult getAllAliasesAndCategories() { + return aliasQueryPort.getAllAliasesAndCategories(); + } +} From 5d3839e07b79bf88f2b1d68c2b5d0378ea5b0f1e Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sat, 28 Jun 2025 02:41:03 +0900 Subject: [PATCH 12/17] =?UTF-8?q?[feat]=20:=20=EC=B9=AD=ED=98=B8=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20view=20api=20query=20adapter=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit querydsl 활용하여 조회로직 구현 --- .../out/persistence/AliasJpaRepository.java | 2 +- .../AliasQueryPersistenceAdapter.java | 18 +++++++++ .../persistence/AliasRepositoryCustom.java | 8 ++++ .../AliasRepositoryCustomImpl.java | 40 +++++++++++++++++++ .../application/port/out/AliasQueryPort.java | 8 ++++ 5 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryPersistenceAdapter.java create mode 100644 src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustom.java create mode 100644 src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustomImpl.java create mode 100644 src/main/java/konkuk/thip/user/application/port/out/AliasQueryPort.java diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasJpaRepository.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasJpaRepository.java index 655bd4977..eef071682 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasJpaRepository.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasJpaRepository.java @@ -3,5 +3,5 @@ import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; -public interface AliasJpaRepository extends JpaRepository { +public interface AliasJpaRepository extends JpaRepository, AliasRepositoryCustom { } \ No newline at end of file diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryPersistenceAdapter.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryPersistenceAdapter.java new file mode 100644 index 000000000..5f4e01dd4 --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryPersistenceAdapter.java @@ -0,0 +1,18 @@ +package konkuk.thip.user.adapter.out.persistence; + +import konkuk.thip.user.application.port.in.dto.AliasChoiceViewResult; +import konkuk.thip.user.application.port.out.AliasQueryPort; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +@Repository +@RequiredArgsConstructor +public class AliasQueryPersistenceAdapter implements AliasQueryPort { + + private final AliasJpaRepository aliasJpaRepository; + + @Override + public AliasChoiceViewResult getAllAliasesAndCategories() { + return aliasJpaRepository.getAllAliasesAndCategories(); + } +} diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustom.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustom.java new file mode 100644 index 000000000..77199257d --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustom.java @@ -0,0 +1,8 @@ +package konkuk.thip.user.adapter.out.persistence; + +import konkuk.thip.user.application.port.in.dto.AliasChoiceViewResult; + +public interface AliasRepositoryCustom { + + AliasChoiceViewResult getAllAliasesAndCategories(); +} diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustomImpl.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustomImpl.java new file mode 100644 index 000000000..566587d81 --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustomImpl.java @@ -0,0 +1,40 @@ +package konkuk.thip.user.adapter.out.persistence; + +import com.querydsl.core.types.Projections; +import com.querydsl.jpa.impl.JPAQueryFactory; +import konkuk.thip.room.adapter.out.jpa.QCategoryJpaEntity; +import konkuk.thip.user.adapter.out.jpa.QAliasJpaEntity; +import konkuk.thip.user.application.port.in.dto.AliasChoiceViewResult; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class AliasRepositoryCustomImpl implements AliasRepositoryCustom { + + private final JPAQueryFactory jpaQueryFactory; + + @Override + public AliasChoiceViewResult getAllAliasesAndCategories() { + QAliasJpaEntity alias = QAliasJpaEntity.aliasJpaEntity; + QCategoryJpaEntity category = QCategoryJpaEntity.categoryJpaEntity; + + List aliasChoices = jpaQueryFactory + .select(Projections.constructor( + AliasChoiceViewResult.AliasChoice.class, + alias.aliasId, + alias.value, + category.value, + alias.imageUrl, + alias.color + )) + .from(alias) + .leftJoin(category) + .on(category.aliasForCategoryJpaEntity.eq(alias)) + .fetch(); + + return new AliasChoiceViewResult(aliasChoices); + } +} diff --git a/src/main/java/konkuk/thip/user/application/port/out/AliasQueryPort.java b/src/main/java/konkuk/thip/user/application/port/out/AliasQueryPort.java new file mode 100644 index 000000000..c832e863a --- /dev/null +++ b/src/main/java/konkuk/thip/user/application/port/out/AliasQueryPort.java @@ -0,0 +1,8 @@ +package konkuk.thip.user.application.port.out; + +import konkuk.thip.user.application.port.in.dto.AliasChoiceViewResult; + +public interface AliasQueryPort { + + AliasChoiceViewResult getAllAliasesAndCategories(); +} From 5135aa1db2d9de2299f8a98d0e25e3e4e047523c Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sat, 28 Jun 2025 02:41:19 +0900 Subject: [PATCH 13/17] =?UTF-8?q?[test]=20:=20=EC=B9=AD=ED=98=B8=20?= =?UTF-8?q?=EC=84=A0=ED=83=9D=20view=20api=20=ED=86=B5=ED=95=A9=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ShowAliasChoiceViewControllerTest.java | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java new file mode 100644 index 000000000..c7af13096 --- /dev/null +++ b/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java @@ -0,0 +1,108 @@ +package konkuk.thip.user.adapter.in.web; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; +import konkuk.thip.room.adapter.out.persistence.CategoryJpaRepository; +import konkuk.thip.user.adapter.in.web.response.ShowAliasChoiceResponse; +import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; +import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; +import org.junit.jupiter.api.AfterEach; +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.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.tuple; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@ActiveProfiles("test") +@AutoConfigureMockMvc +class ShowAliasChoiceViewControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private AliasJpaRepository aliasJpaRepository; + + @Autowired + private CategoryJpaRepository categoryJpaRepository; + + @AfterEach + void tearDown() { + categoryJpaRepository.deleteAll(); + aliasJpaRepository.deleteAll(); + } + + @Test + @DisplayName("현재 DB에 존재하는 모든 [칭호, 카테고리] 정보를 반환한다.") + void show_alias_choice_view() throws Exception { + //given + saveAliasesAndCategories(); + + //when + ResultActions result = mockMvc.perform(get("/users/alias") + .contentType(MediaType.APPLICATION_JSON)); + + //then + result.andExpect(status().isOk()) + .andExpect(jsonPath("$.data.aliasChoices").exists()); + + String json = result.andReturn().getResponse().getContentAsString(); + JsonNode jsonNode = objectMapper.readTree(json); + ShowAliasChoiceResponse showResponse = objectMapper.treeToValue(jsonNode.get("data"), ShowAliasChoiceResponse.class); + List choices = showResponse.aliasChoices(); + + assertThat(choices).hasSize(2); + assertThat(choices) + .extracting("aliasName", "categoryName", "imageUrl", "color") + .containsExactlyInAnyOrder( + tuple("문학가", "문학", "문학가_image", "red"), + tuple("과학자", "과학/IT", "과학자_image", "blue") + ); + } + + private void saveAliasesAndCategories() { + AliasJpaEntity alias1 = AliasJpaEntity.builder() + .value("문학가") + .imageUrl("문학가_image") + .color("red") + .build(); + aliasJpaRepository.save(alias1); + + CategoryJpaEntity category1 = CategoryJpaEntity.builder() + .value("문학") + .aliasForCategoryJpaEntity(alias1) + .build(); + categoryJpaRepository.save(category1); + + AliasJpaEntity alias2 = AliasJpaEntity.builder() + .value("과학자") + .imageUrl("과학자_image") + .color("blue") + .build(); + aliasJpaRepository.save(alias2); + + CategoryJpaEntity category2 = CategoryJpaEntity.builder() + .value("과학/IT") + .aliasForCategoryJpaEntity(alias2) + .build(); + categoryJpaRepository.save(category2); + } +} From 047ea40201653368cf55e790768a9540e3dea431 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sun, 29 Jun 2025 21:38:40 +0900 Subject: [PATCH 14/17] =?UTF-8?q?[refactor]=20:=20Querydsl=20=EC=A0=84?= =?UTF-8?q?=EC=9A=A9=20repository=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - interface : xxxQueryRepository - 구현체 : xxxQueryRepositoryImpl --- .../thip/user/adapter/out/persistence/AliasJpaRepository.java | 2 +- .../{AliasRepositoryCustom.java => AliasQueryRepository.java} | 2 +- ...sRepositoryCustomImpl.java => AliasQueryRepositoryImpl.java} | 2 +- .../thip/user/adapter/out/persistence/UserJpaRepository.java | 2 +- .../{UserRepositoryCustom.java => UserQueryRepository.java} | 2 +- ...erRepositoryCustomImpl.java => UserQueryRepositoryImpl.java} | 2 +- .../user/adapter/in/web/ShowAliasChoiceViewControllerTest.java | 1 - 7 files changed, 6 insertions(+), 7 deletions(-) rename src/main/java/konkuk/thip/user/adapter/out/persistence/{AliasRepositoryCustom.java => AliasQueryRepository.java} (81%) rename src/main/java/konkuk/thip/user/adapter/out/persistence/{AliasRepositoryCustomImpl.java => AliasQueryRepositoryImpl.java} (94%) rename src/main/java/konkuk/thip/user/adapter/out/persistence/{UserRepositoryCustom.java => UserQueryRepository.java} (57%) rename src/main/java/konkuk/thip/user/adapter/out/persistence/{UserRepositoryCustomImpl.java => UserQueryRepositoryImpl.java} (72%) diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasJpaRepository.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasJpaRepository.java index eef071682..130df4c2c 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasJpaRepository.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasJpaRepository.java @@ -3,5 +3,5 @@ import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; -public interface AliasJpaRepository extends JpaRepository, AliasRepositoryCustom { +public interface AliasJpaRepository extends JpaRepository, AliasQueryRepository { } \ No newline at end of file diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustom.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepository.java similarity index 81% rename from src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustom.java rename to src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepository.java index 77199257d..25ce90252 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustom.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepository.java @@ -2,7 +2,7 @@ import konkuk.thip.user.application.port.in.dto.AliasChoiceViewResult; -public interface AliasRepositoryCustom { +public interface AliasQueryRepository { AliasChoiceViewResult getAllAliasesAndCategories(); } diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustomImpl.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepositoryImpl.java similarity index 94% rename from src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustomImpl.java rename to src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepositoryImpl.java index 566587d81..8c5893c3a 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasRepositoryCustomImpl.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepositoryImpl.java @@ -12,7 +12,7 @@ @Repository @RequiredArgsConstructor -public class AliasRepositoryCustomImpl implements AliasRepositoryCustom { +public class AliasQueryRepositoryImpl implements AliasQueryRepository { private final JPAQueryFactory jpaQueryFactory; diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserJpaRepository.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserJpaRepository.java index 41d61a491..39798fe6a 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserJpaRepository.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserJpaRepository.java @@ -3,7 +3,7 @@ import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import org.springframework.data.jpa.repository.JpaRepository; -public interface UserJpaRepository extends JpaRepository, UserRepositoryCustom { +public interface UserJpaRepository extends JpaRepository, UserQueryRepository { boolean existsByNickname(String nickname); } diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustom.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryRepository.java similarity index 57% rename from src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustom.java rename to src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryRepository.java index 11c30268a..72f18a70f 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustom.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryRepository.java @@ -1,5 +1,5 @@ package konkuk.thip.user.adapter.out.persistence; -public interface UserRepositoryCustom { +public interface UserQueryRepository { } diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustomImpl.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryRepositoryImpl.java similarity index 72% rename from src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustomImpl.java rename to src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryRepositoryImpl.java index 7991e25e5..09a96a8b3 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/UserRepositoryCustomImpl.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/UserQueryRepositoryImpl.java @@ -3,7 +3,7 @@ import org.springframework.stereotype.Repository; @Repository -public class UserRepositoryCustomImpl implements UserRepositoryCustom { +public class UserQueryRepositoryImpl implements UserQueryRepository { /** * QueryDsl 을 활용한 복잡한 조회 로직 구현 diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java index c7af13096..fac5f353d 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java @@ -8,7 +8,6 @@ import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; import org.junit.jupiter.api.AfterEach; -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; From 5cab3ff1d1f3a3a4cdc30323e782be376f6c29ce Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sun, 29 Jun 2025 21:40:54 +0900 Subject: [PATCH 15/17] =?UTF-8?q?[refactor]=20:=20aliasId=20=EA=B8=B0?= =?UTF-8?q?=EC=A4=80=20=EC=98=A4=EB=A6=84=EC=B0=A8=EC=88=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A0=AC=20=ED=9B=84=20=EB=B0=98=ED=99=98=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/adapter/out/persistence/AliasQueryRepositoryImpl.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepositoryImpl.java b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepositoryImpl.java index 8c5893c3a..9cabe24cf 100644 --- a/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepositoryImpl.java +++ b/src/main/java/konkuk/thip/user/adapter/out/persistence/AliasQueryRepositoryImpl.java @@ -33,6 +33,7 @@ public AliasChoiceViewResult getAllAliasesAndCategories() { .from(alias) .leftJoin(category) .on(category.aliasForCategoryJpaEntity.eq(alias)) + .orderBy(alias.aliasId.asc()) .fetch(); return new AliasChoiceViewResult(aliasChoices); From d375564bc45e02fd0137cc617e5e34ae82f50f40 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sun, 29 Jun 2025 21:45:16 +0900 Subject: [PATCH 16/17] =?UTF-8?q?[refactor]=20:=20request,=20response=20dt?= =?UTF-8?q?o=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=88=98=EC=A0=95=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 팀 컨벤션에 맞추어 수정 --- .../adapter/in/web/UserCommandController.java | 16 ++++++++-------- .../adapter/in/web/UserQueryController.java | 6 +++--- ...pRequest.java => PostUserSignupRequest.java} | 2 +- ....java => PostUserVerifyNicknameRequest.java} | 2 +- ...java => GetUserShowAliasChoiceResponse.java} | 6 +++--- .../in/web/response/PostUserSignupResponse.java | 7 +++++++ .../PostUserVerifyNicknameResponse.java | 7 +++++++ .../in/web/response/UserSignupResponse.java | 7 ------- .../in/web/response/VerifyNicknameResponse.java | 7 ------- .../web/ShowAliasChoiceViewControllerTest.java | 6 +++--- .../in/web/UserSignupControllerTest.java | 17 ++++++++--------- .../in/web/VerifyNicknameControllerTest.java | 13 ++++++------- 12 files changed, 47 insertions(+), 49 deletions(-) rename src/main/java/konkuk/thip/user/adapter/in/web/request/{UserSignupRequest.java => PostUserSignupRequest.java} (95%) rename src/main/java/konkuk/thip/user/adapter/in/web/request/{VerifyNicknameRequest.java => PostUserVerifyNicknameRequest.java} (89%) rename src/main/java/konkuk/thip/user/adapter/in/web/response/{ShowAliasChoiceResponse.java => GetUserShowAliasChoiceResponse.java} (75%) create mode 100644 src/main/java/konkuk/thip/user/adapter/in/web/response/PostUserSignupResponse.java create mode 100644 src/main/java/konkuk/thip/user/adapter/in/web/response/PostUserVerifyNicknameResponse.java delete mode 100644 src/main/java/konkuk/thip/user/adapter/in/web/response/UserSignupResponse.java delete mode 100644 src/main/java/konkuk/thip/user/adapter/in/web/response/VerifyNicknameResponse.java diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/UserCommandController.java b/src/main/java/konkuk/thip/user/adapter/in/web/UserCommandController.java index 10f8fb4c5..8fcfa2206 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/UserCommandController.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/UserCommandController.java @@ -1,10 +1,10 @@ package konkuk.thip.user.adapter.in.web; import konkuk.thip.common.dto.BaseResponse; -import konkuk.thip.user.adapter.in.web.request.UserSignupRequest; -import konkuk.thip.user.adapter.in.web.request.VerifyNicknameRequest; -import konkuk.thip.user.adapter.in.web.response.UserSignupResponse; -import konkuk.thip.user.adapter.in.web.response.VerifyNicknameResponse; +import konkuk.thip.user.adapter.in.web.request.PostUserSignupRequest; +import konkuk.thip.user.adapter.in.web.request.PostUserVerifyNicknameRequest; +import konkuk.thip.user.adapter.in.web.response.PostUserSignupResponse; +import konkuk.thip.user.adapter.in.web.response.PostUserVerifyNicknameResponse; import konkuk.thip.user.application.port.in.UserSignupUseCase; import konkuk.thip.user.application.port.in.VerifyNicknameUseCase; import lombok.RequiredArgsConstructor; @@ -21,15 +21,15 @@ public class UserCommandController { private final VerifyNicknameUseCase verifyNicknameUseCase; @PostMapping("/users/signup") - public BaseResponse signup(@Validated @RequestBody UserSignupRequest request) { - return BaseResponse.ok(UserSignupResponse.of( + public BaseResponse signup(@Validated @RequestBody PostUserSignupRequest request) { + return BaseResponse.ok(PostUserSignupResponse.of( userSignupUseCase.signup(request.toCommand())) ); } @PostMapping("/users/nickname") - public BaseResponse verifyNickname(@Validated @RequestBody VerifyNicknameRequest request) { - return BaseResponse.ok(VerifyNicknameResponse.of( + public BaseResponse verifyNickname(@Validated @RequestBody PostUserVerifyNicknameRequest request) { + return BaseResponse.ok(PostUserVerifyNicknameResponse.of( verifyNicknameUseCase.isNicknameUnique(request.nickname())) ); } diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java b/src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java index 5b986533e..01ca9f6b0 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/UserQueryController.java @@ -1,7 +1,7 @@ package konkuk.thip.user.adapter.in.web; import konkuk.thip.common.dto.BaseResponse; -import konkuk.thip.user.adapter.in.web.response.ShowAliasChoiceResponse; +import konkuk.thip.user.adapter.in.web.response.GetUserShowAliasChoiceResponse; import konkuk.thip.user.application.port.in.ShowAliasChoiceViewUseCase; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; @@ -14,8 +14,8 @@ public class UserQueryController { private final ShowAliasChoiceViewUseCase showAliasChoiceViewUseCase; @GetMapping("/users/alias") - public BaseResponse showAliasChoiceView() { - return BaseResponse.ok(ShowAliasChoiceResponse.of( + public BaseResponse showAliasChoiceView() { + return BaseResponse.ok(GetUserShowAliasChoiceResponse.of( showAliasChoiceViewUseCase.getAllAliasesAndCategories() )); } diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/request/UserSignupRequest.java b/src/main/java/konkuk/thip/user/adapter/in/web/request/PostUserSignupRequest.java similarity index 95% rename from src/main/java/konkuk/thip/user/adapter/in/web/request/UserSignupRequest.java rename to src/main/java/konkuk/thip/user/adapter/in/web/request/PostUserSignupRequest.java index 720435b7e..99e45578c 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/request/UserSignupRequest.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/request/PostUserSignupRequest.java @@ -3,7 +3,7 @@ import jakarta.validation.constraints.*; import konkuk.thip.user.application.port.in.dto.UserSignupCommand; -public record UserSignupRequest( +public record PostUserSignupRequest( @NotNull(message = "aliasId는 필수입니다.") Long aliasId, diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/request/VerifyNicknameRequest.java b/src/main/java/konkuk/thip/user/adapter/in/web/request/PostUserVerifyNicknameRequest.java similarity index 89% rename from src/main/java/konkuk/thip/user/adapter/in/web/request/VerifyNicknameRequest.java rename to src/main/java/konkuk/thip/user/adapter/in/web/request/PostUserVerifyNicknameRequest.java index b552614d9..3a8734d9f 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/request/VerifyNicknameRequest.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/request/PostUserVerifyNicknameRequest.java @@ -3,7 +3,7 @@ import jakarta.validation.constraints.Pattern; import jakarta.validation.constraints.Size; -public record VerifyNicknameRequest( +public record PostUserVerifyNicknameRequest( @Pattern(regexp = "[가-힣a-zA-Z0-9]+", message = "닉네임은 한글, 영어, 숫자로만 구성되어야 합니다.(공백불가)") @Size(max = 10, message = "닉네임은 최대 10자 입니다.") String nickname diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/response/ShowAliasChoiceResponse.java b/src/main/java/konkuk/thip/user/adapter/in/web/response/GetUserShowAliasChoiceResponse.java similarity index 75% rename from src/main/java/konkuk/thip/user/adapter/in/web/response/ShowAliasChoiceResponse.java rename to src/main/java/konkuk/thip/user/adapter/in/web/response/GetUserShowAliasChoiceResponse.java index 30df2d7ac..b9f3116af 100644 --- a/src/main/java/konkuk/thip/user/adapter/in/web/response/ShowAliasChoiceResponse.java +++ b/src/main/java/konkuk/thip/user/adapter/in/web/response/GetUserShowAliasChoiceResponse.java @@ -4,9 +4,9 @@ import java.util.List; -public record ShowAliasChoiceResponse(List aliasChoices) { +public record GetUserShowAliasChoiceResponse(List aliasChoices) { - public static ShowAliasChoiceResponse of(AliasChoiceViewResult result) { + public static GetUserShowAliasChoiceResponse of(AliasChoiceViewResult result) { List choices = result.aliasChoices().stream() .map(ac -> new AliasChoice( ac.aliasId(), @@ -16,7 +16,7 @@ public static ShowAliasChoiceResponse of(AliasChoiceViewResult result) { ac.color() )) .toList(); - return new ShowAliasChoiceResponse(choices); + return new GetUserShowAliasChoiceResponse(choices); } public record AliasChoice( diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/response/PostUserSignupResponse.java b/src/main/java/konkuk/thip/user/adapter/in/web/response/PostUserSignupResponse.java new file mode 100644 index 000000000..c3cbb993c --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/in/web/response/PostUserSignupResponse.java @@ -0,0 +1,7 @@ +package konkuk.thip.user.adapter.in.web.response; + +public record PostUserSignupResponse(Long userId) { + public static PostUserSignupResponse of(Long userId) { + return new PostUserSignupResponse(userId); + } +} \ No newline at end of file diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/response/PostUserVerifyNicknameResponse.java b/src/main/java/konkuk/thip/user/adapter/in/web/response/PostUserVerifyNicknameResponse.java new file mode 100644 index 000000000..c254d052e --- /dev/null +++ b/src/main/java/konkuk/thip/user/adapter/in/web/response/PostUserVerifyNicknameResponse.java @@ -0,0 +1,7 @@ +package konkuk.thip.user.adapter.in.web.response; + +public record PostUserVerifyNicknameResponse(boolean isVerified) { + public static PostUserVerifyNicknameResponse of(boolean isVerified) { + return new PostUserVerifyNicknameResponse(isVerified); + } +} diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/response/UserSignupResponse.java b/src/main/java/konkuk/thip/user/adapter/in/web/response/UserSignupResponse.java deleted file mode 100644 index f5a490e6e..000000000 --- a/src/main/java/konkuk/thip/user/adapter/in/web/response/UserSignupResponse.java +++ /dev/null @@ -1,7 +0,0 @@ -package konkuk.thip.user.adapter.in.web.response; - -public record UserSignupResponse(Long userId) { - public static UserSignupResponse of(Long userId) { - return new UserSignupResponse(userId); - } -} \ No newline at end of file diff --git a/src/main/java/konkuk/thip/user/adapter/in/web/response/VerifyNicknameResponse.java b/src/main/java/konkuk/thip/user/adapter/in/web/response/VerifyNicknameResponse.java deleted file mode 100644 index b6ef18cb5..000000000 --- a/src/main/java/konkuk/thip/user/adapter/in/web/response/VerifyNicknameResponse.java +++ /dev/null @@ -1,7 +0,0 @@ -package konkuk.thip.user.adapter.in.web.response; - -public record VerifyNicknameResponse(boolean isVerified) { - public static VerifyNicknameResponse of(boolean isVerified) { - return new VerifyNicknameResponse(isVerified); - } -} diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java index fac5f353d..892e45555 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/ShowAliasChoiceViewControllerTest.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import konkuk.thip.room.adapter.out.jpa.CategoryJpaEntity; import konkuk.thip.room.adapter.out.persistence.CategoryJpaRepository; -import konkuk.thip.user.adapter.in.web.response.ShowAliasChoiceResponse; +import konkuk.thip.user.adapter.in.web.response.GetUserShowAliasChoiceResponse; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; import org.junit.jupiter.api.AfterEach; @@ -65,8 +65,8 @@ void show_alias_choice_view() throws Exception { String json = result.andReturn().getResponse().getContentAsString(); JsonNode jsonNode = objectMapper.readTree(json); - ShowAliasChoiceResponse showResponse = objectMapper.treeToValue(jsonNode.get("data"), ShowAliasChoiceResponse.class); - List choices = showResponse.aliasChoices(); + GetUserShowAliasChoiceResponse showResponse = objectMapper.treeToValue(jsonNode.get("data"), GetUserShowAliasChoiceResponse.class); + List choices = showResponse.aliasChoices(); assertThat(choices).hasSize(2); assertThat(choices) diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java index 685818a1d..cc7d92e83 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/UserSignupControllerTest.java @@ -2,13 +2,12 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import konkuk.thip.user.adapter.in.web.request.UserSignupRequest; +import konkuk.thip.user.adapter.in.web.request.PostUserSignupRequest; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.UserJpaRepository; import org.junit.jupiter.api.AfterEach; -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; @@ -60,7 +59,7 @@ void signup_success() throws Exception { .build(); aliasJpaRepository.save(aliasJpaEntity); - UserSignupRequest request = new UserSignupRequest( + PostUserSignupRequest request = new PostUserSignupRequest( aliasJpaEntity.getAliasId(), "테스트유저", "test@test.com" @@ -90,7 +89,7 @@ void signup_success() throws Exception { @DisplayName("[칭호id]값이 null일 경우, 400 error가 발생한다.") void signup_alias_id_null() throws Exception { //given: aliasId null - UserSignupRequest request = new UserSignupRequest( + PostUserSignupRequest request = new PostUserSignupRequest( null, "테스트유저", "test@test.com" @@ -109,7 +108,7 @@ void signup_alias_id_null() throws Exception { @DisplayName("[닉네임]값이 공백일 경우, 400 error가 발생한다.") void signup_nickname_blank() throws Exception { //given: nickname blank - UserSignupRequest request = new UserSignupRequest( + PostUserSignupRequest request = new PostUserSignupRequest( 1L, "", "test@test.com" @@ -128,7 +127,7 @@ void signup_nickname_blank() throws Exception { @DisplayName("[닉네임]값이 한글, 영어, 숫자 외의 문자를 포함할 경우, 400 error가 발생한다.") void signup_nickname_invalid_pattern() throws Exception { //given: nickname with invalid characters - UserSignupRequest request = new UserSignupRequest( + PostUserSignupRequest request = new PostUserSignupRequest( 1L, "닉네임!!", "test@test.com" @@ -147,7 +146,7 @@ void signup_nickname_invalid_pattern() throws Exception { @DisplayName("[닉네임]값이 11자 이상일 경우, 400 error가 발생한다.") void signup_nickname_too_long() throws Exception { //given: 11글자 nickname - UserSignupRequest request = new UserSignupRequest( + PostUserSignupRequest request = new PostUserSignupRequest( 1L, "11글자닉네임입니다아", "test@test.com" @@ -166,7 +165,7 @@ void signup_nickname_too_long() throws Exception { @DisplayName("[이메일]값이 공백일 경우, 400 error가 발생한다.") void signup_email_blank() throws Exception { //given - UserSignupRequest request = new UserSignupRequest( + PostUserSignupRequest request = new PostUserSignupRequest( 1L, "테스트유저", "" @@ -185,7 +184,7 @@ void signup_email_blank() throws Exception { @DisplayName("[이메일]값이 유효한 이메일 형식이 아닐 경우, 400 error가 발생한다.") void signup_email_invalid_format() throws Exception { //given - UserSignupRequest request = new UserSignupRequest( + PostUserSignupRequest request = new PostUserSignupRequest( 1L, "테스트유저", "invalid-email-format" diff --git a/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java b/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java index 8075eb26e..a2c04a7f3 100644 --- a/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java +++ b/src/test/java/konkuk/thip/user/adapter/in/web/VerifyNicknameControllerTest.java @@ -2,13 +2,12 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import konkuk.thip.user.adapter.in.web.request.VerifyNicknameRequest; +import konkuk.thip.user.adapter.in.web.request.PostUserVerifyNicknameRequest; import konkuk.thip.user.adapter.out.jpa.AliasJpaEntity; import konkuk.thip.user.adapter.out.jpa.UserJpaEntity; import konkuk.thip.user.adapter.out.persistence.AliasJpaRepository; import konkuk.thip.user.adapter.out.persistence.UserJpaRepository; import org.junit.jupiter.api.AfterEach; -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; @@ -54,7 +53,7 @@ void tearDown() { @DisplayName("[닉네임]값이 unique 할 경우, true를 반환한다.") void verify_nickname_true() throws Exception { //given - VerifyNicknameRequest request = new VerifyNicknameRequest("테스트유저"); + PostUserVerifyNicknameRequest request = new PostUserVerifyNicknameRequest("테스트유저"); //when ResultActions result = mockMvc.perform(post("/users/nickname") @@ -92,7 +91,7 @@ void verify_nickname_false() throws Exception { .build(); userJpaRepository.save(userJpaEntity); - VerifyNicknameRequest request = new VerifyNicknameRequest("테스트유저"); + PostUserVerifyNicknameRequest request = new PostUserVerifyNicknameRequest("테스트유저"); //when ResultActions result = mockMvc.perform(post("/users/nickname") @@ -114,7 +113,7 @@ void verify_nickname_false() throws Exception { @DisplayName("[닉네임]값이 공백일 경우, 400 error가 발생한다.") void nickname_blank() throws Exception { //given: nickname blank - VerifyNicknameRequest request = new VerifyNicknameRequest(""); + PostUserVerifyNicknameRequest request = new PostUserVerifyNicknameRequest(""); //when //then mockMvc.perform(post("/users/nickname") @@ -129,7 +128,7 @@ void nickname_blank() throws Exception { @DisplayName("[닉네임]값이 한글, 영어, 숫자 외의 문자를 포함할 경우, 400 error가 발생한다.") void nickname_invalid_pattern() throws Exception { //given: nickname with invalid characters - VerifyNicknameRequest request = new VerifyNicknameRequest("닉네임!!"); + PostUserVerifyNicknameRequest request = new PostUserVerifyNicknameRequest("닉네임!!"); //when //then mockMvc.perform(post("/users/nickname") @@ -144,7 +143,7 @@ void nickname_invalid_pattern() throws Exception { @DisplayName("[닉네임]값이 11자 이상일 경우, 400 error가 발생한다.") void nickname_too_long() throws Exception { //given: 11글자 nickname - VerifyNicknameRequest request = new VerifyNicknameRequest("11글자닉네임입니다아"); + PostUserVerifyNicknameRequest request = new PostUserVerifyNicknameRequest("11글자닉네임입니다아"); //when //then mockMvc.perform(post("/users/nickname") From 32fb424c96c332ef81a9f024410824e52eab5c89 Mon Sep 17 00:00:00 2001 From: seongjunnoh Date: Sun, 29 Jun 2025 21:49:27 +0900 Subject: [PATCH 17/17] =?UTF-8?q?[fix]=20:=20querydsl=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20build.gradle=20=EC=97=90=EB=9F=AC=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 build.gradle 코드 중 tasks.withType(JavaCompile) 로 인해 테스트 컴파일 단계에서 Q클래스 중복 생성되는 에러 확인 - compileJava 테스크에서만(= main 소스를 컴파일할 때만) Q클래스 생성하도록 강제 --- build.gradle | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 5d3b82f80..6dd1f49ee 100644 --- a/build.gradle +++ b/build.gradle @@ -55,10 +55,16 @@ dependencies { def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile -tasks.withType(JavaCompile).configureEach { +// QueryDSL Q-클래스는 compileJava 단계에서만 생성 +tasks.named('compileJava', org.gradle.api.tasks.compile.JavaCompile) { options.generatedSourceOutputDirectory.set(querydslDir) } +// test 컴파일 단계에서는 어노테이션 프로세서를 비워서 Q-클래스 중복 생성 방지 +tasks.named('compileTestJava', org.gradle.api.tasks.compile.JavaCompile) { + options.annotationProcessorPath = files() +} + sourceSets { main.java.srcDirs += [ querydslDir ] }