22.11.26 테이블 생성하기 / insert
model 패키지 생성
package com.cos.blog.model;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.hibernate.annotations.ColumnDefault;
import org.hibernate.annotations.CreationTimestamp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
//jpa의 ORM -> Java(다른언어포함) Object를 테이블로 매핑해주는 기술
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder //빌더 패턴
@Entity //User 클래스가 MySql에 테이블이 자동 생성
public class User {
@Id //PK
@GeneratedValue(strategy = GenerationType.IDENTITY) //프로젝트에서 연결된 DB의 넘버링 전략을 따라간다.
private int id; //시퀀스(오라클),auto_increment(mysql)
// NOT NULL
@Column(nullable = false, length = 30)
private String username; //아이디
//비밀번호 => 해쉬( 비밀번호 암호화하면 길이 길어짐)
@Column(nullable = false, length = 100)
private String password;
@Column(nullable = false, length = 50)
private String email;
@ColumnDefault("'user'") // ' ' 추가해서 문자라는 것 알려주기
private String role; //원래 Enum을 쓰는게 좋다.
//admin, user, manager 별로 권한을 주는 role
@CreationTimestamp //시간이 자동 입력
private Timestamp creatDate;
}
package com.cos.blog.model;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Board {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false, length = 100)
private String title;
@Lob //대용량 데이터사용할때 사용
private String content; //섬머노트 라이브러리 사용<html>태그가 섞여서 디자인이 됨.
@ColumnDefault("0")
private int count; //조회수
@ManyToOne(fetch = FetchType.EAGER) //Many = Board, One = User
@JoinColumn(name="userId") //컬럼 생성될때 userId로 생성됨
private User user; //DB는 오브젝트를 저장할 수 없어서 FK를 사용하는데 자바는 오브젝트를 저장할 수 있다.
// private int userId; 원래는 이렇게(FK) 사용해야 하지만 jpa(ORM)을 사용하면 오브젝트를 바로 저장할 수 있다.
// @JoinColumn(name = "replyId") 필요없음
@OneToMany(mappedBy = "board", fetch = FetchType.EAGER) //mappedBy 연관관계의 주인이 아니다(FK가 아니다) DB에 컬럼을 만들지 마라.
private List<Reply> reply;
@CreationTimestamp
private Timestamp createDate;
}
package com.cos.blog.model;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Reply {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
@Column(nullable = false, length = 200)
private String content;
@ManyToOne
@JoinColumn(name = "boardId")
private Board board;
@ManyToOne
@JoinColumn(name = "userId")
private User user;
@CreationTimestamp
private Timestamp createDate;
}
(FetchType.LAZY or EAGER)
엔티티 조회 시 연관관계에 있는 데이터까지 한 번에 조회해오는 기능
(참고로 @ManyToOne 매핑의 기본 fetch가 EAGER라서 생략해도 EAGER로 동작한다.)
엔티티 조회 시점이 아닌 엔티티 내 연관관계를 참조할 때 해당 연관관계에 대한 SQL이 질의되는 기능
@ManyToOne
@OneToMany
@OneToOne
@ManyToMany
ManyToMany는 사용하지 않는다. 그 이유는 서로의 primary key로만 중간 테이블을 생성해주는데, 날짜나 시간 다른 필드들이 필요할 수 있기 때문에, 내가 중간 테이블을 직접만들고 @OneToMany, @OneToMany를 사용한다.
참고 https://ict-nroo.tistory.com/127
[JPA] @ManyToMany, 다대다[N:M] 관계
다대다[N:M] 실무에선 사용하지 않는 것을 추천한다. 사용하면 안되는 이유를 학습하자. 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다. 연결 테이블(조인 테이블)�
ict-nroo.tistory.com
repository 패키지 -> UserRepository.java 인터페이스 생성
JpaRepository를 상속.
JpaRepository<User, Integer> = User 테이블이 관리하는 repository, user 테이블의 PK는 Integer
✨ JpaRepository 메서드
JpaRepository가 기본적인 메서드들을 다 가지고 있기 때문에
기본 CRUD만 사용할 경우 아무것도 작성하지 않아도 된다.
package com.cos.blog.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.cos.blog.model.User;
// JSP의 DAO와 같다
// 자동으로 bean으로 등록이 되기 때문에 어노테이션 생략가능.
//@Repository 생략가능
public interface UserRepository extends JpaRepository<User, Integer> {
}
package com.cos.blog.test;
// html파일이 아니라 data를 리턴해주는 controller = RestController
@RestController
public class DummyControllerTest {
@Autowired //의존성주입(DI)
private UserRepository userRepository;
@PostMapping("/dummy/join")
// public String join(String username, String password,String email) { //변수명일치하면 @RequestParam생략가능
public String join(User user) { //객체로도 받을 수 있음.
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.getCreatDate());
userRepository.save(user);
//JpaRepository의 save메서드 이용
return "회원가입이 완료되었습니다.";
}
}
post / x-www-form-urlencoded
KEY=VALUE 로 전송
변수명 일치하면 @RequestParam("usernamer") 생략가능.
매개변수 따로 받을 수도 있지만 객체로 한 번에 받기도 가능하다.
콘솔에서 확인 가능
DB에서 확인 가능
❓ 회원가입은 완료되었지만 role이 안들어 갔다. 왜일까 ?
@ColumnDefault("'user'")
private String role;
role은 Default 값이 user이기 때문에 role을 제외한 다른 컬럼을 insert 할때 작동한다.
(createDate, email, password, username)에서 role 제외
insert into user (createDate, email, password, role, username)
values(?, ?, ?, ?)
role을 포함해서 insert 시키면 role에 null값이 들어가기 때문에
role을 제외하고 insert하는 방법을 찾아야한다.
방법 : @DynamicInsert를 사용한다.
User클래스에 @DynamicInsert을 붙이기.
@DynamicInser
public class User {
...
}
@DynamicInser을 붙이면 null인 role을 제외한 쿼리가 실행되고 DB에도 role이 잘 들어간다.
하지만 이렇게 하면 어노테이션이 너무 많아지기 때문에 간략하게 수정해보자.
@DynamicInsert은 주석처리.
role에 있던 @ColumnDefault("'user'") 주석처리.
role의 타입을 스트링으로 주게되면 사용자가 실수(오타 등)를
할 수 있기 때문에 Enum타입으로 변경해준다.
package com.cos.blog.model;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder //빌더 패턴
@Entity //User 클래스가 MySql에 테이블이 자동 생성
//@DynamicInsert //insert시에 null인 필드를 제외시켜준다.
public class User {
@Id //PK
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id; //시퀀스(오라클),auto_increment(mysql)
// NOT NULL
@Column(nullable = false, length = 30)
private String username; //아이디
//비밀번호 => 해쉬( 비밀번호 암호화하면 길이 길어지기 때문에 length 길게)
@Column(nullable = false, length = 100)
private String password;
@Column(nullable = false, length = 50)
private String email;
<script>
// @ColumnDefault("'user'") // ' ' 추가해서 문자라는 것 알려주기
//DB는 RoleType이라는게 없기 때문에 해당 Enum이 String이라고 명시해주기
@Enumerated(EnumType.STRING)
private RoleType role;
//role의 타입을 String으로 하면 오타를 낼 수 있기때문에 Enum타입으로 강제시키기
//ADMIN, USER 별로 권한을 주는 role
</script>
@CreationTimestamp //시간 자동 입력 후 insert
private Timestamp creatDate;
}
✨ Enum
데이터의 도메인을 만들때 사용.
도메인(범위)안에서 값을 강제 시킬 수 있다. (오타방지 등)
package com.cos.blog.model;
public enum RoleType {
USER, ADMIN
}
RoleType에는 USER, ADMIN만 들어갈 수 있다.
role에 null이 들어가기 때문에 save하기 전에
role값 설정해주기.
package com.cos.blog.test;
@RestController
public class DummyControllerTest {
@Autowired //의존성주입(DI)
private UserRepository userRepository;
@PostMapping("/dummy/join")
// public String join(String username, String password,String email) { //변수명일치하면 @RequestParam생략가능
public String join(User user) { //객체로도 받을 수 있음.
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.getCreatDate());
// user.getRole("user"); String 불가
user.setRole(RoleType.USER);
userRepository.save(user);
return "회원가입이 완료되었습니다.";
}
}
수정 후 postman으로 다시 send하면 role 값이 USER로 잘 들어간다.