2025-04-08T19:56:24

This commit is contained in:
2025-04-08 19:56:24 +09:00
parent a75a1dbd0f
commit eef061c1c9
100 changed files with 18639 additions and 0 deletions

View File

@@ -0,0 +1,505 @@
# **Spring Boot MVC: 컨트롤러와 요청 처리**
Spring Boot의 핵심 기능 중 하나는 **MVC(Model-View-Controller) 패턴을 사용한 웹 요청 처리**입니다.
이 글에서는 **Spring Boot에서 컨트롤러가 어떻게 요청을 처리하는지**, 그리고 실무에서 **자주 사용하는 컨트롤러 관련 기능**을 예제와 함께 설명합니다.
---
## **1. 컨트롤러란?**
컨트롤러(Controller)는 **클라이언트의 요청을 받아서 비즈니스 로직을 수행하고, 응답을 반환하는 역할**을 합니다.
Spring Boot에서는 `@RestController` 또는 `@Controller` 어노테이션을 사용하여 컨트롤러를 정의합니다.
---
## **2. 기본 컨트롤러 작성하기**
Spring Boot에서는 `@RestController`를 사용하면 JSON 형태로 응답을 반환할 수 있습니다.
### **📌 기본 컨트롤러 예제**
```java
@RestController
@RequestMapping("/api")
public class HelloController {
@GetMapping("/hello")
public String sayHello() {
return "Hello, Spring Boot!";
}
}
```
#### **📌 실행 결과 (`http://localhost:8080/api/hello` 요청)**
```json
Hello, Spring Boot!
```
**설명:**
- `@RestController` → REST API를 위한 컨트롤러를 정의.
- `@RequestMapping("/api")` → 모든 경로가 `/api`로 시작하도록 설정.
- `@GetMapping("/hello")``/api/hello`로 GET 요청이 들어오면 `"Hello, Spring Boot!"` 반환.
---
## **3. 요청 매개변수 처리**
클라이언트가 **쿼리 파라미터** 또는 **URL 경로 변수**를 전달하면, 이를 컨트롤러에서 처리할 수 있습니다.
### **📌 `@RequestParam` 사용 (쿼리 파라미터)**
```java
@RestController
@RequestMapping("/api")
public class GreetingController {
@GetMapping("/greet")
public String greet(@RequestParam String name) {
return "Hello, " + name + "!";
}
}
```
#### **📌 실행 결과 (`http://localhost:8080/api/greet?name=John` 요청)**
```json
Hello, John!
```
**설명:**
- `@RequestParam`을 사용하면 **쿼리 파라미터에서 값을 가져올 수 있음**.
- 예제에서는 `name` 값을 받아 `"Hello, John!"`을 반환.
---
### **📌 `@PathVariable` 사용 (URL 경로 변수)**
```java
@RestController
@RequestMapping("/api")
public class UserController {
@GetMapping("/user/{id}")
public String getUser(@PathVariable int id) {
return "User ID: " + id;
}
}
```
#### **📌 실행 결과 (`http://localhost:8080/api/user/5` 요청)**
```json
User ID: 5
```
**설명:**
- `@PathVariable`을 사용하면 **URL 경로에서 변수를 추출**할 수 있음.
- 예제에서는 `/user/5` 요청 시, `id=5`로 인식하여 `"User ID: 5"` 반환.
---
## **4. 요청 본문 처리 (POST 요청)**
클라이언트가 **JSON 데이터를 요청 본문(body)에 담아 전송**하면, 이를 컨트롤러에서 처리할 수 있습니다.
### **📌 `@RequestBody` 사용**
```java
@RestController
@RequestMapping("/api")
public class ProductController {
@PostMapping("/product")
public String createProduct(@RequestBody Product product) {
return "Product created: " + product.getName();
}
}
class Product {
private String name;
private double price;
// 기본 생성자 필요 (JSON 역직렬화)
public Product() {}
public String getName() { return name; }
public double getPrice() { return price; }
}
```
#### **📌 실행 결과 (`POST /api/product` 요청)**
##### **요청 본문(JSON)**
```json
{
"name": "Laptop",
"price": 1200.00
}
```
##### **응답**
```json
Product created: Laptop
```
**설명:**
- `@RequestBody`를 사용하면 **JSON 데이터를 Java 객체로 변환하여 받을 수 있음**.
- 클라이언트가 `{ "name": "Laptop", "price": 1200.00 }`을 전송하면, 이를 `Product` 객체로 매핑.
- `"Product created: Laptop"`을 반환.
---
## **5. 응답 데이터 처리**
Spring Boot에서는 다양한 방식으로 응답을 반환할 수 있습니다.
### **📌 `ResponseEntity`를 사용한 응답 처리**
```java
@RestController
@RequestMapping("/api")
public class ResponseController {
@GetMapping("/status")
public ResponseEntity<String> getStatus() {
return ResponseEntity.status(HttpStatus.OK)
.body("Everything is fine!");
}
}
```
#### **📌 실행 결과 (`GET /api/status` 요청)**
```json
Everything is fine!
```
**설명:**
- `ResponseEntity`를 사용하면 **HTTP 상태 코드와 응답 데이터를 함께 설정 가능**.
- `HttpStatus.OK` → 200 응답 코드 설정.
---
## **6. 요청 및 응답 헤더 처리**
### **📌 `@RequestHeader` 사용 (요청 헤더 읽기)**
```java
@RestController
@RequestMapping("/api")
public class HeaderController {
@GetMapping("/header")
public String getHeader(@RequestHeader("User-Agent") String userAgent) {
return "Your User-Agent: " + userAgent;
}
}
```
#### **📌 실행 결과 (`GET /api/header` 요청)**
```json
Your User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
```
**설명:**
- `@RequestHeader("User-Agent")`를 사용하여 요청 헤더에서 **User-Agent 값 추출**.
---
## **7. 예외 처리 (`@ExceptionHandler`)**
### **📌 컨트롤러에서 예외 처리하기**
```java
@RestController
@RequestMapping("/api")
public class ExceptionController {
@GetMapping("/error")
public String throwError() {
throw new RuntimeException("Something went wrong!");
}
@ExceptionHandler(RuntimeException.class)
public ResponseEntity<String> handleRuntimeException(RuntimeException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Error: " + e.getMessage());
}
}
```
#### **📌 실행 결과 (`GET /api/error` 요청)**
```json
Error: Something went wrong!
```
**설명:**
- `@ExceptionHandler(RuntimeException.class)`을 사용하여 **컨트롤러 내에서 예외 처리**.
---
## **8. 정리**
| 기능 | 어노테이션 | 설명 |
|------|----------|------|
| **기본 컨트롤러** | `@RestController` | REST API 컨트롤러 정의 |
| **GET 요청 처리** | `@GetMapping` | HTTP GET 요청 매핑 |
| **POST 요청 처리** | `@PostMapping` | HTTP POST 요청 매핑 |
| **쿼리 파라미터** | `@RequestParam` | URL 쿼리 매개변수 받기 |
| **URL 경로 변수** | `@PathVariable` | URL 경로에서 값 추출 |
| **JSON 요청 본문** | `@RequestBody` | 요청 본문을 객체로 매핑 |
| **요청 헤더 처리** | `@RequestHeader` | 요청 헤더 값을 읽기 |
| **응답 처리** | `ResponseEntity` | 상태 코드와 함께 응답 반환 |
| **예외 처리** | `@ExceptionHandler` | 예외 발생 시 응답 처리 |
Spring Boot의 컨트롤러는 **간결하면서도 강력한 기능**을 제공합니다.
실무에서는 **REST API 개발 시 `@RestController`, 요청 처리 시 `@RequestParam`, `@RequestBody`, 예외 처리 시 `@ExceptionHandler`** 등을 적극 활용하면 좋습니다!
------
# **Spring Boot MVC에서 컨트롤러와 요청 처리**
Spring Boot MVC에서 컨트롤러는 **클라이언트 요청을 받아 적절한 응답을 반환하는 역할**을 합니다. 컨트롤러를 정의하려면 `@Controller` 또는 `@RestController`를 사용하며, 요청을 처리하는 메서드는 `@RequestMapping`, `@GetMapping`, `@PostMapping` 등의 어노테이션을 사용하여 HTTP 요청을 매핑할 수 있습니다.
---
## **1. 컨트롤러 기본 개념**
컨트롤러는 **MVC(Model-View-Controller) 패턴에서 "C(Controller)" 역할**을 하며, 클라이언트의 요청을 받아서 처리한 후 적절한 뷰(HTML) 또는 데이터를 응답으로 반환합니다.
### **📌 컨트롤러를 정의하는 어노테이션**
| 어노테이션 | 설명 |
|------------|----------------------------------|
| `@Controller` | 뷰(HTML)를 반환하는 컨트롤러 |
| `@RestController` | JSON, XML 데이터를 반환하는 컨트롤러 |
| `@RequestMapping` | HTTP 요청을 특정 메서드에 매핑 |
| `@GetMapping` | GET 요청을 처리 |
| `@PostMapping` | POST 요청을 처리 |
| `@PutMapping` | PUT 요청을 처리 |
| `@DeleteMapping` | DELETE 요청을 처리 |
---
## **2. 기본 컨트롤러 예제**
```java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "Hello, Spring Boot!");
return "home"; // home.html 템플릿을 반환
}
}
```
### **🛠️ 코드 설명**
- `@Controller`**이 클래스를 컨트롤러로 선언**
- `@GetMapping("/")`**루트 경로(`/`)로 GET 요청이 들어오면 `home()` 메서드 실행**
- `Model` 객체를 이용해 `"message"` 데이터를 뷰로 전달
- `return "home"`**`home.html` 템플릿을 사용하여 응답 반환**
---
## **3. `@RestController`를 사용한 JSON 응답 컨트롤러**
```java
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ApiController {
@GetMapping("/api/hello")
public String hello(@RequestParam(defaultValue = "Guest") String name) {
return "Hello, " + name + "!";
}
}
```
### **🛠️ 코드 설명**
- `@RestController`**뷰가 아니라 JSON 데이터 응답을 위한 컨트롤러**
- `@GetMapping("/api/hello")`**`/api/hello`로 GET 요청이 들어오면 `hello()` 실행**
- `@RequestParam("name")`**쿼리 파라미터(name)를 받아서 사용**
- `return "Hello, " + name + "!";`**단순한 문자열을 응답으로 반환**
### **✅ 실행 예시**
요청:
```
GET http://localhost:8080/api/hello?name=John
```
응답:
```json
Hello, John!
```
---
## **4. `@RequestParam`과 `@PathVariable`의 차이**
### **1) `@RequestParam`: 쿼리 파라미터 받기**
```java
@GetMapping("/search")
public String search(@RequestParam String keyword) {
return "검색어: " + keyword;
}
```
- 요청 예시:
```
GET /search?keyword=spring
```
- 응답: `"검색어: spring"`
---
### **2) `@PathVariable`: URL 경로 변수 받기**
```java
@GetMapping("/user/{id}")
public String getUser(@PathVariable int id) {
return "User ID: " + id;
}
```
- 요청 예시:
```
GET /user/123
```
- 응답: `"User ID: 123"`
---
## **5. `@PostMapping`을 이용한 데이터 전송 처리**
### **📌 POST 요청을 이용한 폼 데이터 처리**
```java
import org.springframework.web.bind.annotation.*;
@RestController
public class UserController {
@PostMapping("/user")
public String createUser(@RequestParam String name, @RequestParam int age) {
return "User Created: " + name + ", Age: " + age;
}
}
```
- 요청 예시 (POST 요청):
```
POST /user
Content-Type: application/x-www-form-urlencoded
name=John&age=25
```
- 응답:
```
User Created: John, Age: 25
```
---
## **6. `@RequestBody`를 이용한 JSON 데이터 처리**
`@RequestBody`를 사용하면 **JSON 데이터를 Java 객체로 변환**할 수 있습니다.
```java
import org.springframework.web.bind.annotation.*;
@RestController
public class UserController {
static class User {
public String name;
public int age;
}
@PostMapping("/user")
public String createUser(@RequestBody User user) {
return "User Created: " + user.name + ", Age: " + user.age;
}
}
```
### **✅ 실행 예시**
요청 (POST 요청, JSON 데이터 전달):
```json
POST /user
Content-Type: application/json
{
"name": "Alice",
"age": 30
}
```
응답:
```json
User Created: Alice, Age: 30
```
---
## **7. `@ResponseEntity`를 활용한 응답 제어**
`ResponseEntity`를 사용하면 **HTTP 상태 코드와 응답을 함께 제어**할 수 있습니다.
```java
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
public class ResponseController {
@GetMapping("/status")
public ResponseEntity<String> getStatus() {
return ResponseEntity.ok("서버 정상 작동 중");
}
@GetMapping("/error")
public ResponseEntity<String> getError() {
return ResponseEntity.status(400).body("잘못된 요청입니다.");
}
}
```
### **✅ 실행 예시**
- 정상 요청:
```
GET /status
```
응답: `200 OK`, `"서버 정상 작동 중"`
- 오류 요청:
```
GET /error
```
응답: `400 Bad Request`, `"잘못된 요청입니다."`
---
## **8. `@ExceptionHandler`를 활용한 예외 처리**
```java
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
public class ExceptionController {
@GetMapping("/divide")
public int divide(@RequestParam int a, @RequestParam int b) {
return a / b; // b가 0이면 오류 발생
}
@ExceptionHandler(ArithmeticException.class)
public ResponseEntity<String> handleArithmeticException() {
return ResponseEntity.status(400).body("0으로 나눌 수 없습니다.");
}
}
```
### **✅ 실행 예시**
- 정상 요청:
```
GET /divide?a=10&b=2
```
응답: `5`
- 오류 요청 (`b=0`):
```
GET /divide?a=10&b=0
```
응답: `400 Bad Request`, `"0으로 나눌 수 없습니다."`
---
## **🔍 정리**
Spring Boot MVC에서 컨트롤러를 사용하면 **HTTP 요청을 처리하고, 클라이언트에게 적절한 응답을 반환**할 수 있습니다.
- `@Controller`: HTML 뷰 반환
- `@RestController`: JSON 응답 반환
- `@RequestParam`, `@PathVariable`: 요청 데이터 받기
- `@PostMapping` + `@RequestBody`: JSON 데이터 처리
- `ResponseEntity`: 응답 제어
- `@ExceptionHandler`: 예외 처리
**이제 실무에서도 자신 있게 컨트롤러를 활용해 보세요!**

View File

@@ -0,0 +1,222 @@
# **Spring Boot의 뷰 렌더링과 Thymeleaf 템플릿 사용법**
Spring Boot에서는 **Thymeleaf**를 사용하여 **HTML 기반의 동적 웹 페이지를 렌더링**할 수 있습니다.
이 글에서는 **뷰 렌더링 개념, Thymeleaf 설정, 기본 문법, 폼 처리, 반복문 및 조건문 활용** 등을 예제와 함께 설명합니다.
---
## **1. 뷰(View) 렌더링이란?**
- 클라이언트가 요청을 보내면, **컨트롤러가 요청을 처리하고 데이터를 모델(Model)에 담아 뷰(View)로 전달**합니다.
- 뷰(View)는 **HTML 페이지**로, Thymeleaf 같은 템플릿 엔진을 사용하면 **서버에서 동적으로 HTML을 생성**할 수 있습니다.
- Spring Boot에서 대표적인 뷰 템플릿 엔진: **Thymeleaf, JSP, FreeMarker** 등이 있지만, **Thymeleaf가 가장 많이 사용됨**.
---
## **2. Thymeleaf 설정하기**
### **📌 1) Thymeleaf 의존성 추가 (Maven)**
`pom.xml`에 다음과 같이 Thymeleaf 의존성을 추가합니다.
```xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
```
### **📌 2) Thymeleaf 템플릿 디렉토리**
Spring Boot는 기본적으로 **`src/main/resources/templates/`** 경로에서 Thymeleaf 템플릿을 찾습니다.
```
src/
├── main/
│ ├── java/com.example.demo/
│ ├── resources/
│ │ ├── templates/ → Thymeleaf HTML 파일 위치
│ │ │ ├── index.html
│ │ │ ├── user.html
│ │ ├── application.properties
```
---
## **3. 기본 컨트롤러와 템플릿 렌더링**
### **📌 1) 컨트롤러 작성**
```java
@Controller
public class HomeController {
@GetMapping("/")
public String home(Model model) {
model.addAttribute("message", "Welcome to Thymeleaf!");
return "index"; // templates/index.html 파일을 렌더링
}
}
```
**설명:**
- `@Controller` → HTML을 반환하는 컨트롤러.
- `Model`**뷰로 데이터를 전달하는 객체**.
- `model.addAttribute("message", "Welcome to Thymeleaf!")``message`라는 데이터를 전달.
- `return "index";``templates/index.html` 파일을 렌더링.
---
### **📌 2) Thymeleaf 템플릿 (index.html)**
```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Thymeleaf Example</title>
</head>
<body>
<h1 th:text="${message}">Default Message</h1>
</body>
</html>
```
#### **📌 실행 결과 (`http://localhost:8080/` 요청)**
```html
<h1>Welcome to Thymeleaf!</h1>
```
**설명:**
- `th:text="${message}"``message` 값이 `"Welcome to Thymeleaf!"`로 변경됨.
- **템플릿 엔진이 동적으로 HTML을 생성**하여 클라이언트에 응답.
---
## **4. 변수 출력 및 표현식**
### **📌 1) 기본 표현식 (`th:text`)**
```html
<p th:text="${username}">Default Name</p>
```
- **`${변수명}`** → `Model`에서 전달된 변수를 표시.
### **📌 2) 객체의 필드 출력 (`th:text`)**
```java
class User {
private String name;
private int age;
public User(String name, int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public int getAge() { return age; }
}
```
```java
@GetMapping("/user")
public String userProfile(Model model) {
model.addAttribute("user", new User("Alice", 25));
return "user";
}
```
```html
<p th:text="${user.name}">Default Name</p>
<p th:text="${user.age}">Default Age</p>
```
**📌 실행 결과 (`/user` 요청)**
```html
<p>Alice</p>
<p>25</p>
```
---
## **5. 반복문 (`th:each`)**
### **📌 1) 리스트 반복 (`th:each`)**
```java
@GetMapping("/users")
public String users(Model model) {
List<User> userList = Arrays.asList(
new User("Alice", 25),
new User("Bob", 30),
new User("Charlie", 22)
);
model.addAttribute("users", userList);
return "users";
}
```
```html
<ul>
<li th:each="user : ${users}">
<span th:text="${user.name}"></span> - <span th:text="${user.age}"></span>
</li>
</ul>
```
#### **📌 실행 결과 (`/users` 요청)**
```html
<ul>
<li>Alice - 25</li>
<li>Bob - 30</li>
<li>Charlie - 22</li>
</ul>
```
---
## **6. 조건문 (`th:if`, `th:unless`)**
### **📌 1) 값이 있을 때만 표시 (`th:if`)**
```html
<p th:if="${user.age >= 18}">Adult</p>
```
### **📌 2) 값이 없을 때 표시 (`th:unless`)**
```html
<p th:unless="${user.age >= 18}">Minor</p>
```
---
## **7. 폼 처리 (`@PostMapping`)**
### **📌 1) 컨트롤러에서 폼 데이터 받기**
```java
@Controller
@RequestMapping("/form")
public class FormController {
@GetMapping
public String showForm(Model model) {
model.addAttribute("user", new User("", 0));
return "form";
}
@PostMapping
public String submitForm(@ModelAttribute User user, Model model) {
model.addAttribute("submittedUser", user);
return "result";
}
}
```
### **📌 2) Thymeleaf 폼 (form.html)**
```html
<form action="#" th:action="@{/form}" th:object="${user}" method="post">
Name: <input type="text" th:field="*{name}" />
Age: <input type="number" th:field="*{age}" />
<button type="submit">Submit</button>
</form>
```
### **📌 3) 결과 페이지 (result.html)**
```html
<p>Name: <span th:text="${submittedUser.name}"></span></p>
<p>Age: <span th:text="${submittedUser.age}"></span></p>
```
---
## **8. 정리**
| 기능 | Thymeleaf 문법 | 설명 |
|------|--------------|------|
| **텍스트 출력** | `th:text="${변수}"` | 변수 값을 출력 |
| **객체 속성 출력** | `th:text="${객체.필드}"` | 객체의 필드 값을 출력 |
| **반복문** | `th:each="item : ${리스트}"` | 리스트 반복 출력 |
| **조건문** | `th:if`, `th:unless` | 조건부 렌더링 |
| **폼 바인딩** | `th:object` + `th:field` | HTML 폼과 객체 바인딩 |
| **URL 매핑** | `th:action="@{경로}"` | 폼 요청 경로 설정 |
Thymeleaf는 **Spring Boot와 강력한 통합을 제공**하여, 동적 웹 페이지를 쉽게 렌더링할 수 있습니다.
**특히, HTML 파일을 유지하면서 동적 데이터를 추가할 수 있어 유지보수성이 뛰어납니다.**

View File

@@ -0,0 +1,213 @@
# **서비스 계층과 비즈니스 로직**
Spring Boot 애플리케이션을 설계할 때, 코드의 **재사용성, 유지보수성, 테스트 용이성**을 높이려면 **비즈니스 로직을 서비스 계층(Service Layer)에 분리**하는 것이 중요합니다.
이 글에서는 **서비스 계층의 역할, 설계 방식, 그리고 예제 코드**를 통해 비즈니스 로직을 어떻게 다루어야 하는지 설명합니다.
---
## **1. 서비스 계층이란?**
Spring Boot 애플리케이션은 일반적으로 **MVC (Model-View-Controller) 구조**를 따릅니다.
이때 **서비스 계층은 컨트롤러와 데이터 계층(Repository) 사이에서 비즈니스 로직을 처리하는 역할**을 합니다.
### **📌 계층별 역할**
| 계층 | 역할 |
|------|------|
| **Controller (컨트롤러 계층)** | 사용자 요청을 받아 서비스 계층에 전달 |
| **Service (서비스 계층)** | 비즈니스 로직을 처리하고 트랜잭션을 관리 |
| **Repository (데이터 계층)** | 데이터베이스와 직접적인 통신을 담당 |
---
## **2. 서비스 계층의 필요성**
### **📌 컨트롤러에서 직접 로직을 처리하는 문제점**
```java
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserRepository userRepository; // 데이터 계층 직접 접근
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
if (user.getName() == null || user.getAge() < 0) {
throw new IllegalArgumentException("Invalid user data");
}
return ResponseEntity.ok(userRepository.save(user)); // 비즈니스 로직이 컨트롤러에 있음
}
}
```
**🚨 문제점:**
1. **컨트롤러가 너무 많은 책임을 가짐** → 가독성과 유지보수성이 떨어짐.
2. **비즈니스 로직이 중복될 가능성 증가** → 여러 컨트롤러에서 같은 로직을 작성할 가능성이 큼.
3. **테스트가 어려움** → 서비스 계층이 없으면 컨트롤러 단위 테스트가 복잡해짐.
---
## **3. 서비스 계층을 활용한 개선된 설계**
### **📌 1) Entity (데이터 모델)**
```java
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age;
// 기본 생성자 및 getter, setter
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
```
### **📌 2) Repository (데이터 계층)**
```java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
```
**설명:**
- `JpaRepository<User, Long>``User` 엔티티를 다루는 JPA 리포지토리.
- `findById(id)`, `save(entity)`, `deleteById(id)` 등 기본적인 DB 연산 제공.
---
### **📌 3) Service (비즈니스 로직 계층)**
```java
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public User createUser(User user) {
if (user.getName() == null || user.getAge() < 0) {
throw new IllegalArgumentException("Invalid user data");
}
return userRepository.save(user);
}
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found"));
}
}
```
**🚀 개선된 점:**
**컨트롤러에서 비즈니스 로직이 제거됨** → 역할이 명확해짐.
**비즈니스 로직이 서비스 계층에 집중됨** → 재사용성 증가.
**트랜잭션 관리 가능**`@Transactional`을 활용하여 데이터 일관성 유지.
---
### **📌 4) Controller (컨트롤러 계층)**
```java
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
return ResponseEntity.ok(userService.createUser(user));
}
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
return ResponseEntity.ok(userService.getUserById(id));
}
}
```
**🚀 컨트롤러가 깔끔해짐!**
✔ 비즈니스 로직을 서비스 계층에 위임.
✔ 컨트롤러는 단순히 요청을 받고 응답을 반환하는 역할만 수행.
---
## **4. 서비스 계층에서 트랜잭션 관리**
### **📌 트랜잭션 (`@Transactional`)이란?**
- 여러 개의 DB 연산을 하나의 단위로 묶어 **"모두 성공하거나, 하나라도 실패하면 롤백"**하도록 보장.
- `@Transactional`을 붙이면, **예외가 발생할 경우 자동으로 롤백**됨.
### **📌 예제: 트랜잭션을 적용한 서비스**
```java
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void registerUsers(List<User> users) {
for (User user : users) {
if (user.getAge() < 0) {
throw new RuntimeException("Invalid age");
}
userRepository.save(user);
}
}
}
```
**🚀 특징:**
- 만약 `user.getAge() < 0`인 사용자가 있다면, **이전까지 저장된 사용자도 롤백됨**.
- 데이터 무결성을 보장할 수 있음.
---
## **5. 서비스 계층을 활용한 테스트**
### **📌 JUnit을 활용한 서비스 계층 테스트**
```java
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void testCreateUser() {
User user = new User("Alice", 25);
User savedUser = userService.createUser(user);
assertNotNull(savedUser);
assertEquals("Alice", savedUser.getName());
}
}
```
**🚀 서비스 계층이 분리되어 있어, 테스트가 쉬워짐!**
`UserService`만 단독으로 테스트 가능.
`UserRepository`가 직접 드러나지 않으므로, Mocking(가짜 데이터)도 쉽게 적용 가능.
---
## **6. 정리**
| 계층 | 설명 |
|------|------|
| **Controller** | 요청을 받고 응답을 반환 (비즈니스 로직 X) |
| **Service** | 비즈니스 로직 처리 및 트랜잭션 관리 |
| **Repository** | 데이터베이스와 직접 통신 |
### **✅ 좋은 서비스 계층 설계 원칙**
✔ **컨트롤러는 서비스에 로직을 위임**하고, 직접 처리하지 않음.
✔ **비즈니스 로직은 서비스 계층에서 일괄적으로 관리**하여 재사용성을 높임.
✔ **트랜잭션 관리 (`@Transactional`)을 서비스 계층에서 수행**하여 데이터 무결성을 보장.
**테스트가 용이하도록 서비스 계층을 단독으로 분리**.
서비스 계층을 잘 활용하면, **더 유지보수하기 좋은 코드**를 만들 수 있습니다.

View File

@@ -0,0 +1,213 @@
# **데이터 처리와 JPA**
웹 애플리케이션에서 **데이터 처리(Data Processing)**는 필수적인 요소이며, 이를 효율적으로 다루기 위해 ORM 프레임워크인 **JPA (Java Persistence API)**가 널리 사용됩니다.
이번 글에서는 **JPA의 기본 개념, 주요 기능, 실무 적용 방법**을 살펴보겠습니다.
---
## **1. 데이터 처리란?**
데이터 처리는 애플리케이션이 데이터를 **생성(Create), 읽기(Read), 수정(Update), 삭제(Delete)**하는 과정(**CRUD**)을 의미합니다.
Spring Boot에서는 **JPA와 Spring Data JPA**를 활용하여 효율적인 데이터 처리를 구현할 수 있습니다.
**📌 전통적인 JDBC 방식과 JPA 방식 비교**
| 방식 | 특징 | 코드 복잡도 | 유지보수성 |
|------|------|------------|------------|
| **JDBC (기본 SQL 사용)** | SQL 쿼리를 직접 작성 | 높음 | 낮음 |
| **JPA (ORM 방식)** | 객체 중심의 데이터 처리 | 낮음 | 높음 |
---
## **2. JPA란?**
**JPA (Java Persistence API)**는 객체지향적인 방식으로 데이터베이스를 다룰 수 있도록 도와주는 **ORM(Object-Relational Mapping) 기술**입니다.
JPA를 사용하면 SQL을 직접 작성하지 않고, **엔티티(Entity) 객체를 이용하여 데이터베이스를 조작**할 수 있습니다.
### **📌 JPA의 핵심 개념**
1. **엔티티(Entity):** 데이터베이스 테이블과 매핑되는 클래스
2. **리포지토리(Repository):** 데이터 저장 및 조회를 담당하는 계층
3. **트랜잭션(Transaction):** 데이터 변경 작업을 하나의 단위로 처리
4. **JPQL(Java Persistence Query Language):** 객체를 대상으로 하는 쿼리
---
## **3. JPA 실무 적용**
### **📌 1) Entity (데이터 모델 정의)**
JPA에서는 `@Entity` 어노테이션을 사용하여 **클래스를 데이터베이스 테이블과 매핑**합니다.
```java
import jakarta.persistence.*;
@Entity // User 엔티티는 DB의 users 테이블과 매핑됨
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 자동 증가 ID
private Long id;
@Column(nullable = false) // name 컬럼은 null을 허용하지 않음
private String name;
@Column(nullable = false)
private int age;
public User() {}
public User(String name, int age) {
this.name = name;
this.age = age;
}
// Getter & Setter 생략
}
```
**`@Entity`**: 해당 클래스가 데이터베이스 테이블과 연결됨
**`@Table(name = "users")`**: 테이블명을 `users`로 지정
**`@Id`**: 기본 키(Primary Key) 설정
**`@GeneratedValue(strategy = GenerationType.IDENTITY)`**: 자동 증가(AUTO_INCREMENT) 설정
**`@Column(nullable = false)`**: `null`을 허용하지 않도록 설정
---
### **📌 2) Repository (데이터 접근 계층)**
JPA에서는 **Spring Data JPA**의 `JpaRepository` 인터페이스를 사용하면, 기본적인 CRUD 기능을 자동으로 구현할 수 있습니다.
```java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
// 기본 CRUD 기능 제공
}
```
**`JpaRepository<User, Long>`**: `User` 엔티티를 관리하며, 기본 키 타입은 `Long`
`findById(id)`, `save(entity)`, `deleteById(id)` 등 기본적인 데이터 처리 메서드 제공
---
### **📌 3) Service (비즈니스 로직 계층)**
데이터 처리 로직을 서비스 계층에서 구현하여 컨트롤러와 분리합니다.
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public User createUser(String name, int age) {
if (age < 0) {
throw new IllegalArgumentException("나이는 0 이상이어야 합니다.");
}
return userRepository.save(new User(name, age));
}
public List<User> getAllUsers() {
return userRepository.findAll();
}
}
```
**서비스 계층을 사용하여 비즈니스 로직을 분리**
**`@Transactional`을 사용하여 트랜잭션 관리**
---
### **📌 4) Controller (요청 처리 계층)**
사용자의 요청을 받아 서비스 계층을 호출하고 응답을 반환합니다.
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<User> createUser(@RequestParam String name, @RequestParam int age) {
return ResponseEntity.ok(userService.createUser(name, age));
}
@GetMapping
public ResponseEntity<List<User>> getAllUsers() {
return ResponseEntity.ok(userService.getAllUsers());
}
}
```
**`@RestController`**: JSON 형식으로 데이터를 반환하는 컨트롤러
**`@RequestMapping("/users")`**: `/users` 경로의 API를 처리
**`@PostMapping`**: 새로운 사용자 생성
**`@GetMapping`**: 모든 사용자 조회
---
## **4. JPA에서 데이터 조회 (JPQL & Native Query)**
### **📌 1) JPQL (Java Persistence Query Language)**
JPA에서는 SQL 대신 **JPQL**을 사용하여 객체 중심의 쿼리를 작성할 수 있습니다.
```java
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface UserRepository extends JpaRepository<User, Long> {
// 이름으로 사용자 찾기
@Query("SELECT u FROM User u WHERE u.name = :name")
List<User> findByName(@Param("name") String name);
}
```
✔ SQL과 유사하지만, **테이블명이 아니라 엔티티 클래스명을 사용**
---
### **📌 2) Native Query (SQL 직접 사용)**
기본 SQL 쿼리를 직접 사용할 수도 있습니다.
```java
@Query(value = "SELECT * FROM users WHERE age >= :age", nativeQuery = true)
List<User> findUsersByAge(@Param("age") int age);
```
✔ 복잡한 SQL 쿼리를 그대로 활용 가능
---
## **5. JPA의 장점과 단점**
### **📌 JPA의 장점**
**SQL을 직접 작성할 필요 없음** → 생산성 증가
**객체지향적인 데이터 처리 가능** → 코드의 가독성과 유지보수성 향상
**트랜잭션 관리가 용이함**
**캐싱 및 성능 최적화 기능 제공**
### **📌 JPA의 단점**
❌ 초기 학습 비용이 존재
❌ 복잡한 SQL 튜닝이 필요한 경우 SQL보다 불리할 수 있음
❌ 데이터베이스 변경 시, 마이그레이션이 필요
---
## **6. 정리**
**JPA는 객체지향 방식으로 데이터를 처리하는 ORM 기술**
**Entity, Repository, Service, Controller 구조로 데이터 처리를 설계**
**JPQL 및 Native Query를 활용하여 데이터 조회 가능**
**트랜잭션을 활용하여 데이터 일관성을 유지**
JPA를 활용하면 **효율적인 데이터 처리와 유지보수성 높은 애플리케이션을 만들 수 있습니다!**

View File

@@ -0,0 +1,184 @@
# **Spring Boot 요청 처리 고급 기능: 필터, 인터셉터, AOP 활용**
Spring Boot에서 클라이언트의 **요청을 처리하는 과정**은 단순히 컨트롤러에서 요청을 받고 응답을 반환하는 것 이상으로 확장될 수 있습니다.
특히 **보안, 로깅, 성능 모니터링, 인증/인가**와 같은 공통 기능을 처리하려면 **필터(Filter), 인터셉터(Interceptor), AOP(Aspect-Oriented Programming)** 등의 개념을 활용할 필요가 있습니다.
이번 글에서는 **필터, 인터셉터, AOP**를 활용하여 **요청을 가로채고, 원하는 로직을 추가하는 방법**을 실무 예제와 함께 설명하겠습니다.
---
# **1. 필터(Filter) - 요청 전/후 공통 처리**
### **📌 필터란?**
필터는 **서블릿 수준에서 동작하며, 요청이 컨트롤러에 도달하기 전/후에 특정 로직을 실행**할 수 있는 기능입니다.
Spring Boot에서는 `javax.servlet.Filter` 인터페이스를 구현하여 커스텀 필터를 만들 수 있습니다.
### **📌 필터의 주요 활용 사례**
- **CORS 처리**
- **요청 및 응답 로깅**
- **JWT 인증 처리**
- **IP 차단 등 보안 정책 적용**
### **📌 필터 구현 예제 - 요청 로깅**
아래는 **모든 요청의 URL과 실행 시간을 기록하는 필터**입니다.
```java
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component // 자동으로 필터 등록
public class LoggingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
long startTime = System.currentTimeMillis();
System.out.println("[LoggingFilter] 요청 URI: " + req.getRequestURI());
chain.doFilter(request, response); // 요청을 다음 필터 또는 컨트롤러로 전달
long duration = System.currentTimeMillis() - startTime;
System.out.println("[LoggingFilter] 요청 처리 시간: " + duration + "ms");
}
}
```
`doFilter()` 메서드는 **요청을 가로채서 원하는 작업을 수행한 후, 체인(chain)으로 넘겨줌**
✔ 요청 전후로 실행할 로직을 자유롭게 추가 가능
---
# **2. 인터셉터(Interceptor) - 요청 흐름을 제어**
### **📌 인터셉터란?**
인터셉터는 **Spring MVC에서 동작하며, 컨트롤러 실행 전후에 특정 로직을 추가할 수 있는 기능**입니다.
필터보다 **더 세부적인 요청 흐름을 제어**할 수 있으며, **특정 컨트롤러 또는 요청 경로에만 적용 가능**합니다.
### **📌 인터셉터의 주요 활용 사례**
- **사용자 인증 및 권한 체크**
- **API 요청 제한 (Rate Limiting)**
- **로그 및 성능 모니터링**
- **특정 요청의 파라미터 검사**
### **📌 인터셉터 구현 예제 - 인증 체크**
아래는 **특정 API에 접근할 때, 인증된 사용자만 허용하는 인터셉터**입니다.
```java
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.stereotype.Component;
@Component
public class AuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Unauthorized");
return false; // 요청을 차단
}
// JWT 검증 로직 추가 가능 (예: Token 검증)
System.out.println("[AuthInterceptor] 인증 성공");
return true; // 요청 진행 허용
}
}
```
`preHandle()` 메서드는 **컨트롤러 실행 전에 요청을 가로채서 검사 가능**
✔ 인증이 실패하면 `false`를 반환하여 **요청을 차단할 수 있음**
### **📌 인터셉터 등록 (WebMvcConfigurer)**
인터셉터를 사용하려면 **WebMvcConfigurer**에 등록해야 합니다.
```java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private AuthInterceptor authInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authInterceptor)
.addPathPatterns("/api/**") // 특정 URL에만 적용
.excludePathPatterns("/api/public/**"); // 예외 URL 설정
}
}
```
---
# **3. AOP (Aspect-Oriented Programming) - 횡단 관심사 처리**
### **📌 AOP란?**
AOP는 **비즈니스 로직과는 별개로 공통 기능(로깅, 트랜잭션, 보안 등)을 적용하는 프로그래밍 기법**입니다.
Spring Boot에서는 `@Aspect``@Around`를 활용하여 **메서드 실행 전후에 특정 로직을 추가**할 수 있습니다.
### **📌 AOP의 주요 활용 사례**
- **로깅(Log Tracing)**
- **트랜잭션 관리**
- **메서드 실행 시간 측정**
- **입출력 값 검증**
### **📌 AOP 구현 예제 - 로깅 및 실행 시간 측정**
아래는 **모든 서비스 메서드의 실행 시간을 로깅하는 AOP**입니다.
```java
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Around("execution(* com.example.service.*.*(..))") // 모든 서비스 메서드에 적용
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed(); // 실제 메서드 실행
long duration = System.currentTimeMillis() - start;
System.out.println("[AOP] " + joinPoint.getSignature() + " 실행 시간: " + duration + "ms");
return result;
}
}
```
`@Aspect` 선언으로 AOP 활성화
`@Around("execution(* com.example.service.*.*(..))")`**특정 패키지의 모든 메서드에 적용 가능**
`joinPoint.proceed()`를 호출하여 **실제 메서드를 실행하고, 이후 로직을 추가할 수 있음**
---
# **4. 필터, 인터셉터, AOP 비교**
| 기능 | 동작 위치 | 주요 목적 | 적용 대상 | 실행 시점 |
|------|---------|---------|---------|---------|
| **Filter** | 서블릿 레벨 | 요청 전처리 및 후처리 (보안, 로깅) | 모든 요청 | 컨트롤러 실행 전후 |
| **Interceptor** | Spring MVC 레벨 | 인증, 권한 체크 | 특정 요청 (API) | 컨트롤러 실행 전후 |
| **AOP** | 메서드 레벨 | 로깅, 트랜잭션, 성능 측정 | 특정 패키지/클래스의 메서드 | 메서드 실행 전후 |
---
# **5. 정리**
**필터(Filter)**: **모든 요청에 대해 전역적인 로직 적용 (보안, CORS, 로깅)**
**인터셉터(Interceptor)**: **컨트롤러 실행 전후에 특정 요청을 가로채서 인증/인가 처리**
**AOP(Aspect-Oriented Programming)**: **특정 메서드(비즈니스 로직)의 실행 전후에 로직 추가 (로깅, 성능 측정 등)**
이러한 고급 기능을 활용하면 **Spring Boot 애플리케이션을 더욱 강력하고 유지보수하기 쉽게 만들 수 있습니다!**

View File

@@ -0,0 +1,226 @@
# **Spring Boot: 세션 & 쿠키, 파일 업로드 & 다운로드**
Spring Boot 애플리케이션에서 **세션과 쿠키**는 사용자 상태를 관리하는 데 유용하며, **파일 업로드 및 다운로드** 기능은 다양한 애플리케이션에서 필수적인 기능입니다.
이번 글에서는 **세션과 쿠키의 개념 및 사용법**을 살펴보고, **파일 업로드 및 다운로드를 처리하는 방법**을 예제와 함께 설명하겠습니다.
---
# **1. 세션(Session)과 쿠키(Cookie)**
### **📌 세션(Session)이란?**
- **서버 측에서 사용자 상태를 유지하는 기술**
- **각 사용자에게 고유한 세션 ID(Session ID)를 부여하고, 서버에서 해당 사용자의 데이터를 저장**
- 로그인 정보, 장바구니 데이터 등 **사용자의 지속적인 상태 유지**가 필요한 경우 사용
### **📌 쿠키(Cookie)란?**
- **클라이언트(브라우저)에 저장되는 작은 데이터 조각**
- 서버에서 응답 시 쿠키를 설정하면, 클라이언트는 이후 요청에서 해당 쿠키를 함께 전송
- **세션과 달리 서버가 아닌 클라이언트에 저장됨**
- 로그인 유지, 사이트 설정 저장 등에 활용
---
## **1.1 세션(Session) 사용하기**
### **✅ 세션 저장 및 조회 예제**
Spring Boot에서는 `HttpSession`을 사용하여 **세션 데이터를 저장 및 조회**할 수 있습니다.
```java
import jakarta.servlet.http.HttpSession;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/session")
public class SessionController {
@PostMapping("/set")
public String setSession(HttpSession session) {
session.setAttribute("username", "JohnDoe"); // 세션에 저장
return "세션에 username=JohnDoe 저장 완료";
}
@GetMapping("/get")
public String getSession(HttpSession session) {
String username = (String) session.getAttribute("username");
return username != null ? "세션 값: " + username : "세션 값이 없습니다.";
}
@PostMapping("/remove")
public String removeSession(HttpSession session) {
session.invalidate(); // 세션 삭제
return "세션 삭제 완료";
}
}
```
`setSession()`: `"username"` 값을 세션에 저장
`getSession()`: 저장된 세션 값을 조회
`removeSession()`: 세션 데이터를 삭제
---
## **1.2 쿠키(Cookie) 사용하기**
### **✅ 쿠키 설정 및 조회 예제**
Spring Boot에서는 `HttpServletResponse``HttpServletRequest`를 사용하여 쿠키를 설정하고 조회할 수 있습니다.
```java
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/cookie")
public class CookieController {
@PostMapping("/set")
public String setCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("userId", "12345");
cookie.setMaxAge(60 * 60); // 1시간 동안 유지
cookie.setPath("/"); // 모든 경로에서 유효
response.addCookie(cookie);
return "쿠키 설정 완료: userId=12345";
}
@GetMapping("/get")
public String getCookie(HttpServletRequest request) {
Cookie[] cookies = request.getCookies();
if (cookies != null) {
for (Cookie cookie : cookies) {
if ("userId".equals(cookie.getName())) {
return "쿠키 값: " + cookie.getValue();
}
}
}
return "쿠키가 없습니다.";
}
@PostMapping("/delete")
public String deleteCookie(HttpServletResponse response) {
Cookie cookie = new Cookie("userId", null);
cookie.setMaxAge(0); // 즉시 삭제
cookie.setPath("/");
response.addCookie(cookie);
return "쿠키 삭제 완료";
}
}
```
`setCookie()`: `"userId"` 쿠키를 설정
`getCookie()`: 저장된 쿠키 값을 조회
`deleteCookie()`: `"userId"` 쿠키를 삭제
---
# **2. 파일 업로드 및 다운로드**
Spring Boot에서는 `MultipartFile`을 사용하여 **파일 업로드 및 다운로드**를 간편하게 처리할 수 있습니다.
---
## **2.1 파일 업로드 처리**
### **✅ 파일 업로드 예제**
아래는 **Spring Boot에서 파일을 업로드하여 로컬 저장소에 저장하는 코드**입니다.
```java
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
@RestController
@RequestMapping("/file")
public class FileUploadController {
private static final String UPLOAD_DIR = "uploads/";
@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
try {
File uploadDir = new File(UPLOAD_DIR);
if (!uploadDir.exists()) {
uploadDir.mkdirs(); // 디렉토리 생성
}
String filePath = UPLOAD_DIR + file.getOriginalFilename();
file.transferTo(new File(filePath)); // 파일 저장
return "파일 업로드 성공: " + filePath;
} catch (IOException e) {
return "파일 업로드 실패: " + e.getMessage();
}
}
}
```
`MultipartFile`을 받아서 `uploads/` 디렉토리에 저장
`file.transferTo(new File(filePath))`로 실제 파일을 저장
`@RequestParam("file")`로 HTML 폼에서 파일을 받을 수 있음
### **✅ HTML 파일 업로드 폼 예제**
```html
<form action="/file/upload" method="post" enctype="multipart/form-data">
<input type="file" name="file" />
<button type="submit">파일 업로드</button>
</form>
```
---
## **2.2 파일 다운로드 처리**
### **✅ 파일 다운로드 예제**
Spring Boot에서는 `ResponseEntity`를 사용하여 **파일을 다운로드할 수 있습니다**.
```java
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/file")
public class FileDownloadController {
private static final String UPLOAD_DIR = "uploads/";
@GetMapping("/download/{filename}")
public ResponseEntity<Resource> downloadFile(@PathVariable String filename) {
try {
Path filePath = Paths.get(UPLOAD_DIR).resolve(filename).normalize();
Resource resource = new UrlResource(filePath.toUri());
if (!resource.exists()) {
return ResponseEntity.notFound().build();
}
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
.body(resource);
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
}
```
`UrlResource`를 이용하여 파일을 읽어옴
`CONTENT_DISPOSITION`을 설정하여 **다운로드 가능한 형태로 응답**
`/file/download/{filename}` 경로로 요청하면 해당 파일을 다운로드 가능
### **✅ 파일 다운로드 요청 예제**
```html
<a href="/file/download/sample.txt">파일 다운로드</a>
```
---
# **3. 정리**
**세션(Session)**: 서버 측에서 사용자 정보를 관리 (로그인 상태 유지 등)
**쿠키(Cookie)**: 클라이언트 측에 저장되며, 서버와의 요청에서 사용 가능
**파일 업로드**: `MultipartFile`을 이용하여 서버에 파일 저장
**파일 다운로드**: `ResponseEntity<Resource>`를 활용하여 파일 제공
Spring Boot에서 **세션과 쿠키를 활용하여 사용자 상태를 관리**하고, **파일 업로드 및 다운로드를 구현하는 방법**을 익히면 다양한 웹 애플리케이션에서 활용할 수 있습니다!

326
docs/_archive/core.md Normal file
View File

@@ -0,0 +1,326 @@
# Spring Boot Core 어노테이션 정리
Spring Boot Core에서 사용되는 주요 어노테이션을 표로 정리한 후, 각각의 어노테이션에 대한 설명과 예제를 제공합니다.
---
## 1. 어노테이션 정리표
| 어노테이션 | 설명 |
|------------------------|----------------------------------|
| `@SpringBootApplication` | Spring Boot 애플리케이션의 시작점 설정 |
| `@Configuration` | 스프링 설정 클래스를 정의 |
| `@ComponentScan` | 스프링이 컴포넌트를 자동 검색하도록 설정 |
| `@Bean` | 수동으로 빈을 등록 |
| `@Component` | 일반적인 빈을 정의 |
| `@Service` | 비즈니스 로직을 담당하는 빈을 정의 |
| `@Repository` | 데이터 접근 계층 빈을 정의 |
| `@Autowired` | 자동으로 빈을 주입 |
| `@Qualifier` | 특정 빈을 지정하여 주입 |
| `@Primary` | 기본적으로 주입될 빈을 지정 |
| `@Value` | 프로퍼티 값을 주입 |
| `@PropertySource` | 외부 설정 파일을 로드 |
| `@Profile` | 특정 프로파일에서만 빈을 로드 |
| `@Lazy` | 필요한 경우에만 빈을 초기화 |
| `@Scope` | 빈의 스코프를 지정 |
| `@DependsOn` | 특정 빈이 다른 빈보다 먼저 로드되도록 설정 |
| `@PostConstruct` | 빈이 생성된 후 실행할 메서드 지정 |
| `@PreDestroy` | 빈이 제거되기 전 실행할 메서드 지정 |
---
## 2. 어노테이션 설명 및 예제
### 1) `@SpringBootApplication`
Spring Boot 애플리케이션의 시작 클래스를 정의하는 어노테이션.
- 내부적으로 `@Configuration`, `@EnableAutoConfiguration`, `@ComponentScan`을 포함.
#### 예제:
```java
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
```
- 이 클래스가 애플리케이션의 시작점 역할을 합니다.
---
### 2) `@Configuration`
Java 기반 설정을 정의하는 클래스에 사용.
#### 예제:
```java
@Configuration
public class AppConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
```
- `MyService` 객체를 빈으로 등록.
---
### 3) `@ComponentScan`
패키지를 검색하여 `@Component`, `@Service`, `@Repository` 등을 자동으로 등록.
#### 예제:
```java
@ComponentScan(basePackages = "com.example.service")
@Configuration
public class AppConfig {
}
```
- `"com.example.service"` 패키지를 스캔하여 빈 등록.
---
### 4) `@Bean`
메서드의 반환 객체를 스프링 빈으로 등록.
#### 예제:
```java
@Configuration
public class BeanConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
```
- `myService()`의 반환 객체가 빈으로 등록.
---
### 5) `@Component`
일반적인 스프링 빈을 정의할 때 사용.
#### 예제:
```java
@Component
public class MyComponent {
public void doSomething() {
System.out.println("Component working");
}
}
```
- 스프링이 자동으로 빈으로 등록.
---
### 6) `@Service`
비즈니스 로직을 담당하는 서비스 계층의 빈을 정의.
#### 예제:
```java
@Service
public class MyService {
public String getMessage() {
return "Hello, Service!";
}
}
```
- 서비스 계층의 빈으로 등록.
---
### 7) `@Repository`
데이터 접근 계층의 빈을 정의.
#### 예제:
```java
@Repository
public class MyRepository {
public String findData() {
return "Data from DB";
}
}
```
- DAO(Data Access Object) 역할을 하는 클래스.
---
### 8) `@Autowired`
빈을 자동으로 주입.
#### 예제:
```java
@Component
public class MyController {
private final MyService myService;
@Autowired
public MyController(MyService myService) {
this.myService = myService;
}
}
```
- `MyService` 빈이 자동 주입됨.
---
### 9) `@Qualifier`
같은 타입의 여러 빈 중 특정 빈을 선택하여 주입.
#### 예제:
```java
@Component
public class FirstService implements MyService {
}
@Component
public class SecondService implements MyService {
}
@Component
public class MyController {
private final MyService myService;
@Autowired
public MyController(@Qualifier("secondService") MyService myService) {
this.myService = myService;
}
}
```
- `secondService` 빈이 주입됨.
---
### 10) `@Primary`
여러 빈이 있을 때 기본 빈을 지정.
#### 예제:
```java
@Primary
@Component
public class DefaultService implements MyService {
}
```
- `@Autowired` 시 기본적으로 `DefaultService`가 주입됨.
---
### 11) `@Value`
설정 파일에서 값을 주입.
#### 예제:
```java
@Component
public class ConfigComponent {
@Value("${app.name}")
private String appName;
}
```
- `application.properties`에서 `app.name` 값을 읽음.
---
### 12) `@PropertySource`
설정 파일을 로드.
#### 예제:
```java
@Configuration
@PropertySource("classpath:app.properties")
public class AppConfig {
}
```
- `app.properties` 파일을 로드.
---
### 13) `@Profile`
특정 프로파일에서만 빈을 로드.
#### 예제:
```java
@Profile("dev")
@Component
public class DevService {
}
```
- `"dev"` 프로파일에서만 로드.
---
### 14) `@Lazy`
빈을 필요할 때만 초기화.
#### 예제:
```java
@Component
@Lazy
public class LazyComponent {
}
```
- `LazyComponent`는 필요할 때만 생성됨.
---
### 15) `@Scope`
빈의 스코프를 설정.
#### 예제:
```java
@Component
@Scope("prototype")
public class PrototypeComponent {
}
```
- 새로운 객체가 매번 생성됨.
---
### 16) `@DependsOn`
다른 빈이 먼저 로드되도록 설정.
#### 예제:
```java
@Component
@DependsOn("anotherComponent")
public class MyComponent {
}
```
- `anotherComponent`가 먼저 로드됨.
---
### 17) `@PostConstruct`
빈 생성 후 실행할 메서드 지정.
#### 예제:
```java
@Component
public class InitComponent {
@PostConstruct
public void init() {
System.out.println("Initialized!");
}
}
```
- 빈 생성 후 `init()` 실행.
---
### 18) `@PreDestroy`
빈 제거 전에 실행할 메서드 지정.
#### 예제:
```java
@Component
public class DestroyComponent {
@PreDestroy
public void destroy() {
System.out.println("Destroyed!");
}
}
```
- 빈 제거 전 `destroy()` 실행.
---
Spring Boot Core에서 사용되는 주요 어노테이션을 정리했습니다. 이를 활용하면 애플리케이션의 설정과 빈 관리를 효과적으로 수행할 수 있습니다.

289
docs/_archive/jpa.md Normal file
View File

@@ -0,0 +1,289 @@
# Spring Boot의 Model 및 JPA 관련 어노테이션 정리
Spring Boot에서 **모델(Model)과 JPA(Java Persistence API)** 를 활용할 때 사용되는 주요 어노테이션을 표로 정리하고, 각각에 대한 설명과 예제 코드를 제공합니다.
---
## 1. Model 및 JPA 관련 어노테이션 정리표
| 어노테이션 | 설명 |
|------------------------|----------------------------------|
| `@Entity` | JPA 엔티티 클래스임을 명시 |
| `@Table` | 데이터베이스의 테이블과 매핑 |
| `@Id` | 기본 키(PK) 지정 |
| `@GeneratedValue` | 기본 키 값 자동 생성 전략 설정 |
| `@Column` | 데이터베이스 컬럼과 매핑 |
| `@Transient` | 특정 필드를 영속성에서 제외 |
| `@Embedded` | 내장(Embeddable) 타입을 포함 |
| `@Embeddable` | 내장 타입을 정의 |
| `@Enumerated` | Enum 타입을 컬럼에 매핑 |
| `@Lob` | 대용량 데이터(Long Text, Blob) 저장 |
| `@Temporal` | 날짜/시간 타입 매핑 |
| `@ManyToOne` | 다대일 관계 설정 |
| `@OneToMany` | 일대다 관계 설정 |
| `@OneToOne` | 일대일 관계 설정 |
| `@ManyToMany` | 다대다 관계 설정 |
| `@JoinColumn` | 외래 키(FK) 설정 |
| `@JoinTable` | 다대다 관계에서 조인 테이블 설정 |
| `@MappedSuperclass` | 공통 속성을 가지는 부모 클래스 지정 |
| `@Inheritance` | 상속 매핑 전략 설정 |
| `@DiscriminatorColumn`| 상속 엔티티 구분 컬럼 설정 |
| `@NamedQuery` | JPQL로 미리 정의된 쿼리 설정 |
| `@Query` | 사용자 정의 JPQL 쿼리 작성 |
| `@Modifying` | 데이터 수정 JPQL 쿼리 작성 |
| `@Transactional` | 트랜잭션 범위 설정 |
| `@Repository` | 데이터 액세스 계층을 나타냄 |
| `@EnableJpaRepositories` | JPA 리포지토리 활성화 |
---
## 2. Model 및 JPA 관련 어노테이션 설명 및 예제
### 1) `@Entity`
JPA에서 엔티티 클래스를 나타냅니다. 해당 클래스는 데이터베이스 테이블과 매핑됩니다.
#### 예제:
```java
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
```
- `User` 클래스가 `users` 테이블과 매핑됩니다.
---
### 2) `@Table`
엔티티와 매핑될 테이블의 이름을 지정합니다.
#### 예제:
```java
@Entity
@Table(name = "user_table")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
```
- `User` 엔티티가 `user_table`과 매핑됩니다.
---
### 3) `@Id`
엔티티의 **기본 키(PK)** 를 지정합니다.
#### 예제:
```java
@Entity
public class Product {
@Id
private Long productId;
}
```
- `productId`가 **기본 키**가 됩니다.
---
### 4) `@GeneratedValue`
기본 키를 자동 생성하도록 설정합니다.
#### 예제:
```java
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
}
```
- `GenerationType.IDENTITY`**AUTO_INCREMENT** 방식으로 기본 키를 생성합니다.
---
### 5) `@Column`
필드를 특정 컬럼과 매핑할 때 사용합니다.
#### 예제:
```java
@Entity
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "emp_name", length = 100, nullable = false)
private String name;
}
```
- `emp_name`이라는 컬럼에 매핑되고, 길이는 100이며, **NULL을 허용하지 않음**.
---
### 6) `@Transient`
해당 필드를 **DB에 저장하지 않도록** 설정합니다.
#### 예제:
```java
@Entity
public class Person {
@Id
private Long id;
@Transient
private int age;
}
```
- `age` 필드는 **DB에 저장되지 않음**.
---
### 7) `@Enumerated`
Enum 타입을 컬럼에 저장할 때 사용합니다.
#### 예제:
```java
@Entity
public class Task {
public enum Status { PENDING, COMPLETED }
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Enumerated(EnumType.STRING)
private Status status;
}
```
- `EnumType.STRING`을 사용하여 `"PENDING"`, `"COMPLETED"` 형태로 저장됩니다.
---
### 8) `@ManyToOne`
**다대일(N:1) 관계**를 정의합니다.
#### 예제:
```java
@Entity
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
```
- `Order` 엔티티는 **User와 다대일 관계**.
---
### 9) `@OneToMany`
**일대다(1:N) 관계**를 정의합니다.
#### 예제:
```java
@Entity
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "user")
private List<Order> orders;
}
```
- 한 명의 `User`가 여러 개의 `Order`를 가질 수 있음.
---
### 10) `@OneToOne`
**일대일(1:1) 관계**를 정의합니다.
#### 예제:
```java
@Entity
public class Passport {
@Id
private Long id;
@OneToOne
@JoinColumn(name = "user_id")
private User user;
}
```
-`User`는 하나의 `Passport`를 가짐.
---
### 11) `@ManyToMany`
**다대다(N:M) 관계**를 정의합니다.
#### 예제:
```java
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses;
}
```
- `Student``Course`는 다대다 관계이며 **중간 테이블(`student_course`)** 을 가짐.
---
### 12) `@Query`
JPQL을 사용하여 **사용자 정의 쿼리**를 작성합니다.
#### 예제:
```java
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
@Query("SELECT u FROM User u WHERE u.name = :name")
List<User> findByName(@Param("name") String name);
}
```
- `name`이 특정 값인 `User`를 조회하는 쿼리.
---
### 13) `@Transactional`
**트랜잭션 범위를 설정**합니다.
#### 예제:
```java
@Service
public class UserService {
@Transactional
public void updateUser(Long id, String name) {
User user = userRepository.findById(id).orElseThrow();
user.setName(name);
}
}
```
- 메서드 실행 중 예외 발생 시 **자동 롤백**.
---
## 3. 정리
Spring Boot에서 **모델과 JPA 관련 어노테이션**을 정리했습니다.
- `@Entity`, `@Table`, `@Id`, `@Column` → 기본 엔티티 정의
- `@ManyToOne`, `@OneToMany`, `@OneToOne`, `@ManyToMany` → 관계 매핑
- `@Query`, `@Transactional` → 데이터 액세스 및 트랜잭션 처리
이제 **Spring Boot + JPA** 개발을 효과적으로 할 수 있습니다!

269
docs/_archive/mvc.md Normal file
View File

@@ -0,0 +1,269 @@
# Spring Boot MVC 어노테이션 정리
Spring Boot MVC에서 사용되는 주요 어노테이션을 표로 정리한 후, 각각의 어노테이션에 대한 설명과 예제를 제공합니다.
---
## 1. 어노테이션 정리표
| 어노테이션 | 설명 |
|--------------------|-----------------------------------------|
| `@Controller` | Spring MVC의 컨트롤러 클래스를 정의 |
| `@RestController` | `@Controller` + `@ResponseBody`, JSON 응답을 기본으로 함 |
| `@RequestMapping` | URL 요청을 특정 컨트롤러 또는 메서드에 매핑 |
| `@GetMapping` | HTTP GET 요청을 특정 메서드에 매핑 |
| `@PostMapping` | HTTP POST 요청을 특정 메서드에 매핑 |
| `@PutMapping` | HTTP PUT 요청을 특정 메서드에 매핑 |
| `@DeleteMapping` | HTTP DELETE 요청을 특정 메서드에 매핑 |
| `@PatchMapping` | HTTP PATCH 요청을 특정 메서드에 매핑 |
| `@RequestParam` | 요청 파라미터를 메서드의 파라미터로 매핑 |
| `@PathVariable` | URL 경로 변수를 메서드의 파라미터로 매핑 |
| `@ModelAttribute` | 폼 데이터를 객체로 변환하여 전달 |
| `@RequestBody` | 요청 본문(JSON 등)을 객체로 변환하여 전달 |
| `@ResponseBody` | 반환 데이터를 JSON 형태로 응답 |
| `@ResponseStatus` | HTTP 응답 상태 코드를 지정 |
| `@ExceptionHandler` | 특정 예외 발생 시 처리할 메서드를 정의 |
| `@InitBinder` | 컨트롤러에서 요청 데이터를 변환하는 바인딩 설정을 정의 |
| `@CrossOrigin` | 다른 도메인에서 API 요청을 허용하도록 설정 |
---
## 2. 어노테이션 설명 및 예제
### 1) `@Controller`
Spring MVC 컨트롤러 클래스임을 나타냅니다.
#### 예제:
```java
@Controller
public class MyController {
@GetMapping("/hello")
public String hello() {
return "hello"; // hello.html을 렌더링
}
}
```
- `hello.html` 뷰 페이지를 반환합니다.
---
### 2) `@RestController`
`@Controller``@ResponseBody`를 합친 역할을 합니다. 즉, JSON 응답을 기본으로 합니다.
#### 예제:
```java
@RestController
public class MyRestController {
@GetMapping("/api/hello")
public String hello() {
return "Hello, World!";
}
}
```
- `"Hello, World!"`라는 문자열을 JSON 형식으로 반환합니다.
---
### 3) `@RequestMapping`
URL과 컨트롤러 메서드를 매핑합니다.
#### 예제:
```java
@Controller
@RequestMapping("/users")
public class UserController {
@GetMapping("/{id}")
public String getUser(@PathVariable Long id) {
return "user"; // user.html 렌더링
}
}
```
- `/users/{id}` 경로로 들어오는 요청을 `getUser` 메서드가 처리합니다.
---
### 4) `@GetMapping`, `@PostMapping`, `@PutMapping`, `@DeleteMapping`, `@PatchMapping`
각 HTTP 메서드에 대한 매핑을 제공합니다.
#### 예제:
```java
@RestController
@RequestMapping("/items")
public class ItemController {
@GetMapping("/{id}")
public String getItem(@PathVariable Long id) {
return "Item: " + id;
}
@PostMapping
public String createItem(@RequestBody String item) {
return "Created: " + item;
}
@PutMapping("/{id}")
public String updateItem(@PathVariable Long id, @RequestBody String item) {
return "Updated item " + id + " to " + item;
}
@DeleteMapping("/{id}")
public String deleteItem(@PathVariable Long id) {
return "Deleted item " + id;
}
}
```
- 각각 `GET`, `POST`, `PUT`, `DELETE` 요청을 처리하는 컨트롤러입니다.
---
### 5) `@RequestParam`
쿼리 파라미터를 매핑할 때 사용합니다.
#### 예제:
```java
@RestController
public class ParamController {
@GetMapping("/search")
public String search(@RequestParam String query) {
return "Searching for: " + query;
}
}
```
- `/search?query=Spring` 요청 시 `"Searching for: Spring"` 반환.
---
### 6) `@PathVariable`
URL 경로 변수를 매핑할 때 사용합니다.
#### 예제:
```java
@RestController
public class PathVariableController {
@GetMapping("/product/{id}")
public String getProduct(@PathVariable Long id) {
return "Product ID: " + id;
}
}
```
- `/product/100` 요청 시 `"Product ID: 100"` 반환.
---
### 7) `@ModelAttribute`
폼 데이터를 객체로 바인딩할 때 사용합니다.
#### 예제:
```java
@Controller
public class FormController {
@PostMapping("/submit")
public String submit(@ModelAttribute User user) {
return "result"; // result.html 렌더링
}
}
class User {
private String name;
private int age;
// Getter & Setter 생략
}
```
- 폼에서 `name``age` 값을 받아 `User` 객체로 변환.
---
### 8) `@RequestBody`
JSON 데이터를 객체로 변환할 때 사용합니다.
#### 예제:
```java
@RestController
public class JsonController {
@PostMapping("/json")
public String receiveJson(@RequestBody User user) {
return "Received: " + user.getName();
}
}
```
- `{ "name": "Alice", "age": 25 }` 데이터를 `User` 객체로 변환.
---
### 9) `@ResponseBody`
메서드의 반환값을 HTTP 응답으로 직접 반환할 때 사용합니다.
#### 예제:
```java
@Controller
public class ResponseController {
@ResponseBody
@GetMapping("/text")
public String textResponse() {
return "Hello, ResponseBody!";
}
}
```
- `"Hello, ResponseBody!"`가 그대로 반환.
---
### 10) `@ResponseStatus`
HTTP 응답 상태 코드를 설정할 때 사용합니다.
#### 예제:
```java
@RestController
public class StatusController {
@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/create")
public String create() {
return "Created successfully!";
}
}
```
- HTTP 201 Created 응답을 반환.
---
### 11) `@ExceptionHandler`
예외 발생 시 처리할 메서드를 정의합니다.
#### 예제:
```java
@RestController
public class ExceptionController {
@GetMapping("/error")
public String error() {
throw new RuntimeException("Something went wrong!");
}
@ExceptionHandler(RuntimeException.class)
public String handleRuntimeException(RuntimeException e) {
return "Handled error: " + e.getMessage();
}
}
```
- `/error` 요청 시 `"Handled error: Something went wrong!"` 반환.
---
### 12) `@CrossOrigin`
CORS 문제를 해결할 때 사용합니다.
#### 예제:
```java
@RestController
@CrossOrigin(origins = "http://example.com")
public class CorsController {
@GetMapping("/data")
public String getData() {
return "CORS enabled";
}
}
```
- `http://example.com`에서 요청 가능.
---
이제 Spring Boot MVC의 주요 어노테이션과 예제들을 이해했을 것입니다. 필요에 따라 적절한 어노테이션을 활용하여 프로젝트를 개발하면 됩니다.

View File

@@ -0,0 +1,280 @@
# Spring Boot의 Thymeleaf 템플릿 렌더링 관련 어노테이션 정리
Spring Boot에서 **Thymeleaf**를 활용하여 템플릿을 렌더링할 때 사용되는 주요 어노테이션을 표로 정리하고, 각각에 대한 설명과 예제 코드를 제공합니다.
---
## 1. Thymeleaf 관련 어노테이션 정리표
| 어노테이션 | 설명 |
|------------------------|----------------------------------|
| `@Controller` | 컨트롤러 클래스를 정의 |
| `@RestController` | RESTful API를 제공하는 컨트롤러를 정의 |
| `@RequestMapping` | 요청 URL을 매핑 |
| `@GetMapping` | GET 요청을 처리 |
| `@PostMapping` | POST 요청을 처리 |
| `@ModelAttribute` | 모델 데이터를 초기화하여 뷰로 전달 |
| `@RequestParam` | 요청 파라미터를 컨트롤러 메서드로 전달 |
| `@PathVariable` | URL 경로 변수 값을 컨트롤러 메서드로 전달 |
| `@SessionAttributes` | 특정 속성을 세션에 저장 |
| `@SessionAttribute` | 세션에서 특정 속성을 가져옴 |
| `@RequestBody` | HTTP 요청 본문을 객체로 변환 |
| `@ResponseBody` | 객체를 JSON 등의 형식으로 응답 |
| `@ResponseStatus` | HTTP 응답 상태 코드를 설정 |
---
## 2. Thymeleaf 관련 어노테이션 설명 및 예제
### 1) `@Controller`
Spring MVC에서 사용되는 컨트롤러 클래스임을 나타냅니다.
Thymeleaf 템플릿을 반환하는 역할을 합니다.
#### 예제:
```java
@Controller
public class HomeController {
@GetMapping("/")
public String home() {
return "index"; // src/main/resources/templates/index.html 렌더링
}
}
```
- `"index"``templates/index.html` 파일을 렌더링합니다.
---
### 2) `@RestController`
RESTful API를 제공하는 컨트롤러를 정의할 때 사용합니다.
`@Controller`와 다르게 `@ResponseBody`가 포함되어 있어, 데이터를 JSON 형식으로 반환합니다.
#### 예제:
```java
@RestController
public class ApiController {
@GetMapping("/api/message")
public String getMessage() {
return "Hello, REST!";
}
}
```
- `"Hello, REST!"` 문자열이 그대로 응답됩니다.
---
### 3) `@RequestMapping`
요청 URL을 특정 컨트롤러 메서드에 매핑합니다.
#### 예제:
```java
@Controller
@RequestMapping("/home")
public class HomeController {
@GetMapping
public String home() {
return "home";
}
}
```
- `/home` URL 요청 시 `templates/home.html`이 렌더링됩니다.
---
### 4) `@GetMapping`
GET 요청을 처리하는 메서드를 정의합니다.
#### 예제:
```java
@Controller
public class PageController {
@GetMapping("/about")
public String about() {
return "about";
}
}
```
- `/about` 요청 시 `templates/about.html`이 렌더링됩니다.
---
### 5) `@PostMapping`
POST 요청을 처리하는 메서드를 정의합니다.
#### 예제:
```java
@Controller
public class FormController {
@PostMapping("/submit")
public String submitForm(@RequestParam String name, Model model) {
model.addAttribute("name", name);
return "result";
}
}
```
- `/submit`로 POST 요청을 보내면 `name` 값을 `result.html`에 전달합니다.
---
### 6) `@ModelAttribute`
모델 데이터를 초기화하여 뷰로 전달하는 데 사용됩니다.
#### 예제:
```java
@Controller
public class UserController {
@ModelAttribute("message")
public String welcomeMessage() {
return "Welcome to our site!";
}
@GetMapping("/welcome")
public String welcomePage() {
return "welcome";
}
}
```
- `welcome.html`에서 `${message}`를 사용하여 `"Welcome to our site!"`를 출력할 수 있습니다.
---
### 7) `@RequestParam`
HTTP 요청 파라미터를 컨트롤러 메서드로 전달하는 데 사용됩니다.
#### 예제:
```java
@Controller
public class GreetingController {
@GetMapping("/greet")
public String greet(@RequestParam(defaultValue = "Guest") String name, Model model) {
model.addAttribute("name", name);
return "greeting";
}
}
```
- `/greet?name=John` 요청 시 `"John"``greeting.html`에 전달됩니다.
---
### 8) `@PathVariable`
URL 경로 변수 값을 컨트롤러 메서드로 전달할 때 사용됩니다.
#### 예제:
```java
@Controller
public class ProfileController {
@GetMapping("/profile/{username}")
public String profile(@PathVariable String username, Model model) {
model.addAttribute("username", username);
return "profile";
}
}
```
- `/profile/john` 요청 시 `"john"``profile.html`에 전달됩니다.
---
### 9) `@SessionAttributes`
특정 속성을 세션에 저장하여 여러 요청에서 공유할 수 있도록 합니다.
#### 예제:
```java
@Controller
@SessionAttributes("user")
public class SessionController {
@ModelAttribute("user")
public User user() {
return new User();
}
@GetMapping("/session")
public String sessionPage() {
return "session";
}
}
```
- `user` 객체가 세션에 저장됩니다.
---
### 10) `@SessionAttribute`
세션에 저장된 속성을 가져올 때 사용됩니다.
#### 예제:
```java
@Controller
public class DashboardController {
@GetMapping("/dashboard")
public String dashboard(@SessionAttribute("user") User user, Model model) {
model.addAttribute("user", user);
return "dashboard";
}
}
```
- 세션에서 `user` 객체를 가져와 `dashboard.html`에 전달합니다.
---
### 11) `@RequestBody`
HTTP 요청 본문을 객체로 변환하여 받을 때 사용됩니다.
#### 예제:
```java
@RestController
public class JsonController {
@PostMapping("/json")
public String handleJson(@RequestBody User user) {
return "Received: " + user.getName();
}
}
```
- JSON 데이터를 `User` 객체로 변환하여 받습니다.
---
### 12) `@ResponseBody`
컨트롤러 메서드의 반환값을 HTTP 응답 본문으로 반환할 때 사용됩니다.
#### 예제:
```java
@Controller
public class TextController {
@GetMapping("/text")
@ResponseBody
public String plainText() {
return "This is plain text";
}
}
```
- `"This is plain text"`가 그대로 응답됩니다.
---
### 13) `@ResponseStatus`
HTTP 응답 상태 코드를 설정할 때 사용됩니다.
#### 예제:
```java
@RestController
public class StatusController {
@GetMapping("/forbidden")
@ResponseStatus(HttpStatus.FORBIDDEN)
public String forbidden() {
return "Access Denied";
}
}
```
- `/forbidden` 요청 시 **403 Forbidden** 응답을 반환합니다.
---
## 3. 정리
Spring Boot에서 **Thymeleaf 템플릿을 렌더링**할 때 자주 사용하는 어노테이션을 정리했습니다.
- `@Controller` → Thymeleaf 템플릿을 반환하는 컨트롤러
- `@GetMapping`, `@PostMapping` → 요청을 처리하는 엔드포인트 설정
- `@RequestParam`, `@PathVariable` → 요청 데이터 전달
- `@ModelAttribute` → 뷰에 데이터를 전달
- `@SessionAttributes`, `@SessionAttribute` → 세션 데이터 관리
- `@ResponseBody`, `@RequestBody` → JSON 또는 텍스트 데이터 처리
이제 Thymeleaf를 사용할 때 필요한 어노테이션을 쉽게 활용할 수 있습니다!