2-9 동적 웹페이지로 응답하기 - 머스테치

코딩강사·2022년 10월 21일
post-thumbnail

2-9 동적 웹페이지로 응답하기 - 머스테치

머스테치는 자바 mustache.java로 서버단에서 구현되는 템플릿 엔진과 자바스크립트 mustache.js로 클라이언트(웹브라우저)단에서 구현되는 템플릿 엔진 이렇게 2개가 있습니다. mustache.js는 React.js나 Vue.js 같은 웹 프레임워크에서도 사용하는 인기있는 템플릿 엔진입니다.

머스테치의 가장 큰 장점은 간결함입니다. 조건적인 출력(th:if)과 같은 복잡한 출력문이 없기에 오직 데이타의 출력에만 집중한 템플릿입니다. 그렇다고 기능이 부족해서 생기는 사용상의 어려움은 없습니다. mustache.java의 단점인 로직적인 출력이나 형식(Format) 출력은 mustache.js를 도와주는 확장 자바스크립을 이용할 수 있기 때문입니다.

그럼 머스테치를 이용한 뷰 템플릿 출력 예제를 만들겠습니다.

2-9-1 머스테치 프로젝트 만들기

Ex11Mustache 프로젝트를 만들어보겠습니다. Group은 com.study, Artifact와 Name은 Ex11Mustache이고, Package name은 com.study.springboot로 지정합니다. 디펜던시(Dependencies)는 Spring Web, Dev Tools, Lombok와 추가적으로 Mustache를 추가한 후 zip을 다운로드 합니다. 나머지 과정은 전과 동일합니다.

resources폴더의 application.properties에 다음 내용을 추가하고 저장합니다. 예제 URL : https://bit.ly/3D6vMnD

server.port=8090

build.gradle 파일을 보면 thymeleaf 디펜던시(라이브러리)인 spring-boot-starter-mustache가 들어가 있는 것을 확인할 수 있습니다. 예제 URL : https://bit.ly/3TEHj4x

생략...
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'
	annotationProcessor 'org.projectlombok:lombok'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
생략...

Mustache 템플릿 엔진은 스프링부트 프레임워크 2.7.x대에서는 한글 깨짐 현상이 있어 2.6.2로 낮추어 줍니다. 수정후 저장하고 코끼리 아이콘으로 갱신해주세요.

plugins {
	//<수정된 부분
	//'2.7.5' 에서는 mustache 한글 깨짐 현상이 발생함.
	//id 'org.springframework.boot' version '2.7.5'
	id 'org.springframework.boot' version '2.6.2'
    //수정된 부분>
	id 'io.spring.dependency-management' version '1.0.15.RELEASE'
	id 'java'
}

인텔리제이에서 확장자 .mustache 파일을 인식할 수 있도록 플러그인을 제공합니다. 파일>설정>플러그인 메뉴에서 mustache를 검색하여 플러그인을 설치해주고 확인을 누르고 나오면 됩니다.

2-9-2 변수값 출력하기

com.study.springboot 폴더에 MainController 클래스를 생성합니다. 예제 URL : https://bit.ly/3EVo2XB

package com.study.springboot;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class MainController {

	@GetMapping("/index1")
	public String index1(Model model) {
		
		model.addAttribute("name", "홍길동");
		model.addAttribute("name_html", "<span style='color:red;'>홍길동</span>");
		model.addAttribute("value", "서버값");

		return "index1"; //index1.mustache로 응답함.
	}
	
}

resources 폴더의 templates폴더 밑에 index1.mustache 파일을 생성합니다. 머스테치를 지원하는 html파일은 확장자가 .mustache입니다.

<!DOCTYPE HTML>
<html>
<head>
    <title>머스테치 실습</title>
    <meta http-equiv="Content-Type" content="text/html" charset="UTF-8"/>
</head>
<body> 
    <h2>머스테치 변수값 출력</h2>
    
    <p>당신의 이름은 {{ name }} 입니다.</p>

    <p>주석으로 출력되지 않습니다.<br>
    당신의 이름은 {{! name }} 입니다.</p>

    <p>html로 출력됩니다.<br>
    당신의 이름은 {{{ name_html }}} 입니다.<br>
    당신의 이름은 {{& name_html }} 입니다.</p>

    value속성에 값 넣기<br>
    <input type="text" value="{{ value }}" /><br>

</body>

</html>

저장한 후 Ex11MustacheApplication의 main 메서드를 실행한 후 아래 경로로 요청합니다.

localhost:8090/index1

그러면 아래와 같이 웹브라우저에 출력될 것입니다.

타임리프와 비교하여 머스테치의 출력값을 살펴보겠습니다.

자바 코드

model.addAttribute("name", "홍길동");

html 코드

<p>당신의 이름은 {{ name }} 입니다.</p>

웹브라우저 출력

<p>당신의 이름은 홍길동 입니다.</p>

타임리프에서는 아래와 같이 th:text 속성을 이용하여 출력했지만, 머스테치는 기존의 문자열에 그대로 들어갑니다. 그래서 좀더 가독성이 좋고 심플하게 html 파일을 구성합니다. 머스테치는 Model 안에 들어가 있는 값을 출력하기 위해, {{ }} 2개의 중괄호(콧수염 모양)을 사용합니다. 개인적으로는 타임리프와 JSP보다 이런 심플한 표현이 좀더 html에 어울릴 것 같습니다.

<p th:text="${ name }">innerText 출력</p>

머스테치 변수 name 값이 출력되지 않도록 하려면 {{! }} 심볼을 사용하면 됩니다.

자바 코드

model.addAttribute("name", "홍길동");

html 코드

<p>주석으로 출력되지 않습니다.<br>
    당신의 이름은 {{! name }} 입니다.</p>

웹브라우저 출력

<p>주석으로 출력되지 않습니다.<br>
    당신의 이름은  입니다.</p>

그리고 html 코드를 표현하고 싶으면, 중괄호 3개 {{{ }}} 심볼을 사용하거나 {{& }} 심볼을 사용합니다.

자바 코드

model.addAttribute("name_html", "<span style='color:red;'>홍길동</span>");

html 코드

<p>html로 출력됩니다.<br>
    당신의 이름은 {{{ name_html }}} 입니다.<br>
    당신의 이름은 {{& name_html }} 입니다.</p>

웹브라우저 출력

<p>html로 출력됩니다.<br>
    당신의 이름은 <span style='color:red;'>홍길동</span> 입니다.<br>
    당신의 이름은 <span style='color:red;'>홍길동</span> 입니다.</p>

input 태그의 value에 값을 넣을 때도 {{ }} 심볼에 Model에 들어간 키 이름을 넣으면 됩니다.

자바 코드

model.addAttribute("value", "서버값");

html 코드

value속성에 값 넣기<br>
    <input type="text" value="{{ value }}" /><br>

웹브라우저 출력

value속성에 값 넣기<br>
    <input type="text" value="서버값" /><br>

2-9-3 null 체크하기

머스테치에서 null 값을 체크해 보겠습니다. 먼저 MainController 클래스의 다음 내용을 추가합니다. 예제 URL : https://bit.ly/3EVo2XB

생략...

@Controller
public class MainController {

	생략...
    
	@GetMapping("/index1")
	public String index1(Model model) {
		생략...
	}
    //<추가된 부분
	@GetMapping("/index2")
	public String index2(Model model) {

		model.addAttribute("address", "한양");
		model.addAttribute("address_null", null);
		model.addAttribute("address_empty", "");

		return "index2"; //index2.mustache로 응답함.
	}
    //추가된 부분>
}

model에 address key로 "한양"이라는 값이 정상적으로 들어 있습니다. 하지만 address_null key에는 null 값이 들어 있습니다. address_empty에는 "" 빈 문자열이 들어 있습니다. 3가지 형태의 값을 머스테치에서 구분해 보도록 하겠습니다.

templates폴더에 index2.html을 만듭니다. 예제 URL : https://bit.ly/3EVLvrJ

<!DOCTYPE HTML>
<html>
<head>
    <title>머스테치 실습</title>
    <meta http-equiv="Content-Type" content="text/html" charset="UTF-8"/>
</head>
<body>
    <h2>머스테치 null 체크하기</h2>

    <p>당신의 주소는 {{ address }}입니다.</p>
    <hr>

    문자열의 길이는 {{ address.length }}  입니다.<br>
    <hr>
	
    #을 붙이면 null이 아닐때 출력됨.<br>
    {{# address }}
    <p>address가 null이 아닙니다. </p>
    {{/ address }}
    <hr>

    ^을 붙이면 null일때 출력됨.<br>
    {{^ address }}
    <p>address가 null입니다. </p>
    {{/ address }}
    <hr>

    ^을 붙이면 null일때 출력됨.<br>
    {{^ address_null }}
    <p>address_null이 null입니다.<br>
       또는 undefined, false 또는 0, NaN, 빈 문자열, 빈 리스트입니다.<p>
    {{/ address_null }}
    <hr>

    #을 붙이면 빈 문자열일 때 출력됨.<br>
    {{# address_empty }}
        <p>address_empty는 빈 문자열입니다.</p>
    {{/ address_empty }}
	<hr>

    ^을 붙이면 빈 문자열일 때 출력안함.<br>
    {{^ address_empty }}
        <p>address_empty는 빈 문자열입니다.</p>
    {{/ address_empty }}
</body>
</html>

실행해서 localhost:8090/index2로 호출해 보면, 웹브라우저에 아래와 같이 보일겁니다.

좀 복잡해 보이지만 하나씩 살펴보겠습니다. 먼저 아래 코드를 보면 model 객체에 설정된 address 키의 "한양"이라는 값이 머스테치 {{ address }} 에 출력되었습니다. 문자열 또는 리스트의 길이는 .length를 통해 가져올 수 있습니다. 문자열의 길이는 2입니다.

자바 코드

model.addAttribute("address", "한양");

html 코드

<p>당신의 주소는 {{ address }}입니다.</p>
<hr>
문자열의 길이는 {{ address.length }} 입니다.<br>
<hr>

웹브라우저 출력

<p>당신의 주소는 한양입니다.</p>
<hr>
문자열의 길이는 2 입니다.<br>
<hr>

머스테치에서 null 체크 기능을 살펴보겠습니다. {{# 값 }}과 {{/ 값 }}을 이용하면 값이 null이 아닐 때만 이 두 심볼이 감싸는 영역을 출력합니다. 즉 address 값이 null이 아니므로, <p>address가 null이 아닙니다. </p> 부분이 출력되는 것입니다.

자바 코드

model.addAttribute("address", "한양");

html 코드

#을 붙이면 null이 아닐때 출력됨.<br>
{{# address }}
<p>address가 null이 아닙니다. </p>
{{/ address }}

웹브라우저 출력

#을 붙이면 null이 아닐때 출력됨.<br>
<p>address가 null이 아닙니다. </p>

반면에 {{^ 값 }}과 {{/ 값 }}을 이용하면 값이 null 일때만 감싼 영역을 출력합니다. addres 값이 null이 아니므로, <p>address가 null입니다. </p> 부분이 출력되지 않습니다. 또한 값이 undefined, false 또는 0, NaN또는 빈 문자열, 빈 리스트일때도 출력되지 않습니다.

자바 코드

model.addAttribute("address", "한양");

html 코드

^을 붙이면 null일때 출력됨.<br>
{{^ address }}
<p>address가 null입니다. </p>
{{/ address }}

웹브라우저 출력

^을 붙이면 null일때 출력됨.<br>

이제 값이 null인 address_null 키에 대해서 살펴보겠습니다. address_null 키에 대한 값이 null 이므로 아래 웹브라우저 출력에는 <p>address_null이 null입니다. 생략... <p> 부분이 출력됩니다.

자바 코드

model.addAttribute("address_null", null);

html 코드

^을 붙이면 null일때 출력됨.<br>
{{^ address_null }}
<p>address_null이 null입니다.<br>
  또는 undefined, false 또는 0, NaN, 빈 문자열, 빈 리스트입니다.<p>
{{/ address_null }}

웹브라우저 출력

^을 붙이면 null일때 출력됨.<br>
<p>address_null이 null입니다.<br>
  또는 undefined, false 또는 0, NaN, 빈 문자열, 빈 리스트입니다.<p>

주소값은 할당되었으나 실제 값은 없는 값을 emtpy라고 합니다. 이제 값이 null이 아닌 empty인 상태를 체크해 보겠습니다.
이때는 {{# 값 }} {{/ 값 }}을 이용하여, empty인 즉 빈 문자열인 경우에 출력할 수 있습니다.

자바 코드

model.addAttribute("address_empty", "");

html 코드

#을 붙이면 빈 문자열일 때 출력됨.<br>
{{# address_empty }}
<p>address_empty는 빈 문자열입니다.</p>
{{/ address_empty }}

웹브라우저 출력

#을 붙이면 빈 문자열일 때 출력됨.<br>
<p>address_empty는 빈 문자열입니다.</p>

반대로 {{^ 값 }} {{/ 값 }}을 사용하면, 값이 empty인 경우 출력하지 감싼 부분을 출력하지 않습니다.
자바 코드

model.addAttribute("address_empty", "");

html 코드

^을 붙이면 빈 문자열일 때 출력안함.<br>
{{^ address_empty }}
<p>address_empty는 빈 문자열입니다.</p>
{{/ address_empty }}

웹브라우저 출력

^을 붙이면 빈 문자열일 때 출력안함.<br>

2-9-4 표현 형식(Format)

숫자를 천 단위로 쉼표를 사용해 표현한다든지, 날짜를 년-월-일 형식으로 표현하기 위해서, 타임리프나 JSP에서는 별도의 기능을 제공하는데 비해, 머스테치는 단순한 값 출력을 위해 만들어진 경량 템플릿 엔진이므로 이러한 기능을 프론트엔드에서 하려면, 자바스크립트의 도움을 받아야 합니다. 핸들바(Handlebars.js)와 같은 라이브러리를 활용할 수도 있지만, 자바스크립트로 후처리를 하는 것이 훨씬 간단합니다. 타임리프에서 날짜와 숫자의 형식화된 출력을 해본 것 처럼 비슷한 결과를 출력해 보도록 하겠습니다.

MainController 클래스에 다음과 같이 추가합니다. 예제 URL : https://bit.ly/3XFNmbp

@GetMapping("/index3")
	public String index3(Model model) {

		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String standardDate = simpleDateFormat.format(new Date());

		model.addAttribute( "standardDate", standardDate );

		DateTimeFormatter dtFormatter1= DateTimeFormatter.ofPattern("yyyy-MM-dd");
		DateTimeFormatter dtFormatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		String localDate = LocalDate.now().format(dtFormatter1);
		String localDateTime = LocalDateTime.now().format(dtFormatter2);


		return "index3"; //index3.mustache로 응답함.
	}

index3.mustache를 생성하고 아래와 같이 추가합니다. 예제 URL : https://bit.ly/3V9RRta

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html" charset="UTF-8"/>
    <title>머스테치 실습3</title>
</head>
<body>
<h2>머스테치 표현 형식</h2>

Data 객체 <br>
{{ standardDate }}<br>
LocalDate 객체<br>
{{ localDate }}<br>
LocalDateTime 객체<br>
{{ localDateTime }}<br>
<br>

</body>
</html>

localhost:8090/index3으로 요청하면 아래와 같이 출력될 것입니다.

2-9-5 조건적인 출력

2-9-6 객체 데이타와 리스트 출력

2-9-7 머스테치 레이아웃

https://github.com/janl/mustache.js/

profile
강의하는 개발자

0개의 댓글