개발(React | Java)/자바 기초 | 문법

📘 Spring Boot 입문 (2)Controller · Service · Repository 구조 완전 이해 — 스프링의 기본 3계층(3-Tier Architecture)

dev-parrot 2025. 12. 11. 14:20

스프링을 배우기 시작하면 가장 먼저 마주치는 구조가 바로
Controller – Service – Repository 입니다.

이 3계층 구조는 스프링뿐 아니라 대부분의 백엔드 시스템에서 사용되는 표준 아키텍처이며,
“유지보수성이 좋고 역할이 명확해지는 구조”입니다.

이번 글에서는 각 계층의 역할, 실제 예제 코드, 데이터 흐름까지 완전히 이해할 수 있도록 설명합니다.


📌 목차

  1. 3계층 구조란?
  2. Controller의 역할
  3. Service의 역할
  4. Repository의 역할
  5. 계층 간 데이터 흐름
  6. 실전 전체 예제
  7. 자주 하는 실수
  8. 대표 태그

1️⃣ 3계층 구조란?

스프링 프로젝트는 일반적으로 아래 3개의 계층으로 구성됩니다.

Controller    ← 사용자의 요청(HTTP) 처리
Service       ← 비즈니스 로직 처리
Repository    ← DB와 데이터 저장/조회

 

왜 이렇게 나눌까?

✔ 역할이 명확해짐
✔ 테스트하기 쉬움
✔ 유지보수 간편
✔ 대규모 서비스에서 확장 용이


2️⃣ Controller — HTTP 요청을 받는 문

Controller는 사용자의 요청(브라우저, 앱, 클라이언트) 을 가장 먼저 받아 처리하는 계층입니다.

✔ Controller의 역할

  • 요청 URL 매핑 (@GetMapping, @PostMapping)
  • 요청 데이터 전달받기
  • Service 계층 호출
  • 결과를 JSON 또는 View로 응답

✔ 예시 코드: HelloController

@RestController
@RequestMapping("/hello")
public class HelloController {

    private final HelloService helloService;

    public HelloController(HelloService helloService) {
        this.helloService = helloService;
    }

    @GetMapping
    public String hello() {
        return helloService.getHelloMessage();
    }
}

 

➡ Controller는 절대 “비즈니스 로직”을 직접 처리하지 않음
→ Service에게 위임해야 함


3️⃣ Service — 비즈니스 로직 처리

Service는 핵심 로직을 처리하는 계층입니다.

예:

  • 회원가입 시 비밀번호 암호화
  • 주문 시 재고 확인
  • 결제 후 포인트 적립

✔ Service 예제

@Service
public class HelloService {

    public String getHelloMessage() {
        return "Hello Spring Service!";
    }
}

 

✔ Controller는 Service에게 일을 시키기만 하고
✔ Service가 실제 비즈니스 로직을 수행함


4️⃣ Repository — DB 접근 계층

Repository는 데이터 저장소(DB, 파일, 메모리 등)에 접근하는 계층입니다.

스프링부트에서는 보통 Spring Data JPA 사용하지만,
입문 단계에서는 간단한 메모리 저장소로 먼저 이해하면 좋습니다.


✔ Repository 예제

@Repository
public class HelloRepository {

    public String findMessage() {
        return "Hello from Repository!";
    }
}

 

추후 JPA 학습 시 이렇게 바뀜:

public interface UserRepository extends JpaRepository<User, Long> {}

 

5️⃣ 계층 간 데이터 흐름

요청 흐름을 한눈에 보자:

[사용자 요청]
      ↓
@Controller
      ↓
@Service
      ↓
@Repository
      ↓
DB 조회/저장
      ↓
응답 반환

 

➡ 이 흐름을 이해하면 스프링의 전체 구조가 보입니다.


6️⃣ 실전 예제 — 메시지 저장/조회 API 만들기

이해를 위해 간단한 “메시지 저장 후 조회 API”를 만들어봅니다.


✔ Repository (메모리 저장소)

@Repository
public class MessageRepository {

    private String message = "기본 메시지";

    public String getMessage() {
        return message;
    }

    public void saveMessage(String msg) {
        this.message = msg;
    }
}

 

✔ Service

@Service
public class MessageService {

    private final MessageRepository repo;

    public MessageService(MessageRepository repo) {
        this.repo = repo;
    }

    public String read() {
        return repo.getMessage();
    }

    public void write(String msg) {
        repo.saveMessage(msg);
    }
}

 

✔ Controller

@RestController
@RequestMapping("/message")
public class MessageController {

    private final MessageService service;

    public MessageController(MessageService service) {
        this.service = service;
    }

    @GetMapping
    public String getMessage() {
        return service.read();
    }

    @PostMapping
    public String setMessage(@RequestBody String msg) {
        service.write(msg);
        return "저장 완료!";
    }
}

 

✔ 실행 흐름

  1. GET /message → 저장된 메시지 반환
  2. POST /message → 새로운 메시지 저장

➡ 이 구조가 실무 서비스 개발의 기반입니다.


7️⃣ 자주 하는 실수

❌ Controller에서 비즈니스 로직 처리

→ 반드시 Service에서 처리해야 한다.

❌ Service 없이 Controller → Repository 직접 호출

→ 규모가 커지면 망함.

❌ @Autowired 필드 주입

→ 비추천. 생성자 주입을 사용해야 함.