Controller - 가장 바깥 부분 요청/응답을 처리함.
Service - 실제 중요한 작동이 많이 일어나는 부분
repository - 가장 안쪽 부분 db와 맞닿아 있음.
데이터로 응답하기
HTML, CSS, javascript 를 한 번에 돌려주기.
💡 - Rest는 뭐고 Controller는 뭐지???근데 우리가 완성된 웹 화면(위에서 2번)말고 “데이터만” 받아오려면 RestController라는걸 이용해야 함.
Rest는 서버의 응답이 JSON(키:값) 형식임을 나타냄.
즉 서버가 HTML, CSS, javascript를 돌려주는게 아니라 JSON을 돌려준다.
Controller는 사용자가 화면(VIEW)단에서 입력이나 어떤 이벤트를 했을 경우,
그 이벤트에 맞는 화면(VIEW)이나 비즈니스 로직(MODEL)을 실행할 수 있도록 업데이트 해주는 역할을 함.
즉, Rest Controller 는 JSON형식으로 응답하는 응답기다.
먼저 MVC를 짚어보자면 Model, View, Controller의 의미이며, 스프링이 제공하는 웹 구축을 위한 프레임워크임.
- Model = 무엇을 할 지에 대한 로직을 담고 비즈니스 로직을 처리하기 위한 역할을 담당.
- View = 최종 사용자에게 결과를 화면(UI)로 보여주기 위한 역할 즉 사용자에게 시각적으로 보여주는 부분.
- Controller = 이 두 사이에 있는 컴포넌트로 Model이 데이터를 어떻게 처리할 지 알려주는 역할을 담당.
즉, 스프링 프레임워크에서의 Controller 역할은 다음과 같음.
대규모 서비스로 갈수록 처리해야 할 서비스들이 많아지는데,
이를 하나의 클래스에서 몰아 처리할게 아니라 controller라는 중간제어자 역할을 만들어서
A요청에 대한 것은 A-controller가 B요청에 대한 것은 B-controller가 맡아 필요한 로직 처리를 위한 서비스를 호출. 역할분담이 핵심.
근데 RestController 와 Controller의 차이는 또 뭔데?
https://dncjf64.tistory.com/288
https://dev-coco.tistory.com/84
https://wondongho.tistory.com/76
https://memostack.tistory.com/244 ‼️
H2 Database = In-memory DB 서버가 작동을 멈추면 데이터가 모두 삭제됨. 연습용으로 딱!
Lombok = @을 사용하여 코드를 절약할 수 있게 해주는거.
예를 들어 자주 사용한 getter,setter 또는 생성자 관련해서 자주 쓰이는 코드롤 자동생성해줌으로써 코드를
절약할 수 있게 도와주는 라이브러리.
보통 개발자들은 다른 사람이 만든 코드를 가져다 쓰는 경우가 많음(의존하는 경우가 많음 )
다른 사람들이 만든 도구를 내려 받는데 있어서
javascript — NPM
python — pip
Java — mavenCentral, jcenter
이런걸 통해서 다른 사람의 코드를 다운받고 적용하는걸 굉장히 간편하게 할 수 있음.
그걸 도와주는 녀석이 Gradle
뿐만 아니라 gradle은 이거 말고도 우리가 스프링 프로젝트를 인터넷에 배포할 수 있게 빌드하는걸 도와주기도 함.
코드를 복사해서 build.gradle 파일 dependencies 부분에 갖다붙임.
src > main > resources > application.propertries에 밑에 코드 삽입.
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb;MODE=MYSQL
그 다음, 서버 작동시키고 웹에서 localhost:8080/h2-console 을 검색하면 됨.
https://leeeehhjj.tistory.com/52
JPA는 자바 명령어를 SQL 언어로 잘 번역해줘서 자바언어로 DB를 다룰 수 있게 해주는 번역기.
JPA가 없으면 우리가 일일이 SQL언어로 데이터를 조회,삽입,수정,삭제 해야 되는데
이를 자바 언어로도 할 수 있게 해줌.
즉, JPA는 SQL언어를 쓰지 않고도 데이터를 생성, 조회, 수정, 삭제 할 수 있게 해주는 번역기.
JPA는 인터페이스를 통해서만 사용가능.
→ Sql 썼다 자바썼다 왔다갔다 해야함.
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
→ 설정은 위에 코드 한 줄이면 끝남.
→ 명령도 그냥 자바로 만들면 됨.
👉🏻 Domain.equls(Table(MySQL))
“자, 나는 지금부터 간단한? 게시판을 만들거야.
게시판에 글을 쓰려면 회원 정보가 필요하겠네?
그럼 회원이 있어야겠다. 게시글이랑 댓글도 있어야겠네? 한 번 만들어보자~”
ID
이름
나이
닉네임 등,,
회원가입
로그인
회원정보 수정
회원 탈퇴
생성날짜
수정날짜
게시글
제목
글쓴이 등,,
비회원은 작성 불가능, 회원만 작성 가능
제목, 내용, 첨부파일을 올릴 수 있음
작성자는 게시물에 대한 수정과 삭제가 가능함
게시물을 삭제하면, 달려있는 댓글들이 일괄적으로 삭제됨
작성자가 회원탈퇴를 하면, 게시물도 삭제됨
게시물에는 댓글을 달 수 있음
(익명 기능도 추가하고 싶지만.. 조금 미루도록 하겠습니다.)
게시글
작성자
댓글 등,,
게시글에 작성할 수 있음
첨부파일은 불가능하게 만들 것임
댓글은 대댓글을 가질 수 있으나. 대대댓글은 가질 수 없음
댓글은 수정과 삭제가 가능하지만, 삭제 시 대댓글이 존재하는 경우 대댓글은 삭제되지 않음.
👉🏻 DB설계 툴 쓸 수 있는 곳
“이제 테이블이랑 분석한 정보 보면서 엔티티 만들어보자!”
@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);
}
}
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;
}
}
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;
}
}
👉🏻 Repository .equls(SQL)
JPA코드를 사용하는 것은 repository에 있는 코드를 사용하는 것과 같음.
Repository는 클래스의 한 역할에 해당하는데, 데이터에 접근할 때 사용하는 하나의 도구(DAO).
.find / .save / .delete 처럼 db를 다룰 수 있는 언어를 제공함.
repository는 엔티티별로 분리.
**→ Course Table을 다루기 위한 CourseRepository를 만들었음.**
JpaRepository
를 상속받음으로써 사용가능해짐.
)
“Course 테이블에 접근할 수 있는 repository를 만들거야 이름은 CourseRepository라고 정했어!
그리고선 JpaRepository를 상속받아야 돼 왜냐구??
상속을 받아야 JpaRepository 안에 있는 Jpa코드를 쓸 수있지!! find / .save / .get 이런거 말이야~
근데 쓸 때 조건이 있어! 뭐냐면 JpaRepository<대상으로 지정할 엔티티, 해당 엔티티의 PK의 타입>이야.
알겠지??”
→ 생성 create
→ 조회 read
→ 변경 update
→ 삭제 delete
⭐️ https://velog.io/@codren/Domain-Repository 이따 정리‼️‼️‼️‼️
Entity
클래스는 DB의 테이블에 존재하는 Column들을 필드로 가지는 객체.👉🏻 참고자료 :https://velog.io/@gudonghee2000/DTO
드디어 주특기 스프링을 공부하는 주가 시작됐다.
자바를 알면 스프링은 저절로 다 알게 되는건 줄 알았는데,,
아니다,,
자바 따로 스프링 따로 공부하는거다,,
하,,ㅎ 공부할거 많아서 너무 행복하다,,ㅎㅎ