질문 목록을 보기위해 컨트롤러에 /question/list 라는 URL을 작성.
package com.myspringboot.question 경로에 QuestionController.java 생성
QuestionController.java
package com.myspringboot.question;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class QuestionController {
@RequestMapping("/question/list")
@ResponseBody
public String list() {
return "question list";
}
}
추가로 화면을 그려줄 템플릿을 설정하기 위해 build.gradle 파일에 아래 내용을 추가한다.
(... 생략 ...)
dependencies {
(... 생략 ...)
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'
}
(... 생략 ...)
템플릿은 자바 코드를 삽입할 수 있는 HTML 형식의 파일이다. 여기에서는 타임리프 템플릿을 사용한다.
진행 중에 패키지 구조 변경이 필요하여 다음과 같이 변경하였다.
answer와 question 패키지가 ssh 아래로 들어갔다.
그 이유는 기존에 ssh 밖으로 question 과 answer 패키지를 뺐을 때 Controller가 인식이 되지 않아서이다.
기본적으로 Spring Boot 가 시작되는 시작점은 xxxApplication.java이다.
메인 클래스에는 @SpringBootApplication 어노테이션이 붙어있는데 이곳이 시작점이다.
이 어노테이션은 @Configuration, @EnableAutoConfiguration, @ComponentScan 3가지를 하나로 합친 것이다.
각각의 기능은
- @Configuration : 해당 클래스가 설정 파일임을 알려주는 용도
- @EnableAutoConfiguration : 스프링의 다양한 설정이 자동으로 구성되고 완료됨
- @ComponentScan : 자동으로 컴포넌트 클래스를 검색하여 컴포넌트와 빈 클래스를 Spring Application Context에 등록함. (단, 메인 클래스가 위치한 패키지부터 이하 모든 클래스를 검색하여 Bean으로 등록)
여기서, 패키지 구조가 다르면 @ComponentScan의 역할이 수행되지 않기에 등록이 되지 않는다.
시작점인 메인클래스가 위치한 패키지의 하위에 있는 클래스들을 검색하여 Bean으로 등록하기에 하위 패키지에 속하지 않는다면 스프링 컨테이너는 해당 클래스를 Bean으로 등록하지 않게 된다.
메인클래스에 @ComponentScan 어노테이션을 쓰면 해결되기는 하나 굳이 패키지를 하위가 아닌 다르게 두어야 할 필요가 없이게 패키지 구조를 변경하였다.
패키지 변경 후 QuestionController 에 작성한 "/question/list" URL로 접속하면 아래와 같이 템플릿이 정상적으로 뜨는것을 확인할 수 있다.
데이터 조회하여 템플릿에 전달하기
Question 리포지터리를 통해서 데이터를 조회한 후 Model 클래스를 사용하여 템플릿에 전달할 수 있다.
QuestionController.java
package com.myspringboot.ssh.question;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
@Controller
public class QuestionController {
private final QuestionRepository questionRepository;
@RequestMapping("/question/list")
public String list(Model model) {
// Model 객체는 따로 생성할 필요없이 컨트롤러 메서드의 매개변수로 지정하기만 하면
// 스프링부트가 자동으로 Model 객체를 생성한다.
List<Question> questionList = questionRepository.findAll();
model.addAttribute("questionList", questionList);
return "question_list";
}
}
- @RequiredArgsConstructor 애너테이션으로 questionRepository 속성을 포함하는 생성자를 생성
@RequiredArgsConstructor는 롬복이 제공하는 애너테이션으로 final이 붙은 속성을 포함하는 생성자를 자동으로 생성하는 역할을 한다. 롬복의 @Getter, @Setter가 자동으로 Getter, Setter 메서드를 생성하는 것과 마찬가지로 @RequiredArgsConstructor는 자동으로 생성자를 생성한다. 따라서 스프링 의존성 주입 규칙에 의해 questionRepository 객체가 자동으로 주입된다.
스프링의 의존성 주입(Dependency Injection) 방식 3가지
- @Autowired 속성 - 속성에 @Autowired 애너테이션을 적용하여 객체를 주입하는 방식
- 생성자 - 생성자를 작성하여 객체를 주입하는 방식 (권장하는 방식)
- Setter - Setter 메서드를 작성하여 객체를 주입하는 방식 (메서드에 @Autowired 애너테이션 적용이 필요하다.)
테스트코드(SbbApplicationTests.java)에서는 속성에 @Autowired 애너테이션을 사용하여 객체를 주입했다.
question_list.html
<table>
<thead>
<tr>
<th>제목</th>
<th>작성일시</th>
</tr>
</thead>
<tbody>
<tr th:each="question : ${questionList}">
<td th:text="${question.subject}"></td>
<td th:text="${question.createDate}"></td>
</tr>
</tbody>
</table>
실행결과
출처 : https://wikidocs.net/161186
'Backend > Spring Boot' 카테고리의 다른 글
[Spring Boot] ROOT URL (0) | 2022.08.17 |
---|---|
[Spring boot] 자주 사용하는 타임리프의 속성 (0) | 2022.08.17 |
[Spring Boot] 도메인 나누기 (0) | 2022.08.10 |
[Spring Boot] JPA Repository (3/3) (0) | 2022.08.10 |
[Spring Boot] JPA Repository (2/3) (0) | 2022.08.08 |