머스테치(Mustache)소개
머스테치는 로직 없는 템플릿 엔진으로 , HTML과 데이터를 결합해 동적 페이지를 생성합니다. 스프링 부트에서 기본적으로
지원되며, 간단한 문법을 통해 데이터 바인딩과 반복 처리가 가능합니다.
{{ mustache }}
Logic-less templates. Available in Ruby, JavaScript, Python, Erlang, Elixir, PHP, Perl, Raku, Objective-C, Java, C#/.NET, Android, C++, CFEngine, Go, Lua, ooc, ActionScript, ColdFusion, Scala, Clojure[Script], Clojure, Fantom, CoffeeScript, D, Haskell, XQu
mustache.github.io

MVC 패턴에서의 데이터 흐름
- Controller : 비즈니스 로직을 처리하고 데이터를 준비
- Model: 데이터 전달을 위한 컨테이너 역활
- view: 데이터를 사용자에게 표현
스프링 부트에서 뷰로 데이터를 전달하는 방식
데이터 전달의 기본 흐름
커트롤러 -> model 객체 -> 탬플릿 엔진 -> 완성된 HTML
model 객체란?
model은 데이터를 담는 상자입니다. 컨트롤러에서 뷰로 정보를 전달할 때 사용하는 임시 저장소 역활을 합니다.
Model 객체의 특징
Model은 요청 범위(Request Scope)내에서 존재하는 데이터 컨테이너입니다.
- 생명주기 : HTTP 요청이 시작될 때 생성되고, 응답이 완료되면 소멸
- 데이터 격리 : 각 요청마다 독립적인 Model 인스턴스 생성
- 상태 비저장 : 요청 간 데이터 공유 불가 (Stateless)
뷰 렌더링 원리
템플릿 엔진은 서버 사이드 렌더링(SSR)방식으로 동작합니다.
1. 템플릿 파싱: 정적 HTML과 동적 태그를 구분
2. 데이터 주입: Model의 데이터를 템플릿의 플레이스홀더에 삽입
3. 최종 렌더링: 완성된 HTML을 클라이언트로 전송
기본 프로젝트 설정 및 확인

의존성 설정 확인 - 일부만 사용할 예정
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-mustache'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
yml 파일 변환 후 설정 확인
spring:
mustache:
#템플릿 파일의 확장자를 .mustache로 지정하영 Mustache
#템플릿 파일을 인식하도록 설정
suffix: .mustache
#템플릿 파일이 위치한
#기본 경로를 src/main/resources/templates/로 설정
prefix: classpath:/templates/
# 개발 중 템플릿 캐시를 비활성화하여 코드
# 수정 후 바로 반영되도록 함 (프로덕션에서는 true로 설정 권장)
cache: false
#템플릿 파일을 UTF-8 인코딩으로 처리하여 한글 등 다양한 문자 지원
charset: UTF-8
server:
#애플리케이션이 실행될 포트를 8080으로 설정(기본값은 8080, 필요 시 변경 가능)
port: 8080
logging:
level:
# Spring Web 관련 로그를 DEBUG 수준으로
# 설정하여 요청/응답 세부 사항을 개발 중 확인 가능
org.springfranework.web:DEBUG
머스태치 사용을 위한 디렉토리 구조 설계
1.2 디렉토리 구조
학습 개념: 관심사의 분리(Separation of Concerns)

메인 클래스 확인
package com.tenco.mustache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 메인 애플리케이션 클래스
*
* - @SpringBootApplication: 스프링 부트 자동 설정 활성화
* - 컴포넌트 스캔의 시작점
* - 내장 톰캣 서버 실행
*/
@SpringBootApplication
public class MustacheApplication {
public static void main(String[] args) {
SpringApplication.run(MustacheApplication.class, args);
}
}


시나리오 코드 1단계
package com.tenco.mustache.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.ArrayList;
import java.util.List;
@Controller
public class Exam1MustacheController {
@GetMapping("/example/test1)
public String basic1(Model model) {
// 컨트롤러에서 뷰로 데이터를 전달 하는 여러 방법 중
// Model 객체 사용
// 1. 데이터를 Model 객체에 추가 하기
// 1.1 기본 변수 출력 : 머스태치 파일에서 {{key}} 값으로 출력할 수 있다.
model.addAttribute("stringValue", "안녕 머스태치야~");
model.addAttribute("intValue", 1234);
// 2. 데이터를 Model 객체에 추가 하기
// 2.1 HTML 이스케이프 해제: {{{key}}}로 HTML 태그를 렌더링하도록 설정 (가능한 사용 x 주의해서 사용)
// XSS 보안에 취약해 진다.
model.addAttribute("htmlContent", "<strong>굵게</strong>와 <em>기울임</em> 텍스트");
// 3. 데이터를 Model 객체에 추가 하기
// 3.1 섹션 : {{#key}} ..... {{/key}}
// #key 값이 참으로 평가 될 때 렌더링 됨 (Truthy - null 아니거나 빈 컬렉션이 아닐 때)
model.addAttribute("hasData", true);
model.addAttribute("data", "비밀 메시지");
// 4. 데이터를 Model 객체에 추가 하기
// 4.1 부정 섹션: {{^key}} .... {{/key}} 로 조건이 거짓일 때 렌더링, null 값 설정
// #key 값이 거짓으로 평가 될 때 렌더링 됨 (Falsy - null 이거나 빈 컬렉션이 일 때)
model.addAttribute("noData", null);
// 5. 데이터를 Model 객체에 추가 하기
// 5.1 컬렉션 반복: {{#collection}}으로 리스트를 반복 출력
List<String> items = new ArrayList<>();
items.add("사과");
items.add("바나나");
items.add("오렌지");
model.addAttribute("items", items);
// 6. 주석: 템플릿에서 {{! comment }}로 렌더링되지 않는 주석 처리
// (컨트롤러에서는 별도 처리 불필요, 뷰에서 확인)
// 7. 부분 템플릿: {{> partialName}}으로 다른 템플릿 포함
// (컨트롤러에서는 별도 데이터 추가 불필요, 뷰에서 설정)
// prefix : classpath:/templates/
// 작성 : examples/test1
// suffix: .mustache
// 완성 : /templates/examples/test.mustache
return "examples/test1";
}
}
|head.mustache
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<header>
<h1>여기는 header 영역이야</h1>
</header>
|examples/teat.mustache
<!--<!DOCTYPE html>-->
<!--<html lang="ko">-->
<!--<head>-->
<!-- <meta charset="UTF-8">-->
<!-- <title>머스태치 학습 예제</title>-->
<!--</head>-->
<!--<body>-->
{{> examples/head}}
<h1>머스태치 학습 예제 1 </h1>
<p>문자열: {{stringValue}}</p>
<p>숫자: {{intValue}}</p>
<p>HTML 렌더링(가능한 사용 금지 - 보안에 취약): {{{htmlContent}}}</p>
{{#hasData}}
<p>데이터 존재: {{data}}</p>
{{/hasData}}
{{^noData}}
<p>데이터가 없습니다.</p>
{{/noData}}
<ul>
{{#items}}
{{! 키 값이 없는 컬렉션을 처리할 때 . 을 사용한다. }}
<li>{{.}}</li>
{{/items}}
</ul>
{{! 이 부분은 출력되지 않습니다 }}
</body>
</html>
시나리오 코드 2 단계
Exam2MustacheController - 1차 코드
package com.tenco.mustache.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* Mustache 문법 학습을 위한 단계별 예제
*/
@Controller
@RequestMapping("/mustache") // 대문 달기 - 각 메서드에서 공통 사용
public class Exam2MustacheController {
/**
* 1. 기본 변수 출력 ({{key}}) 학습
* URL: http://localhost:8080/mustache/basic-variables
*/
@GetMapping("/basic-variables")
public String basicVariables(Model model) {
// 다양한 데이터 타입의 기본 변수들
model.addAttribute("key", "key");
model.addAttribute("pageTitle", "기본 변수 출력 학습");
model.addAttribute("message", "안녕하세요, Mustache입니다!");
model.addAttribute("userName", "김개발자");
model.addAttribute("userAge", 28);
model.addAttribute("userScore", 95.5);
model.addAttribute("isActive", true);
model.addAttribute("currentDate", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
return "examples/basic2";
}
}
examples/basic1.mustache
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{pageTitle}}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1 class="text-center mb-4">{{pageTitle}}</h1>
<div class="card">
<div class="card-header">
<h3>기본 변수 출력 ({{key}}) 예제</h3>
</div>
<div class="card-body">
<h4>문법 설명</h4>
<p class="text-muted">컨트롤러에서 전달한 데이터를 {{key}} 형태로 출력합니다.</p>
<h4>결과</h4>
<ul class="list-group">
<li class="list-group-item"><strong>메시지:</strong> {{message}}</li>
<li class="list-group-item"><strong>사용자명:</strong> {{userName}}</li>
<li class="list-group-item"><strong>나이:</strong> {{userAge}}세</li>
<li class="list-group-item"><strong>점수:</strong> {{userScore}}점</li>
<li class="list-group-item"><strong>활성 상태:</strong> {{isActive}}</li>
<li class="list-group-item"><strong>현재 시간:</strong> {{currentDate}}</li>
</ul>
<div class="mt-4">
<h5>템플릿 코드</h5>
<pre class="bg-light p-3 rounded"><code><p>사용자명: {{userName}}</p>
<p>나이: {{userAge}}세</p>
<p>점수: {{userScore}}점</p></code></pre>
</div>
</div>
</div>
<div class="text-center mt-4">
<a href="/mustache/html-escape" class="btn btn-primary">다음: HTML 이스케이프 학습</a>
</div>
</div>
</body>
</html>
'Spring boot' 카테고리의 다른 글
(스프링 부트 기초)GET 방식과 URL 주소 설계 (5) | 2025.06.19 |
---|---|
(스프링 부트 입문)스프링 부트 간단한 요청과 응답 동작 방식을 알아보자. (0) | 2025.06.19 |
(아파치 톰캣){{웹 서버}}와 {{웹 애플리케이션 서버}}(WAS)란?(1) (1) | 2025.06.19 |
(아파치 톰캣 설치) (1) | 2025.06.18 |
(HTTP기초지식/사전기반) 12. 웹 렌더링이란? (0) | 2025.06.18 |