내배캠/Spring

[내일배움캠프/백엔드] 기초 Spring 3주차 강의

jy3574 2024. 11. 5. 20:00

<목차>

1. MVC 패턴

-Template Engine

-MVC 패턴 개요

-MVC 패턴

-MVC 패턴의 문제점

-프론트 컨트롤러 패턴

-어댑터 패턴

 

2. Spring MVC

-Spring MVC 구조

-Dispatcher Servlet

-Spring MVC의 주요 Interface

-Controller Interface

-Spring Boot의 Handler Mapping, Handler Adapter

-HttpRequestHandler로 알아보는 Spring MVC 동작 순서

-View Resolver

-Spring Boot의 ViewResolver

-InternalResourceViewResolver로 알아보는 Spring MVC 동작순서


Template Engine

-동적인 웹 페이지를 생성하기 위해 사용되는 도구이며 템플릿을 기반으로 정적인 부분과 동적인 데이터를 결합하여 HTML, XML 등의 문서를 생성하는 역할을 수행한다.

-우리가 흔히 말하는 UI(User Interface)를 만들며, SSR(Server Side Rendering)에 사용된다.

*템플릿 엔진이 나온 이유

-자바 코드로 HTML을 만들어 내는 것이 아닌 HTML 문서에 동적으로 변경해야 하는 부분만 자바 코드를 넣을 수 있다면 더 편리하다.

 

*대표적인 템플릿 엔진

1. Thymeleaf

-Spring과 통합이 잘 되어있다.

-다양한 기능을 포함하고 있다.

 

2. JSP(Java Server Pages)

-예전에는 많이 사용했으나, 현재는 안쓰는 추세

 

3. FreeMarker

 

4. Velocity

 

5. Mustache

 

 

MVC 패턴 개요

-Servlet이나 JSP 만으로 비지니스 로직과 View Rendering 까지 모두 처리하면 너무 많은 역할을 하게 되고 유지보수가 굉장히 어려워져서 고안된 패턴이다. (→책임이 너무 많음)

-Web Application은 일반적으로 MVC(Model View Controller) 패턴을 사용한다.

 

1. Servlet 예시

@WebServlet("/hello-world")
public class HelloWorldServlet extends HttpServlet {

// User 저장소
    private UserRepository repository = new UserRepository();
    
    public HelloWorldServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {
        
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        
        try {
            // 비지니스 로직을 처리하는 코드
            // 파라미터 조회 
            String userIdParam = request.getParameter("userId");
            Long userId = null;
            if (userIdParam != null) {
                userId = Long.parseLong(userIdParam);
            }
            
            // 회원 조회 
            String userInfo = repository.findById(userId);
            
            // 화면을 그리는 코드 START
            out.println("<h1>Hello World!</h1>");
            out.println("<div>조회한 회원의 정보: " + userInfo + "</div>");
            // 화면을 그리는 코드 END
            
           
        } catch (NumberFormatException e) {
        // parsing 에러가 발생한 경우
            out.println("<div>Invalid user ID format</div>");
        } finally {
            out.close();
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
        throws ServletException, IOException {        
        doGet(request, response);
    }
}

 

*Servlet 문제점

-화면을 그리는 View 영역과 비지니스 로직이 Servlet 하나에 모두 섞여있다.

-책임을 너무 많이 가지고 있다.

 

*Servlet 동작 순서

1. 사용자가 Client(브라우저)를 통해 서버에 HTTP Request 즉, API 요청을 한다.

2. 요청을 받은 Servlet 컨테이너는 HttpServletRequest, HttpServletResponse 객체를 생성한다.

3. 설정된 정보 (URL, HTTP Method)를 통해 어떠한 Servlet에 대한 요청인지 찾는다.

4. 해당 Servlet에서 service 메서드를 호출한 뒤 브라우저의 요청 Method에 따라 doGet() 혹은 doPost() 등의 메서드를 호출한다.

5. 서버에서 응답을 생성한 뒤 HttpServletResponse 객체에 응답을 담아 Client(브라우저)에 반환한다.

6. 응답이 완료되면 생성한 HttpServletRequest, HttpServletResponse 객체를 소멸한다.

 

2. JSP 예시

-Servlet 코드에서 HTML을 만드는 부분인 View가 분리되었다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!-- HTML 코드... -->
<!-- <%...%> 영역에는 Java 코드를 사용할 수 있다. -->
    <%
    // 게시글 저장소 싱글톤으로 인스턴스 생성
    BoardRepository boardRepository = BoardRepository.getInstance();
    
    // 게시글 제목, 내용 
        String title = request.getParameter("title");
        String content = request.getParameter("content");
        
        // 게시글 객체 생성
        Board board = new Baord(title, content);
        
        // 게시글 객체 저장
        repository.save(board);
        
    %>
    <div>
        ID : <input type ="text" name = "id" value="<%=id %>">
    </div>
<!-- JSP 코드... -->
<!-- HTML 코드... -->
    <jsp:forward page="<%=url %>" />
</body>
</html>

 

*Servlet 과 JSP 구조

 

*Servlet, JSP 방식의 문제점

-Servlet 만을 사용한 경우 View를 위한 코드와 비지니스 로직을 처리하는 코드가 Servlet에 모두 존재하여 유지보수가 어려워진다.

-JSP를 사용하여 View를 분리하였지만 비지니스 로직의 일부가 JSP 파일 안에 존재한다. 여전히 책임이 많아 유지보수가 어렵다.

 

 

MVC 패턴

-하나의 Servlet이나 JSP로 처리하던 것들을 Model, View, Controller 영역으로 나눈 것이다.

 

*핵심 내용

-View가 분리된 이유의 핵심은 변경이다.

-기획이 변하지 않는 이상 비지니스 로직과 View의 수정 원인은 별개로 발생한다.

  • 화면 구성에 수정이 발생하면 View만 변경
  • 요구 사항에 수정이 발생하는 경우 비지니스 로직 변경

-서로 연관이 없는 코드끼리 함께 존재할 필요가 없다. = 완전히 분리

 

*MVC 패턴 구조

 

*Controller

-예시 코드에서 Servlet에 해당하는 영역이다.

1. HTTP Request를 전달 받아 파라미터를 검증한다.

2. 비지니스 로직을 실행한다.

  • 비지니스 로직을 Controller에 포함하게 되면 Controller가 너무 많은 역할을 담당하게 되어 일반적으로 Service Layer를 별도로 만들어서 처리한다.
  • Database와 상호작용하는 Layer를 따로 구분하여 Repository Layer를 추가로 구성한다.
  • Controller도 비지니스 로직을 포함할 수 있지만 일반적으로 Service Layer를 호출하는 역할을 담당한다.

3. View에 전달할 결과를 조회하여 Model 객체에 임시로 저장한다.

 

*Model

1. View에 출력할 Data를 저장하는 객체이다.

2. View는 비지니스 로직이나 Data 접근을 몰라도 되고 View Rendering에만 집중하면 된다. (책임분리)

 

*View

-예시 코드에서 JSP에 해당하는 영역이다.

1. Model 객체에 담겨져 있는 Data를 사용하여 화면을 Rendering 한다.

 

 

MVC 패턴의 문제점

-MVC 패턴을 적용 후 View의 역할은 필요한 데이터를 Model에서 참조하여 화면을 그리는 역할만 수행하면 된다.

-하지만, Controller에 해당하는 부분은 여전히 문제를 가지고 있다.

 

*MVC 패턴 적용

*문제점

1. dispatcher.forward(request, response) View로 이동하는 forward가 항상 중복 호출된다.

2. String path="/WEB-INF/views?new-form.jsp" View의 path를 입력(중복작업)한다.

  • jsp 파일의 경로 혹은 이름이 바뀌면 해당 코드가 변경되어야 한다.
  • JSP 이외의 확장자를 사용하려면 전체가 변경되어야 한다.

3. HttpServletResponse 객체를 사용하는 경우가 적다. (JSP에서 모두 해결하기 때문)

  • HttpServletRequest와 HttpServletResponse는 Test 코드를 작성하기도 매우 힘들다.

4. 공통 기능이 추가될수록 Controller에서 처리해야 하는 부분들이 많아진다.

 

*공통 기능 처리

-모든 컨트롤러에서 공통으로 적용되는 기능을 뜻한다. (ex. Log 출력, 인증, 인가 등)

+공통 기능을 Method로 분리하여 각각의 컨트롤러에서 사용하면 되는 것 아닌가?

-공통 기능으로 만들어 놓은 Method 또한 항상 중복적으로 호출이 필요하다. 또한, 사람인 개발자가 작업하다보면 Method를 호출하는 일을 깜빡할 수도 있고 Method가 많아지면 많아질수록 Controller의 책임이 점점 커진다. 따라서 Method를 분리하여도 여전히 해결하지 못하는 문제점으로 남는다.

 

 

프론트 컨트롤러 패턴

-Servlet(Controller)이 호출되기 전에 공통 기능을 하나의 Servlet에서 처리해주는 패턴

-프론트 컨트롤러(Servlet) 하나에 모든 크라이언트측 요청이 들어온다.

-입구가 오직 하나, 프론트 컨트롤러(Servlet)에서 공통 기능을 처리하면 된다.

 

*프론트 컨트롤러 패턴 구조

 

*프론트 컨트롤러의 역할

1. 모든 요청을 하나의 프론트 컨트롤러가 받는다.

2. 공통 기능을 처리한다.

3. 요청을 처리할 수 있는 Controller를 찾아서 호출한다. (Controller Mapping)

4. 프론트 컨트롤러를 제외한 나머지 컨트롤러는 Servlet을 사용하지 않아도 된다.

  • 일반 Controller들을 HttpServlet을 상속받거나, @WebServlet을 사용하지 않아도 된다.

*프론트 컨트롤러 의문점

-프론트 컨트롤러를 사용하면 모든 컨트롤러에서 같은 형태의 응답을 해야하는가?

-위 그림처럼 공통 로직에 모든 컨트롤러가 연결되기 위해서는 모든 컨트롤러가 return 하는 결과의 형태가 동일해야한다.

-하지만, Controller마다 로직이나 응답해야하는 결과는 당연히 다를테고 응답을 동일하게 맞추려고 한다면 해당 애플리케이션은 확장성, 유지보수성을 잃는다.

-공통 로직에서 응답별로 퍼즐을 다시 하나하나 처리할 수 있으나 공통 부분의 책임이 너무 커지게 된다. 또한, 컨트롤러에서 반환되는 결과가 달라지면 공통처리 부분의 변경 또한 불가피하다.

-여기서 고안된 것이 어댑터 패턴이다.

 

 

어댑터 패턴

-다양한 컨트롤러(Handler)를 유연하게 만들기 위해 어댑터 패턴을 도입하게 되었다.

-컨트롤러들은 동일한 인터페이스를 구현하도록 하고 해당 인터페이스와 공통 로직 사이에 어댑터를 두어 유연하게 만든다.

-서로 다른 인터페이스를 갖는 두 클래스를 연결해주는 패턴이다.

 

**어댑터 : 다른 전기나 기계 장치를 서로 연결해서 작동할 수 있도록 만들어 주는 결합 도구

 

*어댑터 패턴 구조

1. 컨트롤러(Handler)는 비지니스 로직을 처리하고 알맞은 결과를 반환한다.

2. 어댑터는 공통 로직과 컨트롤러(Handler)가 자연스럽게 연결되도록 한다.

3. 프론트 컨트롤러는 공통으로 처리되는 로직을 수행한다.

 

*어댑터 패턴 장점

-프론트 컨트롤러, 어댑터, 핸들러 모두 각자의 역할만 수행한다.(책임분리)

-새로운 컨트롤러(Handler)가 추가되어도 컨트롤러와 어댑터만 추가한다면 공통 로직의 변경이 발생하지 않는다.

 

<요약>

1. Servlet 사용

-비지니스 로직을 처리하는 코드와 화면을 그리는 View 코드가 함께 존재하는 문제

 

2. JSP 사용

-View에 해당하는 코드를 분리하였지만, 여전히 비지니스 로직을 JSP에 포함하는 문제

 

3. MVC 패턴 사용

-공통 로직을 처리하는 것에 코드가 중복되는 문제

 

4. 프론트 컨트롤러 패턴 사용

-공통 로직을 하나의 입구에서 처리하기 위해서 프론트 컨트롤러 패턴 적용

-각각의 핸들러 호출 후 응답을 프론트 컨트롤러에 맞게 변형시켜야하는 문제

 

5. Spring MVC 사용

-프론트 컨트롤러 패턴, 어댑터 패턴이 모두 적용된 현재

-우리가 사용하는 Spring을 이용한 Web Application 개발 방식에 사용됨

-Spring은 MVC 패턴에 프론트 컨트롤러 패턴, 어댑터 패턴이 적용되어 있다.

 

 

Spring MVC 구조

-Spring은 MVC 패턴에 프론트 컨트롤러 패턴, 어댑터 패턴이 적용된 구조를 가지고 있다.

 

*MVC 패턴 구조

1. 요청이 오면 Controller에서 파라미터 정보 확인하여 비지니스 로직을 실행한다.

2. 비지니스 로직의 결과 Data를 Model에 담아서 View에 전달해준다.

3. View는 모델의 Data를 참조하여 화면을 그려준다.

 

*Spring MVC 구조

-DispatcherServlet : Spring의 프론트 컨트롤러

-View : 인터페이스로 구성되어 있다. / 확장성을 가지고 있다.

 

*실행순서

1. Client로 부터 HTTP 요청(Request)을 받는다.

 

2. Handler 조회

-Handler Mapping을 통해 요청 URL에 Mapping된 Handler(Controller)를 조회

 

3. Handler를 처리할 Adapter 조회

-Handler를 처리할 수 있는 Handler Adapter를 조회

 

4. Handler Adapter 실행(handle)

-알맞은 어댑터가 존재한다면 Handler Adapter에게 요청을 위임한다.

 

5. Handler 실행(호출)

-Handler Adapter가 실제 Handler(Controller)를 호출하여 실행 및 결과 반환

 

6. Model And View 반환(return)

-Handler Adapter는 Handler가 반환하는 정보를 ModelAndView 객체로 변환하여 반환

 

7. ViewResolver 호출(알맞은 View 요청)

-View Resolver를 찾고 실행

 

8. View 반환

-View Resolver는 View의 논리 이름을 물리 이름으로 전환하는 역할을 수행하고 Rendering 역할을 담당하는 View 객체를 반환

 

9. View Rendering

-View를 통해서 View를 Rendering

 

<요약>

-Dispatcher Servlet

  1. 클라이언트 HTTP Request를 알맞게 파싱하고 클라이언트에게 알맞은 응답을 반환
  2. 핸들러 목록 정보를 알고 있다.
  3. 핸들러 어댑터 목록 정보를 알고 있다.

-Handler Adapter

  1. 자신이 처리할 수 있는 Handler인지 확인할 수 있는 기능(Method)이 필요하다.
  2. 프론트 컨트롤러에서 요청을 위임받았을 때 핸들러에게 요청을 지시하는 기능이 필요하다.
  3. return시 Handler로부터 전달받은 결과를 알맞은 응답으로 변환한다.

-Handler

  1. 요청에 대한 로직을 수행하는 기능이 필요하다.

 

Dispatcher Servlet

-Spring MVC의 프론트 컨트롤러는 Disppatcher Servlet(Servlet의 한 종류)이다.

 

*IntelliJ Class Diagram

1. Dispatcher Servlet은 HttpServlet을 상속 받아서 사용하고 Servlet의 한 종류이다.

2. Spring Boot는 Dispatcher Servlet을 서블릿으로 자동으로 등록(내장 Tomcat WAS를 실행하면서 등록한다)하고 모든 URL 경로에 대해서 Mapping한다. →(urlPatterns="/")

3. 더 자세한 URL 경로가 높은 우선순위를 가진다.

-개발자가 만들 Servlet이 항상 우선순위가 높아서 실행된다.

 

*DispatcherServlet의 service()

1. Servlet이 호출되면 HttpServlet이 제공하는 service()가 호출된다.

2. Spring MVC는 DispatcherServlet의 부모인 FrameworkServlet에서 service()를 Override해두었다.

3. FrameworkServlet.service()를 시작으로 여러 메서드가 호출됨과 동시에 가장 중요한 DispatcherServlet.doDispatch()가 호출된다.

protected void doDispatch() {
...
// 1. 핸들러 조회
mappedHandler = getHandler(processedRequest); 
if (mappedHandler == null) {
noHandlerFound(processedRequest, response); // NotFound 404
}

// 2. 핸들러 어댑터 조회 : 핸들러를 처리할 수 있는 어댑터
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

// 3. 핸들러 어댑터 실행
// 4. 핸들러 어댑터를 통해 핸들러 실행 
// 5. ModelAndView 반환 
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 여기 안에서 render   
processDispatchResult(processedRequest, response, mappedHandler, mv,dispatchException);
...
}


// processDispatchResult()
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {

if (mv != null && !mv.wasCleared()) {
// View Render 호출
render(mv, request, response);
if (errorView) {
WebUtils.clearErrorRequestAttributes(request);
}
}
}

// render()
protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
View view;
String viewName = mv.getViewName();

// 6. ViewResolver를 통해 View 조회
// 7. View 반환
view = resolveViewName(viewName, mv.getModelInternal(), locale, request);

// 8. View Rendering
view.render(mv.getModelInternal(), request, response);
}

 

 

Spring MVC의 주요 Interface

-Spring MVC는 DispatcherServlet 코드의 변경 없이 기능 변경 및 확장이 가능하다.(기능들이 대부분 Interface로 만들어져있기 때문)

-인터페이스를 implements하여 구현하면 내가 만든 클래스를 사용할 수 있다. (다형성)

 

*org.springframework.web.servlet

1. HandlerMapping

2. HandlerAdapter

3. ViewResolver

4. View

 

*이 복잡한 Spring MVC의 구조와 구성 요소들을 모두 알아야 하나?

1. 복잡하게 구성되고 숨겨져있는 Spring Framework의 모든 내부 구조를 알 필요는 없다.

2. 이미 많은 개발자들의 요구사항에 의해 다양한 인터페이스 구현체들이 만들어져 있다.

3. 전체적인 동작 방식을 알아야 어떤 부분에서 문제가 발생했는지 파악할 수 있다.

4. 개발자가 구현하고자 하는 기능이 어떤 인터페이스에서 확장해야 하는지 파악할 수 있다.

 

 

Controller Interface

-Controller Interface를 implements하여 구현하게되면 개발자가 원하는 Controller(Handler)를 사용할 수 있게 된다.

 

-구현 예시

package com.example.springbasicmvc.controller;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.Controller;

// Spring Bean 이름을 URL로 설정
@Component("/example-controller")
public class ExampleController implements Controller {

    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        System.out.println("example-controller가 호출 되었습니다.");
        return null;
    }
}

 

-http://localhost:8080/example-controller로 HTTP 요청을 하게 되면 응답 결과가 반환된다.

 

*@Component

-Spring Bean에 등록하는 역할을 수행한다.

  • Spring Bean은 애플리케이션 구성 요소를 정의하는 객체이다.
  • 마치 Servlet이 Servlet Container에 등록되는 것과 같다.

*ExampleController는 Spring MVC 구조에서 Handler Mapping, Handler Adapter가 해당 컨트롤러(핸들러)가 호출되도록 만들어 준다.

1. Handler Mapping

-핸들러 매핑에서 ExampleController를 찾을 수 있어야한다.

→Spring Bean의 이름으로 핸들러를 찾을 수 있는 핸들러 매핑이 필요하다.

 

2. Handler Adapter

-Handler Mapping을 통해 찾은 핸들러를 실행할 수 있는 Handler Adapter가 필요

→Controller Interface를 실행할 수 있는 Handler Adapter를 찾고 실행한다.

 

+Spring Boot를 사용하면 이미 개발에 필요한 HandlerMapping과 HandlerAdapter가 대부분 구현되어 있어서 개발자가 직접 HandlerMapping과 HandlerAdapter를 구현하는 일은 거의 없다.

 

 

Spring Boot의 Handler Mapping, Handler Adapter

-Spring Boot를 사용하면 개발에 필요하여 자동으로 등록되는 HandlerMapping과 HandlerAdapter들이 있다.

-HandlerMapping, HandlerAdapter 모두 우선순위대로 조회한다.

 

*HandlerMapping

-우선순위 순서

1. RequestMappingHandlerMapping

  • 우선순위가 가장 높다.
  • Annotation 기반 Controller의 @RequestMapping 에 사용

2. BeanNameUrlHandlerMapping

  • Spring Bean Name으로 HandlerMapping

*HandlerAdapter

-우선순위 순서

1. RequestMappingHandlerAdapter

  • Annotation 기반 Controller의 @RequestMapping에서 사용

2. HttpRequestHandlerAdapter

  • HttpRequestHandler 처리

3. SimpleControllerHandlerAdapter

  • Controller Interface 처리

+@RequestMapping은 가장 높은 우선순위의 HandlerMapping인 RequestMappingHandlerMapping과 가장 높은 우선순위의 HandlerAdapter인 RequestMappingHandlerAdapter 두 가지를 사용하며 현대에 사용하는 Annotation 기반의 컨트롤러를 지원한다.

 

 

HttpRequestHandler로 알아보는 Spring MVC 동작 순서

-기존 방식에서 사용하는 Servlet과 가장 유사한 Handler이다.

-예시 코드

// 인터페이스
public interface HttpRequestHandler {
void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException;

}
// 구현체
@Component("/request-handler")
public class ExampleRequestHandler implements HttpRequestHandler {

@Override
public void handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("request-handler Controller 호출");
// 구현 로직
}
}

 

-postman

-출력결과

 

-실행 순서

 

1. HandlerMapping으로 핸들러 조회

-BeanName으로 Handler 조회(BeanNameUrlHandlerMapping 실행)

-ExampleRequestHandler 반환

 

2. HandlerAdapter 조회

-HandlerAdapter의 supports()를 우선순위 순서대로 호출

-HttpRequestHandlerAdapter가 HttpRequestHandler Interface를 지원한다.

-HttpRequestHandlerAdapter.supports()

 

3. HandlerAdapter 실행

-DispatcherServlet이 조회한 HttpRequestHandlerAdapter를 실행하며 Handler 정보도 넘긴다

-HttpRequestHandlerAdapter는 ExampleRequestHandler를 내부에서 실행 후 결과를 반환

-HttpRequestHandlerAdapter.handle()

→단순히 handleRequest를 호출한다. = 오버라이딩된 handleRequest() 호출

-DispatcherServlet에서 호출 → ha.handle()

 

View Resolver

-intelliJ 실습

 

Spring Boot의 ViewResolver

-Spring Boot를 사용하면 개발에 필요해 자동으로 등록되는 ViewResolver 들이 있다.

 

*우선순위 순서

-아래 두 가지 이외에도 많은 ViewResolver가 존재한다.

1. BeanNameViewResolver

-Bean Name으로 View를 찾아 반환

 

2. InternalResourceViewResolver

-application.properties 설정 파일에 등록한 prefix, suffix 설정 정보를 사용하여 ViewResolver 등록

// 아래 코드를 자동으로 해주는것과 마찬가지이다.
@Bean
InternalResourceViewResolver internalResourceViewResolver() {
return new InternalResourceViewResolver("/WEB-INF/views", ".jsp");
}

 

 

InternalResourceViewResolver로 알아보는 Spring MVC 동작순서

-application.properties 설정 파일에 등록한 prefix, suffix 설정 정보를 사용하는 ViewResolver

 

*실행 순서

1. HandlerAdapter 호출

-HandlerAdapter를 통해 "test" 논리 View Name 얻음

 

2. ViewResolver 호출

-"test" 라는 View Name으로 viewResolver를 우선순위대로 호출

  • BeanNameViewResolver는 View를 찾지 못한다.
  • InternalResourceViewResolver 호출

3. InternalResourceViewResolver

  • InternalResourceViewResolver.buildView(String viewName)

→InternalResourceView 반환

 

4. InternalResourceView

-JSP와 같이 서버에서 이동하는 forward()를 호출하는 경우와 같을 때 사용

renderMergedOutputModel() → Model을 Request로 바꾼다.

 

5. view.render()

-외부에서 view.render()를 호출 후 RequestDispatcher를 가져와 forward()한다.

매우 복잡한 구조를 가지고 있음, 찾아보지 않아도됨.

 

+Thymeleaf는 View와 Resolver가 이미 존재한다.

라이브러리 의존성만 추가해주면 SpringBoot가 모두 자동으로 해준다.

즉, return "viewName"; 만으로 View가 Rendering 된다.


[TIL]

-중간에 실습 영상이 있어서 보면서 따라해보고 실행해봤는데 복잡하면서도 분리가 되있어서 가독성은 좋고 편리했던 것 같다. 아직 제대로 이해는 못했지만 계속 공부해서 이해할 수 있도록 해봐야겠다. 그래도 실습하는 걸 보면서 이건 이렇게 작동되는구나 이런식으로 되는 구나 정도의 구조?이해는 한 것 같다.

 

-과제를 하면서 강의를 다시 듣고 정리하며 복습을 하니 조금씩 이해가 되고 진도가 나가는 것 같은데 아직은 조금 헷갈린다.