Post

[Spring Boot] MVC 패턴 이해

뷰 템플릿과 MVC 패턴

뷰 템플릿이란?

화면을 담당하는 기술로, 웹 페이지(View)를 하나의 틀(Template)로 만들고 여기에 변수를 삽입해 서로 다른 페이지로 보여주는 것

  • 이 프로젝트에서는 프로젝트를 만들 때 사용한 Mustache라는 도구를 사용한다.

🧔🏻 Mustache?

  • `` 형태로 손쉽게 사용할 수 있는 템플릿 엔진이다.
  • 문법이 다른 템플릿 엔진(JSP, Velocity, Freemarker, Thymleaf)보다 쉽다.
  • 비즈니스 로직을 사용할 수 없어 View의 역할과 서버의 역할이 명확하게 구분된다.

MVC 패턴

사용자 인터페이스, 데이터 및 논리 제어를 구현하는데 널리 사용되는 소프트웨어 디자인 패턴. 소프트웨어의 비즈니스 로직과 화면을 구분하는데 중점을 두고 있다.

MVC Pattern
이미지 출처: https://developer.mozilla.org/ko/docs/Glossary/MVC
  • Model : 데이터와 비즈니스 로직 관리
  • View : 레이아웃과 화면 처리
  • Controller : 모델과 뷰로 명령 전달

각 요소가 실행하는 역할을 예시를 통해 살펴보겠다.

간단한 쇼핑 리스트 앱에서 이번 주에 사야할 각 항목의 이름, 개수, 가격의 목록을 요청한다면?

  • Model
    • 앱이 포함해야할 데이터가 무엇인지 정의
    • 데이터의 상태가 변경되면, 모델을 일반적으로 뷰에게 알리고(필요한 대로 화면을 변경할 수 있도록) 가끔 컨트롤러에게 알리기도 한다.(업데이트 된 뷰를 조절하기 위해 다른 로직이 필요한 경우)
    • 모델은 리스트 항목이 포함해야 하는 데이터와 이미 존재하는 리스트 항목이 무엇인지를 지정한다.
  • View
    • 앱의 데이터를 보여주는 방식을 정의
    • 표시할 데이터를 모델로부터 받는다.
  • Controller
    • 앱의 사용자로부터 받은 입력에 대한 응답으로 모델 및 뷰를 업데이트하는 로직을 포함
    • 항목 추가 혹은 삭제와 같이 모델이 업데이트 되어야 하는 경우, 입력 > 컨트롤러에서 모델 처리 > 업데이트 된 데이터를 뷰로 전송
    • 단순히 데이터를 다른 형태로 나타내기 위해 뷰를 업데이트 하는 경우(정렬 등) 모델 업데이트 없이 바로 처리

MVC 패턴을 활용해 뷰 템플릿 페이지 만들기

뷰 템플릿 페이지 만들기

  1. 이전에 만들었던 firstProject 프로젝트를 열고 templates 폴더에 greetings.mustache 파일을 만든다. mustache 플러그인을 설치하기 위해 Install Handlebars/Mustache plugin을 클릭하고 Install한다.

Mustache Install

  1. 윗줄에 doc를 입력하고 Tab키를 누르면 기본 HTML 코드가 자동으로 작성된다. 본문에 <h1>OO님, 반갑습니다!</h1>를 추가한다.
1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>다영님, 반갑습니다!</h1>
</body>
</html>

이제 이 페이지를 웹 브라우저에서 보기 위해 컨트롤러와 모델을 작성해야 한다.

컨트롤러 만들고 실행하기

뷰 템플릿 페이지는 templates 디렉터리에 만들어야 하듯, 컨트롤러도 src > main > java > com.example.firstproject 패키지 안에 하나의 패키지로 만들어야 한다.

  1. com.example.firstproject에 com.example.firstproject.controller 패키지를 만들어준다.
  2. 해당 패키지에 FirstController 클래스를 만들어준다.

Package Structure

  1. FirstController 클래스에 다음과 같이 작성한다.
    1. 이 클래스가 컨트롤러임을 알려주는 @Controller 어노테이션을 작성한다. 이렇게 하면 Controller 클래스 패키지(org.springframework.stereotype.Controller)가 자동으로 임포트된다.
    2. 반환형이 문자열인 niceToMeetYou() 메서드를 선언하고 공백 문자열을 반환한다. 이 반환문을 이용해 앞에서 만든 greetings.mustache 페이지를 반환하게 된다.
1
2
3
4
5
6
7
8
9
10
package com.example.firstproject.controller;

import org.springframework.stereotype.Controller;

@Controller
public class FirstController {
    String niceToMeetYou() {
        return "";
    }
}
  1. niceToMeetYou()메서드로 greetings.mustache 페이지를 반환하려면 파일 이름인 greetings만 반환값으로 적어주면 된다. 즉 return "greetings";로 적어주면 서버가 알아서 templates 디렉터리에서 greetings.mustache 파일을 찾아 웹 브라우저로 전송한다.
1
2
3
    String niceToMeetYou() {
        return "greetings";
    }
  1. 이제 페이지를 반환해 달라는 URL 요청을 접수하기 위해 niceToMeetYou() 메서드 앞에 @GetMapping()을 추가한다. 자동으로 org.springframework.web.bind.annotation.GetMapping 패키지가 임포트된다.
  2. @GetMaiing("/hi")라고 입력하면, 웹 브라우저에서 localhost:8080/hi로 접속했을 때 greetings.mustache 파일을 찾아 반환하라는 뜻이 된다.
    1
    2
    3
    4
    
     @GetMapping("/hi")
     String niceToMeetYou() {
         return "greetings";
     }
    

Mapping Done

정리하면, 컨트롤러를 만들 때 먼저 컨트롤러를 선언(@Controller)해야 하고, 반환값으로 보여 줄 페이지의 이름만 따서 적은 다음(return “greetings”;) URL 요청을 접수해야 (@GetMapping(“/hi”)) 동작하게 된다.

어노테이션(Annotaion)이란?

  • 소스 코드에 추가해 사용하는 메타 데이터의 일종
  • 프로그램에서 처리해야 할 데이터가 아니라 컴파일 및 실행 과정에서 코드를 어떻게 처리해야 할지 알려주는 추가 정보

View에 한글 깨짐 현상이 발생하는 경우

  • src > main > resources > application.properties 파일을 열어 server.servlet.encoding.force=true 코드를 추가한 후 서버를 재시작한다.

모델 추가하기

  1. 데이터에 따라 여러 이름들을 사용할 수 있도록 머스테치 문법을 사용해 뷰 템플릿 페이지에 변수를 삽입한다.
1
<h1>님, 반갑습니다!</h1>
  1. 모델은 컨트롤러의 메서드에서 매개변수로 받아 온다. FirstController의 niceToMeetYou() 메서드에 Mdoel 타입의 model 매개변수를 추가한다. Model 클래스 패키지가 자동으로 임포트된다.
1
2
3
4
    @GetMapping("/hi")
    String niceToMeetYou(Model model) {
        return "greetings";
    }
  1. Model 패키지가 임포트됐다면 모델을 통해 변수를 등록할 수 있다. 모델에서 변수를 등록할 때는 addAttribute() 메서드를 사용한다.
1
2
3
4
5
    @GetMapping("/hi")
    String niceToMeetYou(Model model) {
        model.addAttribute("username", "Dayoming");
        return "greetings";
    }

이는 서버 내부에 username 이라는 key값과 Dayoming이라는 value값을 저장한다.

Model create done

MVC의 역할과 실행 흐름 이해하기

Model, View, Controller가 유기적으로 역할을 분담해 클라이언트의 요청을 처리

컨트롤러가 클라이언트의 요청을 받고, 뷰가 최종 페이지를 만들고, 모델이 최종 페이지에 쓰일 데이터를 뷰에 전달한다.

/hi 페이지의 실행 흐름

1
2
3
4
5
6
7
8
@Controller
public class FirstController {
    @GetMapping("/hi")
    String niceToMeetYou(Model model) {
        model.addAttribute("username", "Dayoming");
        return "greetings";
    }
}
  1. 이 파일이 Controller임을 선언한다.
  2. 클라이언트로부터 “/hi”라는 요청을 받아 접수한다.
  3. “/hi”라는 요청을 받음과 동시에 niceToMeetYou() 메서드를 수행한다.
  4. 뷰 템플릿 페이지에서 사용할 변수를 등록하기 위해 모댈 객체를 매개변수로 가져온다.
  5. 모델에서 사용할 변수를 등록한다. 변숫값에 따라 서로 다른 뷰 템플릿 페이지가 출력된다.
  6. 메서드를 수행한 결과로 greetings.mustache 파일을 반환한다.

/bye 페이지의 실행 흐름

위와 같은 과정을 거쳐 FirstController에 seeYouNext() 메서드를 만들어 /bye로 요청을 받았을 때 “OO님, 다음에 또 만나요!”를 출력한다.

1
2
3
4
5
6
7
8
9
10
11
12
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <h1>님, 다음에 또 만나요!</h1>
</body>
</html>

goodbye.mustache

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Controller
public class FirstController {
    @GetMapping("/hi")
    String niceToMeetYou(Model model) {
        model.addAttribute("username", "Dayoming");
        return "greetings";
    }

    @GetMapping("/bye")
    String seeYouNext(Model model) {
        model.addAttribute("nickname", "다영");
        return "goodbye";
    }
}

FirstController.java

Create bye page

결과 화면

참고자료

This post is licensed under CC BY 4.0 by the author.