-
Notifications
You must be signed in to change notification settings - Fork 0
feat: 사용자 회원가입 기능 구현 #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 45 commits
22574c6
af21ba6
0998526
c4828de
2f83a01
86cbc52
9416a2c
4a78fb4
ea1ac42
abd1120
ed9c25b
804d08f
16ec2c2
220520b
1b03b82
b0ae2d2
7e41f10
9c42aaa
c9ba0fd
50b98e6
7802513
0a919de
789331d
eac7c9a
43ba1bb
f3a9018
a3347d8
978f13c
d76d899
8529873
56a96e3
a195785
155e062
9915ec0
15d61fc
ca16721
75337f9
8e06340
54fbbae
c44d480
7fe1008
b3e6726
386c329
06b6961
0eaa0f1
a0f2565
3eaf910
bb9ca16
d4f540c
ed2b053
5ce6acf
ff8762a
114339e
3ab3f83
119f343
01f37ab
62e487e
7177d52
3b4de32
29f3e5b
ff79ca6
517c1ca
0d5dc4a
1060d9a
5698b5b
841bed8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,3 +35,6 @@ out/ | |
|
|
||
| ### VS Code ### | ||
| .vscode/ | ||
|
|
||
| ### applicaiton.yml ### | ||
| /src/main/resources/application.yml | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,30 @@ | ||
| package com.sangyunpark.user.application; | ||
|
|
||
| import com.sangyunpark.user.application.mapper.UserMapper; | ||
| import com.sangyunpark.user.domain.dto.request.UserSignupRequestDto; | ||
| import com.sangyunpark.user.domain.entity.User; | ||
| import com.sangyunpark.user.exception.UserDuplicateException; | ||
| import com.sangyunpark.user.infrastructure.repository.UserJpaRepository; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import static com.sangyunpark.user.constant.ExceptionMessages.*; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class UserService { | ||
|
|
||
| private final UserMapper userMapper; | ||
| private final UserJpaRepository userJpaRepository; | ||
|
|
||
| @Transactional | ||
| public Long signup(UserSignupRequestDto userSignupRequestDto) { | ||
| User user = userMapper.toEntity(userSignupRequestDto); | ||
| userJpaRepository.findUserByEmail(userSignupRequestDto.email()) | ||
| .ifPresent(u -> { throw new UserDuplicateException(EXCEPTION_USER_DUPLICATE.message()); }); | ||
|
||
| User savedUser = userJpaRepository.save(user); | ||
|
||
|
|
||
| return savedUser.getId(); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| package com.sangyunpark.user.application.mapper; | ||
|
|
||
| import com.sangyunpark.user.domain.dto.request.UserAddressRequestDto; | ||
| import com.sangyunpark.user.domain.entity.UserAddress; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| public class UserAddressMapper { | ||
|
|
||
| public static UserAddress toEntity(UserAddressRequestDto dto) { | ||
| return UserAddress.builder() | ||
| .address(dto.address()) | ||
| .defaultAddress(dto.defaultAddress()) | ||
| .receiverName(dto.receiverName()) | ||
| .build(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| package com.sangyunpark.user.application.mapper; | ||
|
|
||
| import com.sangyunpark.user.domain.dto.request.UserSignupRequestDto; | ||
| import com.sangyunpark.user.domain.entity.User; | ||
| import com.sangyunpark.user.domain.entity.UserAddress; | ||
| import com.sangyunpark.user.domain.vo.UserStatus; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; | ||
| import org.springframework.security.crypto.password.PasswordEncoder; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| @Component | ||
| @RequiredArgsConstructor | ||
| public class UserMapper { | ||
|
|
||
| private static final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); | ||
|
|
||
| public User toEntity(UserSignupRequestDto dto) { | ||
|
|
||
| UserAddress userAddress = UserAddressMapper.toEntity(dto.shippingInfo()); | ||
|
|
||
| User user = User.builder() | ||
| .email(dto.email()) | ||
| .username(dto.username()) | ||
| .password(passwordEncoder.encode(dto.password())) | ||
| .registerType(dto.registerType()) | ||
| .phoneNumber(dto.phoneNumber()) | ||
| .userType(dto.userType()) | ||
| .userStatus(UserStatus.ACTIVE) | ||
| .build(); | ||
|
|
||
| user.addUserAddress(userAddress); | ||
|
|
||
| return user; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.sangyunpark.user.common; | ||
|
|
||
| import jakarta.persistence.Column; | ||
| import jakarta.persistence.EntityListeners; | ||
| import jakarta.persistence.MappedSuperclass; | ||
| import lombok.Getter; | ||
| import org.springframework.data.annotation.CreatedDate; | ||
| import org.springframework.data.annotation.LastModifiedDate; | ||
| import org.springframework.data.jpa.domain.support.AuditingEntityListener; | ||
|
|
||
| import java.time.LocalDateTime; | ||
|
|
||
| @Getter | ||
| @MappedSuperclass | ||
| @EntityListeners(AuditingEntityListener.class) | ||
| public abstract class BaseEntity { | ||
|
|
||
| @CreatedDate | ||
| @Column(updatable = false, nullable = false) | ||
| private LocalDateTime createdAt; | ||
|
|
||
| @LastModifiedDate | ||
| @Column(nullable = false) | ||
| private LocalDateTime updatedAt; | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.sangyunpark.user.config; | ||
|
|
||
| import org.springframework.context.annotation.Configuration; | ||
| import org.springframework.data.jpa.repository.config.EnableJpaAuditing; | ||
|
|
||
| @Configuration | ||
| @EnableJpaAuditing | ||
| public class JpaConfig { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.sangyunpark.user.constant; | ||
|
|
||
| public enum ExceptionMessages { | ||
|
|
||
| EXCEPTION_USER_DUPLICATE("이미 존재하는 회원입니다."); | ||
|
||
|
|
||
| private final String message; | ||
|
|
||
| ExceptionMessages(String message) { | ||
| this.message = message; | ||
| } | ||
|
|
||
| public String message() { | ||
| return message; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.sangyunpark.user.constant; | ||
|
|
||
| public enum ResponseMessages { | ||
|
|
||
| SUCCESS_SIGNUP("회원가입이 완료되었습니다."); | ||
|
|
||
| private final String message; | ||
|
|
||
| ResponseMessages(String message) { | ||
| this.message = message; | ||
| } | ||
|
|
||
| public String message() { | ||
| return message; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| package com.sangyunpark.user.constant; | ||
|
|
||
| public class ValidationMessages { | ||
| public static final String EMAIL_INVALID = "이메일 형식이 올바르지 않습니다."; | ||
| public static final String EMAIL_REQUIRED = "이메일은 필수로 입력해야 합니다."; | ||
|
|
||
| public static final String USERNAME_REQUIRED = "사용자 이름은 필수로 작성해야 합니다."; | ||
| public static final String USERNAME_LENGTH = "이름은 2자 이상 10자 이하로 입력해야 합니다."; | ||
|
|
||
| public static final String PASSWORD_REQUIRED = "비밀번호는 필수로 입력해야 합니다."; | ||
| public static final String PASSWORD_LENGTH = "비밀번호는 8자 이상 20자 이하여야 합니다."; | ||
|
|
||
| public static final String PHONE_REQUIRED = "전화번호는 필수입니다."; | ||
| public static final String PHONE_INVALID = "전화번호 형식이 올바르지 않습니다."; | ||
| public static final String PHONE_REGEX = "^010-?\\d{4}-?\\d{4}$"; | ||
|
|
||
| public static final String REGISTER_TYPE_REQUIRED = "가입 유형은 필수입니다."; | ||
|
|
||
| public static final String SHIPPING_INFO_REQUIRED = "배송지 정보는 필수입니다."; | ||
|
|
||
| public static final String RECEIVER_NAME_REQUIRED = "수령인 이름은 필수입니다."; | ||
| public static final String ADDRESS_REQUIRED = "주소 정보는 필수입니다."; | ||
|
|
||
| public static final String USERTYPE_REQUIRED = "회원 유형은 필수입니다."; | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| package com.sangyunpark.user.domain.dto.request; | ||
|
|
||
|
|
||
| import com.sangyunpark.user.constant.ValidationMessages; | ||
| import jakarta.validation.constraints.NotBlank; | ||
|
|
||
| public record UserAddressRequestDto( | ||
| @NotBlank(message = ValidationMessages.RECEIVER_NAME_REQUIRED) | ||
| String receiverName, | ||
|
|
||
| @NotBlank(message = ValidationMessages.ADDRESS_REQUIRED) | ||
| String address, | ||
|
|
||
| boolean defaultAddress | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| package com.sangyunpark.user.domain.dto.request; | ||
|
|
||
| import com.sangyunpark.user.domain.vo.RegisterType; | ||
| import com.sangyunpark.user.domain.vo.UserType; | ||
| import jakarta.validation.constraints.*; | ||
|
|
||
| import static com.sangyunpark.user.constant.ValidationMessages.*; | ||
|
|
||
| public record UserSignupRequestDto( | ||
|
|
||
| @Email(message = EMAIL_INVALID) | ||
| @NotBlank(message = EMAIL_REQUIRED) | ||
| String email, | ||
|
|
||
| @NotBlank(message = USERNAME_REQUIRED) | ||
| @Size(min = 2, max = 10, message = USERNAME_LENGTH) | ||
| String username, | ||
|
|
||
| @NotBlank(message = PASSWORD_REQUIRED) | ||
| @Size(min = 8, max = 20, message = PASSWORD_LENGTH) | ||
| String password, | ||
|
|
||
| @NotBlank(message = PHONE_REQUIRED) | ||
| @Pattern(regexp = PHONE_REGEX, message = PHONE_INVALID) | ||
| String phoneNumber, | ||
|
|
||
| @NotNull(message = REGISTER_TYPE_REQUIRED) | ||
| RegisterType registerType, | ||
|
|
||
| @NotNull(message = USERTYPE_REQUIRED) | ||
| UserType userType, | ||
|
|
||
| @NotNull(message = SHIPPING_INFO_REQUIRED) | ||
| UserAddressRequestDto shippingInfo | ||
| ) { | ||
|
|
||
|
|
||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.sangyunpark.user.domain.dto.response; | ||
|
|
||
| public record UserSignupResponseDto( | ||
| Long userId, | ||
| String message | ||
| ) { | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,64 @@ | ||
| package com.sangyunpark.user.domain.entity; | ||
|
|
||
| public class User { | ||
| import com.sangyunpark.user.common.BaseEntity; | ||
| import com.sangyunpark.user.domain.vo.RegisterType; | ||
| import com.sangyunpark.user.domain.vo.UserStatus; | ||
| import com.sangyunpark.user.domain.vo.UserType; | ||
| import jakarta.persistence.*; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Builder; | ||
| import lombok.Getter; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| @Entity | ||
| @Table(name = "users") | ||
| @Getter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder | ||
| public class User extends BaseEntity { | ||
|
|
||
| @Id @GeneratedValue | ||
| @Column(name = "user_id") | ||
| private Long id; | ||
|
|
||
| @Column(unique = true, nullable = false) | ||
| private String email; | ||
|
|
||
| @Column(nullable = false) | ||
| private String username; | ||
|
|
||
| @Column(nullable = false) | ||
| private String password; | ||
|
|
||
| @Column(nullable = false) | ||
| @Enumerated(value = EnumType.STRING) | ||
| private UserType userType; | ||
|
|
||
| @Column(nullable = false) | ||
| @Enumerated(value = EnumType.STRING) | ||
| private UserStatus userStatus; | ||
|
|
||
| @Column | ||
| private String providerId; | ||
|
|
||
| @Column(nullable = false) | ||
| @Enumerated(value = EnumType.STRING) | ||
| private RegisterType registerType; | ||
|
|
||
| @Column(nullable = false) | ||
| private String phoneNumber; | ||
|
|
||
| @Builder.Default | ||
| @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) | ||
| private List<UserAddress> userAddress = new ArrayList<>(); | ||
|
|
||
| public void addUserAddress(UserAddress address) { | ||
| this.userAddress.add(address); | ||
| address.setUser(this); | ||
| } | ||
|
|
||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final User user = userMapper.toEntity(userSignupRequestDto);