Skip to content

Commit

Permalink
[BE] 멤버 도메인 작성 (#41)
Browse files Browse the repository at this point in the history
* feat: 멤버 도메인 작성

* feat: MemberRepository, MemberTeamPlaceRepository 추가

* refactor: Email VO에 @embeddable, @NoArgsConstructor, Getter 추가
  • Loading branch information
sh111-coder authored and SproutMJ committed Aug 16, 2023
1 parent b091e90 commit 446c886
Show file tree
Hide file tree
Showing 11 changed files with 268 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package team.teamby.teambyteam.member.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import team.teamby.teambyteam.member.domain.vo.Email;
import team.teamby.teambyteam.member.domain.vo.Name;
import team.teamby.teambyteam.member.domain.vo.ProfileImageUrl;

import java.util.List;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Embedded
private Name name;

@Embedded
private Email email;

@Embedded
private ProfileImageUrl profileImageUrl;

@Column
@OneToMany(mappedBy = "member", cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true)
private List<MemberTeamPlace> memberTeamPlaces;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package team.teamby.teambyteam.member.domain;

import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package team.teamby.teambyteam.member.domain;

import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import team.teamby.teambyteam.teamplace.domain.TeamPlace;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MemberTeamPlace {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(nullable = false)
private Member member;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(nullable = false)
private TeamPlace teamPlace;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package team.teamby.teambyteam.member.domain;

import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberTeamPlaceRepository extends JpaRepository<MemberTeamPlace, Long> {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package team.teamby.teambyteam.member.domain.vo;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import team.teamby.teambyteam.member.exception.MemberException;

import java.util.Objects;
import java.util.regex.Pattern;

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Email {

private static final String EMAIL_REGEX = "^([\\w\\.\\_\\-])*[a-zA-Z0-9]+([\\w\\.\\_\\-])*([a-zA-Z0-9])+([\\w\\.\\_\\-])+@([a-zA-Z0-9]+\\.)+[a-zA-Z0-9]{2,8}$";

@Column(name = "email", nullable = false)
private String value;

public Email(final String value) {
validate(value);
this.value = value;
}

private void validate(final String value) {
if (Objects.isNull(value)) {
throw new NullPointerException("이메일은 null일 수 없습니다.");
}

if (isNotMatchEmailForm(value)) {
throw new MemberException.EmailRegexException("정해진 이메일의 양식이 아닙니다.");
}
}

private boolean isNotMatchEmailForm(final String value) {
return !Pattern.matches(EMAIL_REGEX, value);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package team.teamby.teambyteam.member.domain.vo;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
import team.teamby.teambyteam.member.exception.MemberException;

import java.util.Objects;

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class Name {

private static final int MAX_LENGTH = 20;

@Column(name = "name", nullable = false, length = MAX_LENGTH)
private String value;

public Name(final String value) {
validate(value);
this.value = value;
}

private void validate(final String value) {
if (Objects.isNull(value)) {
throw new NullPointerException("멤버 이름은 null일 수 없습니다.");
}
if (value.length() > MAX_LENGTH) {
throw new MemberException.NameLengthException("입력한 길이가 최대 이름 길이인 " + MAX_LENGTH + "를 초과했습니다.");
}
if (value.isBlank()) {
throw new MemberException.NameLengthException("멤버 이름은 공백을 제외한 1자 이상이어야 합니다.");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package team.teamby.teambyteam.member.domain.vo;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class ProfileImageUrl {

@Column(name = "profile_image_url", nullable = false)
private String value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package team.teamby.teambyteam.member.exception;

public class MemberException extends RuntimeException {

public MemberException(final String message) {
super(message);
}

public static class NameLengthException extends MemberException {
public NameLengthException(final String message) {
super(message);
}
}

public static class EmailRegexException extends MemberException {
public EmailRegexException(final String message) {
super(message);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import team.teamby.teambyteam.member.domain.MemberTeamPlace;

import java.util.List;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
Expand All @@ -14,4 +17,7 @@ public class TeamPlace {

@Embedded
private Name name;

@OneToMany(mappedBy = "teamPlace", cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true)
private List<MemberTeamPlace> memberTeamPlaces;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package team.teamby.teambyteam.member.domain.vo;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import team.teamby.teambyteam.member.exception.MemberException;

class EmailTest {

@Test
@DisplayName("이메일 이름이 null이 되면 예외가 발생한다.")
void failEmailNull() {
// given
final String nullEmail = null;

// when & then
Assertions.assertThatThrownBy(() -> new Email(nullEmail))
.isInstanceOf(NullPointerException.class)
.hasMessage("이메일은 null일 수 없습니다.");
}

@ParameterizedTest
@ValueSource(strings = {"aaaagmail.com", "aaa@gmailcom", "aaagmailcom"})
@DisplayName("이메일이 양식을 만족하지 않으면 예외가 발생한다.")
void failEmailOverMaxLength(String value) {
// when & then
Assertions.assertThatThrownBy(() -> new Email(value))
.isInstanceOf(MemberException.EmailRegexException.class)
.hasMessage("정해진 이메일의 양식이 아닙니다.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package team.teamby.teambyteam.member.domain.vo;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import team.teamby.teambyteam.member.exception.MemberException;

class NameTest {

@Test
@DisplayName("멤버 이름이 null이 되면 예외가 발생한다.")
void failNameNull() {
// given
final String nullName = null;

// when & then
Assertions.assertThatThrownBy(() -> new Name(nullName))
.isInstanceOf(NullPointerException.class)
.hasMessage("멤버 이름은 null일 수 없습니다.");
}

@Test
@DisplayName("멤버 이름이 최대 길이(20자) 초과면 예외가 발생한다.")
void failNameOverMaxLength() {
// given
final int maxLength = 20;
final String overLengthName = "a".repeat(21);

// when & then
Assertions.assertThatThrownBy(() -> new Name(overLengthName))
.isInstanceOf(MemberException.NameLengthException.class)
.hasMessage("입력한 길이가 최대 이름 길이인 " + maxLength + "를 초과했습니다.");
}

@ParameterizedTest
@ValueSource(strings = {"", " ", " "})
@DisplayName("멤버 이름이 빈 값으로 이루어지면 예외가 발생한다.")
void failNameIsBlank(final String blankName) {
// when & then
Assertions.assertThatThrownBy(() -> new Name(blankName))
.isInstanceOf(MemberException.NameLengthException.class)
.hasMessage("멤버 이름은 공백을 제외한 1자 이상이어야 합니다.");
}
}

0 comments on commit 446c886

Please sign in to comment.