SpringBoot 블로그 만들기- 테이블 생성하기

정원·2022년 11월 26일
0

SpringBoot

목록 보기
8/34

22.11.26 테이블 생성하기 / insert

1. Blog 테이블 만들기 (User, Board, Reply)

model 패키지 생성

User.java

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;
}

Board.java

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;

}

Reply.java

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;
}

JPA 즉시 로딩과 지연 로딩

(FetchType.LAZY or EAGER)

즉시 로딩(EAGER)

엔티티 조회 시 연관관계에 있는 데이터까지 한 번에 조회해오는 기능
(참고로 @ManyToOne 매핑의 기본 fetch가 EAGER라서 생략해도 EAGER로 동작한다.)

지연 로딩(LAZY)

엔티티 조회 시점이 아닌 엔티티 내 연관관계를 참조할 때 해당 연관관계에 대한 SQL이 질의되는 기능

2. 연관관계 만들기

@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

3. 더미 데이터 insert

repository 생성

repository 패키지 -> UserRepository.java 인터페이스 생성
JpaRepository를 상속.
JpaRepository<User, Integer> = User 테이블이 관리하는 repository, user 테이블의 PK는 Integer

✨ JpaRepository 메서드

    1. findAll() 메소드
      Member 테이블에서 레코드 전체 목록을 조회
      List 객체가 리턴
    1. findById(id)
      Member 테이블에서 기본키 필드 값이 id인 레코드를 조회
      Optional 타입의 객체가 리턴
      이 객체의 get 메서드를 호출하면 Member 객체가 리턴 예) Member m = memberRepository.findById(id).get();
    1. save(member)
      Member 객체를 Member 테이블에 저장
      객체의 id(기본키) 속성값이 0이면 INSERT / 0이 아니면 UPDATE
    1. saveAll(memberList)
      Member 객체 목록을 Member 테이블에 저장
    1. delete(member)
      Member 객체의 id(기본키) 속성값과 일치하는 레코드를 삭제
    1. deleteAll(memberList)
      Member 객체 목록을 테이블에서 삭제
    1. count()
      Member 테이블의 전체 레코드 수를 리턴
    1. exists(id)
      Member 테이블에서 id에 해당하는 레코드가 있는지 true/false를 리턴
    1. flush()
      지금까지 Member 테이블에 대한 데이터 변경 작업들이 디스크에 모두 기록

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> {

}

DummyControllerTest.java 생성

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 "회원가입이 완료되었습니다.";
	}
}

postman으로 send

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를 사용한다.

  • @DynamicInsert - insert할때 null 인 필드 제외

User.java 수정

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;
}

model 패키지에 RoleType Enum파일 생성.

✨ Enum
데이터의 도메인을 만들때 사용.
도메인(범위)안에서 값을 강제 시킬 수 있다. (오타방지 등)

package com.cos.blog.model;

public enum RoleType {
	USER, ADMIN
}

RoleType에는 USER, ADMIN만 들어갈 수 있다.

DummyController.java

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로 잘 들어간다.

0개의 댓글