[2026] Java Spring Boot | REST API 서버 만들기
이 글의 핵심
Java Spring Boot: REST API 서버 만들기. Spring Boot 프로젝트 설정·REST Controller.
들어가며
Spring Boot는 설정을 줄이고 관례에 맞춘 뼈대를 빠르게 올리는 데 유리합니다. 컨트롤러·서비스·리포지토리를 설계도(클래스)에 나누어 두고, 의존성 주입으로 조립하는 방식이 일반적입니다.
실무에서 마주한 현실
개발을 배울 때는 모든 게 깔끔하고 이론적입니다. 하지만 실무는 다릅니다. 레거시 코드와 씨름하고, 급한 일정에 쫓기고, 예상치 못한 버그와 마주합니다. 이 글에서 다루는 내용도 처음엔 이론으로 배웠지만, 실제 프로젝트에 적용하면서 “아, 이래서 이렇게 설계하는구나” 하고 깨달은 것들입니다. 특히 기억에 남는 건 첫 프로젝트에서 겪은 시행착오입니다. 책에서 배운 대로 했는데 왜 안 되는지 몰라 며칠을 헤맸죠. 결국 선배 개발자의 코드 리뷰를 통해 문제를 발견했고, 그 과정에서 많은 걸 배웠습니다. 이 글에서는 이론뿐 아니라 실전에서 마주칠 수 있는 함정들과 해결 방법을 함께 다루겠습니다.
1. Spring Boot 프로젝트 설정
프로젝트 생성
- Project: Maven
- Language: Java
- Spring Boot: 3.x
- Dependencies: Spring Web, Spring Data JPA, H2 Database
Application.java
아래 코드는 java를 사용한 구현 예제입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
다음은 간단한 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
다음은 java를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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 엔티티
다음은 java를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
다음은 java를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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
다음은 java를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
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)
생성자 주입 (권장)
아래 코드는 java를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
@Service
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
}
필드 주입
아래 코드는 java를 사용한 구현 예제입니다. 함수를 통해 로직을 구현합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
@Service
public class UserService {
@Autowired
private UserRepository userRepository;
}
7. 실전 예제
예제: Todo API
다음은 java를 활용한 상세한 구현 코드입니다. 함수를 통해 로직을 구현합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
// 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: 데이터 접근 계층