Java Spring Boot | REST API 서버 만들기
이 글의 핵심
Java Spring Boot에 대한 실전 가이드입니다. REST API 서버 만들기 등을 예제와 함께 상세히 설명합니다.
들어가며
Spring Boot는 설정을 줄이고 관례에 맞춘 뼈대를 빠르게 올리는 데 유리합니다. 컨트롤러·서비스·리포지토리를 설계도(클래스)에 나누어 두고, 의존성 주입으로 조립하는 방식이 일반적입니다.
1. Spring Boot 프로젝트 설정
프로젝트 생성
- Project: Maven
- Language: Java
- Spring Boot: 3.x
- Dependencies: Spring Web, Spring Data JPA, H2 Database
Application.java
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.properties
server.port=8080
spring.datasource.url=jdbc:h2:mem:testdb
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
2. REST Controller
UserController
package com.example.demo.controller;
import com.example.demo.model.User;
import com.example.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/users")
public class UserController {
@Autowired
private UserService userService;
@GetMapping
public List<User> getUsers() {
return userService.findAll();
}
@GetMapping("/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
User user = userService.findById(id);
if (user != null) {
return ResponseEntity.ok(user);
} else {
return ResponseEntity.notFound().build();
}
}
@PostMapping
public ResponseEntity<User> createUser(@RequestBody User user) {
User saved = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(saved);
}
@PutMapping("/{id}")
public ResponseEntity<User> updateUser(
@PathVariable Long id,
@RequestBody User user) {
User updated = userService.update(id, user);
if (updated != null) {
return ResponseEntity.ok(updated);
} else {
return ResponseEntity.notFound().build();
}
}
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
boolean deleted = userService.delete(id);
if (deleted) {
return ResponseEntity.noContent().build();
} else {
return ResponseEntity.notFound().build();
}
}
}
3. JPA Entity
User 엔티티
package com.example.demo.model;
import jakarta.persistence.*;
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false, unique = true)
private String email;
private Integer age;
public User() {}
public User(String name, String email, Integer age) {
this.name = name;
this.email = email;
this.age = age;
}
// Getters
public Long getId() { return id; }
public String getName() { return name; }
public String getEmail() { return email; }
public Integer getAge() { return age; }
// Setters
public void setId(Long id) { this.id = id; }
public void setName(String name) { this.name = name; }
public void setEmail(String email) { this.email = email; }
public void setAge(Integer age) { this.age = age; }
}
4. Repository
UserRepository
package com.example.demo.repository;
import com.example.demo.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByName(String name);
User findByEmail(String email);
List<User> findByAgeGreaterThan(Integer age);
}
5. Service
UserService
package com.example.demo.service;
import com.example.demo.model.User;
import com.example.demo.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
public List<User> findAll() {
return userRepository.findAll();
}
public User findById(Long id) {
return userRepository.findById(id).orElse(null);
}
public User save(User user) {
return userRepository.save(user);
}
public User update(Long id, User user) {
User existing = findById(id);
if (existing != null) {
existing.setName(user.getName());
existing.setEmail(user.getEmail());
existing.setAge(user.getAge());
return userRepository.save(existing);
}
return null;
}
public boolean delete(Long id) {
if (userRepository.existsById(id)) {
userRepository.deleteById(id);
return true;
}
return false;
}
}
6. 의존성 주입 (DI)
생성자 주입 (권장)
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
필드 주입
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}
7. 실전 예제
예제: Todo API
// TodoController.java
@RestController
@RequestMapping("/api/todos")
public class TodoController {
private final TodoService todoService;
public TodoController(TodoService todoService) {
this.todoService = todoService;
}
@GetMapping
public List<Todo> getTodos() {
return todoService.findAll();
}
@PostMapping
public ResponseEntity<Todo> createTodo(@RequestBody Todo todo) {
Todo saved = todoService.save(todo);
return ResponseEntity.status(HttpStatus.CREATED).body(saved);
}
@PutMapping("/{id}/toggle")
public ResponseEntity<Todo> toggleTodo(@PathVariable Long id) {
Todo updated = todoService.toggle(id);
if (updated != null) {
return ResponseEntity.ok(updated);
} else {
return ResponseEntity.notFound().build();
}
}
}
// Todo.java
@Entity
public class Todo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private boolean completed;
// Constructors, Getters, Setters
}
// TodoService.java
@Service
public class TodoService {
private final TodoRepository todoRepository;
public TodoService(TodoRepository todoRepository) {
this.todoRepository = todoRepository;
}
public List<Todo> findAll() {
return todoRepository.findAll();
}
public Todo save(Todo todo) {
return todoRepository.save(todo);
}
public Todo toggle(Long id) {
Todo todo = todoRepository.findById(id).orElse(null);
if (todo != null) {
todo.setCompleted(!todo.isCompleted());
return todoRepository.save(todo);
}
return null;
}
}
// TodoRepository.java
@Repository
public interface TodoRepository extends JpaRepository<Todo, Long> {
List<Todo> findByCompleted(boolean completed);
}
정리
핵심 요약
- Spring Boot: 자동 설정, 빠른 개발
- @RestController: REST API 엔드포인트
- JPA: 객체 관계 매핑 (ORM)
- 의존성 주입: @Autowired, 생성자 주입
- Repository: 데이터 접근 계층
다음 단계
- Java 멀티스레딩
- Kotlin Spring Boot
- Java 예외 처리
관련 글
- Kotlin Spring Boot | REST API 서버 만들기
- C++ HTTP 클라이언트 완벽 가이드 | REST API 호출·연결 풀·타임아웃·프로덕션 패턴
- C++ JSON 파싱 완벽 가이드 | nlohmann·RapidJSON·커스텀 타입·에러 처리·프로덕션 패턴
- C++ REST API 클라이언트 완벽 가이드 | CRUD·인증·에러 처리·프로덕션 패턴 [#21-3]
- [Go 2주 완성 #08] Day 14: 실전 미니 프로젝트 - REST API 서버 구축