6. 게시글 목록보기 기능 만들기
게시글 쓰기 화면이 완성되었다면, 게시글 목록보기 화면도 만들어보자.
6-1. href 수정하기
먼저 아래의 mustache 파일들의 하이퍼링크 href 를 하나씩 수정하자.

header.mustache 파일에서 ‘Metacoding’ 로고를 눌렀을 때, 이동하는 하이퍼링크 설정/수정하기

그리고 이동한 list.mustache 파일에서 상세보기를 눌렀을 때, 이동할 하이퍼링크도 수정하기.

detail.mustache 파일에도 html 주소로 되어있던 것을 바꾼다.
html 주소로 되어있는 것들을 순서대로 하나씩 바꾼다.

6-2. 더미 데이터 만들기
이것이 게시글 목록보기 화면.
게시글 목록보기 화면에 뜨는 값을 내가 넣은 데이터로 바꿔볼 테다.

더미 데이터 파일 만들기
더미 데이터를 넣어서 게시글 목록보기 화면에서 더미 데이터들이 화면에 출력 되도록 해보자.
resource 폴더에 data.sql 파일을 만든다.

데이터 초기화 시, 보통은 data.sql, schema.sql 두 개를 만들어서 사용한다.
schema.sql 에는 DDL 코드를(테이블 생성코드)넣고, CREATE, ALTER..
// 예시
CREATE TABLE users (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL,
password VARCHAR(100) NOT NULL
);
data.sql 에는 초기 데이터를 삽입하는 코드를 넣는다.
// 예시
INSERT INTO users (username, password) VALUES ('user1', 'pass1');
INSERT INTO users (username, password) VALUES ('user2', 'pass2');
우리는 왜 schema.sql 를 만들지 않았는가?
→ 하이버네이트(Hibernate) 덕에 Entity 가 자동으로 create 되기 때문이다. Yay!
(application.properties 에서 spring.jpa.hibernate.ddl-auto 를 설정 했었다.)

하이버네이트를 사용하면 엔티티 클래스를 기반으로 자동으로 데이터베이스 스키마를 생성할 수 있기 때문에, schema.sql 파일을 만들지 않아도 된다.
내가 MyBatis 나 순수 Jdbc 를 하고있다면, 정석대로 schema.sql 을 따로 파일 2 개로 만들어야 한다.
아래와 같이 data.sql 파일에 더미를 만든다.

application.properties 에 더미 파일인 db/data.sql 을 연결한다.

하고 실행하면 에러가 뜰 것이다.
오류는 항상 위에서 부터 봐야 한다. 콘솔 로그는 stack trace 이기 때문에, 위의 원인만 찾으면 밑의 내용을 볼 필요가 없다.

Bean = 객체
BeanCreationException → Bean이 안만들어졌다는 에러
내용에서 확인 되는 ‘db/data.sql’ 위치에서 data scripts 를 찾을 수 없다는 말..


classpath: 를 써줘야 resource 폴더에 도달한다. 이건 문법이다.

spring.sql.init.data-locations=classpath:db/data.sql
위와 같이 수정하고 재실행 했을 때, 이번에는 다른 에러가 뜬다.
Board_tb 테이블을 찾을 수 없다는 내용.

순서는 위의 create 가 먼저 실행되게 하여야 한다.

하이버네이트 세팅에 아래와 같이 하나 더 넣어줘야 에러가 해결된다.

지금까지의 application 설정은 아래와 같다.
# 1. UTF-8
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true
# 2. H2
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.url=jdbc:h2:mem:test
spring.datasource.username=sa
# 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
더미 데이터를 만드는 이유
협업 할 때, 각자 mysql 에 만들어서 진행하게 되면, 서로 보는 데이터가 다르기 때문에 협업이 힘들기 때문 TT
ex. 한 명이 ‘회원가입’ 개발하고 한 명이 ‘로그인’ 을 개발한다면, 로그인 개발자가 ‘회원가입’ 기능이 완성될 때까지 기다릴 순 없지 않은가!
→ 기능을 독립적으로 만들 수 있어야 한다. 회원가입 안해도 회원 데이터를 DB 에 더미로 넣어 놓으면 로그인 기능을 독립적으로 만들 수 있다.
더미만 있으면, 테스트 시간이 짧아진다.
모든 프로그램은 독립적으로 만들 수 있어야 한다. 그게 아니라면 협업이 안된다.
H2 데이터베이스 세팅 확인
아래는 테이블 세팅 할 때 넣은 application.properties 의 H2 데이터베이스 세팅 부분이다.

위의 세팅은 메모리에 저장되고, 아래는 하드에 저장되는 세팅으로, 아래와 같이 하면 안됨! 주의.

6-3. 게시글 목록보기 기능 만들기
게시글 쓰기에 이어 두번째 기능을 만들어보자.
DB 에 있는 더미데이터를 불러와서 화면에 출력해보자.
MVC (Model View Controller) 패턴
Hibernate는 JPA(Java Persistence API)의 구현체로, EntityManager 인터페이스를 구현하여 데이터베이스에서 데이터를 가져오고 이를 자바 객체로 변환하는 역할을 한다.
브라우저 → Controller → Repository → Hibernate(가 EntityManager를 구현함) → DB
브라우저 ← Controller(Model) ← Repository(Model) ← EM 에서 Board 객체로 만들어서 리턴 ← DB

Board 객체로 응답한다.
Board 객체를 Model 이라 한다.
클라이언트는 보통 웹브라우저이다.
최종적으로 Controller 가 해줘야 하는 일은
→ HTML 페이지를 만들고, 필요한 데이터를 model 에 바인딩 한다. 이 과정은 템플릿 엔진을 통해 이루어진다.
대표적인 템플릿 엔진이 jsp 와 mustache 이다. (여기서는 mustache 템플릿 엔진 사용)
이렇게 생성된 HTML 은 단순 그림(정적 페이지)이 아니라, 그림에 Mdoel 데이터를 끼워넣어 동적으로 내용을 구성할 수 있다. 이때 데이터를 표시하는 부분을 뷰(View) 라고 한다.
Model 은 응답되는 데이터로, 이러한 구조를 MVC(Model, View, Controller) 패턴이라 한다.
DB 에 넣어 둔 더미데이터를 SELECT 하는 쿼리를 만들어서 그게 잘 작동하는지부터 보자.
Repository 부터 만든다.
1) Repository 에 메서드 만들기
em 을 통해 DB 에 접근할 거고, 이제는 데이터를 SELECT 불러오기 해야 하니 메서드 명을 findAll() 로 넣어준다.

insert 할 때와 동일하게 NativeQuery 문 사용.
public void findAll() {
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
}
마지막에 Board.class 를 붙여서 오브젝트 매핑(OM)을 해준다. 쿼리 적고, Board.class 해주면 끝이다.
Board.class 들어가는 애들은 @Entity 가 붙은 애들만 된다.
일반클래스 X, 엔티티로 관리되는 애들만 매핑이 된다.
오브젝트 매핑으로, query 에는 Board 객체들이 담길 것.
쿼리에 하나만 담겨 나오면 getSingleResult() / 여러개면 getResultList() 를 적용한다.

select * 로 단건이 아닌 전체 데이터를 가져오는 쿼리문을 사용했으니,
여기서는 getResultList() 사용. List 형태로 리턴 된다.
public List<Board> findAll() {
Query query = em.createNativeQuery("select * from board_tb order by id desc", Board.class);
List<Board> boardList = query.getResultList(); // 5개의 데이터니까
return boardList;
}

내장 데이터베이스(예: H2, HSQLDB 등)를 사용할 때, 해당 데이터베이스가 애플리케이션의 생명주기와 함께 관리되기 때문에, 명시적으로 연결을 닫을 필요가 없다.
= 데이터소스가 내장되어있으면 close 하지 않아도 된다.
외부 데이터베이스를 사용하는 경우에는 연결을 명시적으로 닫아야 하며, 리소스를 관리하고 성능을 최적화하기 위해 연결을 적절히 관리하는 것이 중요하다.
Spring 프레임워크에서는 일반적으로 데이터소스 풀을 사용하여 연결 관리를 자동으로 처리하므로, 직접 연결을 닫는 일이 줄어들지만, 수동으로 연결을 관리해야 하는 상황에서는 명시적으로 닫아주는 것이 필요하다.
트랜잭션은 insert, update 할 때 commit 이 필요할 때에만 붙기 때문에,
select 할 때에는 안붙여도 된다. (@Transactional 붙이지 않기)
2) RepositoryTest 에서 단위 테스트
항상 기능을 만들었다면, BoardRepositoryTest 에서 단위 테스트를 통해 기능이 잘 돌아가는지 검증 먼저 해보도록 한다.

테스트에서 실행을 하고, 콘솔 로그를 보면
Hibernate 가 어떤 쿼리를 실행하는지 알 수 있다.

테스트가 잘 돌아가는지 보려면,
Repository 로 가서 쿼리 내용을 다르게 넣어서 테스트에서 실행해보고 콘솔 로그에 무엇이 에러로 표시되는지 확인해보라.
id 를 ids 로 바꿔서 테스트를 실행해보겠다.

굿, 테스트가 제대로 실행되는 것을 확인.

이제 em을 통해 리턴된 Board 객체들이 잘들어왔는지 검증해볼 차례.
System.out.println 을 통해 확인해본다.
더미 데이터 5개를 넣고, 데이터 전체(select * )를 불러왔으니 콘솔 로그에 5가 찍힌다면 옳다구나!

더 정확하게는 아래와 같이 for 문을 통해 확인해보면 된다. 굿.


인코딩 문제 해결
만약 로그에서 확인되어야 하는 한글이 깨져서 나온다면, 메뉴바 에서 File > Settings 을 찾아가 아래와 같이 바꾸도록 한다.

Spring MVC와 Tomcat 서버의 동작 방식
오늘 배운 Spring MVC와 Tomcat 서버의 동작 방식. 뒤에서 한번 더 다룰거라, 가볍게 알고 가자.
사용자가 웹 애플리케이션에 URL을 통해 요청을 보낼 때, 이 요청은 특정 리소스(예: HTML 페이지, API 데이터 등)에 대한 요청을 나타낸다.
이때, 요청된 URL이 어떤 메서드와 매핑되는지는 Spring MVC의 컨트롤러에서 정의한다.

식별자 요청이나, 내가 처리 할 수 없는 요청이 들어오면 톰캣이 매핑된 메서드를 찾아서 해당 메서드를 실행시킨다. (적절한 메서드를 찾을 수 없는 경우 404 Not Found 오류 발생)
그 메서드는 처리 결과로 Mustache 템플릿 파일을 반환하여 클라이언트에 응답하게 된다.
Share article