01_환경설정
JDK : 17
IDE : IntelliJ
SpringBoot : 3.1.0

02_Hello World 출력하기
📍 프로젝트 실행
src/main/java/com.example.firstproject/FirstprojectApplication.java
package com.example.firstproject;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class FirstprojectApplication {
public static void main(String[] args) {
SpringApplication.run(FirstprojectApplication.class, args);
}
}
서버를 실행하면 톰캣이 8080 포트에서 수행된다.
브라우저에 localhost:8080을 입력하면 아래와 같은 에러 페이지 뜬다.
아직 웹페이지가 없기 때문에 발생하는 에러다.

- localhost : '내 컴퓨터' 서버의 주소를 의미
- 8080 : 포트번호. 스프링부트 프로젝트가 톰캣에 담겨 8080에서 수행됨
📍 HTML 파일 생성
아래 위치에 HTML 파일 생성한다.
src/main/resources/static/hello.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>hello world!</h1>
</body>
</html>
브라우저에서 localhost:8080/hello.html로 접속하면 내 컴퓨터의 8080번 포트에서 수행되는 서버에 hello.html 파일을 요청한다.
hello world! 가 정상적으로 출력된 것을 확인할 수 있다.

03_MVC 패턴
📍 MVC 패턴이란
웹페이지를 화면에 보여주고(View), 클라이언트의 요청을 받아 처리하고(Controller), 데이터를 관리하는(Model) 역할을 영역별로 나누어 하는 기법
- Model : 데이터 관리
- View : 화면 담당
- Controller : 클라이언트의 요청에 따라 서버에서 이를 처리

📍 뷰(View) 템플릿
웹 페이지를 하나의 템플릿으로 만들고 여기에 변수를 삽입해 서로 다른 페이지로 보여준다.
템플릿 엔진에는 Mustache, Thymeleaf, JSP 등이 있다.
mustache 파일을 생성하고 doc을 입력한 다음 Tab 키를 누르면 기본 HTML 코드가 제공된다.
src/main/resources/templates/greetings.mustache
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>푸딩님, 반갑습니다!</h1>
</body>
</html>
📍 컨트롤러(Controller) 생성
기본 패키지 안에 controller라는 패키지 생성하고 그 내부에 Controller 자바 클래스를 생성한다.
src/main/java/com.example.firstproject/controller/FirstController.java
package com.example.firstproject.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class FirstController {
@GetMapping("/hi")
public String niceToMeetYou() {
return "greetings"; // greetings.mustache 파일 반환
}
}
🔍 코드 설명
- @Controller : 이 클래스가 컨트롤러임을 선언하는 어노테이션
- @GetMapping() : 메서드에서 반환된 값을 괄호 내부 주소로 반환해달라는 URL 요청을 접수
브라우저에서 localhost:8080/hi로 접속하면 뷰 템플릿 페이지가 나온다.

📍 모델(Model) 추가
mustache 파일을 동적으로 바꾸기 위해서는 우선 뷰 템플릿 코드에 변수를 삽입한다.
💡 {{변수명}}
src/main/resources/templates/greetings.mustache
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>{{username}}님, 반갑습니다!</h1>
</body>
</html>
다음으로 모델을 추가한다.
Controller에서 NiceToMeetYou 메서드에 Model 타입의 매개변수를 추가한다.
이 모델을 통해 변수 등록할 수 있다.
💡 model.addAttribute("변수명", 변숫값) // 모델 객체가 변숫값을 변수에 연결해 웹 브라우저로 보냄
src/main/java/com.example.firstproject/controller/FirstController.java
package com.example.firstproject.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class FirstController {
@GetMapping("/hi")
public String niceToMeetYou(Model model) { // model 객체 받아오기
model.addAttribute("username", "우유");
return "greetings"; // greetings.mustache 파일 반환
}
}
🔍 코드 설명
- @Controller 에서 이 파일이 컨트롤러임을 선언
- @GetMapping("/hi")에서 클라이언트로부터 "/hi"라는 요청을 받아 접수
- niceToMeetYou() 메서드 수행
- 모델 객체를 매개변수로 가져옴
- model.addAttribute에서 모델에서 사용할 변수 등록
- greetings.mustache 파일 반환
이렇게 하면 변숫값에 따라 결과가 그때그때 다르게 출력된다.

만약 작별인사하는 페이지를 만들고 싶다면 다음과 같이 만들면 된다.
src/main/java/com.example.firstproject/controller/FirstController.java
package com.example.firstproject.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class FirstController {
@GetMapping("/hi")
public String niceToMeetYou(Model model) { // model 객체 받아오기
model.addAttribute("username", "우유");
return "greetings"; // greetings.mustache 파일 반환
}
@GetMapping("/bye")
public String seeYouNext(Model model) {
model.addAttribute("nickname", "홍길동");
return "goodbye";
}
}
src/main/resources/templates/goodbye.mustache
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<h1>{{nickname}}님, 다음에 또 만나요!</h1>
</body>
</html>
브라우저에서 localhost:8080/hi로 접속하면 뷰 템플릿 페이지가 나온다.

05_레이아웃 적용
📍 header-footer layout
상단의 헤더(header) 영역에는 사이트 안내를 위한 네비게이션을 넣고, 하단의 푸터(footer) 영역에는 사이트 정보를 넣는다.
두 영역 사이에는 핵심 내용인 콘텐트(content)를 배치한다.
/hi 페이지에 레이아웃 적용
Bootstrap
Powerful, extensible, and feature-packed frontend toolkit. Build and customize with Sass, utilize prebuilt grid system and components, and bring projects to life with powerful JavaScript plugins.
getbootstrap.com
부트스트랩에서 starter template, navbar를 가져와서 코드 작성하였다.
src/main/resources/templates/greetings.mustache
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<!-- navigation -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">Navbar</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
Dropdown
</a>
<ul class="dropdown-menu" aria-labelledby="navbarDropdown">
<li><a class="dropdown-item" href="#">Action</a></li>
<li><a class="dropdown-item" href="#">Another action</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#">Something else here</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul>
<form class="d-flex">
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">Search</button>
</form>
</div>
</div>
</nav>
<!-- content -->
<h1>{{username}}님, 반갑습니다!</h1>
<!-- site info -->
<div class="bg-dark text-white p-5">
<hr>
<p>Ⓒ CloudStudying | <a href="#">Privacy</a> | <a href="#">Terms</a></p>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
</body>
</html>

📍 레이아웃 템플릿화
/bye 페이지에도 같은 레이아웃 적용하려면 코드 다시 복사해야 하는데 불편하다.
그래서 코드를 하나의 틀로 만들어서 변수화를 하는 것이 좋다.
src/main/resources/templates/layouts 안에 header.mustache와 footer.mustache 파일을 생성하고, 각 부분의 코드를 삽입하면 템플릿이 만들어진다.
사용방법은 다음과 같다.
💡 {{>layouts/header}}
src/main/resources/templates/goodbye.mustache
{{>layouts/header}}
<div class="bg-dark text-white p-5">
<h1>{{nickname}}님, 다음에 또 만나요!</h1>
</div>
{{>layouts/footer}}
06_한글 깨짐 해결

위 이미지처럼 한글 깨짐이 발생하면 src/main/resources/application.properties 파일에 다음 코드를 추가하고 재시작한다.
server.servlet.encoding.force=true'Back-end > SpringBoot' 카테고리의 다른 글
| [SpringBoot] 3-4장 게시글 생성(CREATE), 롬복(lombok)과 리팩터링 (0) | 2026.01.11 |
|---|---|
| [SpringBoot] 프로젝트 초기화 방법 (0) | 2024.01.13 |
| [SpringBoot] 스프링 입문 - 1. 프로젝트 환경 설정 (0) | 2024.01.07 |