7. 게시글쓰기v2

송민경's avatar
Mar 12, 2024
7. 게시글쓰기v2

1. JPA

  • Java 애플리케이션에서 데이터베이스와의 상호 작용을 관리하는 Java 표준 스펙
  • Hibernate와 동일하다 생각해도 됨
JPA를 구현한 가장 널리 사용되는 ORM 프레임워크 중 하나
  • 비영속 객체 : 아직 데이터베이스에 저장되지 않은 객체
영속성 컨텍스트에 저장되지 않은 상태
  • 객체를 Persistence Context에 저장하여 관리
 
notion image

2. Persistence Context

  • JPA가 데이터베이스와 상호 작용하는 데 사용하는 환경
  • 모든 문맥을 다 알고 있음
  • 영속 객체 : 영속성 컨텍스트에 저장, 데이터베이스와의 동기화 됨
비영속 객체 : 아직 HD(DB)에 저장되지 않음, PK가 없음
  • 영속 엔티티를 만들 때는 보통 DB의 PK 값을 사용하여 객체를 식별
  • 객체를 처음으로 영속성 컨텍스트에 저장할 때는 DB에 저장된 PK 값이 없음
  • Hibernate와 같은 ORM 프레임워크가 새로운 PK 값을 생성하고 객체에 할당
객체 값을 만들어서 insert쿼리로 DB에 집어 넣음
  • DB에 저장, PK 값이 생성되면 영속성 컨텍스트와 동기화되어 영속 객체로서의 상태를 유지
insert가 되고 PK가 생기면 PC가 동기화 되면서 영속성 객체로 바뀜

리팩토링하기

1. Board 수정하기

  • 빈 생성자가 디폴트
  • 변경하는 데이터를 PC에 담기 위해 해당 데이터의 생성자 만들기
package shop.mtcoding.blog.board; import jakarta.persistence.*; import lombok.Data; import lombok.NoArgsConstructor; import org.hibernate.annotations.CreationTimestamp; import shop.mtcoding.blog.util.MyDateUtil; import java.sql.Timestamp; @NoArgsConstructor // 빈생성자 만들어주기 @Data // 변경되는 데이터에만 setter가 필요함 @Table(name = "board_tb") @Entity public class Board { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String title; private String content; private String username; @CreationTimestamp // PC로 인해 DB에 INSERT될 때 날짜 주입 private Timestamp createdAt; public Board(String title, String content, String username) { this.title = title; this.content = content; this.username = username; } public String getBoardDate(){ return MyDateUtil.timestampFormat(createdAt); } }
 

2. BoardPersistRepository 만들어 save() 수정하기

  • PC에 Data(주소) 넣기 / Entity만 가능함
  • 복잡한 통계들은 Native Query 사용
package shop.mtcoding.blog.board; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import java.util.List; @RequiredArgsConstructo @Repository public class BoardPersistRepository { private final EntityManager em; @Transactional public Board save(String title, String content, String username) { // 보드 객체 만들기 Board board = new Board(title, content, username); // PC에 Data 주소 넣기(Entity만 가능함) em.persist(board); // 실행후 영속 객체가 됨 return board; } }
 
  • save() 단위 테스트하기
package shop.mtcoding.blog.Board; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; import shop.mtcoding.blog.board.Board; import shop.mtcoding.blog.board.BoardNativeRepository; import shop.mtcoding.blog.board.BoardPersistRepository; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @Import(BoardNativeRepository.class) @DataJpaTest public class boardPersistRepositoryTest { @Autowired // DI private BoardPersistRepository boardPersistRepository; @Test public void save_test() { // given String title = "제목5"; String content = "내용5"; String username = "ssar"; // when Board board = boardPersistRepository.save(title, content, username); System.out.println("save_test : " + board); // then } }
notion image
 

3. BoardRequest 만들어서 SaveDTO() 만들기

  • 비영속 객체를 PC에 넣기 위해 insert 때만 Entity로 바꾸는 메서드가 필요함
package shop.mtcoding.blog.board; import lombok.Data; public class BoardRequest { @Data public static class SaveDTO { private String title; private String content; private String username; // Entity로 바꾸는 메서드 - 비영속 객체를 PC에 넣기 위해 insert 때만 필요함 public Board toEntity(){ return new Board(title, content, username); } } }
  • 수정하기
매개변수 Board객체 집어넣기
package shop.mtcoding.blog.board; import jakarta.persistence.EntityManager; import jakarta.persistence.Query; import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; import java.util.Lis @RequiredArgsConstructor @Repository public class BoardPersistRepository { private final EntityManager em; @Transactional public Board save(Board board) { // PC에 Data 주소 넣기(Entity만 가능함) em.persist(board); // 실행후 영속 객체가 됨 return board; } }
 
  • Board로 단위 테스트하기
package shop.mtcoding.blog.Board; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.context.annotation.Import; import shop.mtcoding.blog.board.Board; import shop.mtcoding.blog.board.BoardPersistRepository; @Import(BoardPersistRepository.class) @DataJpaTest public class BoardPersistRepositoryTest { @Autowired //DI private BoardPersistRepository boardPersistRepository; @Test public void save_test() { //given Board board = new Board("제목5","내용5","ssar"); //when boardPersistRepository.save(board); //then System.out.println(board); } }
notion image
 

4. BoardController 에 save() 수정하기

package shop.mtcoding.blog.board; import ch.qos.logback.core.model.Model; import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import java.lang.annotation.Native; import java.util.List; @RequiredArgsConstructor @Controller public class BoardController { private final BoardNativeRepository boardNativeRepository; private final BoardPersistRepository boardPersistRepository; @PostMapping("/board/{id}/update") public String update(@PathVariable Integer id, String title, String content, String username){ boardNativeRepository.updateById(id, title, content, username); return "redirect:/board/"+id; } @GetMapping("/board/{id}/update-form") public String updateForm(@PathVariable (name="id") Integer id, HttpServletRequest request) { Board board = boardNativeRepository.findById(id); request.setAttribute("board", board); return "/board/update-form"; // 서버가 내부적으로 index를 요청 - 외부에서는 다이렉트 접근이 안됨 } @PostMapping("/board/{id}/delete") public String delete(@PathVariable Integer id) { // DTO 없이 구현 boardNativeRepository.deleteById(id); return "redirect:/"; } @GetMapping("/") public String index(HttpServletRequest request) { // 조회하기 List<Board> boardList = boardNativeRepository.findAll(); // 가방에 담기 request.setAttribute("boardList", boardList); return "index"; // 서버가 내부적으로 index를 요청 - 외부에서는 다이렉트 접근이 안됨 } @PostMapping("/board/save") public String save(BoardRequest.SaveDTO reqDTO) { // DTO 없이 구현 boardPersistRepository.save(reqDTO.toEntity()); return "redirect:/"; } @GetMapping("/board/save-form") public String saveForm() { return "board/save-form"; } @GetMapping("/board/{id}") public String detail(@PathVariable Integer id, HttpServletRequest request) { // Integer : 없으면 null, int : 0 Board board = boardNativeRepository.findById(id); request.setAttribute("board", board); return "board/detail"; } }
notion image
 
Share article

vosw1