ํ์๊ฐ์ ์, ๋๋ฉ์ธ ์ค๊ณ๊ฐ ๋๋๊ณ ์ดํ ํ์ ์๋น์ค๋ฅผ ๊ตฌํํ ๋ ๊ตฌํํ๋๋ก ํ๊ฒ ์ต๋๋ค!
- ์ํ๋ฆฌํฐ๋ฅผ ์ด์ฉํ JSON ๋ฐ์ดํฐ๋ก ๋ก๊ทธ์ธ (์๋ฃ)
- JWT๋ฅผ ์ด์ฉํ ์ธ์ฆ (์๋ฃ)
- ๋๋ฉ์ธ, ํ ์ด๋ธ ์ค๊ณ, ์ํฐํฐ ์์ฑ (์งํ ์ค)
- ๋๊ธ ์ญ์ ๋ก์ง ๊ตฌํ
- ํ์๊ฐ์ + ์ ๋ณด์์ ๋ฑ ํ์ ์๋น์ค ๊ตฌํ
- ๊ฒ์ํ ์๋น์ค ๊ตฌํ
- ๋๊ธ ์๋น์ค ๊ตฌํ (1๋๊ธ -> *(๋ฌดํ) ๋๋๊ธ ๊ตฌ์กฐ)
- ์์ธ ์ฒ๋ฆฌ
- ์์ธ ๋ฉ์ธ์ง ๊ตญ์ ํ
- ์นดํ ๊ณ ๋ฆฌ๋ณ ๊ฒ์ํ ๋ถ๋ฅ
- ๊ฒ์๊ธ ํ์ด์ง
- ๋์ ์ธ ๊ฒ์ ์กฐ๊ฑด์ ์ฌ์ฉํ ๊ฒ์
- ์ฌ์ฉ์ ๊ฐ ์ชฝ์ง ๊ธฐ๋ฅ
- ๋ฌดํ ์ชฝ์ง ์คํฌ๋กค
- ๊ฒ์๋ฌผ & ๋๊ธ์ ๋ํ ์๋
- ์ชฝ์ง์ ๋ํ ์๋
- ์ ์ํ ์ฌ์ฉ์ ๊ฐ ์ค์๊ฐ ์ฑํ
- ํ์๊ฐ์ ์ ๊ฒ์ฆ(์: XX๋ํ๊ต XX๊ณผ๊ฐ ์๋๋ฉด ๊ฐ์ ํ ์ ์๊ฒ)
- Swagger๋ฅผ ์ฌ์ฉํ API ๋ฌธ์ ๋ง๋ค๊ธฐ
- ์ ๊ณ & ๋ธ๋๋ฆฌ์คํธ ๊ธฐ๋ฅ
- AOP๋ฅผ ํตํ ๋ก๊ทธ
- ์ด๋๋ฏผ ํ์ด์ง
- ์บ์
- ๋ฐฐํฌ (+ ๋ฌด์ค๋จ ๋ฐฐํฌ)
- ๋ฐฐํฌ ์๋ํ
- ํฌํธ์ ์ด๋ํฐ ์ค๊ณ๋ฅผ ๋ฐ๋ฅด๋ ํจํค์ง ๊ตฌ์กฐ ์ค๊ณํ๊ธฐ
- ...
์๊ตฌ์ฌํญ ๋ถ์ํ๊ธฐ
์ ๊ฐ ๋ง๋๋ ค๋ ๊ฒ์ "์๋ธ๋ฆฌํ์" ๊ฐ์ ์ปค๋ฎค๋ํฐ์ ๋๋ค.
์ดํ ์ฌ์ฉ์ ์ธ์ฆ์ด๋ผ๋๊ฐ, ์ถ๊ฐ์ ์ธ ๊ธฐ๋ฅ ๋ฑ์ด ์ถ๊ฐ๋ ์ ์๊ฒ ์ง๋ง, ์ฐ์ ๊ฐ์ฅ ๊ธฐ๋ณธ์ด ๋๋ ๊ธฐ๋ฅ๋ถํฐ ์ค๊ณํ๊ณ , ์ดํ ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ ๋ฐฉ์์ผ๋ก ๊ฐ๋ฐ์ ์งํํ๋ ค ํฉ๋๋ค.
์ ๋ง ๊ฐ๋จํ ๊ฒ์ํ์ ๋ง๋ค ๊ฒ์ ๋๋ค.
ํ์
- ํ์๊ฐ์
- ๋ก๊ทธ์ธ
- ํ์์ ๋ณด ์์
- ํ์ ํํด
๊ฒ์๊ธ
- ๋นํ์์ ์์ฑ ๋ถ๊ฐ๋ฅ, ํ์๋ง ์์ฑ ๊ฐ๋ฅ
- ์ ๋ชฉ, ๋ด์ฉ, ์ฒจ๋ถํ์ผ์ ์ฌ๋ฆด ์ ์์
- ์์ฑ์๋ ๊ฒ์๋ฌผ์ ๋ํ ์์ ๊ณผ ์ญ์ ๊ฐ ๊ฐ๋ฅํจ
- ๊ฒ์๋ฌผ์ ์ญ์ ํ๋ฉด, ๋ฌ๋ ค์๋ ๋๊ธ๋ค์ด ์ผ๊ด์ ์ผ๋ก ์ญ์ ๋จ
- ์์ฑ์๊ฐ ํ์ํํด๋ฅผ ํ๋ฉด, ๊ฒ์๋ฌผ๋ ์ญ์ ๋จ
- ๊ฒ์๋ฌผ์๋ ๋๊ธ์ ๋ฌ ์ ์์
- (์ต๋ช ๊ธฐ๋ฅ๋ ์ถ๊ฐํ๊ณ ์ถ์ง๋ง.. ์กฐ๊ธ ๋ฏธ๋ฃจ๋๋ก ํ๊ฒ ์ต๋๋ค.)
๋๊ธ
- ๊ฒ์๊ธ์ ์์ฑํ ์ ์์
- ์ฒจ๋ถํ์ผ์ ๋ถ๊ฐ๋ฅํ๊ฒ ๋ง๋ค ๊ฒ์
- ๋๊ธ์ ๋๋๊ธ์ ๊ฐ์ง ์ ์์ผ๋. ๋๋๋๊ธ์ ๊ฐ์ง ์ ์์
- ์ฆ, ์ต๋ ๋๊ธ์ ๊น์ด๊ฐ 2์. ์๋์์ ์ข ๋ ์ค๋ช ํ๊ฒ ์ต๋๋ค.
- ๋๊ธ์ ์์ ๊ณผ ์ญ์ ๊ฐ ๊ฐ๋ฅํ์ง๋ง, ์ญ์ ์ ๋๋๊ธ์ด ์กด์ฌํ๋ ๊ฒฝ์ฐ ๋๋๊ธ์ ์ญ์ ๋์ง ์์.
- ๋๋๊ธ์ด ์๋ ๊ฒฝ์ฐ์๋ง ๋๊ธ์ด ์์ ํ ์ญ์ ๊ฐ ๋จ
- ๋๋๊ธ์ด ๋จ์์๋ ๊ฒฝ์ฐ์๋ ๋๊ธ์ "์ญ์ ๋ ๋๊ธ์ ๋๋ค" ํ์, ๋๋๊ธ์ ๊ทธ๋๋ก ๋ฌ๋ ค์์
- ๊ทธ์ํ์์ ๋๋๊ธ์ด ๋ชจ๋ ์ฌ๋ผ์ง๋ค๋ฉด ๋๊ธ ์์ฒด๋ฅผ ์ญ์ ํจ
- ๋๋๊ธ์ด ์ฌ๋ฌ๊ฐ ๋ฌ๋ ค์๋ ์ํฉ์์ ์ค๊ฐ ๋๋๊ธ์ ์ง์ฐ๋ฉด, ์์๋ ์ ์ง๋๊ณ , "์ญ์ ๋ ๋๊ธ์ ๋๋ค" ๋ผ๊ณ ๋ธ
๋๋ฉ์ธ ์ค๊ณ
์ค๊ณํ ๋๋ฉ์ธ์ ๊ธฐ๋ฐ์ผ๋ก DB ํ ์ด๋ธ์ ์ค๊ณํด ๋ณด๊ฒ ์ต๋๋ค.
ํ ์ด๋ธ ์ค๊ณ
์ฌ์ฉํ ์ฌ์ดํธ๋ ์ด๊ณณ์ ๋๋ค!
์ํฐํฐ ์ค๊ณ
์ด์ ํ ์ด๋ธ์ ์ ๋ณด๋ฅผ ๊ฐ์ง๊ณ ์ํฐํฐ๋ฅผ ๊ตฌํํด์ ๋งคํํด๋ณด๊ฒ ์ต๋๋ค!
Member
@Table(name = "MEMBER")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@AllArgsConstructor
@Builder
public class Member extends BaseTimeEntity {
@Id @GeneratedValue(strategy = IDENTITY)
@Column(name = "member_id")
private Long id; //primary Key
@Column(nullable = false, length = 30, unique = true)
private String username;//์์ด๋
private String password;//๋น๋ฐ๋ฒํธ
@Column(nullable = false, length = 30)
private String name;//์ด๋ฆ(์ค๋ช
)
@Column(nullable = false, length = 30)
private String nickName;//๋ณ๋ช
@Column(nullable = false, length = 30)
private Integer age;//๋์ด
@Enumerated(STRING)
@Column(nullable = false, length = 30)
private Role role;//๊ถํ -> USER, ADMIN
@Column(length = 1000)
private String refreshToken;//RefreshToken
//== ํ์ํํด -> ์์ฑํ ๊ฒ์๋ฌผ, ๋๊ธ ๋ชจ๋ ์ญ์ ==//
@OneToMany(mappedBy = "writer", cascade = ALL, orphanRemoval = true)
private List<Post> postList = new ArrayList<>();
@OneToMany(mappedBy = "writer", cascade = ALL, orphanRemoval = true)
private List<Comment> commentList = new ArrayList<>();
//== ์ฐ๊ด๊ด๊ณ ๋ฉ์๋ ==//
public void addPost(Post post){
//post์ writer ์ค์ ์ post์์ ํจ
postList.add(post);
}
public void addComment(Comment comment){
//comment์ writer ์ค์ ์ comment์์ ํจ
commentList.add(comment);
}
//== ์ ๋ณด ์์ ==//
public void updatePassword(PasswordEncoder passwordEncoder, String password){
this.password = passwordEncoder.encode(password);
}
public void updateName(String name){
this.name = name;
}
public void updateNickName(String nickName){
this.nickName = nickName;
}
public void updateAge(int age){
this.age = age;
}
public void updateRefreshToken(String refreshToken){
this.refreshToken = refreshToken;
}
public void destroyRefreshToken(){
this.refreshToken = null;
}
//== ํจ์ค์๋ ์ํธํ ==//
public void encodePassword(PasswordEncoder passwordEncoder){
this.password = passwordEncoder.encode(password);
}
}
Post
import static javax.persistence.CascadeType.ALL;
import static javax.persistence.FetchType.*;
import static javax.persistence.GenerationType.IDENTITY;
@Table(name = "POST")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Post extends BaseTimeEntity {
@Id @GeneratedValue(strategy = IDENTITY)
@Column(name = "post_id")
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "writer_id")
private Member writer;
@Column(length = 40, nullable = false)
private String title;
@Lob
@Column(nullable = false)
private String content;
@Column(nullable = true)
private String filePath;
//== ๊ฒ์๊ธ์ ์ญ์ ํ๋ฉด ๋ฌ๋ ค์๋ ๋๊ธ ๋ชจ๋ ์ญ์ ==//
@OneToMany(mappedBy = "post", cascade = ALL, orphanRemoval = true)
private List<Comment> commentList = new ArrayList<>();
//== ์ฐ๊ด๊ด๊ณ ํธ์ ๋ฉ์๋ ==//
public void confirmWriter(Member writer) {
//writer๋ ๋ณ๊ฒฝ์ด ๋ถ๊ฐ๋ฅํ๋ฏ๋ก ์ด๋ ๊ฒ๋ง ํด์ฃผ์ด๋ ๋ ๋ฏ
this.writer = writer;
writer.addPost(this);
}
public void addComment(Comment comment){
//comment์ Post ์ค์ ์ comment์์ ํจ
commentList.add(comment);
}
//== ๋ด์ฉ ์์ ==//
public void updateTitle(String title) {
this.title = title;
}
public void updateContent(String content) {
this.content = content;
}
public void updateFilePath(String filePath) {
this.filePath = filePath;
}
}
Comment
import static javax.persistence.FetchType.LAZY;
@Table(name="COMMENT")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class Comment extends BaseTimeEntity {
@Id @GeneratedValue
@Column(name = "comment_id")
private Long id;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "writer_id")
private Member writer;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "post_id")
private Post post;
@ManyToOne(fetch = LAZY)
@JoinColumn(name = "parent_id")
private Comment parent;
@Lob
@Column(nullable = false)
private String content;
private boolean isRemoved= false;
//== ๋ถ๋ชจ ๋๊ธ์ ์ญ์ ํด๋ ์์ ๋๊ธ์ ๋จ์์์ ==//
@OneToMany(mappedBy = "parent")
private List<Comment> childList = new ArrayList<>();
//== ์ฐ๊ด๊ด๊ณ ํธ์ ๋ฉ์๋ ==//
public void confirmWriter(Member writer) {
this.writer = writer;
writer.addComment(this);
}
public void confirmPost(Post post) {
this.post = post;
post.addComment(this);
}
public void confirmParent(Comment parent){
this.parent = parent;
parent.addChild(this);
}
public void addChild(Comment child){
childList.add(child);
}
//== ์์ ==//
public void updateContent(String content) {
this.content = content;
}
//== ์ญ์ ==//
public void remove() {
this.isRemoved = true;
}
@Builder
public Comment( Member writer, Post post, Comment parent, String content) {
this.writer = writer;
this.post = post;
this.parent = parent;
this.content = content;
this.isRemoved = false;
}
}
ํ์ธ
์ด๋ ๊ฒ ๊ธฐ๋ณธ์ ์ธ ํ ์ด๋ธ ์ค๊ณ๋ฅผ ๋ง์ณค์ต๋๋ค.
๋ค์ ํฌ์คํ ์์๋ ์ํฐํฐ์ ๊ตฌ์ฒด์ ์ธ ๋น์ฆ๋์ค ๋ก์ง์ ๋ฃ์ด๋ณผ๊น ํฉ๋๋ค.
์ฌ์ค ์ ์ผ ์ค์ํ๊ฒ ์๊ฐํ๋๊ฑด ๋๊ธ๊ณผ ๋๋๊ธ์ ์ด๋ป๊ฒ ๊ตฌํํ ๊น ์ธ๋ฐ, ๋ค์ ํฌ์คํ ์์ ์ด์ด ์งํํ๋๋ก ํ๊ฒ ์ต๋๋ค.
์ ์ฒด ์ฝ๋๋ ๊นํ๋ธ์์ ํ์ธํ์ค ์ ์์ต๋๋ค.
https://github.com/ShinDongHun1/SpringBoot-Board-API