Blog

[Spring-LDW] 템플릿 엔진? 머스테치 사용해보기(VS Thymeleaf)

Category
Author
citeFred
citeFred
PinOnMain
1 more property
스프링 부트와 AWS로 혼자 구현하는 웹 서비스  : 인텔리제이, JPA, JUnit 테스트, 그레이들, 소셜 로그인, AWS 인프라로 무중단 배포까지 이동욱 저
현재까지 뷰 템플릿 엔진으로 주로 타임리프를 사용해봤었는데, 현재 교재에서는 머스테치를 소개해주고 있다. 사용을 통해 차이점을 직접 느껴보고자 한다.
Table of Content

템플릿엔진?

우선 웹 개발에 있어 템플릿 엔진이란, 지정된 템플릿 양식과 데이터가 합쳐져 HTML문서를 출력하는 소프트웨어를 이야 기한다. 쉽게 이야기해서, 웹사이트 화면을 어떤 형태로 만들지 도와주는 양식이라고 생각하면 된다.
템플릿 엔진이란 간단히 말하면 다음과 같다.
지정된 템플릿 양식과 데이터가 합쳐져 HTML 문서를 출력하는 소프트웨어이다.
웹 템플릿 엔진은 view code(HTML)와 data logic code(DB connection)를 분리해주는 기능을 한다.
서버 사이드 템플릿 엔진과 클라이언트 사이트 템플릿 엔진으로 구분할 수 있다.
여기에는 JSP, Freemarker 부터 시작해서, 리액트, 뷰와 같은 View 파일이 있다. 모두 지정되어있는 템플릿과 데이터를 이용하여 HTML을 생성하는 템플릿 엔진이지만, 전자는 서버 템플릿 엔진, 후자는 클라이언트 템플릿 엔진이다.
개발을 시작하는 많은 사람들이 서버 템플릿 엔진과 클라이언트 템플릿 엔진을 오해한다. 이 책에서는 설명 전, 간단한 예 시가 하나 주어진다.
<script type="text/javascript"> $(document).ready(function(){ if(a=="1"){ <% System.out.println("test"); %> } });
Java
복사
이 코드는 if문과 관계없이 무조건 test를 콘솔에 출력한다. 이유는 프론트엔드의 자바스크립트가 작동하는 영역과 JSP가 작동하는 영역이 다르기 때문이다.

위 코드가 잘 이해가 되지않는다?

서버 사이드 템플릿 엔진이란?

기본 개념

서버에서 구동되는 템플릿 엔진을 말한다.
서버에서 DB 혹은 API에서 가져온 데이터를 미리 정의된 템플릿에 넣어 HTML 문서를 만들어 클라이언트에 전달해주는 역할
즉, HTML 코드에서 고정적으로 사용되는 부분은 템플릿으로 만들고, 동적으로 생성되는 부분은 템플릿의 특정 부분에 끼워 넣는 방식으로 동작

동작 과정

클라이언트 요청을 받는다.
필요한 데이터를 DB, API에서 가져온다.
미리 정의된 템플릿에 해당 데이터를 배치한다.
서버에서 HTML을 그린다.
해당 HTML을 클라이언트에 전달한다.

클라이언트 템플릿 엔진이란?

기본 개념

HTML 형태로 코드를 작성할 수 있으며 DOM을 그리게 해주는 역할
데이터를 받아서 DOM 객체에 동적으로 그려주는 프로세스를 담당
브라우저 위에서 작동하며 react, Vue.js등이 있다.
서버에서는 JSON, Xml 형식의 데이터만 전달하고 클라이언트에서 이를 혼합해 화면을 만든다.
예를 들어, 다 같은 형식의 프레임에 내용만 바뀌어 사용하는 경우 클라이언트가 매번 템플릿을 입력하거나 바꾸기 보다 Script 타입을 템플릿으로 미리 만들어 사용하며 안의 내용을 replace 하는 식으로 동작한다.

동작 과정

클라이언트에서 공통적인 프레임을 미리 템플릿으로 만든다.
서버에서 필요한 데이터를 받는다.
데이터를 템플릿에 배치하고 DOM 객체에 동적으로 그려준다.

템플릿 엔진을 사용하는 이유는?

많은 코드를 줄일 수 있다.
기존 HTML에 비해 간단한 문법을 사용한다.
재사용성이 높다.
똑같은 페이지에 데이터만 바뀌는 경우 템플릿 엔진을 사용하면 템플릿을 만들어놓고 데이터를 바꾸면서 수많은 페이지를 만들어 낼 수 있어서 효율적이다.
유지보수에 용이하다.
하나의 템플릿을 만들어 여러 페이지를 렌더링할 수 있다.

머스테치와 타임리프의 주요 차이점

머스테치와 타임리프는 모두 서버 사이드 템플릿 엔진으로서, 웹 애플리케이션에서 동적으로 HTML을 생성하는 데 사용된다. 이 두 템플릿 엔진은 유사한 목적을 가지고 있지만 몇 가지 차이가 있다.
1.
문법 및 특성:
머스테치는 간단하고 일관된 문법을 가지고 있다. 머스테치의 문법은 가독성이 좋고 사용하기 쉽다.
타임리프는 HTML과 유사한 문법을 사용하며, 특히 태그 속성 안에 표현식을 집어넣는 방식이 자연스럽다.
1.
특정 기능:
타임리프는 자연스러운 자바 객체 그래프의 표현이 가능하며, 자동으로 이스케이핑을 처리한다. 또한 Spring Framework와의 통합이 용이하다.
머스테치는 간단하고 빠르게 동작하는 특징이 있으며, 스프링 부트와의 통합이 잘 되어 있다.
1.
유연성:
머스테치는 상대적으로 단순하고 가벼운 템플릿 엔진으로, 특히 성능이 중요한 상황에서 유용하다.
타임리프는 풍부한 기능 세트를 가지고 있어, 더 복잡한 상황에서도 대응할 수 있다.

머스테치 사용해보기

Handlebars 플러그인 설치

문법체크, 문법 지원, 자동완성 기능 등 Mustache의 부가 기능을 위한 플러그인을 설치해준다.

의존성 추가

build.gradle 에 의존성을 추가
... dependencies { ... // Mustache implementation 'org.springframework.boot:spring-boot-starter-mustache' } ...
Java
복사

index.mustache 기본 페이지 만들기

<!DOCTYPE HTML> <html> <head> <title>스프링 부트 웹 서비스</title> <meta http-equiv="Content-Type" content="text/html;" charset="UTF-8" /> </head> <body> <h1>스프링 부트로 시작하는 웹 서비스</h1> </body> </html>
Java
복사
.mustache라는 확장자는 처음 본다. 이전 타임리프에서도 .html 확장자를 사용했었는데, 조금 차이가 있다. jsp의 경우 .jsp 확장자로 다루었던 기억이 난다.
뷰 페이지의 기본적인 경로는 /src/main/resources/templates 이다. 타임리프와 동일한 경로를 가지고 있다.
IDE에서도 독특하게 콧수염 모양의 아이콘으로 파일이 표시되는 것을 확인 할 수 있다.

IndexController.java 컨트롤러

package com.citefred.ldwspring.web; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; @Controller public class IndexController { @GetMapping("/") public String index(){ return "index"; } }
Java
복사
@Controller 어노테이션을 통해 String을 반환하는 메소드는 반환 문자열+뷰 템플릿 엔진의 확장자(여기서는 .mustache ) 를 반환한다. 타임리프에서는 .html 의 파일을 반환했다.
여기서 반환하는 뷰 파일의 위치는 /src/main/resources/templates에 있어야 한다.

IndexControllerTest.java 테스트 코드

컨트롤러가 정상적으로 작동하는지(뷰 페이지를 반환 == 뷰 HTML코드를 반환하는지) 를 테스트해야 한다.
package com.citefred.ldwspring.web; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.test.context.junit.jupiter.SpringExtension; import static org.assertj.core.api.Assertions.assertThat; @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) class IndexControllerTest { @Autowired private TestRestTemplate restTemplate; @Test public void 메인페이지_로딩(){ //given //when String body = this.restTemplate.getForObject("/", String.class); //then assertThat(body).contains("스프링 부트로 시작하는 웹 서비스"); } }
Java
복사
테스트 코드를 통해서 body태그 안에 “스프링 부트로 시작하는 웹 서비스” 라는 문자열이 포함되어 있는지 확인하고 있다. 하지만 이 부분에서 오류가 발생했다.
??로 나타나는 것을 보니 문자 타입의 문제인것으로 보여진다. 특히 Mac 개발 환경에서는 자주 나타나는 문제이다. 캐릭터 인코딩 부분에 대한 문제 해결 방법을 접근해야 한다.

캐릭터 인코딩 문제를 해결하는데 다양한 문제가 있었다.

우선 Mac의 문제인가? OS의 문제인지 파악이 필요하고
Thymeleaf에서는 문제는 없었다. 그럼 OS적인 문제보다 Mustache의 문제일 가능성도 생각해야 한다.

VM옵션의 수정

여러 해결 방법 중에 기본적으로 VM웨어에 문자 인코딩을 입력하라는 해결 방법이 많았다.
이처럼 Dfile, Dconsole의 인코딩을 UTF-8로 명시적으로 기입했다.
IDE자체에서도 기본 설정 파일의 인코딩(application.properties 등)의 인코딩이 ISO로 되어있었다 이 부분을 UTF-8로 수정했다.
하지만 IDE를 재시작해도 문제는 해결되지 않았다.

이제 Mustache의 문제일 가능성이 있었다.

IDE에서 파일 인코딩과 관련된 부분은 전반적으로 살펴보았지만 아무리봐도 Mustache의 문제로 보여지고 있다.
서버는 동적으로 컨텐츠 타입에 따라 인코딩을 결정하는데. 만약 클라이언트나 서버에서 명시적으로 인코딩을 지정하지 않았고, 기본 설정도 제대로 이루어지지 않았다면 깨진 문자가 나타날 수 있다.
해결책으로는 application.properties 같은 설정 파일에 서블릿 응답 인코딩을 명시적으로 지정하면 된다.server.servlet.encoding.force-response=true와 같이 명시적으로(강제) 인코딩을 설정하면 된다.
위 처럼 정상적으로 테스트 코드가 작성되었으며 테스트 코드에서의 검증 부분이었던 “스프링 부트로 시작하는 웹 서비스” 라는 문자열이 뷰 페이지 index.mustache 의 body에 존재하는 것으로 정상적으로 작동, 테스트 된 것을 확인 할 수 있다.
Search
 | Main Page | Category |  Tags | About Me | Contact | Portfolio