스프링부트 강좌 24강(블로그 프로젝트) - 회원가입 위한 insert 테스트
연관관계 만들기
@ManyToOne
@OneToMany
@OneToOne
@ManyToMany
ManyToMany는 사용하지 않는다. 그 이유는 서로의 primary key로만 중간 테이블을 생성해주는데, 날짜나 시간 다른 필드들이 필요할 수 있기 때문에, 내가 중간 테이블을 직접만들고 @OneToMany, @OneToMany를 사용한다.
ManyToMany는 두개의 테이블의 중간 테이블을 만들어준다.
x-www-form-urlencoded 타입으로 데이터를 전송한다는 것은 데이터를 key=value 형태로 전송한다는 것이다.
또 추가적인 게 있다면 key=value&key=value 이런 식으로....
package com.yuri.blog.test;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DummyControllerTest {
// http://localhost:8000/blog/dummy/join (요청)
// http와 body에 username, password, email 데이터를 가지고 (요청)
@PostMapping("/dummy/join")
public String join(String username, String password, String email) {
System.out.println("username: "+username);
System.out.println("password: "+password);
System.out.println("email: "+email);
return "회원가입이 완료되었습니다 :)";
}
}
join이라는 함수의 파라미터 3개는 key=value 형태의 데이터를 받아준다는 것이다. 이것은 약속된 규칙이다. 스프링이 제공해준다.
x-www-form-urlencoded 로 전송되는 데이터는 key=value로 오는데 그것은 스프링이 함수의 파라미터로 파싱해서 집어넣어준다는 것이다. 이거 말고도 훨씬 더 강력한 일을 해주는데 object로 받게 해준다!!!!
package com.yuri.blog.test;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yuri.blog.model.User;
@RestController
public class DummyControllerTest {
// http://localhost:8000/blog/dummy/join (요청)
// http와 body에 username, password, email 데이터를 가지고 (요청)
@PostMapping("/dummy/join")
public String join(User user) { //key=value (약속된 규칙)
System.out.println("id: "+user.getId());
System.out.println("username: "+user.getUsername());
System.out.println("password: "+user.getPassword());
System.out.println("email: "+user.getEmail());
System.out.println("role :"+user.getRole());
System.out.println("createDate: "+user.getCreateDate());
return "회원가입이 완료되었습니다 :)";
}
}
id,
role, createDate는 전송받지 않기 때문에 null값이 들어올 것이다.
id 에 0을 볼 수 있는데 int 값이니까 default으로 0이 들어가 있는 것~
이제 데이터베이스에 insert를 해볼 것인데 insert하기 위해서는 패키지를 하나 만들어야 한다. com.yuri.blog.repository y라는 패키지 하나를 만들자. 여기에 인터페이스를 만든다. User 테이블의 레파지토리니까 UserRepository라고..!!
package com.yuri.blog.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.yuri.blog.model.User;
//DAO
//자동으로 bean 등록이 된다.
//bean으로 등록된다는 것은 스프링 ioc에서 객체를 가지고 있나요? 라고 물어보는 것이다.
//Repository 생략 가능하다.
//JpaRepository는 User table이 관리하는 레파지토리이다. 이 user table의 primary key는 Integer이다.
public interface UserRepository extends JpaRepository<User, Integer>{
}
DAO란 Data Access Object의 약자.
이렇게 하면 bean으로 등록이 되나요? bean으로 등록 된다는 것은 스프링 ioc에서 객체를 가지고 있나요?라고 물어보는 것과 같은 말이다. 그래야지 injection을 통해 DI라는 것을 할 수 있다.
자동으로 bean으로 등록 되어서 @Repository가 생략 가능하다. 예전이면 @Repository 을 등록해야 했었다. 그래야 스프링이 컴포넌트 스캔을 할때 유저 레파지토리를 메모리에 띄어주는데 . @Repository가 생략이 가능하다.
UserRepository를 메모리에 띄어주기 때문에 DummyControllerTest로 와서 사용할 수 있음
JpaRepository는 여러가지 함수를 갖고 있는데 그 중에서도 findAll()은 유저 테이블이 들고 있는 모든 행을 리턴해라는 뜻이다.
정렬해서, 페이징해서 받을 수도 있다. 데이터를 sava()함수로 인서트와 업데이트를 동시에 할 수 있다. (회원가입 할때 사용) findById() 등등 .. 함수를 통해 바로 찾을 수 있도록 제공을 해준다. 따라서 이것들을 직접 만들지 않아도 된다. UserRepository는 JpaRepository를 extends하고 있기 때문에 다 들고 있다. 기본적인 CRUD는 이렇게만 만들어 놓으면 okay~
package com.yuri.blog.test;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yuri.blog.model.User;
import com.yuri.blog.repository.UserRepository;
@RestController
public class DummyControllerTest {
// 스프링이 @RestController 어노테이션을 읽어서 DummyControllerTest 를 메모리에 띄어줄 때 얘는 null
private UserRepository userRepository;
// http://localhost:8000/blog/dummy/join (요청)
// http와 body에 username, password, email 데이터를 가지고 (요청)
@PostMapping("/dummy/join")
public String join(User user) { //key=value (약속된 규칙)
System.out.println("id: "+user.getId());
System.out.println("username: "+user.getUsername());
System.out.println("password: "+user.getPassword());
System.out.println("email: "+user.getEmail());
System.out.println("role :"+user.getRole());
System.out.println("createDate: "+user.getCreateDate());
return "회원가입이 완료되었습니다 :)";
}
}
스프링에서 @CreationTimestamp 라는 어노테이션을 붙이면 자바에서 현재 시간을 넣고 인서트를 해준다. 근데 role은 안들어감 ㅠ
@ColumnDefault("'user'") 라고 붙여져 있으면 ..
insert
into
User
(createDate, email, password, role, username)
values
(?, ?, ?, ?, ?)
이런 쿼리가 날라갔는데...
id 값은 autoincrement로 들어갈 것인데 createDate 같은 경우는 @CreationTimestamp라는 어노테이션을 붙이면 자바에서 현재 시간을 쑤욱 넣고 insert를 해준다. 그래서 createDate도 잘 들어간다. 근데 role은 왜 들어가지 않을까?
우리가 만든 User 엔티티는
save 될 때 CreationTimestamp가 작동해서 현재 시간을 넣어서 데이터베이스에 insert 해준다. (java에서 만들어서 insert 해준다는 의미) 근데 role 같은 경우는 ... 어떤 어노테이션이 붙여져 있냐면 ColumnDefault 값으로 'user'이렇게 붙여져 있으면 데이터베이스에는 다음과 같이 만들어진다.
role 같은 경우는 Default Value가 user이니까 이 user 값이 언제 작동하냐면..
insert
into
User
(createDate, email, password, username)
values
(?, ?, ?, ?)
이렇게 될 것이다. 근데 쿼리가
insert
into
User
(createDate, email, password, role, username)
values
(?, ?, ?, null, ?)
이렇게 동작한다는 것! 그러면 default 값이 작동을 안한다는 것이다. 그럼 얘를 없애서 인서트 하는 방법을 찾아야 한다. 그럴 때 @Dynamicinsert 라는 어노테이션을 붙이는 것이다. 얘를 사용하면 insert 할때 null인 필드를 제외시켜준다. JAP(JPA는 자바 진영의 ORM 기술 표준이다)에서~~!!
@DynamicInsert이 좋은 일을 해주기는 하는데 이런 어노테이션을 계속 붙이다 보면 끝이 없다. 계속 이런 것들을 덕지덕지 붙이는 게 무조건 좋은 방법이 아니다.
// @ColumnDefault("'user'") //데이터베이스에서 varchar로 사용할 것이기 때문에 ' ' 추가
// private String role; // Enum을 쓰는 게 좋다. 왜? 도메인을 만들 수 있음
// //admin, user, manager 권한을 줘서... 실수로 managerrrr 로 오타를 낼 수도 있다.
// //enum을 사용하면 도메인을 설정할 수 있다. 어떤 범위가 정해졌다는 것을 의미, 근데 일단은 string으로...
아예 이 부분을 빼버리면 디폴트 값이 들어가지 않을 것이다.
user.setRole("user"); 을 넣어준다.
근데 그냥 유저라고 하면 개발자들이 실수를 할 수 있다.
user.setRole("user2"); 같은 그런 실수?..그래서 모델에다가 마우스 우클릭해서 이넘이라고...
package com.yuri.blog.model;
public enum RoleType {
USER, ADMIN
}
라고 설정해주자.
//DB는 RoleType이라는 게 없다.
//따라서 어노테이션을 붙여 해당 이넘이 스트링이라고 알려줘야 한다.
@Enumerated(EnumType.STRING)
private RoleType role; //Enum을 쓰는 게 좋다. //ADMIN, USER
package com.yuri.blog.test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yuri.blog.model.RoleType;
import com.yuri.blog.model.User;
import com.yuri.blog.repository.UserRepository;
@RestController
public class DummyControllerTest {
// 스프링이 @RestController 어노테이션을 읽어서 DummyControllerTest 를 메모리에 띄어줄 때 얘는 null,
// 하지만 Autowired 어노테이션 붙이면 얘도 같이 메모리에 띄어줄 수 있다.
//UserRepository 타입으로 스프링이 관리하고 있는 객체가 있다면 userRepository에 쏘옥 넣어준다.
@Autowired //의존성 주입(DI)
private UserRepository userRepository;
// http://localhost:8000/blog/dummy/join (요청)
// http와 body에 username, password, email 데이터를 가지고 (요청)
@PostMapping("/dummy/join")
public String join(User user) { //key=value (약속된 규칙)
System.out.println("id: "+user.getId());
System.out.println("username: "+user.getUsername());
System.out.println("password: "+user.getPassword());
System.out.println("email: "+user.getEmail());
System.out.println("role :"+user.getRole());
System.out.println("createDate: "+user.getCreateDate());
//default 값을 회원가입 할때 미리 넣어버리면 된다.
user.setRole(RoleType.USER);
// user 객체를 집어넣으면 회원가입이 된다!
userRepository.save(user);
return "회원가입이 완료되었습니다 :)";
}
}
post요청 후 확인 결과이다.USER라고 잘 들어가 있다. 이제 role에는 소문자도 들어가지 않고, 대문자 USER가 잘 들어갈 것이다. 놓다보면 실수를 할 수 있는 것들을 방지하려면 이넘을 만들면 된다. 내가 넣는 값들을 강제할 수 있다.
강제하는 이유는? USER, 아니면 ADMIN만 넣을 수 있게 하려고~~ USER라는 것을 넣을 때 users 라고 실수해서 넣지 않아도 된다.
enum은 데이터의 도메인을 만들 때 사용한다. 도메인이라는 것은 어떤 범위를 의미한다. 어떤 범위 안에 데이터를 넣을 때!
-이 글은 유투버 겟인데어의 스프링 부트 강좌를 바탕으로 정리한 내용입니다.-