SpringBoot로 Hello World 화면에 출력해보기(a.k.a Mustache)

간단한 튜토리얼인데, 최근에 간단한 Spring MVC 개발할 일이 있었는데, 지금까지 모르면서 간과하며 개발했던걸 알게되어 정리하고자 남기는 포스팅이다.
어떤걸 모르면서 개발했는지는 포스팅에서 자세히 설명하도록 하겠다.

프로젝트 생성하기

본 튜토리얼은 Spring Tool Suite 4.4.9(STS)으로 진행했다.

STS를 실행하고 [FILE] 에서 [Spring Start Project] 를 실행한다.

프로젝트명은 HelloSpringBootApp 으로 생성했다.

간단한 Hello World를 출력하는 스프링부트앱을 만들기 위해서는 Spring Web과 Mustache를 의존성으로 불러와야한다. Mustache는 화면에서 HTML 파일을 반환하기 위한 ViewResolver를 위해 필요한 의존성이다. Mustache가 아니어도 Thymeleaf 의존성을 불러와도 무방하다.

Mustache는 Thymeleaf와 달리 백엔드 개발자가 화면에서 로직을 구현할 수 없는 logicless 템플릿엔진이다.


HTML 페이지 생성하기

스프링부트 프로젝트에서는 src/main/resources에서 HTML 파일을 관리한다. 해당 디렉토리 하위에는 static과 templates 디렉토리가 있는데, static은 말그대로 정적인 자원을 반환할때 사용하는 디렉토리이고, templates는 스프링 컨테이너에 의해 동적으로 반환될 자원을 사용하는 디렉토리이다.

본 튜토리얼에서는 둘 다 사용하며 어떤 차이가 있는지 확인하려고 한다.

똑같이 hello.html 파일을 각각 src와 template 디렉토리에 생성한다.

그러나 파일내부는 서로 다른 코드를 작성해서 브라우저에서 어떻게 반환되는지를 구별하려고 한다.

static/hello.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<!-- 한글 utf-8 설정 -->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>SpringMVC - static</title>
</head>
<body>
<h1>Hello Spring Boot!</h1>
이것은 static 페이지입니다.
</body>
</html>

templates/hello.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<!-- 한글 utf-8 설정 -->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>SpringMVC - templates</title>
</head>
<body>
<h1>Hello SpringBoot!</h1>
이것은 컨트롤러에 의해 동적으로 반환되는 템플릿 html입니다.
</body>
</html>

이 파일이 스프링 컨테이너에서 찾을수 있도록 하기 위해서는 resources 디렉토리에 있는 application.properties에서 설정을 한 줄 추가한다.

1
spring.mustache.suffix: .html

이 설정을 넣어야 Mustache가 클라이언트에서 읽어들일 자원의 포맷으로 .mustache가 아닌 .html도 읽어들이게 된다.

이제 static 디렉토리와 templates 디렉토리에 이름만 같고 코드는 다른 hello.html을 생성하는 작업이 끝났다.

컨트롤러 생성하기

위에서 생성한 html 파일을 반환하도록 요청하는 컨트롤러를 생성하는 작업이다.

1
2
3
4
5
6
7
8
9
@Controller
public class HelloController(){

@GetMapping("/hello)
public String hello(){
return "hello";
}

}

여기서 주의해야할 점이 있다. 컨트롤러를 생성하는 패키지 경로는 SpringApplication.run()이 있는 스프링부트 애플리케이션 클래스와 같은 경로에 있어야 한다.

내가 그동안 아무생각없이 Spring MVC 개발을 하다가 당황스러웠던 경험도 이 때문이었다. 스프링부트 애플리케이션과 다른 경로에 패키지를 설정하면 컨트롤러가 제대로 작동되지 않는다.
아래 이미지를 참고하자.

API 요청하기

이제 스프링부트웹앱을 브라우저에서 실행해서 위에서 만든 html 파일들을 어떻게 반환받을 수 있는지 알아보자.

첫번째로는 static 디렉토리에 있는 정적인 파일을 반환받으려고 한다. 브라우저 주소창에 localhost:8080/hello.html 이라고 입력하면 아래와 같이 정상적으로 화면이 출력된다.

이번에는 templates 디렉토리에 있는 동적인 파일을 반환받으려고 한다. 브라우저 주소창에 localhost:8080/hello 라고만 입력하면 아래처럼 화면을 출력받을 것이다.

여기까지는 사실 파일의 확장자를 붙이느냐, 안붙이느냐 정도의 차이만 구별되는데, 동적으로 파일을 반환할 수 있는 templates 자원의 경우 API를 요청할때 들어오는 인자값에 따라 화면에 인자값을 출력하거나 값을 가공하여 동적으로 반환할 수도 있다.

이를위해 templates 디렉토리에 있는 파일과 컨트롤러를 수정해보겠다.

templates/hello.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!DOCTYPE html>
<html>
<head>
<!-- 한글 utf-8 설정 -->
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>SpringMVC - templates</title>
</head>
<body>
<h1>Hello SpringBoot!</h1>
Welcome, {{name}}.
</body>
</html>

HelloController.java

1
2
3
4
5
6
7
8
9
10
@Controller
public class HelloController(){

@GetMapping("/hello)
public String hello(String name, Model model){
model.addAttribute("name", name);
return "hello";
}

}

hello()의 파라미터로 2가지를 주입했다. String형 name은 클라이언트로부터 입력받는 값을 name이라는 변수에 담기 위함이며, Model 객체는 화면에 뿌려주기 위해 필요한 객체이다.
Model 객체의 addAttribute()를 이용하면, Model 객체에 값을 저장하여 화면에 뿌려준다.

이 때, addAttribute("name", name)의 첫번째 파라미터가 화면에서 받을 property 이름이며, 두번째 파라미터가 이 model 객체로 넣을 파라미터 객체이다.

그럼 이제 브라우저에 아까와 다른 URL를 요청해보자.

localhost:8080/hello?name=devandy

다른 이름을 대입하면 그 이름이 화면에 출력될 것이다. 이것이 API 컨트롤러와 templates 경로내 자원으로 할 수 있는 일이다.