사이먼's 코딩노트
[SpringBoot] Thymeleaf / 데이터 전달 및 랜더링 / Redirect 본문
[Thymeleaf 설치]
- 스프링 부트에 타임리프를 설치하고 템플릿을 사용하여 페이지를 하나 만들어봅시다.
- Thymeleaf(타임리프)는 웹 애플리케이션 개발을 위한 서버 측 템플릿 엔진으로서, 여기서 말하는 템플릿은 HTML, CSS, JavaScript, XML 및 일반 텍스트를 의미한다.
- 이번에는 HTML 템플릿을 생성하여 DB에 담겨진 전체 question 데이터를 가져와 페이지에 보여지도록 합시다.
- 먼저 타임리프를 설치하기 위해선 build.gradle에 해당 라이브러리를 implementation을 해야한다.
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
- question 데이터 전달을 위해서 QuestionController.java 클래스를 생성하고, 주소를 매핑하여 올바르게 작동하는 지 테스트를 해 볼 필요가 있다.
- 아래 코드는 QuestionController.java 클래스에 작성된 코드이다.
package com.sbs.sbb.Question;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class QuestionController {
@GetMapping("/question/list")
public String list() {
return "question_list";
}
}
- @Controller 어노테이션은 해당 클래스가 컨트롤러의 역할을 한다는 것을 알려주는 용도이다.
- @GetMapping을 통해 localhost:8090/question/list의 URL 경로를 매핑한다.
- 실제로 해당 주소로 접속하게 되면 return 값인 question_list라는 문자열이 출력되는 것을 볼 수 있다.
- 하지만 보통 브러우저에 응답하는 문자열은 위의 예시처럼 자바 코드에서 직접 만들지 않는다.
- 아래는 templates라는 패키지를 생성하여 question_list.html 템플릿을 생성해 question 목록 페이지를 만든 모습이다.
<h1 style="color: red;">안녕하세요</h1>
- 템플릿 명이 question_list.html인 이유는 QuestionController.java 에서 return 값을 question_list로 반환했기 때문에 템플릿 명을 동일하게 맞춰야한다.
- 다시 로컬 서버를 실행하여 localhost:8090/question/list에 접속하면 아래와 같이 빨간 글의 '안녕하세요'가 출력된다.
[데이터 전달 및 랜더링]
- 템플릿이 적용된 모습을 확인했다면, 이번에는 question 목록이 담긴 데이터를 조회하여 이를 템플릿을 통해 화면에 전달해봅시다.
- question 목록과 관련된 데이터를 조회하기 위해서는 questionRepository를 사용해야 한다.
- QuestionRepository로 조회한 question 목록 데이터는 Model 클래스를 사용하여 템플릿에 전달할 수 있다.
- 아래는 수정된 QuestionController.java 클래스이다.
package com.sbs.sbb.Question;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
@Controller
@RequiredArgsConstructor
public class QuestionController {
private final QuestionRepository questionRepository;
@GetMapping("/question/list")
public String list(Model model) {
List<Question> questionList = this.questionRepository.findAll();
model.addAttribute("questionList", questionList);
return "question_list";
}
}
- 자바의 MVC를 생각해보면 Controller -> Service -> Repository의 순서가 맞지만, 현재 코드는 Service가 도입되어 있지 않아 임시적으로 Controller에서 바로 Repository로 전달되었다. 반드시 후에 QuestionService 클래스를 생성하여 해당 실행 경로를 수정해야한다.
- 데이터 조회를 위한 questionRepository 객체를 생성하였고, @Autowired를 대신 @RequiredArgsConstructor 어노테이션을 사용하였다.
- @RequiredArgsConstructor 어노테이션은 QuestionController 생성자를 통해 QuestionRepository 객체를 생성하는 역할이라고 생각하면 좋다. 이 때 final 속성을 반드시 붙혀줘야 한다.
- list() 메서드의 매개변수로 Model을 지정하면 Model 객체가 자동으로 생성된다.
- findAll() 메서드를 통해 question 목록을 조회하고 List 형식의 questionList을 생성하여 해당 데이터를 가져오고 Model 객체에 questionList 라는 이름으로 저장했다.
- 여기서 Model 객체는 자바 클래스와 템플릿 간의 연결 고리 역할을 한다. Model 객체에 값을 담아두면 템플릿에서 그 값을 바로 사용할 수 있다.
[Question 데이터 가져오기]
- 아래는 이제 question_list.html 템플릿에 해당 데이터들을 가져오기 위해 테이블을 사용하여 코드를 작성한 모습이다.
<table border="1">
<thead>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
<tr th:each="question : ${questionList}">
<td>
<a th:text="${question.id}" th:href="@{|/question/detail/${question.id}|}"></a>
</td>
<td>
<a th:text="${question.subject}" th:href="@{|/question/detail/${question.id}|}"></a>
</td>
<td th:text="${question.createDate}"></td>
</tr>
</tbody>
</table>
- 각 속성에 작성된 th: 는 타임리프에서 사용되는 속성임을 나타내는데, 이 부분이 자바 코드와 연결된다.
- QuestionController.java 클래스에서 Model 객체에 저장된 이름 questionList를 그대로 가져와 <tr th:each="question : ${questionList}"> 에 적용하였다. 해당 코드는 questionList에 저장된 데이터를 하나씩 꺼내 question 변수에 대입한 후 questionList의 개수만큼 반복하며 문장을 출력하라는 뜻이다.
- 다시 말해, 몇 개의 question 데이터인지 상관없이 반복문을 통해 question 변수에 담아서 가져올 수 있다는 뜻이다.
- th:text="${question.id}"은 question 객체의 id를 출력한다.
- 나머지 question.subject, question.createDate도 모두 같은 의미의 같은 역할을 한다.
- 이렇게 데이터를 전달하여 템플릿에서 성공적으로 나열하는 것을 랜더링한다고 표현하기도 한다.
- 다시 로컬 서버를 실행하여 localhost:8090/question/list에 접속하면 아래와 같이 테이블 형식에 맞춰 모든 question 데이터가 출력된다.
[Redirect]
- 서버의 URL을 요청할 때 도메인 명 뒤에 아무런 주소도 덧붙이지 않는 URL을 Root URL이라고 하고, Root URL을 요청했을 때 보여지는 페이지를 메인 페이지라고 한다.
- 현재 진행중인 Sbb 서비스도 question 목록을 메인 페이지로 정하고, Root URL을 요청했을 때 question 목록 화면으로 이동하도록 만들어봅시다.
- 그리고 위와 같이 사용자가 처음 요청한 URL이 아닌, 다른 URL로 보내는 것을 Redirect(리다이렉트) 라고 한다.
- 현재 localhost:8090 인 Root URL로 접속하게 되면 스프링 시큐리티를 적용하였기 때문에 로그인 과정은 생략하게 되고 404 에러 페이지가 나타나게 된다.
- MainController.java 클래스를 아래와 같이 수정하여 404 에러 페이지를 피하고 바로 localhost:8090/question/list 페이지가 보이도록 합시다.
package com.sbs.sbb;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MainController {
@GetMapping("/sbb")
@ResponseBody
public String index() {
return "안녕하세요!!!";
}
@GetMapping("/")
public String root() {
return "redirect:/question/list";
}
}
- @GetMapping 어노테이션을 통해 Root URL을 매핑하고 root() 메서드에 return 값을 redirect:/question/list 로 반환하면 우리가 원하는 대로 리다이렉트하여 localhost:8090/question/list 페이지로 바로 이동하게 된다.
- 위에서 잠깐 언급했지만, HTTP 응답 상태 코드에는 404 외에도 몇 가지가 존재한다.
- 200번 대는 성공을 의미, 300번 대는 리다이렉트를 의미, 400번 대는 고객의 잘못으로 인한 실패를 의미, 500번 대는 서버의 잘못으로 인한 실패를 의미한다.
- 응답 코드를 보고 HTTP 동작의 어떤 부분이 문제인지 캐치하는 것도 중요한 디버깅의 시작이 될 수 있다.
반응형
'Java > SpringBoot' 카테고리의 다른 글
[SpringBoot] Prefix 적용 / Form 만들기 (0) | 2024.05.09 |
---|---|
[SpringBoot] Detail 링크 및 페이지 추가 / 예외처리 (0) | 2024.05.09 |
[SpringBoot] Repository로 DB 관리하기(3) (0) | 2024.05.07 |
[SpringBoot] Repository로 DB 관리하기(2) (0) | 2024.05.07 |
[SpringBoot] DB 테이블 매핑 / Repository로 DB 관리하기(1) (0) | 2024.05.07 |