지금까지 해오던 프로젝트에 댓글기능을 구현하기 위해서 이전 프로젝트와 별개로 따로 프로젝트를 하나 생성해서 JPA에서 DB 테이블을 Join 하여 호출하는 법을 실습하려고 한다.
총 3개의 DB를 생성하여 2개가 1개의 DB를 가르키도록 설계할 것이다.
@Entity
@Getter
@Table(name = "book")
@AllArgsConstructor
@NoArgsConstructor
public class Book {
@Id
private Long id;
private String name;
private Long authorId;
}
@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class Author {
@Id
private Long id;
private String name;
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
public class BookResponse {
private long BookId;
private String BookName;
private String AuthorName;
public static BookResponse of(Book book,String authorName){
return BookResponse.builder()
.BookId(book.getId()) // Book DB
.BookName(book.getName()) // Book DB
.AuthorName(authorName) // Author DB
.build();
}
}
@Repository
public interface BookRepository extends JpaRepository<Book,Long> {
}
@Repository
public interface AuthorRepository extends JpaRepository<Author,Long> {
}
@Service
public class BookService {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
public BookService(BookRepository bookRepository, AuthorRepository authorRepository) {
this.bookRepository = bookRepository;
this.authorRepository = authorRepository;
}
public Page<Book> TotalList(Pageable pageable){
return bookRepository.findAll(pageable);
}
// Json 형식으로 반환
public List<BookResponse> jsonList(Pageable pageable){
Page<Book> books = bookRepository.findAll(pageable);
List<BookResponse> bookResponses = books.stream()
.map(book ->{
// 위에 찾은 전체 데이터인 books에는 id,bookname,authorid 3개의 데이터로 모든 데이터가 리스트로 저장이 되 있다.
// 그 중에서 authorid인 부분의 값을 가져와 authorRepository를 통해 author DB에서 데이터를 찾아와
// BookResponse의 of메서드(Builder)를 통해 데이터를 매칭 시켜서 반환해준다.
// 아래 방법은 DB에서 Join을 사용하지 않고 DB에서 데이터를 각자 찾아 Build를 통해 데이터를 삽입하는 방식이다.
Optional<Author> optionalAuthor = authorRepository.findById(book.getAuthorId());
return BookResponse.of(book,optionalAuthor.get().getName());
}).collect(Collectors.toList());
return bookResponses;
}
}
@RestController
@RequestMapping("/api/v1/books")
public class BookController {
private final BookService bookService;
public BookController(BookService bookService) {
this.bookService = bookService;
}
// List 형식으로 전체 출력(View로 데이터 넘길때 사용)
@GetMapping("")
public Page<Book> get(Pageable pageable){
return bookService.TotalList(pageable);
}
// Json 형식으로 전체 출력
@GetMapping("/json")
public ResponseEntity<List<BookResponse>> JsonData(Pageable pageable){
return ResponseEntity.ok().body(bookService.jsonList(pageable));
}
}
@Entity
@Getter
@Table(name = "book")
@AllArgsConstructor
@NoArgsConstructor
public class Book {
@Id
private Long id;
private String name;
// JPA가 Foreign Key를 걸어준다.
@ManyToOne
@JoinColumn(name = "author_id") // Book DB의 author_id와 아래의 변수를 Join시킴(즉, 아래의 변수를 FK로 만들어준다)
private Author author; // Author 테이블을 호출함
}
public class BookResponse {
private long BookId;
private String BookName;
private String AuthorName;
public static BookResponse of(Book book){
return BookResponse.builder()
.BookId(book.getId())
.BookName(book.getName())
.AuthorName(book.getAuthor().getName()) // Author Entity의 이름을 가져옴
.build();
}
}
@Service
public class BookService {
private final BookRepository bookRepository;
private final AuthorRepository authorRepository;
public BookService(BookRepository bookRepository, AuthorRepository authorRepository) {
this.bookRepository = bookRepository;
this.authorRepository = authorRepository;
}
public Page<Book> TotalList(Pageable pageable){
return bookRepository.findAll(pageable);
}
// Json 형식으로 반환
public List<BookResponse> jsonList(Pageable pageable){
Page<Book> books = bookRepository.findAll(pageable);
List<BookResponse> bookResponses = books.stream()
.map(book -> BookResponse.of(book)).collect(Collectors.toList()); // books에 있는 데이터를 book으로 리스트 1개씩 전부 받아 BookResponse.of로 보내어 준다.
return bookResponses;
}
}
@Entity
@Getter
@Table(name = "book")
@AllArgsConstructor
@NoArgsConstructor
public class Book {
@Id
private Long id;
private String name;
// JPA가 Foreign Key를 걸어준다.
@ManyToOne // 단방향(한개 이상의 데이터를 호출할 수 있으므로, 저자가 여러명)
@JoinColumn(name = "author_id") // Book DB의 author_id와 아래의 변수를 Join시킴(즉, 아래의 변수를 FK로 만들어준다)
private Author author; // Author 테이블을 호출함
@OneToOne // 단방향(무조건 한개의 데이터만 호출할 수 있으므로, 출판사는 한곳에서만)
@JoinColumn(name = "publisher_id") // publisher_id를 Publisher의 FK로 연결함
private Publisher publisher;
}
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class Publisher {
@Id
private Long id;
private String name;
private String address;
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
public class BookResponse {
private long BookId;
private String BookName;
private String AuthorName;
private String PublisherName;
public static BookResponse of(Book book){
return BookResponse.builder()
.BookId(book.getId())
.BookName(book.getName())
.AuthorName(book.getAuthor().getName()) // Author Entity의 이름을 가져옴
.PublisherName(book.getPublisher().getName()) // Publisher Entity의 이름을 가져옴
.build();
}
}