블로그 만들기(1) 프로젝트 만들기, 엔티티 설계
오늘은 벨로그와 최대한 비슷하게 구현하는 프로젝트를 진행해 볼 것이다. 아직 다 완성되진 않았지만 중간 점검도 할 겸 기록하려 한다.
일단 벨로그와 최대한 비슷하게 구현하기 위해서 erd를 만들어 봤다
이때를 위해 공부한 erd가 도움이 된거같다.
ER다이어그램 (Crow's Foot)
지난 글에 이어서 이번 글에서는 er다이어그램 중 Crow's Foot 표기법에 대해 알아볼 것이다.er 다이어그램에 대한 개념과 Chen 표기법은 전 글에서 확인하자 ER 다이어그램 (Chen 표기법)ER 다이어그램
mhje11.tistory.com
우선 블로그를 이용할 유저, 팔로워, 팔로잉, 포스트, 댓글, 좋아요, 시리즈, 태그 등 여러 엔티티를 설계하고 erd를 그려봤다 하지만 erd를 설계하고 프로젝트를 처음 진행해본 탓일까 생각만큼 erd 설계가 훌륭하지 않아 수정된 부분이 많았다..
현재 설계한 엔티티를 제대로 설계했는지 확인하기 위해 MySQL workbench를 이용해 erd를 확인해볼 것이다.
이 Reverse Engineer를 이용하면 된다.
사진상으론 보기 좀 안좋지만 워크벤치에서 확인하면 괜찮다..
현재는 이러한 형태의 erd로 수정됐다. 팔로워, 팔로잉을 굳이 구분할 필요없이 follows 하나에서 팔로워를 찾고싶으면 자신의 블로그를 팔로우를 하는 사람은 자신의 blogId로 검색하고 자신이 팔로잉 하는사람은 자신의 loginId를 이용해 찾으면 되기 때문에 굳이 두개의 테이블로 관리할 필요가 없었다.
유저의 역할은 (관리자, 일반회원) 테이블로 따로 분리해서 만들어도 되지만 Enum으로 관리하는게 더 편할거 같아 Enum으로 만들었다.
사진으로 보면 뭐와 뭐가 무슨관계인지 알기가 힘드니 entity를 코드로 봐볼것이다 그전에 프로젝트 패키지는
이런식으로 도메인마다 패키지를 만들고
해당 도메인에 해당하는 controller, dto, entity, repository, service 이런식으로 나눴다
이런 방식을 도메인형이라고 한다. 이와 반대대는 개념으론 계층형 방식이 있는데 계층형은 controller, service, dto, repositroy, service끼리 패키지내에 모아놓은것이다. 엔티티가 많아 도메인형이 보기 편할거 같아 이 방식을 택했다.
이제 엔티티를 봐보자 우선 User 엔티티다
@Entity
@Getter
@Setter
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(name = "login_id", unique = true, nullable = false)
private String loginId;
@Column(nullable = false)
private String password;
@Column(unique = true, nullable = false)
private String email;
@Column(name = "registration_date", updatable = false)
@CreatedDate
private LocalDateTime registrationDate = LocalDateTime.now();
@Enumerated(EnumType.STRING)
@Column(name = "role")
private Role role;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments;
@OneToOne(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private Blog blog;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ProfileImage> profileImages;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Post> posts;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Likes> likes;
}
유저는 1대1의 관계로 blog를 갖고 유저가 쓴 댓글과, 게시글 그리고 좋아요를 누른 게시글을 알기 위해서 1 : N 의 관계로 게시글, 댓글, 좋아요를 갖고 있다. 그 외에 유저의 이름, 로그인한 아이디, 비밀번호, 이메일, 프로필이미지, 역할, 등록일자를 갖고 있다.
@Getter
public enum Role {
ROLE_USER("user"), ROLE_ADMIN("admin");
String description;
Role(String description) {
this.description = description;
}
}
유저의 역할인 Role을 enum으로 만든것이다.
@Entity
@Table(name = "blogs")
@Setter@Getter
public class Blog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "login_id", unique = true)
private User user;
@Column(nullable = false)
private String title;
@Column(name = "created_at", updatable = false)
@CreatedDate
private LocalDateTime createdAt = LocalDateTime.now();
@OneToMany(mappedBy = "blog", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Post> posts;
@OneToMany(mappedBy = "blog", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Follow> follows;
@OneToMany(mappedBy = "blog", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Series> series;
}
블로그의 제목, 그리고 이 블로그가 만들어진 날을 갖고 1 : N의 관계로 포스트, 시리즈, 팔로우를 갖는다.
@Entity
@Table(name = "posts")
@Getter@Setter
@RequiredArgsConstructor
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String content;
@ManyToOne
@JoinColumn(name = "login_id", nullable = false)
private User user;
@ManyToOne
@JoinColumn(name = "blog_id")
private Blog blog;
@ManyToOne
@JoinColumn(name = "series_id")
private Series series;
@OneToMany(mappedBy = "post")
private List<Likes> likes;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> comments;
private boolean temporal;
@ManyToMany
@JoinTable(
name = "post_tags",
joinColumns = @JoinColumn(name = "post_id"),
inverseJoinColumns = @JoinColumn(name = "tag_id")
)
private List<Tag> tags;
}
블로그의 핵심기능인 포스트다 게시글은 시리즈와 블로그를 단 하나만 갖을 수 있기 때문에 N : 1 (Many To One)의 관계를 갖는다.
그리고 게시글은 1 : N의 관계로 좋아요, 댓글을 갖고 임시저장 여부를 나타내는 temporal을 boolean값으로 갖는다.
그리고 태그는 생성해놓고 포스트도 태그를 여러개 태그도 포스트를 여러개 갖을 수 있기 때문에 N : N의 관계로 설정했다.
@Entity
@Getter@Setter
@Table(name = "comments")
public class Comment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "post_id")
private Post post;
@ManyToOne
@JoinColumn(name = "login_id", referencedColumnName = "login_id")
private User user;
private String content;
}
마지막으로 댓글이다 댓글은 댓글 여러개가 한 포스트에 존재 할 수 있으므로 N : 1의 관계를 설정했다.
그리고 유저 한명도 여러 댓글을 쓸 수 있으므로 N : 1인건 마찬가지다.
나머지 시리즈, 태그는 erd대로기 때문에 넘어가고 프로필 이미지는 아직 기능을 만들지 않았으므로 생략하겠다.
다음엔 구현한 기능중 어려웠던 부분이나 오류가 생겼던 부분을 설명해보겠다.