5. Spring 게시판 무작정 따라하기

동적 링크 매핑, SQL 스크립트 설정, 더미 데이터 입력
HootJem's avatar
Aug 19, 2024
5. Spring 게시판 무작정 따라하기

1. 정적 링크에서 동적 매핑으로: a 태그의 href 속성 변경하기

notion image
notion image
notion image
 
기존 mustache 안에 정적 링크가 들어가 있음. 이를 controller 에서 지정한 매핑된 주소로 변경한다.
 

2. Spring Boot 데이터베이스 초기화: SQL 스크립트 설정과 에러 해결

notion image
글 목록 리스트 테스트를 위해 db(data base) 에 더미 데이터를 넣을 겁니다.
이때 ddl(데이터 정의어) 를 작성하지 않는 이유는 entity 로 테이블 구조를 만들었기 때문.
 
notion image
기본적인 쿼리문을 사용하여 작성한다.
이는 쿼리문 작성에만 해당되고 실질적으로 데이터가 입력 되지는 않아 properties 에서 설정이 필요함
# 4. Dummy spring.sql.init.data-locations=db/data.sql
해당 커맨드를 입력하고 실행하면 다음과 같은 에러를 마주치게된다.
 
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled. 2024-08-19T09:34:15.079+09:00 ERROR 15244 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Failed to initialize dependency 'dataSourceScriptDatabaseInitializer' of LoadTimeWeaverAware bean 'entityManagerFactory': Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: No data scripts found at location 'db/data.sql' at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:326) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205) ~[spring-beans-6.1.11.jar:6.1.11]
빈 = 객체
db/data.sql 의 위치를 찾을 수 없다는 것 이를 위해 classpath 를 설정해 주어야한다.
spring.sql.init.data-locations=classpath:db/data.sql
이렇게 변경한 뒤 실행해 보면 data.sql 은 찾았으나 다른 에러가 발생했음을 알 수 있다.
(하나씩 실행해 보고 콘솔을 보는 이유는 에러 발생과 해결법에 익숙해 지기 위해서임)
2024-08-19T09:38:43.466+09:00 ERROR 9984 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Failed to initialize dependency 'dataSourceScriptDatabaseInitializer' of LoadTimeWeaverAware bean 'entityManagerFactory': Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Failed to execute SQL script statement #1 of class path resource [db/data.sql]: insert into board_tb(title, content, created_at) values ('제목1', '내용1', now()) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:326) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:205) ~[spring-beans-6.1.11.jar:6.1.11] (중략) Caused by: org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "BOARD_TB" not found (this database is empty); SQL statement: insert into board_tb(title, content, created_at) values ('제목1', '내용1', now()) [42104-224]
 
이는
# 3. hibernate spring.jpa.hibernate.ddl-auto=create spring.jpa.show-sql=true # spring.jpa.defer-datasource-initialization=true # 4. Dummy spring.sql.init.data-locations=classpath:db/data.sql
CREATE 로 인해 데이터 베이스 테이블이 먼저 생성되나 초기화 순서가 잘못되었기 때문이다.
주석 처리된 코드를 추가하고 spring.jpa.defer-datasource-initialization=true (→ 하이버네이트가 테이블을 생성한 뒤 data.sql 스크립트를 실행하게 한다) 다시 실행해 보면 에러없이 실행되고 H2 console 에서 insert 된 내용을 찾아볼 수 있다.
굿👍
굿👍
 

3. db 목록 보기

클라이언트가 데이터를 요청하면 다음과 같은 방식으로 조회가 이루어진다.
notion image
  1. C (Client):
      • 사용자는 웹 브라우저를 통해 서버에 요청을 보낸다.
  1. R (Controller):
      • 컨트롤러는 사용자의 요청을 받아 처리하고, 필요한 데이터를 조회하거나 조작하여 응답을 생성하는 역할
  1. (하이버네이트) Entity Manager:
      • 하이버네이트의 엔티티 매니저는 데이터베이스와의 통신을 담당. 컨트롤러의 요청을 받아 데이터베이스에서 데이터를 조회하거나 업데이트하는 역할을 한다.
      • 엔티티 매니저는 ORM (Object-Relational Mapping) 프레임워크인 하이버네이트를 사용하여 객체와 관계형 데이터베이스 간의 매핑을 처리.
  1. DB (Database):
      • 데이터베이스는 애플리케이션이 사용하는 데이터를 저장하는 곳. 이 데이터베이스는 하이버네이트를 통해 데이터에 접근하고, 데이터를 읽거나 쓸 수 있다.
  1. 데이터 흐름:
      • 클라이언트(C)가 서버에 요청을 보내면, 컨트롤러(R)가 이를 처리하여 엔티티 매니저를 통해 데이터베이스(DB)와 상호작용한다.
      • 필요한 데이터를 조회하거나 변경한 후, 그 결과를 다시 클라이언트(C)에게 HTML 등의 형식으로 반환.
 
 
// 레포지토리 내부에 추가 @Autowired private EntityManager em; public void findAll() { Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class); // 보드객체로 매핑해서 받아옴 }
db 에서 board_tb 의 인서트된 데이터 받아오는 것
notion image
public List<Board> findAll() { Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class); // 보드객체로 매핑해서 받아옴 List<Board> boardList = query.getResultList(); return boardList; }
받아온 query 는 여러건이기 때문에 getResultList 로 받아오며 이는 Board 객체의 list 타입이다.
 

3.1 단위테스트

테스트는 given , when, eye 단계로 이루어지는데
이번 테스트에에서는 findAll 메서드에 매개변수 존재 하지 않음으로 비워둔다
@Test public void findAll_test() { // given // when boardRepository.findAll(); // eye } // 실행 성공 ~
 
notion image
notion image
에러 있는 경우 어느 부분의 에러인지 콘솔 로그 확인. 차례로 1번은 쿼리문에 오타, 2번은 컬럼명 오타이다.
 
@Test public void findAll_test() { List<Board> boardList = boardRepository.findAll(); System.out.println("사이즈 : " + boardList.size()); } /*콘솔에 결과가 잘 나온다. *Hibernate: select * from board_tb order by id desc *사이즈 : 5 **/ @Test public void findAll_test() { List<Board> boardList = boardRepository.findAll(); System.out.println("사이즈 : " + boardList.size()); for (Board board : boardList) { System.out.println("타이틀 : " + board.getTitle() + "| 내용 : " + board.getContent()); } }
notion image
  • 한글로 나오지 않고 글자가 깨질때
settings → Gradle 하단 부분 intelliJ IDEA 로 변경
notion image
 
 

Share article

[HootJem] 개발 기록 블로그