From f42716b42f5bb8d63a040b9505c8950fc75d1d37 Mon Sep 17 00:00:00 2001 From: devholic22 Date: Tue, 20 Feb 2024 12:39:09 +0900 Subject: [PATCH 1/6] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=A0=95=EB=B3=B4=20=EC=8B=9D=EB=B3=84=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - TokenProvider의 extract를 이메일로 수정 - LoginValidCheckerInterceptor에서 TokenProvider의 이메일을 가진 회원의 id를 저장하도록 수정 Co-authored-by: eom-tae-in Co-authored-by: eom-tae-in eti0728@daum.net --- .../com/atwoz/member/config/AuthConfig.java | 9 +++---- .../member/domain/auth/TokenProvider.java | 2 +- .../infrastructure/auth/JwtTokenProvider.java | 10 ++++---- .../LoginValidCheckerInterceptor.java | 9 +++++-- .../ui/auth/AuthControllerWebMvcTest.java | 25 +++++++++++-------- .../LoginValidCheckerInterceptorTest.java | 12 +++++---- 6 files changed, 39 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/atwoz/member/config/AuthConfig.java b/src/main/java/com/atwoz/member/config/AuthConfig.java index 3ceec047..7f4a7358 100644 --- a/src/main/java/com/atwoz/member/config/AuthConfig.java +++ b/src/main/java/com/atwoz/member/config/AuthConfig.java @@ -1,5 +1,8 @@ package com.atwoz.member.config; +import static com.atwoz.member.ui.auth.interceptor.HttpMethod.ANY; +import static com.atwoz.member.ui.auth.interceptor.HttpMethod.OPTIONS; + import com.atwoz.member.ui.auth.interceptor.LoginValidCheckerInterceptor; import com.atwoz.member.ui.auth.interceptor.ParseMemberIdFromTokenInterceptor; import com.atwoz.member.ui.auth.interceptor.PathMatcherInterceptor; @@ -10,12 +13,8 @@ import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; - import java.util.List; -import static com.atwoz.member.ui.auth.interceptor.HttpMethod.ANY; -import static com.atwoz.member.ui.auth.interceptor.HttpMethod.OPTIONS; - @RequiredArgsConstructor @Configuration public class AuthConfig implements WebMvcConfigurer { @@ -33,7 +32,7 @@ public void addInterceptors(InterceptorRegistry registry) { private HandlerInterceptor parseMemberIdFromTokenInterceptor() { return new PathMatcherInterceptor(parseMemberIdFromTokenInterceptor) .excludePathPattern("/**", OPTIONS) - .addPathPatterns("/admin/**", ANY); + .addPathPatterns("/**", ANY); } /** diff --git a/src/main/java/com/atwoz/member/domain/auth/TokenProvider.java b/src/main/java/com/atwoz/member/domain/auth/TokenProvider.java index e52f0488..e91a2b2c 100644 --- a/src/main/java/com/atwoz/member/domain/auth/TokenProvider.java +++ b/src/main/java/com/atwoz/member/domain/auth/TokenProvider.java @@ -4,5 +4,5 @@ public interface TokenProvider { String createTokenWith(final String email); - Long extract(final String token); + String extract(final String token); } diff --git a/src/main/java/com/atwoz/member/infrastructure/auth/JwtTokenProvider.java b/src/main/java/com/atwoz/member/infrastructure/auth/JwtTokenProvider.java index 81995ad9..5bd39284 100644 --- a/src/main/java/com/atwoz/member/infrastructure/auth/JwtTokenProvider.java +++ b/src/main/java/com/atwoz/member/infrastructure/auth/JwtTokenProvider.java @@ -14,13 +14,13 @@ import io.jsonwebtoken.UnsupportedJwtException; import io.jsonwebtoken.security.Keys; import jakarta.annotation.PostConstruct; +import lombok.NoArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; import java.security.Key; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; -import lombok.NoArgsConstructor; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; @NoArgsConstructor @Component @@ -71,13 +71,13 @@ private Date expiredAt() { } @Override - public Long extract(final String token) { + public String extract(final String token) { try { return Jwts.parser() .setSigningKey(secret.getBytes()) .parseClaimsJws(token) .getBody() - .get("id", Long.class); + .get("email", String.class); } catch (SecurityException e) { throw new SignatureInvalidException(); } catch (MalformedJwtException e) { diff --git a/src/main/java/com/atwoz/member/ui/auth/interceptor/LoginValidCheckerInterceptor.java b/src/main/java/com/atwoz/member/ui/auth/interceptor/LoginValidCheckerInterceptor.java index 3d9ea30b..dd3585ae 100644 --- a/src/main/java/com/atwoz/member/ui/auth/interceptor/LoginValidCheckerInterceptor.java +++ b/src/main/java/com/atwoz/member/ui/auth/interceptor/LoginValidCheckerInterceptor.java @@ -1,6 +1,8 @@ package com.atwoz.member.ui.auth.interceptor; import com.atwoz.member.domain.auth.TokenProvider; +import com.atwoz.member.domain.member.Member; +import com.atwoz.member.domain.member.MemberRepository; import com.atwoz.member.exception.exceptions.auth.LoginInvalidException; import com.atwoz.member.ui.auth.support.auth.AuthenticationContext; import com.atwoz.member.ui.auth.support.auth.AuthenticationExtractor; @@ -16,6 +18,7 @@ public class LoginValidCheckerInterceptor implements HandlerInterceptor { private final TokenProvider tokenProvider; private final AuthenticationContext authenticationContext; + private final MemberRepository memberRepository; @Override public boolean preHandle(final HttpServletRequest request, @@ -24,8 +27,10 @@ public boolean preHandle(final HttpServletRequest request, String token = AuthenticationExtractor.extract(request) .orElseThrow(LoginInvalidException::new); - Long memberId = tokenProvider.extract(token); - authenticationContext.setAuthentication(memberId); + String memberEmail = tokenProvider.extract(token); + Member findMember = memberRepository.findByEmail(memberEmail) + .orElseThrow(RuntimeException::new); + authenticationContext.setAuthentication(findMember.getId()); return true; } diff --git a/src/test/java/com/atwoz/member/ui/auth/AuthControllerWebMvcTest.java b/src/test/java/com/atwoz/member/ui/auth/AuthControllerWebMvcTest.java index 1798892b..f28ebea6 100644 --- a/src/test/java/com/atwoz/member/ui/auth/AuthControllerWebMvcTest.java +++ b/src/test/java/com/atwoz/member/ui/auth/AuthControllerWebMvcTest.java @@ -1,7 +1,18 @@ package com.atwoz.member.ui.auth; +import static com.atwoz.helper.RestDocsHelper.customDocument; +import static com.atwoz.member.fixture.auth.OAuthProviderFixture.인증_기관_생성; +import static org.mockito.Mockito.when; +import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; +import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; +import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + import com.atwoz.helper.MockBeanInjection; import com.atwoz.member.application.auth.dto.LoginRequest; +import com.atwoz.member.domain.member.MemberRepository; import com.atwoz.member.infrastructure.auth.dto.OAuthProviderRequest; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.DisplayNameGeneration; @@ -10,19 +21,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import static com.atwoz.helper.RestDocsHelper.customDocument; -import static com.atwoz.member.fixture.auth.OAuthProviderFixture.인증_기관_생성; -import static org.mockito.Mockito.when; -import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath; -import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields; -import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") @AutoConfigureRestDocs @@ -35,6 +37,9 @@ class AuthControllerWebMvcTest extends MockBeanInjection { @Autowired private ObjectMapper objectMapper; + @MockBean + private MemberRepository memberRepository; + @Test void 로그인을_진행한다() throws Exception { // given diff --git a/src/test/java/com/atwoz/member/ui/auth/interceptor/LoginValidCheckerInterceptorTest.java b/src/test/java/com/atwoz/member/ui/auth/interceptor/LoginValidCheckerInterceptorTest.java index 0e353323..5b176031 100644 --- a/src/test/java/com/atwoz/member/ui/auth/interceptor/LoginValidCheckerInterceptorTest.java +++ b/src/test/java/com/atwoz/member/ui/auth/interceptor/LoginValidCheckerInterceptorTest.java @@ -1,7 +1,12 @@ package com.atwoz.member.ui.auth.interceptor; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import com.atwoz.member.exception.exceptions.auth.LoginInvalidException; import com.atwoz.member.infrastructure.auth.JwtTokenProvider; +import com.atwoz.member.infrastructure.member.MemberFakeRepository; import com.atwoz.member.ui.auth.support.auth.AuthenticationContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -9,10 +14,6 @@ import org.junit.jupiter.api.DisplayNameGenerator; import org.junit.jupiter.api.Test; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class) @SuppressWarnings("NonAsciiCharacters") class LoginValidCheckerInterceptorTest { @@ -25,7 +26,8 @@ class LoginValidCheckerInterceptorTest { // given LoginValidCheckerInterceptor loginValidCheckerInterceptor = new LoginValidCheckerInterceptor( new JwtTokenProvider(), - new AuthenticationContext() + new AuthenticationContext(), + new MemberFakeRepository() ); when(req.getHeader("any")).thenReturn(null); From 23ecd38854dc9b37866c27df3f2bc1d081457021 Mon Sep 17 00:00:00 2001 From: devholic22 Date: Tue, 20 Feb 2024 12:50:29 +0900 Subject: [PATCH 2/6] =?UTF-8?q?refactor:=20=ED=81=B4=EB=9E=98=EC=8A=A4=20?= =?UTF-8?q?=EA=B2=BD=EB=A1=9C=20=EB=B0=8F=20=EA=B5=AC=EC=A1=B0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 도메인에 있던 클래스 파일의 패키지 변경 - Hobbies, Styles 엔티티화 Co-authored-by: eom-tae-in - MemberOption, MemberProfile 대신 Option, Profile로 수정 - Option과 Profile을 담은 겉구조를 info로 변경 - Profile 안에 있는 나이, 키, 성별을 MemberBody에 담도록 수정 - Null 예외처리 추가 - 범위 예외처리 추가 - 속성값 조회 실패 예외처리 추가 --- .../exception/GlobalExceptionHandler.java | 14 ++++ .../exceptions/NullValueException.java | 8 ++ .../exceptions/PropertyNotFoundException.java | 8 ++ .../member/domain/info/hobby/Hobbies.java | 75 +++++++++++++++++++ .../atwoz/member/domain/info/hobby/Hobby.java | 30 ++++++++ .../domain/{profile => info}/image/Image.java | 2 +- .../{profile => info}/image/Images.java | 2 +- .../member/domain/info/option/Drink.java | 28 +++++++ .../member/domain/info/option/Graduate.java | 32 ++++++++ .../atwoz/member/domain/info/option/Mbti.java | 31 ++++++++ .../option/Option.java} | 16 +++- .../member/domain/info/option/Religion.java | 28 +++++++ .../member/domain/info/option/Smoke.java | 28 +++++++ .../member/domain/info/profile/Gender.java | 25 +++++++ .../atwoz/member/domain/info/profile/Job.java | 29 +++++++ .../member/domain/info/profile/Location.java | 33 ++++++++ .../domain/info/profile/MemberBody.java | 67 +++++++++++++++++ .../profile/Profile.java} | 22 +++--- .../atwoz/member/domain/info/style/Style.java | 30 ++++++++ .../member/domain/info/style/Styles.java | 75 +++++++++++++++++++ .../atwoz/member/domain/member/Member.java | 16 ---- .../atwoz/member/domain/profile/Drink.java | 13 ---- .../atwoz/member/domain/profile/Gender.java | 10 --- .../atwoz/member/domain/profile/Graduate.java | 17 ----- .../com/atwoz/member/domain/profile/Job.java | 13 ---- .../atwoz/member/domain/profile/Location.java | 16 ---- .../com/atwoz/member/domain/profile/Mbti.java | 21 ------ .../atwoz/member/domain/profile/Religion.java | 13 ---- .../atwoz/member/domain/profile/Smoke.java | 13 ---- .../member/domain/profile/hobby/Hobbies.java | 19 ----- .../member/domain/profile/hobby/Hobby.java | 13 ---- .../member/domain/profile/style/Style.java | 13 ---- .../member/domain/profile/style/Styles.java | 19 ----- .../info/profile/ProfileRangeException.java | 8 ++ 34 files changed, 575 insertions(+), 212 deletions(-) create mode 100644 src/main/java/com/atwoz/global/exception/exceptions/NullValueException.java create mode 100644 src/main/java/com/atwoz/global/exception/exceptions/PropertyNotFoundException.java create mode 100644 src/main/java/com/atwoz/member/domain/info/hobby/Hobbies.java create mode 100644 src/main/java/com/atwoz/member/domain/info/hobby/Hobby.java rename src/main/java/com/atwoz/member/domain/{profile => info}/image/Image.java (80%) rename src/main/java/com/atwoz/member/domain/{profile => info}/image/Images.java (87%) create mode 100644 src/main/java/com/atwoz/member/domain/info/option/Drink.java create mode 100644 src/main/java/com/atwoz/member/domain/info/option/Graduate.java create mode 100644 src/main/java/com/atwoz/member/domain/info/option/Mbti.java rename src/main/java/com/atwoz/member/domain/{profile/MemberOption.java => info/option/Option.java} (64%) create mode 100644 src/main/java/com/atwoz/member/domain/info/option/Religion.java create mode 100644 src/main/java/com/atwoz/member/domain/info/option/Smoke.java create mode 100644 src/main/java/com/atwoz/member/domain/info/profile/Gender.java create mode 100644 src/main/java/com/atwoz/member/domain/info/profile/Job.java create mode 100644 src/main/java/com/atwoz/member/domain/info/profile/Location.java create mode 100644 src/main/java/com/atwoz/member/domain/info/profile/MemberBody.java rename src/main/java/com/atwoz/member/domain/{profile/MemberProfile.java => info/profile/Profile.java} (66%) create mode 100644 src/main/java/com/atwoz/member/domain/info/style/Style.java create mode 100644 src/main/java/com/atwoz/member/domain/info/style/Styles.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/Drink.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/Gender.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/Graduate.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/Job.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/Location.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/Mbti.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/Religion.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/Smoke.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/hobby/Hobbies.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/hobby/Hobby.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/style/Style.java delete mode 100644 src/main/java/com/atwoz/member/domain/profile/style/Styles.java create mode 100644 src/main/java/com/atwoz/member/exception/exceptions/info/profile/ProfileRangeException.java diff --git a/src/main/java/com/atwoz/global/exception/GlobalExceptionHandler.java b/src/main/java/com/atwoz/global/exception/GlobalExceptionHandler.java index 7f90f742..5526550d 100644 --- a/src/main/java/com/atwoz/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/atwoz/global/exception/GlobalExceptionHandler.java @@ -1,5 +1,7 @@ package com.atwoz.global.exception; +import com.atwoz.global.exception.exceptions.NullValueException; +import com.atwoz.global.exception.exceptions.PropertyNotFoundException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -31,4 +33,16 @@ public ResponseEntity handleIllegalArgumentException(final IllegalArgume return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(INTERNAL_SERVER_ERROR_MESSAGE); } + + @ExceptionHandler(NullValueException.class) + public ResponseEntity handleNullException(final NullValueException exception) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(exception.getMessage()); + } + + @ExceptionHandler(PropertyNotFoundException.class) + public ResponseEntity handlePropertyNotFoundException(final PropertyNotFoundException exception) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body(exception.getMessage()); + } } diff --git a/src/main/java/com/atwoz/global/exception/exceptions/NullValueException.java b/src/main/java/com/atwoz/global/exception/exceptions/NullValueException.java new file mode 100644 index 00000000..e44e748f --- /dev/null +++ b/src/main/java/com/atwoz/global/exception/exceptions/NullValueException.java @@ -0,0 +1,8 @@ +package com.atwoz.global.exception.exceptions; + +public class NullValueException extends RuntimeException { + + public NullValueException() { + super("값에 null이 들어가면 안 됩니다."); + } +} diff --git a/src/main/java/com/atwoz/global/exception/exceptions/PropertyNotFoundException.java b/src/main/java/com/atwoz/global/exception/exceptions/PropertyNotFoundException.java new file mode 100644 index 00000000..f34e780e --- /dev/null +++ b/src/main/java/com/atwoz/global/exception/exceptions/PropertyNotFoundException.java @@ -0,0 +1,8 @@ +package com.atwoz.global.exception.exceptions; + +public class PropertyNotFoundException extends RuntimeException { + + public PropertyNotFoundException() { + super("속성 값에 맞는 타입을 찾지 못했습니다."); + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/hobby/Hobbies.java b/src/main/java/com/atwoz/member/domain/info/hobby/Hobbies.java new file mode 100644 index 00000000..af85032b --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/hobby/Hobbies.java @@ -0,0 +1,75 @@ +package com.atwoz.member.domain.info.hobby; + +import com.atwoz.global.exception.exceptions.NullValueException; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Hobbies { + + private static final int MINIMUM_SIZE = 1; + private static final int MAXIMUM_SIZE = 3; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private Long memberId; + + @ElementCollection + private List hobbies; + + public Hobbies(final Long memberId, final List hobbies) { + validateIsNullMemberId(memberId); + validateHobbies(hobbies); + List newHobbies = hobbies.stream() + .map(Hobby::from) + .toList(); + + this.hobbies = newHobbies; + } + + private void validateIsNullMemberId(final Long memberId) { + if (memberId == null) { + throw new NullValueException(); + } + } + + private void validateHobbies(final List hobbies) { + validateIsNull(hobbies); + validateIsDuplicate(hobbies); + validateSize(hobbies); + } + + private void validateIsNull(final List hobbies) { + if (hobbies == null) { + throw new NullValueException(); + } + } + + private void validateIsDuplicate(final List hobbies) { + Set hobbySet = new HashSet<>(hobbies); + if (hobbies.size() != hobbySet.size()) { + throw new IllegalArgumentException(); + } + } + + private void validateSize(final List hobbies) { + if (hobbies.size() < MINIMUM_SIZE || hobbies.size() > MAXIMUM_SIZE) { + throw new IllegalArgumentException(); + } + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/hobby/Hobby.java b/src/main/java/com/atwoz/member/domain/info/hobby/Hobby.java new file mode 100644 index 00000000..7a647fd7 --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/hobby/Hobby.java @@ -0,0 +1,30 @@ +package com.atwoz.member.domain.info.hobby; + +import com.atwoz.global.exception.exceptions.NullValueException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PROTECTED) +@Embeddable +public class Hobby { + + @Column(nullable = false) + private String hobby; + + public static Hobby from(final String hobby) { + validateIsNotNull(hobby); + return new Hobby(hobby); + } + + private static void validateIsNotNull(final String hobby) { + if (hobby == null) { + throw new NullValueException(); + } + } +} diff --git a/src/main/java/com/atwoz/member/domain/profile/image/Image.java b/src/main/java/com/atwoz/member/domain/info/image/Image.java similarity index 80% rename from src/main/java/com/atwoz/member/domain/profile/image/Image.java rename to src/main/java/com/atwoz/member/domain/info/image/Image.java index 2687f8a1..7b24316c 100644 --- a/src/main/java/com/atwoz/member/domain/profile/image/Image.java +++ b/src/main/java/com/atwoz/member/domain/info/image/Image.java @@ -1,4 +1,4 @@ -package com.atwoz.member.domain.profile.image; +package com.atwoz.member.domain.info.image; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; diff --git a/src/main/java/com/atwoz/member/domain/profile/image/Images.java b/src/main/java/com/atwoz/member/domain/info/image/Images.java similarity index 87% rename from src/main/java/com/atwoz/member/domain/profile/image/Images.java rename to src/main/java/com/atwoz/member/domain/info/image/Images.java index 587ded08..71cc8324 100644 --- a/src/main/java/com/atwoz/member/domain/profile/image/Images.java +++ b/src/main/java/com/atwoz/member/domain/info/image/Images.java @@ -1,4 +1,4 @@ -package com.atwoz.member.domain.profile.image; +package com.atwoz.member.domain.info.image; import jakarta.persistence.ElementCollection; import jakarta.persistence.Embeddable; diff --git a/src/main/java/com/atwoz/member/domain/info/option/Drink.java b/src/main/java/com/atwoz/member/domain/info/option/Drink.java new file mode 100644 index 00000000..0de01972 --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/option/Drink.java @@ -0,0 +1,28 @@ +package com.atwoz.member.domain.info.option; + +import com.atwoz.global.exception.exceptions.PropertyNotFoundException; +import lombok.Getter; +import java.util.Arrays; + +@Getter +public enum Drink { + + NEVER("전혀 마시지 않음"), + SOCIETY("사회적 음주"), + OFTEN("가끔 마심"), + ENJOY("술자리를 즐김"), + NOT_NOW("금주 중"); + + private final String name; + + Drink(final String name) { + this.name = name; + } + + public static Drink findByName(final String name) { + return Arrays.stream(values()) + .filter(drink -> name.equals(drink.getName())) + .findFirst() + .orElseThrow(PropertyNotFoundException::new); + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/option/Graduate.java b/src/main/java/com/atwoz/member/domain/info/option/Graduate.java new file mode 100644 index 00000000..459dbf3b --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/option/Graduate.java @@ -0,0 +1,32 @@ +package com.atwoz.member.domain.info.option; + +import com.atwoz.global.exception.exceptions.PropertyNotFoundException; +import lombok.Getter; +import java.util.Arrays; + +@Getter +public enum Graduate { + + SEOUL_FOURTH("서울 4년제"), + ETC_FOURTH("지방 4년제"), + PROFESSIONAL("전문대"), + FOREIGN("해외대"), + MASTER("석사"), + DOCTOR("박사"), + LAW_SCHOOL("로스쿨"), + HIGH_SCHOOL("고등학교 졸업"), + ETC("기타"); + + private final String name; + + Graduate(final String name) { + this.name = name; + } + + public static Graduate findByName(final String name) { + return Arrays.stream(values()) + .filter(graduate -> name.equals(graduate.getName())) + .findFirst() + .orElseThrow(PropertyNotFoundException::new); + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/option/Mbti.java b/src/main/java/com/atwoz/member/domain/info/option/Mbti.java new file mode 100644 index 00000000..b00ce56f --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/option/Mbti.java @@ -0,0 +1,31 @@ +package com.atwoz.member.domain.info.option; + +import com.atwoz.global.exception.exceptions.PropertyNotFoundException; +import java.util.Arrays; + +public enum Mbti { + + ISTJ, + ISFJ, + INFJ, + INTJ, + ISTP, + ISFP, + INFP, + INTP, + ESTP, + ESFP, + ENFP, + ENTP, + ESTJ, + ESFJ, + ENFJ, + ENTJ; + + public static Mbti findByName(final String name) { + return Arrays.stream(values()) + .filter(mbti -> name.equals(mbti.name())) + .findFirst() + .orElseThrow(PropertyNotFoundException::new); + } +} diff --git a/src/main/java/com/atwoz/member/domain/profile/MemberOption.java b/src/main/java/com/atwoz/member/domain/info/option/Option.java similarity index 64% rename from src/main/java/com/atwoz/member/domain/profile/MemberOption.java rename to src/main/java/com/atwoz/member/domain/info/option/Option.java index d209eb4a..c41e6cbe 100644 --- a/src/main/java/com/atwoz/member/domain/profile/MemberOption.java +++ b/src/main/java/com/atwoz/member/domain/info/option/Option.java @@ -1,4 +1,4 @@ -package com.atwoz.member.domain.profile; +package com.atwoz.member.domain.info.option; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -7,14 +7,16 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.Table; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; @Getter +@Table(name = "member_option") @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity -public class MemberOption { +public class Option { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -42,4 +44,14 @@ public class MemberOption { @Column(nullable = false) @Enumerated(value = EnumType.STRING) private Graduate graduate; + + public Option(final Long memberId, final String smoke, final String religion, + final String drink, final String mbti, final String graduate) { + this.memberId = memberId; + this.smoke = Smoke.findByName(smoke); + this.religion = Religion.findByName(religion); + this.drink = Drink.findByName(drink); + this.mbti = Mbti.findByName(mbti); + this.graduate = Graduate.findByName(graduate); + } } diff --git a/src/main/java/com/atwoz/member/domain/info/option/Religion.java b/src/main/java/com/atwoz/member/domain/info/option/Religion.java new file mode 100644 index 00000000..0dbcde46 --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/option/Religion.java @@ -0,0 +1,28 @@ +package com.atwoz.member.domain.info.option; + +import com.atwoz.global.exception.exceptions.PropertyNotFoundException; +import lombok.Getter; +import java.util.Arrays; + +@Getter +public enum Religion { + + CATHOLIC("천주교"), + CHRIST("기독교"), + BUDDHA("불교"), + NONE("무교"), + ETC("기타"); + + private final String name; + + Religion(final String name) { + this.name = name; + } + + public static Religion findByName(final String name) { + return Arrays.stream(values()) + .filter(religion -> name.equals(religion.getName())) + .findFirst() + .orElseThrow(PropertyNotFoundException::new); + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/option/Smoke.java b/src/main/java/com/atwoz/member/domain/info/option/Smoke.java new file mode 100644 index 00000000..460fc41c --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/option/Smoke.java @@ -0,0 +1,28 @@ +package com.atwoz.member.domain.info.option; + +import com.atwoz.global.exception.exceptions.PropertyNotFoundException; +import lombok.Getter; +import java.util.Arrays; + +@Getter +public enum Smoke { + + NEVER("비흡연"), + NOT_NOW("금연 중"), + ELECTRONIC("전자담배"), + OFTEN("가끔 피움"), + EVERYDAY("매일 피움"); + + private final String name; + + Smoke(final String name) { + this.name = name; + } + + public static Smoke findByName(final String name) { + return Arrays.stream(values()) + .filter(smoke -> name.equals(smoke.getName())) + .findFirst() + .orElseThrow(PropertyNotFoundException::new); + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/profile/Gender.java b/src/main/java/com/atwoz/member/domain/info/profile/Gender.java new file mode 100644 index 00000000..f0b0e459 --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/profile/Gender.java @@ -0,0 +1,25 @@ +package com.atwoz.member.domain.info.profile; + +import com.atwoz.global.exception.exceptions.PropertyNotFoundException; +import lombok.Getter; +import java.util.Arrays; + +@Getter +public enum Gender { + + MALE("남성"), + FEMALE("여성"); + + private final String name; + + Gender(final String name) { + this.name = name; + } + + public static Gender findByName(final String name) { + return Arrays.stream(values()) + .filter(gender -> name.equals(gender.getName())) + .findFirst() + .orElseThrow(PropertyNotFoundException::new); + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/profile/Job.java b/src/main/java/com/atwoz/member/domain/info/profile/Job.java new file mode 100644 index 00000000..d4c03c50 --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/profile/Job.java @@ -0,0 +1,29 @@ +package com.atwoz.member.domain.info.profile; + +import com.atwoz.global.exception.exceptions.NullValueException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Embeddable +public class Job { + + @Column(nullable = false) + private String job; + + public Job(final String job) { + validateNotNull(job); + + this.job = job; + } + + public void validateNotNull(final String job) { + if (job == null) { + throw new NullValueException(); + } + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/profile/Location.java b/src/main/java/com/atwoz/member/domain/info/profile/Location.java new file mode 100644 index 00000000..18661bed --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/profile/Location.java @@ -0,0 +1,33 @@ +package com.atwoz.member.domain.info.profile; + +import com.atwoz.global.exception.exceptions.NullValueException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Embeddable +public class Location { + + @Column(nullable = false) + private String city; + + @Column(nullable = false) + private String sector; + + public Location(final String city, final String sector) { + validateValues(city, sector); + + this.city = city; + this.sector = sector; + } + + private void validateValues(final String city, final String sector) { + if (city == null || sector == null) { + throw new NullValueException(); + } + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/profile/MemberBody.java b/src/main/java/com/atwoz/member/domain/info/profile/MemberBody.java new file mode 100644 index 00000000..62dcd197 --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/profile/MemberBody.java @@ -0,0 +1,67 @@ +package com.atwoz.member.domain.info.profile; + +import com.atwoz.global.exception.exceptions.NullValueException; +import com.atwoz.member.exception.exceptions.info.profile.ProfileRangeException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import java.time.LocalDateTime; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Embeddable +public class MemberBody { + + private static final int MIN_AGE = 20; + private static final int MAX_AGE = 45; + private static final int MIN_HEIGHT = 140; + private static final int MAX_HEIGHT = 199; + + @Column(nullable = false) + private Integer age; + + @Column(nullable = false) + private Integer height; + + @Column(nullable = false) + @Enumerated(value = EnumType.STRING) + private Gender gender; + + public MemberBody(final Integer age, final Integer height, final Gender gender) { + validateValues(age, height); + + this.age = age; + this.height = height; + this.gender = gender; + } + + public void validateValues(final Integer age, final Integer height) { + validateAge(age); + validateHeight(height); + } + + private void validateAge(final Integer age) { + if (age == null) { + throw new NullValueException(); + } + LocalDateTime nowTime = LocalDateTime.now(); + int nowYear = nowTime.getYear(); + int memberAge = Math.abs(nowYear - age); + if (memberAge < MIN_AGE|| MAX_AGE < memberAge) { + throw new ProfileRangeException(); + } + } + + private void validateHeight(final Integer height) { + if (height == null) { + throw new NullValueException(); + } + if (height < MIN_HEIGHT || MAX_HEIGHT < height) { + throw new ProfileRangeException(); + } + } +} diff --git a/src/main/java/com/atwoz/member/domain/profile/MemberProfile.java b/src/main/java/com/atwoz/member/domain/info/profile/Profile.java similarity index 66% rename from src/main/java/com/atwoz/member/domain/profile/MemberProfile.java rename to src/main/java/com/atwoz/member/domain/info/profile/Profile.java index 16503539..1d4de8ea 100644 --- a/src/main/java/com/atwoz/member/domain/profile/MemberProfile.java +++ b/src/main/java/com/atwoz/member/domain/info/profile/Profile.java @@ -1,10 +1,8 @@ -package com.atwoz.member.domain.profile; +package com.atwoz.member.domain.info.profile; import jakarta.persistence.Column; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -15,7 +13,7 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Entity -public class MemberProfile { +public class Profile { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -25,14 +23,7 @@ public class MemberProfile { private Long memberId; @Column(nullable = false) - private Integer age; - - @Column(nullable = false) - private Integer height; - - @Column(nullable = false) - @Enumerated(value = EnumType.STRING) - private Gender gender; + private MemberBody memberBody; @Embedded @Column(nullable = false) @@ -41,4 +32,11 @@ public class MemberProfile { @Embedded @Column(nullable = false) private Job job; + + public Profile(final Long memberId, final MemberBody memberBody, final Location location, final Job job) { + this.memberId = memberId; + this.memberBody = memberBody; + this.location = location; + this.job = job; + } } diff --git a/src/main/java/com/atwoz/member/domain/info/style/Style.java b/src/main/java/com/atwoz/member/domain/info/style/Style.java new file mode 100644 index 00000000..27cdad6e --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/style/Style.java @@ -0,0 +1,30 @@ +package com.atwoz.member.domain.info.style; + +import com.atwoz.global.exception.exceptions.NullValueException; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PROTECTED) +@Embeddable +public class Style { + + @Column(nullable = false) + private String style; + + public static Style from(final String style) { + validateIsNotNull(style); + return new Style(style); + } + + private static void validateIsNotNull(final String style) { + if (style == null) { + throw new NullValueException(); + } + } +} diff --git a/src/main/java/com/atwoz/member/domain/info/style/Styles.java b/src/main/java/com/atwoz/member/domain/info/style/Styles.java new file mode 100644 index 00000000..38d22f2e --- /dev/null +++ b/src/main/java/com/atwoz/member/domain/info/style/Styles.java @@ -0,0 +1,75 @@ +package com.atwoz.member.domain.info.style; + +import com.atwoz.global.exception.exceptions.NullValueException; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Entity +public class Styles { + + private static final int MINIMUM_SIZE = 1; + private static final int MAXIMUM_SIZE = 3; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(nullable = false) + private Long memberId; + + @ElementCollection + private List