개인 프로젝트

#002-03 [Spring Boot] 뷰 템플릿 선정 및 적용하기

도미노& 2025. 2. 7. 18:02

내가 뷰 템플릿을 쓰는 이유는 단 하나의 이유, "layout 나누기" 이다.

 

 

서버 호출은 ajax로 할 것이기 때문에

Tiles와 sitemesh 둘 중에 하나를 선택하기로 했다.

 

그리고 둘 중에서 shtemesh를 사용해봤지만

Tiles의 사용이 압도적이라 하여 Tiles를 사용하기로 했다.

구체적인 장단점 비교 >> https://deoki.tistory.com/66

 

Tiles를 프로젝트에 적용하려는데 의존성 주입이 안 되어 검색해 보니

스프링부트 3.0 이상에서 지원하지 않는다고 한다.

그래서 다른 템플릿을 찾아보기로 했다.

 

일단 프리마커와 타임리프는 사용하고 싶지 않았는데, (필요하지 않은 과도한 기능이 많아서)

비슷한 니즈의 블로그 글을 보고 "머스테치(mustache)"를 사용해 보기로 결정했다.

또한 스프링부트에서 공식 지원하는 템플릿이라는 점이 마음에 들었다.

 

mustache를 적용하다 보니.. 로컬에 플러그인을 설치하라는데

그럼 나중에 로컬이 아닌 서버를 올릴 때 리스크가 있을 것 같아서

 

타임리프로 작성하기로 했다.

(한글 예제가 많아 문제가 발생해도 해결하기 비교적 쉬울 것 같았다.)

 

 

 

적용방법

1. build.gradle 의존성 추가

layout을 나누기 위해 꼭 두 가지를 다 추가해야 한다.

// thymeleaf
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect'

 

 

2. application.yml 추가

spring:
# thymeleaf
  thymeleaf:
    prefix: classpath:templates/
    suffix: .html # controller에서 .html 확장자를 생략할 수 있음
    check-template-location: true
    mode: HTML
    cache: false # default true, 개발 시에는 false로 두는 것이 좋음

 

 

3. 예제 코드의 <html> 태그에 아래 코드 추가

<html lang="en" xmlns:th="http://www.thymeleaf.org">

 

 

4. Controller에서 호출

참고로 @RestController를 사용하면 인지를 하지 못한다.

@Controller
public class IndexController {
	
    @GetMapping("/")
    public String index() {
        return "index"; // suffix: .html 설정을 했기 때문에 "index.html"이라고 쓰지 않아도 된다. prefix도 마찬가지.
    }
}

 

 

5. http://127.0.0.1:8080/ 호출 시 화면

 

 

 

6. 이전에 부트스트랩 예제 화면을 static에 넣어 두었는데, (이러면 클라이언트에서 경로를 알면 접근 가능)

내가 원하는 경로에 옮긴 후 신규 컨트롤러를 만들어 줬다. (숨겨 놓고 나만 쓰려고.)

 

 

경로 변경

 

 

신규 컨트롤러 코드

package com.heek.api.v1.publicity.common.example;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Bootstrap 예제 화면 호출 Controller
 */
@Controller
@RequestMapping(value = "/example")
public class BootstrapExampleController {

	private static final String TEMPLATES_PATH = "example/bootstrap/";

	@GetMapping("/main")
	public String main() {
		return TEMPLATES_PATH + "main";
	}

	@GetMapping("/login")
	public String login() {
		return TEMPLATES_PATH + "login";
	}

	@GetMapping("/register")
	public String register() {
		return TEMPLATES_PATH + "register";
	}

	@GetMapping("/password")
	public String password() {
		return TEMPLATES_PATH + "password";
	}

	@GetMapping("/layout-static")
	public String layoutStatic() {
		return TEMPLATES_PATH + "layout-static";
	}

	@GetMapping("/layout-sidenav-light")
	public String layoutSidenavLight() {
		return TEMPLATES_PATH + "layout-sidenav-light";
	}

	@GetMapping("/charts")
	public String charts() {
		return TEMPLATES_PATH + "charts";
	}

	@GetMapping("/tables")
	public String tables() {
		return TEMPLATES_PATH + "tables";
	}

	@GetMapping("/401")
	public String fourZeroOne() {
		return TEMPLATES_PATH + "401";
	}

	@GetMapping("/404")
	public String fourZeroFour() {
		return TEMPLATES_PATH + "404";
	}

	@GetMapping("/500")
	public String fiveZeroZero() {
		return TEMPLATES_PATH + "500";
	}

}

 

 

 

 

그리고 index는 로그인 화면으로 변경했다.

 

 

 

 

참고

https://velog.io/@devharrypmw/Template-Engine-%ED%85%9C%ED%94%8C%EB%A6%BF-%EC%97%94%EC%A7%84

https://gocoder.tistory.com/2438

https://velog.io/@wooryung/JSP%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%98%EB%8A%94-Spring-Boot-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%83%9D%EC%84%B1%ED%95%98%EA%B8%B0

https://velog.io/@nyong_i/%EB%A8%B8%EC%8A%A4%ED%85%8C%EC%B9%98Mustache%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80