자바 백엔드 개발의 절대 강자인 Spring Framework는 강력하지만 초기 설정이 매우 복잡하다는 단점이 있었습니다. 이를 해결하기 위해 등장한 것이 바로 Spring Boot입니다. "단독 실행 가능하고 상용화 수준의 스프링 기반 애플리케이션을 단지 실행(just run)만 하면 될 정도로 쉽게 만드는 것"이 스프링 부트의 철학입니다.
스프링 부트는 기존 스프링의 복잡한 XML 설정, 서버(Tomcat) 설치 및 연동, 의존성 버전 관리 등의 골칫거리들을 모두 자동화하여 개발자가 비즈니스 로직에만 집중할 수 있게 해줍니다.
| 구분 | Spring Framework | Spring Boot |
|---|---|---|
| 의존성 관리 | 개발자가 각 라이브러리 버전의 호환성을 직접 확인하고 설정 | spring-boot-starter 하나로 호환되는 버전 세트 자동 제공 |
| 웹 서버 | 외부 Tomcat 서버에 WAR 파일을 배포해야 함 | Tomcat이 내장되어 있어 .jar 파일 실행만으로 서버 구동 |
| 환경 설정 | 복잡한 XML 또는 Java Config 파일 필수 | 대부분의 설정이 자동으로 적용됨 (Auto-Configuration) |
// Spring Boot 애플리케이션의 진입점
package com.minstudio.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
// @SpringBootApplication: 이 어노테이션 하나가 Spring Boot의 자동 설정 마법을 켭니다.
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
// 단 한 줄로 내장 톰캣 서버가 구동되고 애플리케이션이 실행됩니다.
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping("/")
public String hello() {
return "Hello, Spring Boot! 더 이상 복잡한 설정은 필요 없습니다.";
}
}스프링 부트 개발을 위해서는 자바 코드를 실행할 수 있는 엔진인 JDK(Java Development Kit)와 강력한 코드 편집기이자 작업장인 IntelliJ IDEA가 필수적입니다. 이 두 가지만 있으면 어떤 복잡한 애플리케이션도 만들어낼 수 있습니다.
| 도구 | 역할 (자동차 비유) | 권장 버전 및 종류 |
|---|---|---|
| JDK (Java Development Kit) | 자바 코드를 해석하고 실행하는 엔진 | Java 17 또는 21 (LTS 버전) 무료인 OpenJDK 권장 |
| IntelliJ IDEA | 엔진을 조립하고 설계하는 최첨단 자동차 공장 | Community(무료) 또는 Ultimate(유료) |
JDK를 설치한 후에는 운영체제가 Java의 위치를 알 수 있도록 JAVA_HOME 환경 변수를 등록해야 합니다. (최신 설치 프로그램들은 이 과정을 자동으로 해주기도 합니다.)
# 터미널에서 Java가 정상적으로 설치되었는지 확인하는 명령어
java -version
# 정상 출력 예시 (Java 17 기준)
# openjdk version "17.0.2" 2022-01-18
# OpenJDK Runtime Environment (build 17.0.2+8-86)
# OpenJDK 64-Bit Server VM (build 17.0.2+8-86, mixed mode, sharing)스프링 진영에서는 웹 브라우저에서 프로젝트의 뼈대를 자동으로 생성해 주는 start.spring.io를 제공합니다. 마법처럼 클릭 몇 번만으로 모든 기본 세팅이 완료된 프로젝트 압축 파일을 받을 수 있습니다.
스프링 이니셜라이저에서 선택해야 할 필수 항목들은 다음과 같습니다. 실무에서 가장 널리 쓰이는 표준적인 설정입니다.
| 항목 | 선택 값 | 설명 |
|---|---|---|
| Project | Gradle - Groovy | 요즘 대세 빌드 도구 (Maven보다 빠르고 스크립트 기반으로 유연함) |
| Language | Java | Kotlin도 가능하지만 본 강좌에서는 기본기인 Java를 사용 |
| Spring Boot | 3.2.x (최신 정식 버전) | SNAPSHOT(개발중)이나 M(마일스톤)이 안 붙은 버전을 선택 |
| Packaging | Jar | 스프링 부트의 내장 톰캣을 활용하기 위해 단일 Jar로 패키징 |
| Dependencies | Spring Web, Thymeleaf, Lombok | 웹 서버를 만들고(Web), 화면을 그리고(Thymeleaf), 코드 작성을 줄이기(Lombok) 위한 라이브러리 추가 |
생성된 압축 파일을 다운로드 받아 압축을 해제한 후, IntelliJ IDEA에서 build.gradle 파일을 열어 프로젝트를 로드하면 설정이 완료됩니다.
// Spring Initializr가 생성해준 의존성 파일 예시
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.4'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.minstudio'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencies {
// Spring Web (REST API, MVC 기능을 포함하며 내장 톰캣을 제공함)
implementation 'org.springframework.boot:spring-boot-starter-web'
// Thymeleaf (뷰 템플릿 엔진)
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
// 롬복 (Lombok) - Getter/Setter 등을 자동 생성해줌
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
스프링 부트 프로젝트는 기본적으로 정해진 폴더 구조(Convention)를 따릅니다. 이 구조를 이해하고, 핵심 설정 파일인 application.yml(또는 application.properties)을 다루는 법을 배웁니다.
주요 폴더 및 파일은 다음과 같습니다.
| 설정 파일 포맷 | 특징 | 예시 |
|---|---|---|
.properties |
Key-Value 형태로 작성 (스프링 부트 기본 포맷) | server.port=9090 |
.yml (YAML) |
들여쓰기 계층 구조로 작성 (가독성이 좋아 실무에서 선호) | server: |
# application.properties를 삭제하고 application.yml을 생성하세요.
server:
# 기본 포트 8080 대신 9090으로 웹 서버를 띄웁니다.
port: 9090
spring:
application:
name: minstudio-demo
@RestController 어노테이션을 사용하여 웹 브라우저의 요청(Request)을 받아 응답(Response)을 돌려주는 첫 번째 API를 만들어 봅니다.
@RestController: 이 클래스가 웹 요청을 처리하는 컨트롤러임을 스프링에 알려주며, 반환값을 그대로 문자열(JSON 등)로 전달합니다.
@GetMapping: 웹 브라우저가 주소창을 통해 접근하는 HTTP GET 요청을 특정 메서드와 연결(매핑)해 줍니다.
package com.minstudio.demo.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
// 브라우저에서 http://localhost:8080/hello 주소로 접속하면 이 메서드가 실행됩니다.
@GetMapping("/hello")
public String sayHello() {
return "🚀 Hello World! 스프링 부트로 띄운 첫 번째 웹 서버입니다.";
}
}웹 개발의 기본 뼈대가 되는 MVC 아키텍처 패턴을 배웁니다. 코드를 역할에 따라 세 가지로 나누어 유지보수성과 확장성을 극대화하는 설계 방법입니다.
| 컴포넌트 | 역할 (식당 비유) | 스프링에서의 구현 |
|---|---|---|
| Controller (컨트롤러) | 주문을 받고 요리사에게 지시하는 매니저/웨이터 | @Controller, 브라우저 요청 매핑 |
| Model (모델) | 손님에게 제공될 핵심 요리(데이터)와 로직 | 화면에 전달할 데이터를 담는 Model 객체 |
| View (뷰) | 요리가 예쁘게 담겨 나오는 접시/인테리어 | .html (Thymeleaf, JSP 등) |
이전 강의에서 사용한 @RestController는 View 없이 데이터만 반환하는 API 전용 컨트롤러입니다. 화면(HTML)을 보여주려면 일반 @Controller를 사용해야 합니다.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>MVC 뷰 화면</title>
</head>
<body>
<h2 style="color: blue;">🎉 환영합니다!</h2>
<!-- Thymeleaf 문법: Model에 담긴 userName 값을 출력합니다 -->
<p>안녕하세요, <strong th:text="${userName}">손님</strong>님!</p>
</body>
</html>
웹 브라우저나 모바일 앱이 서버에 데이터를 요청할 때, 서버에서 가장 먼저 요청을 맞이하는 문지기 역할을 하는 것이 바로 Controller입니다. 이번 시간에는 클라이언트에게 데이터를 반환하는 RESTful API를 @RestController와 @GetMapping 어노테이션을 활용해 직접 만들어봅니다.
스프링 부트에서는 골치 아픈 설정 파일 대신, 자바 클래스나 메서드 위에 @어노테이션을 붙여 기능을 부여합니다. 프레임워크가 알아서 어노테이션을 읽고 필요한 빈(Bean)들을 메모리에 올리고 연결해줍니다.
| 어노테이션 | 역할 설명 |
|---|---|
@RestController |
이 클래스가 REST API의 진입점임을 선언하며, 응답 시 기본적으로 JSON/텍스트 형식으로 데이터를 직렬화하여 반환합니다. |
@GetMapping("/경로") |
HTTP GET 요청을 특정 메서드와 매핑합니다. 지정된 URL로 요청이 오면 이 메서드가 실행됩니다. |
사용자가 브라우저 주소창에 /api/hello를 입력하면 환영 메시지를 반환하는 백엔드 코드를 작성해 봅시다.
// 강의 코드가 여기에 표시됩니다.
클라이언트는 서버에게 단순히 페이지를 달라고 요청하는 것을 넘어, 특정 조건(예: 3번 유저의 정보, 검색어 '스프링')을 포함해 요청할 수 있습니다. 이번 강의에서는 URL 경로 자체에 값을 넣는 @PathVariable과 쿼리 스트링(Query String)으로 값을 전달하는 @RequestParam의 사용법을 알아봅니다.
| 어노테이션 | 사용 예시 URL | 설명 |
|---|---|---|
@PathVariable |
/users/3 |
리소스의 고유한 식별자나 경로의 일부를 동적으로 받을 때 사용합니다. |
@RequestParam |
/users?name=kim |
필터링 조건, 검색어, 페이지네이션 등 부가적인 쿼리 파라미터를 받을 때 사용합니다. |
// 강의 코드가 여기에 표시됩니다.
POST나 PUT 요청을 할 때는 주로 대용량의 폼 데이터나 복잡한 구조를 가진 JSON을 HTTP Body에 담아 서버로 전송합니다. 스프링 부트에서는 @RequestBody 어노테이션을 통해 들어오는 JSON 데이터를 우리가 정의한 자바 객체(DTO)로 자동으로 변환(역직렬화)해 줍니다.
계층 간(클라이언트와 컨트롤러, 컨트롤러와 서비스 등) 데이터 교환을 위해 사용하는 순수한 데이터 객체입니다. Entity 객체를 직접 노출하지 않고 DTO를 사용함으로써 보안성과 유연성을 높일 수 있습니다.
// 강의 코드가 여기에 표시됩니다.웹 애플리케이션의 핵심은 데이터를 저장하고 불러오는 것입니다. JPA(Java Persistence API)를 사용하면 복잡한 SQL 쿼리를 직접 작성할 필요 없이, 자바 객체(Entity)와 DB 테이블을 매핑하여 객체 지향적인 방식으로 데이터베이스를 조작할 수 있습니다.
| JPA 구성 요소 | 역할 및 어노테이션 |
|---|---|
| Entity (엔티티) | DB 테이블과 1:1로 매칭되는 자바 클래스입니다. @Entity, @Id, @GeneratedValue 등을 사용합니다. |
| Repository (리포지토리) | 엔티티를 DB에 저장하고 조회하는 메서드를 제공하는 인터페이스입니다. JpaRepository를 상속받기만 하면 기본 CRUD가 완성됩니다. |
// 강의 코드가 여기에 표시됩니다.컨트롤러에 모든 코드를 넣게 되면 프로젝트가 커질수록 유지보수가 불가능해집니다. 따라서 핵심 비즈니스 로직(예: 중복 검사, 할인율 계산 등)은 Service 계층에 작성하고, 스프링의 핵심 기능인 DI(의존성 주입)를 이용해 Controller에 연결해 줍니다.
데이터베이스 상태를 변경하는(Insert, Update, Delete) 서비스 로직은 반드시 @Transactional 어노테이션을 붙여야 합니다. 이를 통해 중간에 에러가 나더라도 데이터가 안전하게 롤백(Rollback) 됩니다.
// 강의 코드가 여기에 표시됩니다.지금까지 배운 Controller, Service, Repository, DTO를 하나로 묶어 실제 현업에서 사용하는 형태의 완전한 CRUD (생성, 조회, 수정, 삭제) API를 완성해 봅니다.
| 기능 (CRUD) | HTTP 메서드 | URL 예시 |
|---|---|---|
| 생성 (Create) | POST |
/api/members |
| 조회 (Read) | GET |
/api/members/{id} |
| 수정 (Update) | PUT / PATCH |
/api/members/{id} |
| 삭제 (Delete) | DELETE |
/api/members/{id} |
// 강의 코드가 여기에 표시됩니다.
서버에서 에러가 발생했을 때 클라이언트에게 지저분한 자바 에러 스택 트레이스를 그대로 노출하는 것은 최악의 설계입니다. 스프링에서는 @RestControllerAdvice를 활용하여 프로젝트 내에서 발생하는 모든 예외를 한 곳에서 가로채어 깔끔한 JSON 응답으로 통일할 수 있습니다.
| 어노테이션 | 설명 및 역할 |
|---|---|
@RestControllerAdvice |
모든 컨트롤러에서 발생하는 예외를 한 클래스에서 전역적으로 처리하게 해주는 마법의 어노테이션입니다. |
@ExceptionHandler |
특정 예외(예: IllegalArgumentException.class)가 발생했을 때 실행될 메서드를 지정합니다. |
클라이언트가 이름, 나이, 이메일 등을 보낼 때 빈 값이거나 형식이 틀린 경우, 서버의 서비스 로직까지 도달하기 전에 컨트롤러 단계에서 미리 차단해야 합니다. spring-boot-starter-validation을 추가하면 DTO에 어노테이션만 붙여서 강력한 유효성 검증을 할 수 있습니다.
| 어노테이션 | 설명 |
|---|---|
@NotBlank |
null, "", " " 모두 허용하지 않습니다. (문자열에 주로 사용) |
@Email |
올바른 이메일 형식(test@domain.com)인지 검증합니다. |
@Valid |
컨트롤러의 파라미터 앞에서 해당 객체의 Validation을 작동시킵니다. |
현실 세계의 데이터는 단일 테이블로 끝나지 않습니다. 회원 1명은 게시글 N개를 쓸 수 있고(1:N), 학생 N명은 수업 N개를 들을 수 있습니다(N:M). JPA는 객체 지향적인 방식으로 이러한 관계를 설정할 수 있게 해줍니다.
| 어노테이션 및 속성 | 설명 |
|---|---|
@ManyToOne |
다대일(N:1) 관계를 매핑합니다. 보통 게시글(N)이 회원(1)을 참조할 때 사용하며, 이 어노테이션이 있는 곳이 연관관계의 주인이 됩니다. |
@OneToMany |
일대다(1:N) 관계를 매핑합니다. 회원(1)이 여러 게시글(N)을 가질 때 사용합니다. |
@JoinColumn |
실제 데이터베이스 테이블에 생성될 외래 키(Foreign Key) 컬럼의 이름을 지정합니다. (예: member_id) |
mappedBy |
양방향 매핑 시, 연관관계의 주인이 아님을 명시합니다. 반대쪽 엔티티의 변수명을 적어줍니다. |
양방향 연관관계를 맺을 때, DB 테이블에 실제 외래 키(FK)를 가지고 있는 쪽이 주인이 됩니다. 따라서 @ManyToOne이 있는 쪽(예: Post)이 주인이 되며, 반대쪽(예: Member)은 읽기 전용 거울 역할만 하도록 mappedBy 속성을 반드시 적어주어야 합니다.
웹 서비스에서 사용자의 비밀번호는 반드시 암호화(BCrypt 등)되어 저장되어야 하며, 허가되지 않은 사용자는 API에 접근할 수 없어야 합니다. Spring Security는 가장 강력한 보안 프레임워크이며, 최근에는 토큰 기반인 JWT를 함께 사용하는 것이 국룰입니다.
| 개념 | 설명 |
|---|---|
| 인증 (Authentication) | 당신이 누구인지 확인하는 과정 (아이디/비밀번호 확인) |
| 인가 (Authorization) | 당신에게 해당 API에 접근할 권한이 있는지 확인하는 과정 (ADMIN vs USER) |
| JWT (JSON Web Token) | 서버가 상태(세션)를 유지하지 않고, 클라이언트가 가진 암호화된 토큰으로 인증하는 현대적 방식 |
게시판에 사진을 첨부하거나 프로필 이미지를 설정할 때 파일 업로드 기능이 필요합니다. 스프링 부트는 MultipartFile이라는 인터페이스를 제공하여 아주 간단하게 파일을 서버 하드디스크나 클라우드 저장소(AWS S3)에 업로드할 수 있게 도와줍니다.
| 클래스 / 설정 | 설명 |
|---|---|
MultipartFile |
스프링에서 업로드된 파일을 처리하는 핵심 인터페이스. transferTo() 메서드로 실제 디스크에 저장합니다. |
max-file-size |
application.yml에서 한 번에 업로드 가능한 최대 파일 크기를 제한합니다. (기본값 1MB) |
API를 다 만들었다면 프론트엔드 개발자가 호출할 수 있도록 "설명서"를 제공해야 합니다. 수동으로 엑셀이나 위키에 작성하면 코드가 수정될 때마다 업데이트하기 매우 고통스럽습니다. Swagger(springdoc) 라이브러리를 하나만 추가하면, 현재 코드를 분석해 예쁜 웹 페이지 형태의 API 문서를 자동 생성해 줍니다.
build.gradle에 implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.2.0' 단 한 줄만 추가하고 서버를 켜면 /swagger-ui.html 경로에서 멋진 문서를 볼 수 있습니다. (Spring Boot 3.x 기준)
| 어노테이션 | 설명 (Swagger UI에 표시되는 내용) |
|---|---|
@Tag(name="...", description="...") |
컨트롤러 클래스 레벨에 붙여서 API 그룹의 이름과 설명을 정의합니다. |
@Operation(summary="...") |
각 API 메서드가 어떤 역할을 하는지 한 줄 요약을 적어줍니다. |
@Parameter(description="...") |
요청 파라미터(예: id, name)의 상세한 의미를 설명합니다. |
"잘 돌아가는지 포스트맨으로 호출해 볼까?" ➔ 매번 직접 클릭해서 테스트하는 것은 비효율적입니다. 실무에서는 자동화된 테스트 코드를 작성하여 클릭 한 번에 수백 개의 로직 결함을 잡아냅니다. JUnit5와 AssertJ를 사용하여 테스트의 신세계를 경험해 보세요.
| 어노테이션 / 메서드 | 역할 |
|---|---|
@Test |
이 메서드가 테스트 코드임을 선언합니다. 해당 메서드를 독립적으로 실행할 수 있게 됩니다. |
@DisplayName("...") |
테스트 실행 결과창(콘솔)에 보여질 한글 이름을 지정하여 가독성을 높입니다. |
assertThat(A).isEqualTo(B) |
(AssertJ) A의 값이 B와 정확히 일치하는지 단언(검증)합니다. 다르면 테스트가 실패합니다. |