5.1 데이터 조회 과정
웹 페이지에서 게시글을 등록하면 서버를 통해 DB에 저장됩니다. 이렇게 DB에 저장된 데이터를 웹 페이지에 출력하는 과정은 앞서 배운 다양한 요소 간 상호 작용으로 이로어집니다.
1. 사용자가 데이터를 조회해 달라고 웹 페이지에서 URL 요청을 보냅니다.
2. 서버의 컨트롤러가 요청을 받아 해당 URL에서 찾으려는 데이터 정보를 리파지터리에 전달합니다.
3. 리파지터리는 정보를 가지고 DB에 데이터 조회를 요청합니다.
4. DB는 해당 데이터를 찾아 이를 엔티티로 반환합니다.
5. 반환된 엔티티는 모델을 통해 뷰 템플릿으로 전달됩니다.
6. 최종적으로 결과 뷰 페이지가 완성돼 사용자의 화면에 출력됩니다.
데이터를 조회하는 과정에서 각 요소의 역할을 이해했나요? 아직은 와닿지 않을 테니 실습해 보며 확인하겠습니다.
5.2 단일 데이터 조회하기
4장까지 데이터를 생성(Create) 하는 작업을 연습했습니다. 다시 한번 확인해 보겠습니다.
서버를 실행하고 localhost:8080/articles/new 페이지에서 제목은 가나다라, 내용은 1111을 입력하고 [Submit] 버튼을 클릭합니다. 인텔리제이의 로그를 보면 데이터가 1번 id를 가진 채 잘 저장된 것을 볼 수 있습니다.
이 데이터를 웹 페이지에서 확인할 수 있도록 코드를 작성해 보겠습니다.
5.2.1 URL 요청받기
DB에 저장한 데이터를 웹 페이지에서 보려면 해당 출력 페이지에 접속해야 합니다. 그러자면 URL 요청이 필요하겠죠. 여기서는 게시글 1번 id를 조회할 때 localhost:8080/articles/1, 2번 id를 조회할 때 localhost:8080/articles/2, 1000번 id를 조회할 때 localhost:8080/articles/1000에 접속하는 식으로 URL 요청을 받겠습니다.
먼저 localhost:8080/articles/1000으로 접속해 봅시다. 아무것도 안 나옵니다. 해당 URL 요청을 받아 줄 컨트롤러가 없기 때문이죠.
articles/id로 URL 요청을 했을 때 이를 받아 줄 컨트롤러를 만들겠습니다.
1. 조회할 데이터가 Article이므로 ArticleController에 코드를 추가하는 방식으로 만들겠습니다.
com.example.firstproject > controller > ArticleController 코드를 엽니다.
2. URL 요청을 받기 위해 기존 코드 맨아래에 @GetMapping() 어노테이션을 작성합니다. 괄호 안에 URL은 id에 따라 /articles/1, /articles/2, articles/3 등으로 받기로 했으므로 "/articles/{id}" 로 입력합니다. 이렇게 중괄호 안에 id를 써 주면 id는 변수로 사용됩니다.
@GetMapping("/articles/{id}") //데이터 조회 요청 접수
3. URL 요청을 받아 수행할 show()라는 메서드를 만듭니다. 메서드의 매개변수는 URL에 있는 id를 가져오는데, id 앞에 @PathVariable 어노테이션을 붙입니다. @PathVariable은 URL 요청으로 들어온 전달값을 컨트롤러의 매개변수로 가져오는 어노테이션입니다.
@GetMapping("/articles/{id}") //데이터 조회 요청 접수
public String show(@PathVariable Long id) { //매개변수로 id 받아 오기
return "";
}
4. 컨트롤러가 id를 잘 받았는지 확인해 보겠습니다. 4장에서 배운 로깅 기능을 이용해 log.info("id =" +id);를 추가합니다.
public String show(@PathVariable Long id) { //매개변수로 id 받아 오기
log.info("id="+id); //id를 잘 받았는지 확인하는 로그 찍기
return "";
}
5. 중간 점검해 봅시다. 서버를 재시작하고 localhost:8080/articles/1000으로 접속합니다. 아직 결과 페이지는 나오지 않았지만 인텔리제이의 로그를 보면 id = 1000이 잘 전달된 것을 확인할 수 있습니다.
지금까지 서버의 컨트롤러가 URL 요청을 받는 것까지 작업했습니다.
5.2.2 데이터 조회해 출력하기
다음으로 할 일은 크게 3단계로 나눌 수 있습니다.
1. id를 조회해 DB에서 해당 데이터 가져오기
2. 가져온 데이터를 모델에 등록하기
3. 조회한 데이터를 사용자에게 보여 주기 위한 뷰 페이지 만들고 반환하기
public String show(@PathVariable Long id) { //매개변수로 id 받아 오기
log.info("id="+id); //id를 잘 받았는지 확인하는 로그 찍기
//1. id를 조회해 DB에서 해당 데이터 가져오기
//2. 가져온 데이터를 모델에 등록하기
//3. 조회한 데이터를 사용자에게 보여 주기 위한 뷰 페이지 만들고 반환하기
return "";
}
- id를 조회해 데이터 가져오기
DB에서 데이터를 가져오는 주체는 리파지터리입니다. 3장에서 리파지터리를 배웠죠. 리파지터리의 구현 객체는 다음과 같이 @Autowired 어노테이션으로 주입받았습니다.
@Autowired //스프링 부트가 미리 생성해 놓은 리파지터리 객체 주입(DI)
private ArticleRepository articleRepository; //2.articleRepository 객체 선언
이 리파지터리로 DB에 저장된 데이터를 가져오겠습니다.
1. articleRepository까지 입력하고 점(.)을 찍으면 사용할 수 있는 메서드 목록이 나옵니다. 목록에서 findById(Long id)를 선택합니다. findById()는 JPA의 CrudRepository가 제공하는 메서드로, 특정 엔티티의 id 값을 기준으로 데이터를 찾아 Optional 타입으로 반환합니다. 일단 반환형을 무시하고 찾은 데이터를 Article 타입의 articleEntity 변수에 저장합니다.
//1. id를 조회해 DB에서 해당 데이터 가져오기
Article articleEntity = articleRepository.findById(id);
2. 역시 문제가 생깁니다. 빨간색 물결로 에러 표시가 뜹니다. articleRepository가 findBy(id)로 찾은 값을 반환할 때 반환형이 Article이 아니라서 생기는 문제입니다. 그렇다면 반환형은 뭘까요? 바로 Optional<Article> 타입입니다. 실제로 Article을 Optional<Article>로 수정하면 에러가 사라집니다.
//1. id를 조회해 DB에서 해당 데이터 가져오기
Optional<Article> articleEntity = articleRepository.findById(id);
앞의 문법은 자바 8버전 부터 사용할 수 있습니다. 그런데 여기서는 다른 방법을 사용하겠습니다. 코드 맨 뒤에 .orElse() 메서드를 추가하고 매개변수로 null 값을 넣습니다. 이는 id 값으로 데이터를 찾을 때 해당 id 값이 없으면 null을 반환하라는 뜻입니다. 데이터를 조회한 결과, 값이 있으면 articleEntity 변수에 값을 넣고 없으면 null을 저장하는거죠.
//1. id를 조회해 DB에서 해당 데이터 가져오기
Article articleEntity = articleRepository.findById(id).orElse(null);
- 모델에 데이터 등록하기
articleEntity에 담긴 데이터를 모델에 등록해 보겠습니다. 데이터를 모델에 등록하는 이유는 MVC 패턴에 따라 조회한 데이터를 뷰 페이지에서 사용하기 위해서입니다.
1. 모델을 사용하기 위해 show() 메서드의 매개변수로 model 객체를 받아 옵니다.
public String show(@PathVariable Long id, Model model) {
(중략)
}
2. 모델에 데이터를 등록할 때는 addAttribute() 메서드를 사용합니다. 형식은 다음과 같습니다.
형식) // name이라는 이름으로 value 객체 추가
model.addAttribute(String name, Object value)
article이라는 이름으로 articleEntity 객체를 등록합니다.
//2. 가져온 데이터를 모델에 등록하기
model.addAttribute("article",articleEntity);
- 뷰 페이지 반환하기
가져온 데이터를 모델에 등록했으니 마지막으로 사용자에게 보여 줄 뷰 페이지를 만들고 반환하겠습니다.
1. 뷰 페이지는 articles라는 디렉터리 안에 show라는 파일이 있다고 가정하고 다음과 같이 반환합니다.
//3. 조회한 데이터를 사용자에게 보여 주기 위한 뷰 페이지 만들고 반환하기
return "articles/show";
2. 그럼 실제로 show.mustache 파일을 만들어야겠죠? 탐색기의 resources > templates > articles에서 마우스 오른쪽 버튼을 누르고 New -> File을 선택한 후 show.mustache 파일을 만듭니다.
3. 3장에서 뷰 페이지를 만들 때 헤더와 푸터 개념을 배웠습니다. show.mustache 파일에도 똑같이 위쪽에 {{>layouts/header}}를 넣고 아래쪽에 {{>layouts/footer}}를 넣습니다.
{{>layouts/header}}
{{>layouts/footer}}
4. 헤더와 푸터 사이에 보고 싶은 데이터를 부트스트랩을 활용해 작성하겠습니다. 부트스트랩 홈페이지(getbootstrap.com)에 접속한 . 후책과 똑같이 실습하기 위해 v5.0.2를 선택합니다. 검색창에 table을 검색하고 목록에서 Tables를 클릭합니다. 화면의 스크롤을 내리면 기본 형식의 테이블이 보입니다. 그 아래 있는 [Copy] 버튼을 클릭해 소스 코드를 복사합니다.
5. show.mustache 파일로 돌아와 헤더와 푸터 사이에 붙여 넣습니다.
{{>layouts/header}}
<table class="table">
<thead>
<tr>
<th scope="col">#</th>
<th scope="col">First</th>
<th scope="col">Last</th>
<th scope="col">Handle</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">1</th>
<td>Mark</td>
<td>Otto</td>
<td>@mdo</td>
</tr>
<tr>
<th scope="row">2</th>
<td>Jacob</td>
<td>Thornton</td>
<td>@fat</td>
</tr>
<tr>
<th scope="row">3</th>
<td colspan="2">Larry the Bird</td>
<td>@twitter</td>
</tr>
</tbody>
</table>
{{>layouts/footer}}
6. 중간 점검해 보겠습니다. 서버를 재시작하고 localhost:8080/articles/100 페이지에 접속합니다. 추가한 표가 . 잘 나옵니다.
7. 표를 원하는 형태로 수정해 보겠습니다.
(1) 제목 행의 이름을 수정합니다.
(2) 필요 없는 코드는 삭제합니다.
(3) 3번째 내용 행에 속성들은(scope="row", colspan="2") 모두 지우고 가짜 데이터를 임시로 넣습니다.
<table class="table">
<thead>
<tr>
<th scope="col">Id</th> <!-- 1. 제목 행의 이름 수정 -->
<th scope="col">Title</th>
<th scope="col">Content</th>
</tr>
</thead>
<tbody>
<!-- 2. 삭제 -->
<tr>
<tr>
<th>1</th> <!-- 3. 속성 삭제, 가짜 데이터 넣기 -->
<td>제목1111</td>
<td>내용1111</td>
</tr>
</tbody>
</table>
8. 망치 아이콘을 클릭해 빌드한 후 localhost:8080/articles/1000 페이지에서 새로 고침합니다. 임시로 넣은 가짜 데이터가 잘 출력됩니다. 아직 DB에서 데이터를 조회하는 단계까지는 못 갔지만, DB에서 데이터를 조회한다면 어떤 식으로 출력되는지 보여 줍니다.
그러면 가짜 데이터 대신 모델에 등록한 진짜 데이터를 뷰 페이지에서 확인해 보겠습니다.
9. 앞서 모델에서 article이라는 이름으로 articleEntity를 등록했습니다. 이렇게 모델에 등록한 article은 . 뷰페이지에서 머스테치 문법인 이중중괄호({{}})를 이용해 출력합니다. 이때 {{#article}}{{/article}}과 같이 샵(#)을 이용해 열고 슬래시(/)를 이용해 닫습니다. 마치 HTML의 <시작태그></종료태그>와 비슷한데요. 이렇게 가져온 데이터를 여러 행에 걸쳐 사용할 때는 어디에서 어디까지 사용할지 범위를 지정합니다.
{{#article}}
<tr>
<tr>
<th>1</th> <!-- 3. 속성 삭제, 가짜 데이터 넣기 -->
<td>제목1111</td>
<td>내용1111</td>
</tr>
</tr>
{{/article}}
10. article의 사용 범위를 지정했으니 article에 담긴 id, title, content를 다음과 같이 이중중괄호({{}})를 이용해 가져옵니다.
{{#article}}
<tr>
<th>{{id}}</th> <!-- 3. 속성 삭제, 가짜 데이터 넣기 -->
<td>{{title}}</td>
<td>{{content}}</td>
</tr>
{{/article}}
11. article에 담긴 id, title, content가 잘 출력되는지 확인해 보겠습니다. 서버를 재시작하고 localhost:8080/articles/3에 접속합니다. 그런데 아무 데이터도 조회되지 않습니다. 왜 그럴까요?
지금 메모리 DB, 즉 휘발성 DB를 사용하고 있기 때문에 서버를 재시작할 때마다 데이터가 날아가 결과가 출력되지 않습니다. 이럴 땐 데이터를 다시 한번 생성해 줘야 합니다.
12. 데이터를 새로 추가하기 위해 localhost:8080/articles/new 페이지에 접속한 후 제목에 오늘은.. 내용에 매우 배가 고프다.. 를 입력하고 [Submit] 버튼을 클릭합니다. 인텔리제이 하단의 실행창에서 로그를 보면 1번 id를 가진 데이터가 만들어졌다고 나옵니다.
13. 웹 브라우저로 돌아가서 localhost:8080/articles/1 페이지에 접속해 보면 에러가 납니다. 에러를 추적하기 위해 인텔리제이 실행창에서 스크롤을 올려 보면 No default constructor for entity 'cohttp://m.example.firstproject.entity.Article' 메시지를 볼 수 있습니다. Article 엔티티에 기본 생성자(default constructor)가 없어서 에러가 났다는 의미입니다.
- 추가 단계 : 기본 생성자 추가하기
1. 기본 생성자를 추가하기 위해 entity > Article 파일을 엽니다. 4장에서 롬복으로 생성자 대신 @AllArgsConstructor 어노테이션을 작성했습니다. 여기에 기본 생성자도 추가해 보겠습니다.
참고로 기본 생성자란 생성자인데 매개변수가 아무것도 없는 생성자를 말합니다.
2. 기본 생성자 역시 롬복으로 간단하게 줄일 수 있습니다. 다음과 같이 @NoArgsConstructor를 추가하면 기본 생성자 코드를 작성하지 않아도 됩니다. @NoArgsConstructor는 기본 생성자를 추가해 주는 어노테이션입니다.
@AllArgsConstructor
@NoArgsConstructor //기본 생성자 추가 어노테이션
@ToString
3. 서버를 재시작합니다. 서버를 껐다 켰으니까 DB에 저장된 데이터가 날아갔겠죠. localhost:8080/articles/new에 접속해서 제목은 다시 한번.., 내용은 데이터를 추가한다!를 입력한 후 전송합니다. 실행창에 . 가보면 데이터가 1번 id로 추가된 것을 확인할 수 있습니다.
4. 드디어 데이터를 조회할 준비가 되었습니다. localhost:8080/articles/1에 다시 접속하면 방금 입력한 데이터가 잘 나옵니다.
5.2.3 실습 정리
이번 실습에서 꼭 기억해야 할 점을 주요 코드를 보면서 정리하겠습니다.
1. 사용자가 입력한 데이터를 조회하려면 먼저 URL 요청을 해야 합니다. 실습에서는 /articles/id 형식으로 URL 요청을 했습니다.
2. 컨트롤러는 @GetMapping("/articles/{id}")로 URL 요청을 받습니다. 그리고 이 URL에 포함된 id를 show() 메서드의 매개변수로 받는데, 이때 매개변수 앞에 @PathVariable 어노테이션을 붙입니다. 그래야 URL의 id를 가져올 수 있습니다.
@GetMapping("/articles/{id}")
public String show(@PathVariable Long id, Model model){
}
3. 리파지터리에서 DB에 저장된 데이터를 id로 조회할 때 findById() 메서드를 사용합니다.
특별히 조회된 데이터가 없는 경우도 처리해야 하므로 orElse() 메서드로 null이 반환되도록 합니다.
Article articleEntity = aritcleRepository.findById(id).orElse(null);
4. id로 DB에서 조회한 데이터는 모델에 article이라는 이름으로 등록합니다.
model.addAttribute("article", articleEntity);
5. 최종적으로 모델에 등록한 데이터를 뷰 페이지에서 사용할 수 있게 설정합니다. 이때 샵(#)과 슬래시(/)를 이용해 열고 닫음으로써 데이터를 사용할 수 있는 영역을 지정합니다.
{{#article}}
<tr>
<td>{{id}}</td>
<td>{{title}}</td>
<td>{{content}}</td>
</tr>
{{/article}}
우리는 이렇게 단일 데이터를 조회하는 과정을 통해 MVC, JPA, DB의 상호 작용을 이해할 수 있었습니다.
5.3 데이터 목록 조회하기
이 절에서는 단일 데이터가 아닌 여러 데이터, 즉 데이터 목록을 조회해 보겠습니다. 단일 데이터를 조회할 때와 방법은 같은데 다른 점이 한 가지 있습니다. 단일 데이터를 조회할 때는 리파지터리가 엔티티를 반환했다면, 데이터 목록을 조회할 때는 엔티티의 묶음인 리스트를 반환합니다.
그럼 직접 실습해 보겠습니다.
5.3.1 URL 요청받기
데이터 목록 조회는 localhost:8080/articles라는 URL 요청이 들어왔을 때 처리하는 것으로 하겠습니다. 이를 위해 먼저 컨트롤러부터 만들어 봅시다.
1. ArticleContorller를 엽니다. show() 메서드 아래에 index()라는 메서드를 추가하고 return 문에서는 아직 아무것도 반환하지 않습니다.
public String show(@PathVariable Long id, Model model) { //매개변수로 id 받아 오기
(중략)
}
public String index(){
return "";
}
2. index() 메서드에 @GetMapping("/articles")를 선언해 URL 요청을 받도록 합니다. 이 요청이 들어오면 index() 메서드가 수행되면서 뷰 페이지를 설정하는 코드들이 실행될 것입니다.
@GetMapping("/articles")
public String index(){
return "";
}
5.3.2 데이터 조회해 출력하기
단일 데이터를 조회할 때와 마찬가지로 3단계로 나누어 코드를 작성하겠습니다.
1. DB에서 모든 Article 데이터 가져오기
2. 가져온 Article 묶음을 모델에 등록하기
3. 사용자에게 보여 줄 뷰 페이지 설정하기
public String index(){
//1. DB에서 모든 Article 데이터 가져오기
//2. 가져온 Article 묶음을 모델에 등록하기
//3. 사용자에게 보여 줄 뷰 페이지 설정하기
return "";
}
- 모든 데이터 가져오기
1. DB에서 데이터를 가져오려면 리파지터리가 필요하다고 배웠습니다. 따라서 articleRepository()를 입력하고 점(.)을 찍은 후 이번에는 findAll()이라는 메서드를 선택합니다.
findAll()은 해당 리파지터리에 있는 모든 데이터를 가져오는 메서드입니다.
메서드를 수행한 결과는 articleEntityList라는 이름으로 받겠습니다. ArticleEntityList의 타입은 데이터의 묶음을 받아 오는 것이므로 List<Article>로 설정합니다. 이렇게 하면 DB에서 조회한 데이터 묶음을 리스트에 담긴 Article 타입으로 가져옵니다.
//1. DB에서 모든 Article 데이터 가져오기
List<Article> articleEntityList = articleRepository.findAll();
코드에 오류를 나타내는 빨간색 물결이 표시됩니다. 마우스를 findAll() 메서드에 올려 보면 findAll() 메서드가 반환하는 데이터 타입은 Iterable인데 작성한 타입은 List라서 서로 불일치한다는 메시지가 뜹니다.
이를 해결하는 방법은 3가지가 있습니다.
첫째, 캐스팅(형변환)하면 됩니다. Iterable, Collection, List 인터페이스의 상하 관계는 다음 그림과 같습니다. Iterable이 가장 상위 인터페이스입니다.
캐스팅(casting)이란 데이터 타입을 변환하는 것을 말하며 형변환이라고도 합니다. 자바에서 상속 관계가 있는 특정 객체는 상황에 따라 더 넓은 범위로 해석될 수도, 때때로 좁은 범위로 해석될 수도 있습니다. 이때 넓은 범위로 해석하는 것을 업캐스팅(upcasting), 좁은 범위로 해석하는 것을 다운캐스팅(downcasting)이라 합니다. 예를 들어 '고양이'를 '생물'로 해석했다면 업캐스팅한 것이고, '생물'에서 다시 '동물'로 해석했다면 다운캐스팅한 것입니다.
따라서 코드를 다음과 같이 수정하면 findAll() 메서드가 반환하는 데이터 타입 Iterable<Article>을 List<Article>로 다운캐스팅할 수 있습니다.
//1. DB에서 모든 Article 데이터 가져오기
List<Article> articleEntityList = (List<Article>)articleRepository.findAll();
둘째, articleEntityList의 타입을 findAll() 메서드가 반환하는 타입으로 맞추는 방법입니다. List<Article>을 Iterable<Artice>로 업캐스팅하면 오류를 해결할 수 있습니다.
//1. DB에서 모든 Article 데이터 가져오기
Iterable<Article> articleEntityList = articleRepository.findAll();
셋째, Iterable 인터페이스가 익숙하지 않다면 많이 사용하는 ArrayList를 이용할 수도 있습니다. findAll() 메서드가 Iterable이 아닌 ArrayList를 반환하도록 수정하는 것입니다. 이 책에서는 세 번째 방법으로 코드를 작성하겠습니다.
2. com.example.firstproject > repositroy > ArticleRepository를 엽니다. 코드를 보면 ArticleRepository가 CrudRepository를 상속받고 있습니다.
public interface ArticleRepository extends CrudRepository<Article, Long> {
}
여기서는 CrudRepository의 메서드를 오버라이딩해 주겠습니다. 블록 안 공간에서 마우스 오른쪽 버튼을 누르고 Generate -> Override Methods를 클릭합니다. 메서드 선택 창이 뜨면 findAll():Iterable<T>를 선택하고 [OK] 버튼을 클릭합니다.
오버라이딩(overriding이란 상위 클래스가 가지고 있는 메서드를 하위 클래스가 재정의해서 사용하는 것을 말합니다.
3. 추가한 코드를 보면 findAll() 메서드의 반환값은 기본적으로 <Article>의 Iterable 타입으로 반환하게 되어 있습니다. 이를 ArrayList로 바꿉니다.
public interface ArticleRepository extends CrudRepository<Article, Long> {
@Override
ArrayList<Article> findAll(); //Iterable -> ArrayList 수정
}
4. ArticleController로 돌아오면 빨간색 물결 표시가 사라져 타입 불일치 문제가 해결된 것을 확인할 수 있습니다.
//1. DB에서 모든 Article 데이터 가져오기
List<Article> articleEntityList = articleRepository.findAll();
물론 정확하게 하려면 다음처럼 articleEntityList의 타입을 ArrayList<Article>로 해야합니다. 하지만 ArrayList의 상위 타입인 List로도 업캐스팅할 수 있다는 점을 기억해 주세요.
//1. DB에서 모든 Article 데이터 가져오기
ArrayList<Article> articleEntityList = articleRepository.findAll();
- 모델에 데이터 등록하기
가져온 데이터를 받은 articleEntityList를 뷰 페이지로 전달할 때는 모델을 사용합니다.
1. index() 메서드의 매개변수로 model 객체를 받아 옵니다.
2. model.addAttribute() 메서드로 전달할 데이터 묶음인 articleEntityList를 "articleList"라는 이름으로 등록합니다.
public String index(Model model){ //1.model 객체 받아오기
//1. DB에서 모든 Article 데이터 가져오기
ArrayList<Article> articleEntityList = articleRepository.findAll();
//2. 가져온 Article 묶음을 모델에 등록하기
model.addAttribute("articleList",articleEntityList); //2.articleEntityList 등록
- 뷰 페이지 설정하기
1. articles 디렉터리 안에 index.mustache 파일이 뷰 페이지로 설정될 수 있도록 return 문을 작성합니다.
//3. 사용자에게 보여 줄 뷰 페이지 설정하기
return "articles/index";
2. index.mustahce 파일을 만들어 줘야겠죠. resources > template > articles에서 마우스 오른쪽 버튼을 누르고 New -> File을 선택한 후 index.mustache 파일을 생성합니다.
3. 편집기가 열리면 DB에서 조회한 데이터 목록이 출력될 수 있도록 코드를 작성합니다. 먼저 위쪽에 {{>layouts/header}}를 넣고 아래쪽에 {{>layouts/footer}}를 넣어 . 뷰 페이지의 기본 틀을 잡습니다.
{{>layouts/header}}
{{>layouts/footer}}
4. 조회한 데이터 목록을 보여 주기 위해 테이블을 작성하는데, 앞에 작성한 코드가 있으니 복사해 붙여 넣겠습니다. show.mustache 파일로 가서 <table class="table">...</table> 코드를 복사한 후 index.mustache 파일로 돌아와 헤더와 푸터 사이에 붙여 넣습니다.
{{>layouts/header}}
<table class="table">
<thead>
<tr>
<th scope="col">Id</th> <!-- 1. 제목 행의 이름 수정 -->
<th scope="col">Title</th>
<th scope="col">Content</th>
</tr>
</thead>
<tbody>
<!-- 2. 삭제 -->
{{#article}}
<tr>
<th>{{id}}</th> <!-- 3. 속성 삭제, 가짜 데이터 넣기 -->
<td>{{title}}</td>
<td>{{content}}</td>
</tr>
{{/article}}
</tbody>
</table>
{{>layouts/footer}}
5. 앞서 모델에서 articleList라는 이름으로 articleEntityList를 등록했습니다. 뷰 페이지에서는 이렇게 모델에 등록한 articleList를 받아 오면 됩니다. 따라서 복사한 코드에서 {{#article}}을 {{#articleList}}로 수정합니다. 닫는 코드도 {{/articleList}}로 수정합니다.
{{#articleList}}
<tr>
<th>{{id}}</th> <!-- 3. 속성 삭제, 가짜 데이터 넣기 -->
<td>{{title}}</td>
<td>{{content}}</td>
</tr>
{{/articleList}}
6. 잘 동작하는지 확인해 보겠습니다. 서버를 재시작하고 localhost:8080/articles로 접속합니다. 그런데 데이터가 아무것도 나오지 않네요. 서버를 껐다 켜서 DB의 데이터가 날아간 상황이니 데이터를 몇 개만 넣어 주겠습니다.
7. localhost:8080/articles/new에 접속합니다. 제목에 가가가가, 내용에 1111을 입력한 후 제출합니다. [뒤로 가기] 버튼을 클릭하고 다시 제목은 나나나나, 2222를 입력합니다. 같은 방식으로 제목은 다다다다, 내용은 3333을 추가합니다.
8. 인텔리제이의 실행창에서 로그를 보면 id가 1번, 2번, 3번인 데이터가 잘 들어간 것을 확인할 수 있습니다.
9. localhost:8080/articles에 다시 접속하면 데이터가 출력되는 것을 확인할 수 있습니다.
여기서 기억해야 할 중요한 점이 있습니다. 바로 머스테치 문법입니다.
index.mustahce 코드를 보면 {{#articleList}} {{/articleList}} 코드가 있는데, 이렇게 머스테치 문법에 쓴 변수(articleList)가 데이터 묶음인 경우 내부 코드가 반복됩니다.
방금 웹 페이지에서 확인한 데이터를 생각해 봅시다. articleList에 데이터가 총 3개 있어습니다. id가 1번, 2번, 3번인 데이터였죠. 뷰. 페이지에서 이 데이터 묶음을 출력할 때는 첫 번째 데이터를 만나면 id 1번의 id, title, content를 출력합니다. 그리고 두 번째 데이터를 만나면 id 2번의 id, title, content를 출력합니다. 마지막 세 번째 데이터를 만났을 때도 마찬가지입니다. 마치 for 문의 반복 실행과 같습니다.
이와 같이 머스테치 변수가 데이터 묶음일 경우에는 그 안쪽에 있는 코드를 반복 실행한다는 점을 기억해 주세요.
'스프링부트' 카테고리의 다른 글
7장 게시글 수정하기: Update (0) | 2025.01.22 |
---|---|
6장 게시판 내 페이지 이동하기 (2) | 2025.01.20 |
4장 롬복과 리팩터링 (2) | 2025.01.15 |
3장 게시판 만들고 새 글 작성하기: Create (3) | 2025.01.15 |
2장 MVC 패턴 이해와 실습 (2) | 2025.01.13 |