질문 목록을 보기위해 컨트롤러에 /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

+ Recent posts