From ef8a5322267f1b651708f579b9707cf44d845f9f Mon Sep 17 00:00:00 2001 From: Gyuhyeok99 <126947828+Gyuhyeok99@users.noreply.github.com> Date: Fri, 7 Feb 2025 13:35:41 +0900 Subject: [PATCH 1/8] =?UTF-8?q?refactor:=20=EC=84=9C=EB=B9=84=EC=8A=A4?= =?UTF-8?q?=EC=9D=98=20=EB=8C=80=ED=95=99=20=EC=84=A0=ED=83=9D=20=EA=B2=80?= =?UTF-8?q?=EC=A6=9D=EC=9D=84=20DTO=EC=97=90=EC=84=9C=20=EC=88=98=ED=96=89?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../application/dto/ApplyRequest.java | 3 ++ .../dto/UniversityChoiceRequest.java | 3 +- .../service/ApplicationSubmissionService.java | 22 +--------- .../annotation/ValidUniversityChoice.java | 20 +++++++++ .../ValidUniversityChoiceValidator.java | 41 +++++++++++++++++++ 5 files changed, 68 insertions(+), 21 deletions(-) create mode 100644 src/main/java/com/example/solidconnection/custom/validation/annotation/ValidUniversityChoice.java create mode 100644 src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java diff --git a/src/main/java/com/example/solidconnection/application/dto/ApplyRequest.java b/src/main/java/com/example/solidconnection/application/dto/ApplyRequest.java index 49c4b01ce..7c4da1c99 100644 --- a/src/main/java/com/example/solidconnection/application/dto/ApplyRequest.java +++ b/src/main/java/com/example/solidconnection/application/dto/ApplyRequest.java @@ -1,14 +1,17 @@ package com.example.solidconnection.application.dto; +import jakarta.validation.Valid; import jakarta.validation.constraints.NotNull; public record ApplyRequest( + @NotNull(message = "gpa score id를 입력해주세요.") Long gpaScoreId, @NotNull(message = "language test score id를 입력해주세요.") Long languageTestScoreId, + @Valid UniversityChoiceRequest universityChoiceRequest ) { } diff --git a/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java b/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java index 2d05cfe5b..354e814c1 100644 --- a/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java +++ b/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java @@ -1,11 +1,12 @@ package com.example.solidconnection.application.dto; +import com.example.solidconnection.custom.validation.annotation.ValidUniversityChoice; import jakarta.validation.constraints.NotNull; +@ValidUniversityChoice public record UniversityChoiceRequest( @NotNull(message = "1지망 대학교를 입력해주세요.") Long firstChoiceUniversityId, - Long secondChoiceUniversityId, Long thirdChoiceUniversityId) { } diff --git a/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java b/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java index beb2f0cb0..2db4786c3 100644 --- a/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java +++ b/src/main/java/com/example/solidconnection/application/service/ApplicationSubmissionService.java @@ -19,7 +19,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Optional; import java.util.Set; @@ -49,7 +51,6 @@ public class ApplicationSubmissionService { @Transactional public boolean apply(SiteUser siteUser, ApplyRequest applyRequest) { UniversityChoiceRequest universityChoiceRequest = applyRequest.universityChoiceRequest(); - validateUniversityChoices(universityChoiceRequest); Long gpaScoreId = applyRequest.gpaScoreId(); Long languageTestScoreId = applyRequest.languageTestScoreId(); @@ -117,23 +118,4 @@ private void validateUpdateLimitNotExceed(Application application) { throw new CustomException(APPLY_UPDATE_LIMIT_EXCEED); } } - - // 입력값 유효성 검증 - private void validateUniversityChoices(UniversityChoiceRequest universityChoiceRequest) { - Set uniqueUniversityIds = new HashSet<>(); - uniqueUniversityIds.add(universityChoiceRequest.firstChoiceUniversityId()); - if (universityChoiceRequest.secondChoiceUniversityId() != null) { - addUniversityChoice(uniqueUniversityIds, universityChoiceRequest.secondChoiceUniversityId()); - } - if (universityChoiceRequest.thirdChoiceUniversityId() != null) { - addUniversityChoice(uniqueUniversityIds, universityChoiceRequest.thirdChoiceUniversityId()); - } - } - - private void addUniversityChoice(Set uniqueUniversityIds, Long universityId) { - boolean notAdded = !uniqueUniversityIds.add(universityId); - if (notAdded) { - throw new CustomException(CANT_APPLY_FOR_SAME_UNIVERSITY); - } - } } diff --git a/src/main/java/com/example/solidconnection/custom/validation/annotation/ValidUniversityChoice.java b/src/main/java/com/example/solidconnection/custom/validation/annotation/ValidUniversityChoice.java new file mode 100644 index 000000000..2ab999e27 --- /dev/null +++ b/src/main/java/com/example/solidconnection/custom/validation/annotation/ValidUniversityChoice.java @@ -0,0 +1,20 @@ +package com.example.solidconnection.custom.validation.annotation; + +import com.example.solidconnection.custom.validation.validator.ValidUniversityChoiceValidator; +import jakarta.validation.Constraint; +import jakarta.validation.Payload; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Constraint(validatedBy = ValidUniversityChoiceValidator.class) +public @interface ValidUniversityChoice { + + String message() default "2지망 없이 3지망을 선택할 수 없습니다"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java new file mode 100644 index 000000000..cd3dc6d30 --- /dev/null +++ b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java @@ -0,0 +1,41 @@ +package com.example.solidconnection.custom.validation.validator; + +import com.example.solidconnection.application.dto.UniversityChoiceRequest; +import com.example.solidconnection.custom.validation.annotation.ValidUniversityChoice; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +import java.util.HashSet; +import java.util.Set; + +public class ValidUniversityChoiceValidator implements ConstraintValidator { + + @Override + public boolean isValid(UniversityChoiceRequest request, ConstraintValidatorContext context) { + if (request.thirdChoiceUniversityId() != null && request.secondChoiceUniversityId() == null) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate("2지망 없이 3지망을 선택할 수 없습니다") + .addConstraintViolation(); + return false; + } + + Set uniqueUniversityIds = new HashSet<>(); + uniqueUniversityIds.add(request.firstChoiceUniversityId()); + + return isValidChoice(request.secondChoiceUniversityId(), uniqueUniversityIds, context) && + isValidChoice(request.thirdChoiceUniversityId(), uniqueUniversityIds, context); + } + + private boolean isValidChoice(Long choiceId, Set uniqueIds, ConstraintValidatorContext context) { + if (choiceId == null) + return true; + + if (!uniqueIds.add(choiceId)) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate("지망 선택이 중복되었습니다") + .addConstraintViolation(); + return false; + } + return true; + } +} From c0496bd233b78755a2a5dde0a85ef83eb4275434 Mon Sep 17 00:00:00 2001 From: Gyuhyeok99 <126947828+Gyuhyeok99@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:57:19 +0900 Subject: [PATCH 2/8] =?UTF-8?q?refactor:=20=EB=8C=80=ED=95=99=20=EC=A7=80?= =?UTF-8?q?=EB=A7=9D=20=EA=B2=80=EC=A6=9D=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=EB=A5=BC=20=EC=83=81=EC=88=98=EB=A1=9C=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validator/ValidUniversityChoiceValidator.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java index cd3dc6d30..d733a95f7 100644 --- a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java +++ b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java @@ -10,11 +10,14 @@ public class ValidUniversityChoiceValidator implements ConstraintValidator { + public static final String ERROR_THIRD_CHOICE_WITHOUT_SECOND = "2지망 없이 3지망을 선택할 수 없습니다."; + public static final String ERROR_DUPLICATE_CHOICE = "지망 선택이 중복되었습니다"; + @Override public boolean isValid(UniversityChoiceRequest request, ConstraintValidatorContext context) { if (request.thirdChoiceUniversityId() != null && request.secondChoiceUniversityId() == null) { context.disableDefaultConstraintViolation(); - context.buildConstraintViolationWithTemplate("2지망 없이 3지망을 선택할 수 없습니다") + context.buildConstraintViolationWithTemplate(ERROR_THIRD_CHOICE_WITHOUT_SECOND) .addConstraintViolation(); return false; } @@ -32,7 +35,7 @@ private boolean isValidChoice(Long choiceId, Set uniqueIds, ConstraintVali if (!uniqueIds.add(choiceId)) { context.disableDefaultConstraintViolation(); - context.buildConstraintViolationWithTemplate("지망 선택이 중복되었습니다") + context.buildConstraintViolationWithTemplate(ERROR_DUPLICATE_CHOICE) .addConstraintViolation(); return false; } From 5567618d96421dee2330f1f48ea62f399e8dd98d Mon Sep 17 00:00:00 2001 From: Gyuhyeok99 <126947828+Gyuhyeok99@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:58:56 +0900 Subject: [PATCH 3/8] =?UTF-8?q?test:=20=EA=B8=B0=EC=A1=B4=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=ED=86=B5=ED=95=A9=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=97=90=EC=84=9C=20=EB=8C=80=ED=95=99=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ApplicationSubmissionServiceTest.java | 20 ---- .../ValidUniversityChoiceValidatorTest.java | 100 ++++++++++++++++++ 2 files changed, 100 insertions(+), 20 deletions(-) create mode 100644 src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java diff --git a/src/test/java/com/example/solidconnection/application/service/ApplicationSubmissionServiceTest.java b/src/test/java/com/example/solidconnection/application/service/ApplicationSubmissionServiceTest.java index 911172bfd..0a20b7733 100644 --- a/src/test/java/com/example/solidconnection/application/service/ApplicationSubmissionServiceTest.java +++ b/src/test/java/com/example/solidconnection/application/service/ApplicationSubmissionServiceTest.java @@ -118,26 +118,6 @@ class ApplicationSubmissionServiceTest extends BaseIntegrationTest { .hasMessage(INVALID_LANGUAGE_TEST_SCORE_STATUS.getMessage()); } - @Test - void 동일한_대학을_중복_선택하면_예외_응답을_반환한다() { - // given - GpaScore gpaScore = createApprovedGpaScore(테스트유저_1); - LanguageTestScore languageTestScore = createUnapprovedLanguageTestScore(테스트유저_1); - UniversityChoiceRequest universityChoiceRequest = new UniversityChoiceRequest( - 괌대학_A_지원_정보.getId(), - 괌대학_A_지원_정보.getId(), - 메모리얼대학_세인트존스_A_지원_정보.getId() - ); - ApplyRequest request = new ApplyRequest(gpaScore.getId(), languageTestScore.getId(), universityChoiceRequest); - - // when & then - assertThatCode(() -> - applicationSubmissionService.apply(테스트유저_1, request) - ) - .isInstanceOf(CustomException.class) - .hasMessage(CANT_APPLY_FOR_SAME_UNIVERSITY.getMessage()); - } - @Test void 지원서_수정_횟수를_초과하면_예외_응답을_반환한다() { // given diff --git a/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java b/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java new file mode 100644 index 000000000..14649049e --- /dev/null +++ b/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java @@ -0,0 +1,100 @@ +package com.example.solidconnection.custom.validation.validator; + +import com.example.solidconnection.application.dto.UniversityChoiceRequest; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validation; +import jakarta.validation.Validator; +import jakarta.validation.ValidatorFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static com.example.solidconnection.custom.validation.validator.ValidUniversityChoiceValidator.ERROR_DUPLICATE_CHOICE; +import static com.example.solidconnection.custom.validation.validator.ValidUniversityChoiceValidator.ERROR_THIRD_CHOICE_WITHOUT_SECOND; +import static org.assertj.core.api.Assertions.assertThat; + +@DisplayName("대학 선택 유효성 검사 테스트") +class ValidUniversityChoiceValidatorTest { + + private static final String MESSAGE = "message"; + private static final String ERROR_FIRST_CHOICE_IS_NULL = "1지망 대학교를 입력해주세요."; + + private Validator validator; + + @BeforeEach + void setUp() { + ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); + validator = factory.getValidator(); + } + + @Test + void 정상적인_지망_선택은_유효하다() { + // given + UniversityChoiceRequest request = new UniversityChoiceRequest(1L, 2L, 3L); + + // when + Set> violations = validator.validate(request); + + // then + assertThat(violations).isEmpty(); + } + + @Test + void 첫_번째_지망만_선택하는_것은_유효하다() { + // given + UniversityChoiceRequest request = new UniversityChoiceRequest(1L, null, null); + + // when + Set> violations = validator.validate(request); + + // then + assertThat(violations).isEmpty(); + } + + @Test + void 두_번째_지망_없이_세_번째_지망을_선택하면_예외_응답을_반환한다() { + // given + UniversityChoiceRequest request = new UniversityChoiceRequest(1L, null, 3L); + + // when + Set> violations = validator.validate(request); + + // then + assertThat(violations) + .extracting(MESSAGE) + .contains(ERROR_THIRD_CHOICE_WITHOUT_SECOND); + } + + @Test + void 첫_번째_지망을_선택하지_않으면_예외_응답을_반환한다() { + // given + UniversityChoiceRequest request = new UniversityChoiceRequest(null, 2L, 3L); + + // when + Set> violations = validator.validate(request); + + // then + + assertThat(violations) + .isNotEmpty() + .extracting(MESSAGE) + .contains(ERROR_FIRST_CHOICE_IS_NULL); + } + + @Test + void 대학을_중복_선택하면_예외_응답을_반환한다() { + // given + UniversityChoiceRequest request = new UniversityChoiceRequest(1L, 1L, 2L); + + // when + Set> violations = validator.validate(request); + + // then + assertThat(violations) + .isNotEmpty() + .extracting(MESSAGE) + .contains(ERROR_DUPLICATE_CHOICE); + } +} From eee9500babc224e25f0f88c7d8ee6cd6b2bf7f06 Mon Sep 17 00:00:00 2001 From: Gyuhyeok99 <126947828+Gyuhyeok99@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:32:18 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat:=20=EA=B8=B0=EB=B3=B8=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../custom/validation/annotation/ValidUniversityChoice.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/example/solidconnection/custom/validation/annotation/ValidUniversityChoice.java b/src/main/java/com/example/solidconnection/custom/validation/annotation/ValidUniversityChoice.java index 2ab999e27..7e5827113 100644 --- a/src/main/java/com/example/solidconnection/custom/validation/annotation/ValidUniversityChoice.java +++ b/src/main/java/com/example/solidconnection/custom/validation/annotation/ValidUniversityChoice.java @@ -14,7 +14,7 @@ @Constraint(validatedBy = ValidUniversityChoiceValidator.class) public @interface ValidUniversityChoice { - String message() default "2지망 없이 3지망을 선택할 수 없습니다"; + String message() default "유효하지 않은 지망 대학 선택입니다."; Class[] groups() default {}; Class[] payload() default {}; } From f7909cdc00aeafd4d42363af7788c03b8dccecd7 Mon Sep 17 00:00:00 2001 From: Gyuhyeok99 <126947828+Gyuhyeok99@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:39:57 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat:=20=EB=8C=80=ED=95=99=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=EA=B2=80=EC=A6=9D=20=EB=A9=94=EC=8B=9C=EC=A7=80?= =?UTF-8?q?=EB=A5=BC=20ErrorCode=20enum=EC=9C=BC=EB=A1=9C=20=ED=86=B5?= =?UTF-8?q?=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../solidconnection/custom/exception/ErrorCode.java | 3 +++ .../validator/ValidUniversityChoiceValidator.java | 10 +++++----- .../ValidUniversityChoiceValidatorTest.java | 12 ++++++------ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java index 8c3032284..35a6ee829 100644 --- a/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java +++ b/src/main/java/com/example/solidconnection/custom/exception/ErrorCode.java @@ -52,6 +52,9 @@ public enum ErrorCode { CANT_APPLY_FOR_SAME_UNIVERSITY(HttpStatus.BAD_REQUEST.value(), "1, 2, 3지망에 동일한 대학교를 입력할 수 없습니다."), CAN_NOT_CHANGE_NICKNAME_YET(HttpStatus.BAD_REQUEST.value(), "마지막 닉네임 변경으로부터 " + MIN_DAYS_BETWEEN_NICKNAME_CHANGES + "일이 지나지 않았습니다."), PROFILE_IMAGE_NEEDED(HttpStatus.BAD_REQUEST.value(), "프로필 이미지가 필요합니다."), + FIRST_CHOICE_REQUIRED(HttpStatus.BAD_REQUEST.value(), "1지망 대학교를 입력해주세요."), + THIRD_CHOICE_REQUIRES_SECOND(HttpStatus.BAD_REQUEST.value(), "2지망 없이 3지망을 선택할 수 없습니다."), + DUPLICATE_UNIVERSITY_CHOICE(HttpStatus.BAD_REQUEST.value(), "지망 선택이 중복되었습니다."), // community INVALID_POST_CATEGORY(HttpStatus.BAD_REQUEST.value(), "잘못된 카테고리명입니다."), diff --git a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java index d733a95f7..c000e1fce 100644 --- a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java +++ b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java @@ -8,16 +8,16 @@ import java.util.HashSet; import java.util.Set; -public class ValidUniversityChoiceValidator implements ConstraintValidator { +import static com.example.solidconnection.custom.exception.ErrorCode.DUPLICATE_UNIVERSITY_CHOICE; +import static com.example.solidconnection.custom.exception.ErrorCode.THIRD_CHOICE_REQUIRES_SECOND; - public static final String ERROR_THIRD_CHOICE_WITHOUT_SECOND = "2지망 없이 3지망을 선택할 수 없습니다."; - public static final String ERROR_DUPLICATE_CHOICE = "지망 선택이 중복되었습니다"; +public class ValidUniversityChoiceValidator implements ConstraintValidator { @Override public boolean isValid(UniversityChoiceRequest request, ConstraintValidatorContext context) { if (request.thirdChoiceUniversityId() != null && request.secondChoiceUniversityId() == null) { context.disableDefaultConstraintViolation(); - context.buildConstraintViolationWithTemplate(ERROR_THIRD_CHOICE_WITHOUT_SECOND) + context.buildConstraintViolationWithTemplate(THIRD_CHOICE_REQUIRES_SECOND.getMessage()) .addConstraintViolation(); return false; } @@ -35,7 +35,7 @@ private boolean isValidChoice(Long choiceId, Set uniqueIds, ConstraintVali if (!uniqueIds.add(choiceId)) { context.disableDefaultConstraintViolation(); - context.buildConstraintViolationWithTemplate(ERROR_DUPLICATE_CHOICE) + context.buildConstraintViolationWithTemplate(DUPLICATE_UNIVERSITY_CHOICE.getMessage()) .addConstraintViolation(); return false; } diff --git a/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java b/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java index 14649049e..c9c32a903 100644 --- a/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java +++ b/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java @@ -11,15 +11,15 @@ import java.util.Set; -import static com.example.solidconnection.custom.validation.validator.ValidUniversityChoiceValidator.ERROR_DUPLICATE_CHOICE; -import static com.example.solidconnection.custom.validation.validator.ValidUniversityChoiceValidator.ERROR_THIRD_CHOICE_WITHOUT_SECOND; +import static com.example.solidconnection.custom.exception.ErrorCode.DUPLICATE_UNIVERSITY_CHOICE; +import static com.example.solidconnection.custom.exception.ErrorCode.FIRST_CHOICE_REQUIRED; +import static com.example.solidconnection.custom.exception.ErrorCode.THIRD_CHOICE_REQUIRES_SECOND; import static org.assertj.core.api.Assertions.assertThat; @DisplayName("대학 선택 유효성 검사 테스트") class ValidUniversityChoiceValidatorTest { private static final String MESSAGE = "message"; - private static final String ERROR_FIRST_CHOICE_IS_NULL = "1지망 대학교를 입력해주세요."; private Validator validator; @@ -64,7 +64,7 @@ void setUp() { // then assertThat(violations) .extracting(MESSAGE) - .contains(ERROR_THIRD_CHOICE_WITHOUT_SECOND); + .contains(THIRD_CHOICE_REQUIRES_SECOND.getMessage()); } @Test @@ -80,7 +80,7 @@ void setUp() { assertThat(violations) .isNotEmpty() .extracting(MESSAGE) - .contains(ERROR_FIRST_CHOICE_IS_NULL); + .contains(FIRST_CHOICE_REQUIRED.getMessage()); } @Test @@ -95,6 +95,6 @@ void setUp() { assertThat(violations) .isNotEmpty() .extracting(MESSAGE) - .contains(ERROR_DUPLICATE_CHOICE); + .contains(DUPLICATE_UNIVERSITY_CHOICE.getMessage()); } } From 64bc75165614a18bd91800e444e0e3fcf51a6be5 Mon Sep 17 00:00:00 2001 From: Gyuhyeok99 <126947828+Gyuhyeok99@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:41:04 +0900 Subject: [PATCH 6/8] =?UTF-8?q?style:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EA=B0=9C=ED=96=89=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../validation/validator/ValidUniversityChoiceValidatorTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java b/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java index c9c32a903..b0267a08b 100644 --- a/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java +++ b/src/test/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidatorTest.java @@ -76,7 +76,6 @@ void setUp() { Set> violations = validator.validate(request); // then - assertThat(violations) .isNotEmpty() .extracting(MESSAGE) From a36eb455696dbed22186bd7f3bfda1cceb09e890 Mon Sep 17 00:00:00 2001 From: Gyuhyeok99 <126947828+Gyuhyeok99@users.noreply.github.com> Date: Sat, 8 Feb 2025 18:44:52 +0900 Subject: [PATCH 7/8] =?UTF-8?q?feat:=20=EB=8C=80=ED=95=99=20=EC=84=A0?= =?UTF-8?q?=ED=83=9D=20=ED=95=84=EC=88=98=EA=B0=92=20=EA=B2=80=EC=A6=9D=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/UniversityChoiceRequest.java | 2 -- .../ValidUniversityChoiceValidator.java | 17 ++++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java b/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java index 354e814c1..d219dbc2e 100644 --- a/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java +++ b/src/main/java/com/example/solidconnection/application/dto/UniversityChoiceRequest.java @@ -1,11 +1,9 @@ package com.example.solidconnection.application.dto; import com.example.solidconnection.custom.validation.annotation.ValidUniversityChoice; -import jakarta.validation.constraints.NotNull; @ValidUniversityChoice public record UniversityChoiceRequest( - @NotNull(message = "1지망 대학교를 입력해주세요.") Long firstChoiceUniversityId, Long secondChoiceUniversityId, Long thirdChoiceUniversityId) { diff --git a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java index c000e1fce..2f9b8ea4a 100644 --- a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java +++ b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java @@ -9,14 +9,21 @@ import java.util.Set; import static com.example.solidconnection.custom.exception.ErrorCode.DUPLICATE_UNIVERSITY_CHOICE; +import static com.example.solidconnection.custom.exception.ErrorCode.FIRST_CHOICE_REQUIRED; import static com.example.solidconnection.custom.exception.ErrorCode.THIRD_CHOICE_REQUIRES_SECOND; public class ValidUniversityChoiceValidator implements ConstraintValidator { - @Override public boolean isValid(UniversityChoiceRequest request, ConstraintValidatorContext context) { + context.disableDefaultConstraintViolation(); + + if (request.firstChoiceUniversityId() == null) { + context.buildConstraintViolationWithTemplate(FIRST_CHOICE_REQUIRED.getMessage()) + .addConstraintViolation(); + return false; + } + if (request.thirdChoiceUniversityId() != null && request.secondChoiceUniversityId() == null) { - context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate(THIRD_CHOICE_REQUIRES_SECOND.getMessage()) .addConstraintViolation(); return false; @@ -24,17 +31,13 @@ public boolean isValid(UniversityChoiceRequest request, ConstraintValidatorConte Set uniqueUniversityIds = new HashSet<>(); uniqueUniversityIds.add(request.firstChoiceUniversityId()); - return isValidChoice(request.secondChoiceUniversityId(), uniqueUniversityIds, context) && isValidChoice(request.thirdChoiceUniversityId(), uniqueUniversityIds, context); } private boolean isValidChoice(Long choiceId, Set uniqueIds, ConstraintValidatorContext context) { - if (choiceId == null) - return true; - + if (choiceId == null) return true; if (!uniqueIds.add(choiceId)) { - context.disableDefaultConstraintViolation(); context.buildConstraintViolationWithTemplate(DUPLICATE_UNIVERSITY_CHOICE.getMessage()) .addConstraintViolation(); return false; From 3e1e8534221f089504622b83761e732a631e24e3 Mon Sep 17 00:00:00 2001 From: Gyuhyeok99 <126947828+Gyuhyeok99@users.noreply.github.com> Date: Sat, 8 Feb 2025 19:03:53 +0900 Subject: [PATCH 8/8] =?UTF-8?q?refactor:=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20=EB=B0=8F=20?= =?UTF-8?q?=EA=B0=80=EB=8F=85=EC=84=B1=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ValidUniversityChoiceValidator.java | 37 +++++++++++++------ 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java index 2f9b8ea4a..6ac9fe1c2 100644 --- a/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java +++ b/src/main/java/com/example/solidconnection/custom/validation/validator/ValidUniversityChoiceValidator.java @@ -6,42 +6,57 @@ import jakarta.validation.ConstraintValidatorContext; import java.util.HashSet; +import java.util.Objects; import java.util.Set; +import java.util.stream.Stream; import static com.example.solidconnection.custom.exception.ErrorCode.DUPLICATE_UNIVERSITY_CHOICE; import static com.example.solidconnection.custom.exception.ErrorCode.FIRST_CHOICE_REQUIRED; import static com.example.solidconnection.custom.exception.ErrorCode.THIRD_CHOICE_REQUIRES_SECOND; public class ValidUniversityChoiceValidator implements ConstraintValidator { + @Override public boolean isValid(UniversityChoiceRequest request, ConstraintValidatorContext context) { context.disableDefaultConstraintViolation(); - if (request.firstChoiceUniversityId() == null) { + if (isFirstChoiceNotSelected(request)) { context.buildConstraintViolationWithTemplate(FIRST_CHOICE_REQUIRED.getMessage()) .addConstraintViolation(); return false; } - if (request.thirdChoiceUniversityId() != null && request.secondChoiceUniversityId() == null) { + if (isThirdChoiceWithoutSecond(request)) { context.buildConstraintViolationWithTemplate(THIRD_CHOICE_REQUIRES_SECOND.getMessage()) .addConstraintViolation(); return false; } - Set uniqueUniversityIds = new HashSet<>(); - uniqueUniversityIds.add(request.firstChoiceUniversityId()); - return isValidChoice(request.secondChoiceUniversityId(), uniqueUniversityIds, context) && - isValidChoice(request.thirdChoiceUniversityId(), uniqueUniversityIds, context); - } - - private boolean isValidChoice(Long choiceId, Set uniqueIds, ConstraintValidatorContext context) { - if (choiceId == null) return true; - if (!uniqueIds.add(choiceId)) { + if (isDuplicate(request)) { context.buildConstraintViolationWithTemplate(DUPLICATE_UNIVERSITY_CHOICE.getMessage()) .addConstraintViolation(); return false; } + return true; } + + private boolean isFirstChoiceNotSelected(UniversityChoiceRequest request) { + return request.firstChoiceUniversityId() == null; + } + + private boolean isThirdChoiceWithoutSecond(UniversityChoiceRequest request) { + return request.thirdChoiceUniversityId() != null && request.secondChoiceUniversityId() == null; + } + + private boolean isDuplicate(UniversityChoiceRequest request) { + Set uniqueIds = new HashSet<>(); + return Stream.of( + request.firstChoiceUniversityId(), + request.secondChoiceUniversityId(), + request.thirdChoiceUniversityId() + ) + .filter(Objects::nonNull) + .anyMatch(id -> !uniqueIds.add(id)); + } }