| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
- java테스트
- Visual Studio Code
- Eclipse
- 자바문법
- input
- javascript
- junit5
- html
- HashMap
- 정규식
- string
- js
- 테스트자동화
- IntelliJ
- junit
- 자바스크립트
- list
- math
- Java
- CSS
- json
- 문자열
- 자바
- 배열
- ArrayList
- 단위테스트
- Array
- vscode
- 인텔리제이
- 이클립스
- Today
- Total
어제 오늘 내일
[Spring Boot 입문 - 11] 화면 만들기 1 - 타임리프(Thymeleaf) & 목록 조회 본문
지금까지 만든 것은 데이터를 주고받는 API(서버)였습니다. 이제 사용자가 브라우저에서 볼 수 있는 화면(View)을 만들어 이 API와 연결해 보겠습니다.
우리는 SSR(Server Side Rendering) 방식인 Thymeleaf를 사용합니다.
Step 1. 의존성 확인 (build.gradle)
프로젝트 생성 시 추가했을 수도 있지만, 혹시 모르니 build.gradle에 타임리프가 있는지 확인합니다. 없다면 추가하고 Load Gradle Changes를 눌러주세요.
dependencies {
// ... 기존 의존성 ...
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
}
Step 2. 전체 조회 쿼리 추가 (Repository & Service)
메인 화면에는 "게시글 전체 목록"이 나와야 합니다. 하지만 우리는 아직 findById(단건 조회)만 만들었죠? 전체 조회 기능을 후딱 추가합시다.
1. BoardRepository.java 수정
JPA는 메소드 이름만으로 쿼리를 만들어줍니다. findAllByOrderByIdDesc는 "모든 데이터를 ID 역순(최신순)으로 가져와라"라는 뜻입니다.
public interface BoardRepository extends JpaRepository<Board, Long> {
// 전체 조회 (최신순 정렬)
List<Board> findAllByOrderByIdDesc();
}
2. BoardService.java 수정
Repository에서 가져온 Entity 리스트를 DTO 리스트로 변환해서 반환합니다.
// ... imports ...
import java.util.stream.Collectors;
import java.util.List;
@RequiredArgsConstructor
@Service
public class BoardService {
private final BoardRepository boardRepository;
// ... save, update, findById 생략 ...
// ▼▼ 전체 조회 메소드 추가 ▼▼
@Transactional(readOnly = true) // 조회 기능이므로 읽기 전용으로 설정 (성능 향상)
public List<BoardResponseDto> findAllDesc() {
return boardRepository.findAllByOrderByIdDesc().stream()
.map(BoardResponseDto::new) // Board -> BoardResponseDto 변환
.collect(Collectors.toList());
}
}
Step 3. 화면용 컨트롤러 만들기 (IndexController)
기존 BoardApiController는 JSON 데이터를 반환하는 용도였습니다.
화면(HTML)을 반환하는 컨트롤러는 보통 따로 분리해서 관리합니다.
- 위치:
src/main/java/com/example/board/controller/IndexController.java
package com.example.board.controller;
import com.example.board.service.BoardService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@RequiredArgsConstructor
@Controller // @RestController 아님! 화면을 반환할 때는 @Controller 사용
public class IndexController {
private final BoardService boardService;
@GetMapping("/") // 메인 페이지 매핑
public String index(Model model) {
// Service에서 가져온 글 목록을 'posts'라는 이름으로 model에 담아 View로 전달
model.addAttribute("posts", boardService.findAllDesc());
return "index"; // src/main/resources/templates/index.html을 찾아감
}
}
Step 4. 메인 화면 만들기 (index.html)
이제 실제 HTML 파일을 만듭니다. 디자인을 위해 Bootstrap 5 CDN을 헤더에 추가했습니다. (설치 없이 링크만 넣으면 디자인이 적용됩니다)
- 위치:
src/main/resources/templates/index.html
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>스프링부트 게시판</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1>🚀 스프링 부트 게시판</h1>
<div class="row mt-4">
<div class="col">
<button class="btn btn-primary" onclick="location.href='/posts/save'">글 등록</button>
</div>
</div>
<table class="table table-horizontal table-bordered mt-3">
<thead class="table-dark">
<tr>
<th>게시글번호</th>
<th>제목</th>
<th>작성자</th>
<th>최종수정일</th>
</tr>
</thead>
<tbody id="tbody">
<tr th:each="post : ${posts}">
<td th:text="${post.id}"></td>
<td><a th:href="@{/posts/update/{id}(id=${post.id})}" th:text="${post.title}"></a></td>
<td th:text="${post.author}"></td>
<td th:text="${#temporals.format(post.modifiedDate, 'yyyy-MM-dd HH:mm')}"></td>
</tr>
</tbody>
</table>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
코드 설명
th:each="post : ${posts}": Java의 for-each 문과 같습니다. 컨트롤러에서 넘겨준posts리스트를 하나씩 꺼내post변수에 담습니다.th:text="${post.id}": 해당 태그의 텍스트를post.id값으로 교체합니다.
✅ 결과 확인
BoardApplication을 실행(Run)합니다.- 브라우저를 켜고
http://localhost:8080에 접속합니다.
[화면은 떴는데 리스트가 비어있나요?]
H2 데이터베이스(In-Memory)를 사용 중이라면 서버를 껐다 켤 때마다 데이터가 초기화됩니다.
Postman을 이용해 지난 시간에 만든 등록 API(POST /api/v1/posts)로 데이터를 몇 개 넣고 새로고침(F5) 해보세요.
예쁜 표에 데이터가 들어간 것을 확인할 수 있습니다!
다음 단계
메인 화면은 만들었지만, "글 등록" 버튼을 눌러도 404 에러가 뜰 겁니다. 아직 등록 화면(posts-save.html)을 안 만들었기 때문이죠.
다음 12편에서는 게시글 등록 화면을 만들고, 자바스크립트(JS)를 이용해 실제로 데이터를 저장하는 기능을 구현해보겠습니다.
'IT > SpringBoot' 카테고리의 다른 글
| [Spring Boot 입문 - 12] 화면 만들기 2 - 게시글 등록 & AJAX(Fetch) 통신 (0) | 2026.02.15 |
|---|---|
| [Spring Boot 입문 - 10] 게시판 작성일/수정일 자동화하기 (JPA Auditing) (0) | 2026.02.14 |
| [Spring Boot 입문 - 9] 게시판(CRUD) 기능 만들기 - 백엔드 API 구현 (0) | 2026.02.14 |
| [Spring Boot 입문 - 8] 데이터베이스 연동? SQL 몰라도 됩니다 (feat. JPA, H2) (0) | 2026.02.13 |
| [Spring Boot 입문 - 3] 5분 컷! IntelliJ로 첫 프로젝트 만들고 실행하기 (0) | 2026.02.13 |
