-
Notifications
You must be signed in to change notification settings - Fork 1
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
[kwj1270-issue5] 회원가입 기능 #9
Changes from all commits
53d5b56
6297426
70f6637
affb9b9
27cd41d
b2a3384
e37e0d3
6d0ffa5
1075bce
3fafb51
d53567b
e0a2b69
3c3ce07
b5bbbea
5010571
755a31c
67bf286
80dc4fe
684c204
1e0bdcb
69545f3
d232a3b
0637539
c251bb1
31a5d7d
e6e9ed2
d965e42
2112888
027dd4c
93dbc5f
4984ede
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package com.study.realworld.domain; | ||
|
||
import org.springframework.data.annotation.CreatedDate; | ||
import org.springframework.data.annotation.LastModifiedDate; | ||
import org.springframework.data.jpa.domain.support.AuditingEntityListener; | ||
|
||
import javax.persistence.Column; | ||
import javax.persistence.EntityListeners; | ||
import javax.persistence.MappedSuperclass; | ||
import java.time.LocalDateTime; | ||
|
||
@MappedSuperclass | ||
@EntityListeners(AuditingEntityListener.class) | ||
public class BaseTimeEntity { | ||
|
||
@CreatedDate | ||
@Column(name = "created_at", updatable = false) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 배워갑니다 👍 |
||
private LocalDateTime createdAt; | ||
|
||
@LastModifiedDate | ||
@Column(name = "updated_at") | ||
private LocalDateTime updatedAt; | ||
|
||
@Column(name = "deleted_at") | ||
private LocalDateTime deletedAt; | ||
|
||
public LocalDateTime createdAt() { | ||
return createdAt; | ||
} | ||
|
||
public LocalDateTime updatedAt() { | ||
return updatedAt; | ||
} | ||
|
||
public LocalDateTime deletedAt() { | ||
return deletedAt; | ||
} | ||
|
||
// 추후 삭제시 읽어서 기록하는 방식으로 변경 예정 | ||
public void recordDeletedTime(final LocalDateTime deletedAt) { | ||
this.deletedAt = deletedAt; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package com.study.realworld.domain.user.application; | ||
|
||
import com.study.realworld.domain.user.domain.User; | ||
import com.study.realworld.domain.user.domain.UserRepository; | ||
import com.study.realworld.domain.user.dto.UserJoinRequest; | ||
import com.study.realworld.domain.user.dto.UserJoinResponse; | ||
import org.springframework.stereotype.Service; | ||
|
||
import javax.validation.Valid; | ||
|
||
@Service | ||
public class UserJoinService { | ||
|
||
private final UserRepository userRepository; | ||
|
||
public UserJoinService(final UserRepository userRepository) { | ||
this.userRepository = userRepository; | ||
} | ||
|
||
@Valid | ||
public UserJoinResponse join(final UserJoinRequest userJoinRequest) { | ||
final User user = userRepository.save(userJoinRequest.toUser()); | ||
return UserJoinResponse.fromUser(user); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 개인적인 견해지만 여기서 그냥 User를 Controller에 Return해줘도 좋지 않을까? 하는 생각이 있습니다~ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 저도 비슷한 의견인데, DDD에서는 application 단에서는 presentation 단의 객체를 가지지 않는 것이 좋아요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @povia , @chance0523 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이번 스터디에서 피드백을 통해 사용하면 좋을 것, 사용하기 조금 껄끄러운 것들을 정의하기 위해서 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
오 이렇게 생각은 못해봤는데 좋은 생각이네요 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @chance0523 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
간결하게 모든걸 정리해줄 수 있는 좋은 문장인것 같아요 :) |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package com.study.realworld.domain.user.domain; | ||
|
||
import com.study.realworld.domain.BaseTimeEntity; | ||
|
||
import javax.persistence.*; | ||
|
||
@Entity | ||
public class User extends BaseTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "user_id") | ||
private Long id; | ||
|
||
@Column(name = "user_email", length = 50, nullable = false, unique = true) | ||
private String email; | ||
|
||
@Column(name = "user_username", length = 20, nullable = false) | ||
private String username; | ||
|
||
@Column(name = "uesr_password", nullable = false) | ||
private String password; | ||
|
||
@Column(name = "user_bio") | ||
private String bio; | ||
|
||
@Column(name = "user_image") | ||
private String image; | ||
|
||
protected User() { | ||
} | ||
|
||
private User(final UserBuilder userBuilder) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Builder를 이런 형태로 반환할 수도 있겠네요 👍 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 개인적으로 생성자 오버로딩은 많을수록 유연함을 준다고 생각해서 빌더를 넘겨서 사용하도록 했습니다! 👍 |
||
this.email = userBuilder.email; | ||
this.username = userBuilder.username; | ||
this.password = userBuilder.password; | ||
this.bio = userBuilder.bio; | ||
this.image = userBuilder.image; | ||
} | ||
|
||
public String email() { | ||
return email; | ||
} | ||
|
||
public String username() { | ||
return username; | ||
} | ||
|
||
public String bio() { | ||
return bio; | ||
} | ||
|
||
public String image() { | ||
return image; | ||
} | ||
|
||
public static UserBuilder Builder() { | ||
return new UserBuilder(); | ||
} | ||
|
||
public boolean checkPassword(final String otherPassword) { | ||
return password.equals(otherPassword); | ||
} | ||
|
||
public static class UserBuilder { | ||
private String email; | ||
private String username; | ||
private String password; | ||
private String bio; | ||
private String image; | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 정적 팩토리 생성자를 사용하셨는데 그럼 private constructor가 필요하지 않을까요? :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 생각도 못했네요!!! 👍 다음에 반영해보겠습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 칼럼명을 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네네 맞아요 |
||
private UserBuilder() { | ||
} | ||
|
||
public UserBuilder email(final String email) { | ||
this.email = email; | ||
return this; | ||
} | ||
|
||
public UserBuilder username(final String username) { | ||
this.username = username; | ||
return this; | ||
} | ||
|
||
public UserBuilder password(final String password) { | ||
this.password = password; | ||
return this; | ||
} | ||
|
||
public UserBuilder bio(final String bio) { | ||
this.bio = bio; | ||
return this; | ||
} | ||
|
||
public UserBuilder image(final String image) { | ||
this.image = image; | ||
return this; | ||
} | ||
|
||
public User build() { | ||
return new User(this); | ||
} | ||
|
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.study.realworld.domain.user.domain; | ||
|
||
import org.springframework.data.repository.CrudRepository; | ||
|
||
public interface UserRepository extends CrudRepository<User, Long> { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 네 감사합니다 :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @DolphaGo |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package com.study.realworld.domain.user.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
import com.fasterxml.jackson.annotation.JsonTypeName; | ||
import com.study.realworld.domain.user.domain.User; | ||
|
||
import javax.validation.constraints.Email; | ||
import javax.validation.constraints.NotBlank; | ||
|
||
@JsonTypeName("user") | ||
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME) | ||
public final class UserJoinRequest { | ||
|
||
@NotBlank | ||
@JsonProperty("username") | ||
private String username; | ||
|
||
@NotBlank | ||
@JsonProperty("email") | ||
private String email; | ||
|
||
@NotBlank | ||
@JsonProperty("password") | ||
private String password; | ||
|
||
private UserJoinRequest() { | ||
} | ||
|
||
// 테스트용 오버로딩 생성자 -> 주관적인 생각으로 이런 상황은 오버로딩으로 유연성을 주는게 좋다고 생각합니다. | ||
UserJoinRequest(final String username, final String email, final String password) { | ||
this.username = username; | ||
this.email = email; | ||
this.password = password; | ||
} | ||
|
||
public final User toUser() { | ||
return User.Builder() | ||
.email(email) | ||
.username(username) | ||
.password(password) | ||
.build(); | ||
} | ||
|
||
@Override | ||
public final String toString() { | ||
return "UserJoinRequest{" + | ||
"username='" + username + '\'' + | ||
", email='" + email + '\'' + | ||
", password='" + password + '\'' + | ||
'}'; | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package com.study.realworld.domain.user.dto; | ||
|
||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
import com.fasterxml.jackson.annotation.JsonTypeName; | ||
import com.study.realworld.domain.user.domain.User; | ||
|
||
import javax.validation.constraints.Email; | ||
import javax.validation.constraints.NotBlank; | ||
|
||
@JsonTypeName("user") | ||
@JsonTypeInfo(include = JsonTypeInfo.As.WRAPPER_OBJECT, use = JsonTypeInfo.Id.NAME) | ||
public final class UserJoinResponse { | ||
|
||
@NotBlank | ||
@JsonProperty("username") | ||
private String username; | ||
|
||
@NotBlank | ||
@JsonProperty("email") | ||
private String email; | ||
|
||
@JsonProperty("bio") | ||
private String bio; | ||
|
||
@JsonProperty("image") | ||
private String image; | ||
|
||
public static final UserJoinResponse fromUser(final User user) { | ||
return new UserJoinResponse(user); | ||
} | ||
|
||
private UserJoinResponse() { | ||
} | ||
|
||
private UserJoinResponse(final User user) { | ||
this.email = user.email(); | ||
this.username = user.username(); | ||
this.bio = user.bio(); | ||
this.image = user.image(); | ||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.study.realworld.domain.user.ui; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 잘 몰라서 그러는데, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 우선 ddd start와 nextStep DDD 기반으로 디렉토리를 구성했습니다. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 앗 거기서 ui로 썼으면 그렇게 써도 되는 것 같아요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DDD 초보자여서 사실 어느 방법으로 써야 되는지 많이 헷갈리더라고요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 찬스님 말씀처럼 패키지명에 제약은 없지만 ui로 패키지명은 프론트의 그 ui와 헷갈려하는 분들이 있을 수도 있다고 생각합니다. 근데 사실 백엔드 개발자가 보기엔 ui, controller, presentation 모두 같은 의미를 담고 있다고 생각할 수도 있으니 요건 고려만 해보셔요 |
||
|
||
import com.study.realworld.domain.user.application.UserJoinService; | ||
import com.study.realworld.domain.user.dto.UserJoinRequest; | ||
import com.study.realworld.domain.user.dto.UserJoinResponse; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
import javax.validation.Valid; | ||
|
||
@RestController | ||
public class UserRestController { | ||
|
||
private static final String JOIN_REQUEST_LOG_MESSAGE = "join request: {}"; | ||
private static final Logger log = LoggerFactory.getLogger(UserRestController.class); | ||
|
||
private final UserJoinService userJoinService; | ||
|
||
public UserRestController(final UserJoinService userJoinService) { | ||
this.userJoinService = userJoinService; | ||
} | ||
|
||
@PostMapping("/api/users") | ||
public ResponseEntity<UserJoinResponse> join(@Valid @RequestBody final UserJoinRequest userJoinRequest) { | ||
log.info(JOIN_REQUEST_LOG_MESSAGE, userJoinRequest.toString()); | ||
return ResponseEntity.ok().body(userJoinService.join(userJoinRequest)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 요런 방식으로 넘길 수도 있었네요 저도 반영하겠습니다~ 👍 |
||
} | ||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.study.realworld.global.config; | ||
|
||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing; | ||
|
||
@EnableJpaAuditing | ||
@Configuration | ||
public class JpaConfig { | ||
} |
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.
이거 아래 한 줄 개행이 필요할듯해요! (아래 Test code들도)
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.
흠.. 개행 컨벤션은 여태 의식하지 않았는데 의식해야겠군요