📚 공부한 책 : 코드로배우는 스프링 부트 웹프로젝트
❤️ github 주소 : https://github.com/qkralswl689/LearnFromCode/tree/main/mreview2022
M:N 관계를 처리할 때는 반드시 맵핑 테이블의 설계는 마지막 단계에서 처리하고 '명사'에 해당하는 클래스를 먼저 설계한다
-> 영화(Movie)와 회원(Member)의 존재가 명사에 해당아므로 먼저 설계한다
import lombok.*;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
public class Movie extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long mno;
private String title;
}
이미지에 대한 정보를 기록한다
- java.util.UUID를 이용해 고유 번호 생성
- 이미지의 저장 경로(path)는 년/월/일 폴더 구조를 의미한다
- 테이블로 생성될 때는 movie 테이블이 PK를 가지고 movie_image 테이블은 FK를 가지게 되므로 @ManyToOne를 적용한다
import lombok.*;
import lombok.extern.java.Log;
import javax.persistence.*;
@Entity
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Getter
@ToString(exclude = "movie")
public class MovieImage {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long inum;
// java.util.UUID를 이용해 고유 번호 생성
private String uuid;
private String imgName;
private String path;
// movie 테이블이 PK를 가지고 movie_image 테이블이 FK를 가지므로 movie_image에 @ManyToOne 적용
@ManyToOne(fetch = FetchType.LAZY)
private Movie movie;
}
프로젝트를 실행하여 테이블을 생성한다
Hibernate:
create table movie_image (
inum bigint not null auto_increment,
img_name varchar(255),
path varchar(255),
uuid varchar(255),
movie_mno bigint,
primary key (inum)
) engine=InnoDB
Hibernate:
alter table movie_image
add constraint FKitwj3761d8j8ku189u4qrseih
foreign key (movie_mno)
references movie (mno)
import lombok.*;
import javax.persistence.*;
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString
@Table(name = "m_member")
public class Member extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long mid;
private String email;
private String pw;
private String nickname;
}
Mapping table은 두 테이블 사이에서 양쪽의 PK를 참조하는 형태로 구성된다
- Review 클래스는 Movie 와 Member를 양쪽으로 참조하는 구조로 @ManyToOne으로 설계한다
import lombok.*;
import javax.persistence.*;
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString(exclude = {"movie","member"})
public class Review extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long reviewnum;
@ManyToOne(fetch = FetchType.LAZY)
private Movie movie;
@ManyToOne(fetch = FetchType.LAZY)
private Member member;
private int grade;
private String text;
}
import com.example.mreview2022.entity.Movie;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MovieRepository extends JpaRepository<Movie,Long> {
}
import com.example.mreview2022.entity.MovieImage;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MovieImageRepository extends JpaRepository<MovieImage,Long> {
}
영화와 이미지들은 같은 시점에 insert 처리가 되어야 한다
-> Movie 객체를 우선 저장(save())하고 save()가 실행된 뒤 Movie 객체는 PK에 해당하는 mno 값이 할당 되고, mno를 이용해 영화의 이미지들을 추가한다. 이미지들은 최대 5개까지 임의로 저장된다
import com.example.mreview2022.entity.Movie;
import com.example.mreview2022.entity.MovieImage;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Commit;
import javax.transaction.Transactional;
import java.util.UUID;
import java.util.stream.IntStream;
@SpringBootTest
public class MovieRepositoryTests {
@Autowired
private MovieRepository movieRepository;
@Autowired
private MovieImageRepository imageRepository;
@Commit
@Transactional
@Test
public void insertMovies() {
IntStream.rangeClosed(1,100).forEach(i ->{
Movie movie = Movie.builder().title("Movie..." + i).build();
System.out.println("------------------------");
movieRepository.save(movie);
int count = (int)(Math.random() * 5) + 1;
for (int j = 0; j < count; j++){
MovieImage movieImage = MovieImage.builder()
.uuid(UUID.randomUUID().toString())
.movie(movie)
.imgName("test" + j +".jpg").build();
imageRepository.save(movieImage);
}
System.out.println("===============================");
});
}
}
import com.example.mreview2022.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;
public interface MemberRepository extends JpaRepository<Member,Long> {
}
import com.example.mreview2022.entity.Member;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.stream.IntStream;
@SpringBootTest
public class MemberRepositoryTests {
@Autowired
private MemberRepository memberRepository;
@Test
public void insertMembers(){
IntStream.rangeClosed(1,100).forEach(i -> {
Member member = Member.builder()
.email("r" + i + "@zerock.org")
.pw("1111")
.nickname("reviewer" + i).build();
memberRepository.save(member);
});
}
}
import com.example.mreview2022.entity.Review;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ReviewRepository extends JpaRepository<Review,Long> {
}
200개의 MovieReview를 저장한다 영화의 번호,회원은 임의의 값으로 현재 DB에 존재하는 값으로 생성하고,
영화의 평점,리뷰 내용을 작성해 MovieReview 객체를 생성해 저장한다
import com.example.mreview2022.entity.Member;
import com.example.mreview2022.entity.Movie;
import com.example.mreview2022.entity.Review;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.stream.IntStream;
@SpringBootTest
public class ReviewRepositoryTests {
@Autowired
private ReviewRepository reviewRepository;
@Test
public void insertMovieReviews(){
// 200개의 리뷰 등록
IntStream.rangeClosed(1,200).forEach(i ->{
//영화 번호
Long mno = ((long)(Math.random()*100) + 1);
//리뷰어 번호
Long mid = ((long)(Math.random()*100) + 1);
Member member = Member.builder().mid(mid).build();
Review movieReview = Review.builder()
.member(member)
.movie(Movie.builder().mno(mno).build())
.grade((int)(Math.random()*5) + 1)
.text("이 영화에 대한 느낌 ..." + i)
.build();
reviewRepository.save(movieReview);
});
}
}