[토이프로젝트] 감정일기장-0 : 도메인 모델

onlydev7777·2024년 9월 19일

❗️ 개요

인프런 이정환님의 React 강의를 통해 만든 감정 일기장 React 프로젝트에 Monolithic 기반 아키텍처 Spring Boot 백엔드 서버에 연동 한다.

✅ 백엔드 기술스택

  • 로그인 인증 : Spring Security
  • OAuth2 / Oidc 로그인 인증 : Spring Security OAuth2 Client
  • 인증방식 : JWT + Redis
  • DB 매핑 기법 : ORM (Spring Data JPA)
  • DTO 매핑 라이브러리 : MapStruct

☀️ Entity Relationship Diagram(ERD)

ERD

1. Member

  • 회원 Entity
  • MemberRole 엔터티와 1:N 연관관계
  @Getter
  @NoArgsConstructor(access = AccessLevel.PROTECTED)
  @Table(name = "members")
  @Entity
  public class Member {

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

    @Column(name = "user_id", nullable = false)
    private String userId;

    @Embedded
    private Password password;

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

    @Embedded
    private Email email;

    @Enumerated(EnumType.STRING)
    private SocialType socialType;

    @OneToMany(mappedBy = "member", orphanRemoval = true, cascade = CascadeType.ALL)
    private List<MemberRole> memberRoles = new ArrayList<>();

    @Builder
    public Member(String userId, Password password, String name, Email email, SocialType socialType) {
      this.userId = userId;
      this.password = password;
      this.name = name;
      this.email = email;
      this.socialType = socialType;
    }

    public static Member of(String userId, Password password, String name, Email email, SocialType socialType) {
      return Member.builder()
          .userId(userId)
          .password(password)
          .name(name)
          .email(email)
          .socialType(socialType)
          .build();
    }
  }

2. MemberRole

  • 회원권한 엔터티
  • 회원-회원권한-권한 (1:N:1) 다대다 관계 연결 인터티
  • 특정 회원이 갖는 권한 목록 정의
    • ex) 홍길동 회원은 admin 권한, manager 권한 등을 갖는다.
  @Getter
  @NoArgsConstructor(access = AccessLevel.PROTECTED)
  @Table(name = "MEMBER_ROLE")
  @Entity
  public class MemberRole {

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "member_id")
    private Member member;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "role_id")
    private Role role;

    private MemberRole(Member member, Role role) {
      this.member = member;
      this.role = role;
    }

    public static MemberRole of(Member member, Role role) {
      return new MemberRole(member, role);
    }
  }

3. Role

  • 권한 엔터티
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "roles")
@Entity
public class Role {

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

  @Column(name = "role_name")
  private String roleName;

  @Column(name = "role_desc")
  private String roleDescription;


  public Role(String roleName, String roleDescription) {
    this.roleName = roleName;
    this.roleDescription = roleDescription;
  }

  public static Role of(String roleName, String roleDescription) {
    return new Role(roleName, roleDescription);
  }
}

4. RoleResources

  • 권한자원 엔터티
  • 자원-권한자원-권한 (1:N:1) 다대다 관계 연결 엔터티
  • 특정 권한이 갖는 URL 자원 목록 정의
    • ex) 어드민 권한은 /admin/**, /manager/** 에 대한 접근 권한을 갖는다.
  @Getter
  @NoArgsConstructor(access = AccessLevel.PROTECTED)
  @Table(name = "ROLE_RESOURCES")
  @Entity
  public class RoleResources {

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "role_id")
    private Role role;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "resources_id")
    private Resources resources;

    private RoleResources(Role role, Resources resources) {
      this.role = role;
      this.resources = resources;
    }

    public static RoleResources of(Role role, Resources resources) {
      return new RoleResources(role, resources);
    }
  }

5. Resources

  • 자원 엔터티
  • URL 정보 저장
  @Getter
  @NoArgsConstructor(access = AccessLevel.PROTECTED)
  @Table(name = "RESOURCES")
  @Entity
  public class Resources {

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

    @Column(name = "resources_name")
    private String resourceName;

    @Column(name = "http_method")
    private HttpMethod httpMethod;

    @OneToMany(mappedBy = "resources", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<RoleResources> roleResources = new ArrayList<>();

    @Builder
    public Resources(String resourceName, HttpMethod httpMethod) {
      this.resourceName = resourceName;
      this.httpMethod = httpMethod;
    }

    public static Resources of(String resourceName, HttpMethod httpMethod) {
      return new Resources(resourceName, httpMethod);
    }
  }

6. Diary

  • 일기 엔터티
  • 회원과 N:1 관계
  @Getter
  @NoArgsConstructor(access = AccessLevel.PROTECTED)
  @Table(name = "diary")
  @Entity
  public class Diary {

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

    @Column(name = "subject", length = 300)
    private String subject;
    @Column(name = "content", nullable = false, length = 5000)
    private String content;

    @Enumerated(EnumType.STRING)
    @Column(name = "emotion_status", nullable = false)
    private EmotionStatus emotionStatus;

    @Column(name = "diary_date", nullable = false)
    private LocalDate diaryDate;

    @Column(name = "diary_year_month", nullable = false, length = 6)
    private String diaryYearMonth;

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

    public void update(String subject, String content, EmotionStatus emotionStatus, LocalDate diaryDate) {
      this.subject = subject;
      this.content = content;
      this.emotionStatus = emotionStatus;
      this.diaryDate = diaryDate;
      this.diaryYearMonth = DateUtil.getYearMonth(diaryDate);
    }

    @Builder
    public Diary(String subject, String content, EmotionStatus emotionStatus, LocalDate diaryDate, Member member) {
      this.subject = subject;
      this.content = content;
      this.emotionStatus = emotionStatus;
      this.diaryDate = diaryDate;
      this.diaryYearMonth = DateUtil.getYearMonth(diaryDate);
      this.member = member;
    }

    public static Diary of(String subject, String content, EmotionStatus emotionStatus, LocalDate diaryDate, Member member) {
      return Diary.builder()
          .subject(subject)
          .content(content)
          .emotionStatus(emotionStatus)
          .diaryDate(diaryDate)
          .member(member)
          .build();
    }
  }

★ 테스트 코드 수행 결과

테스트 코드 수행 결과

★ GitHub URL

front-end : https://github.com/onlydev7777/emotion-diary-react
back-end : https://github.com/onlydev7777/emotion-diary-monolithic

profile
https://github.com/onlydev7777

0개의 댓글