Study/Spring Boot

Repository, Service, Controller 계층 비교

sowon02 2025. 11. 1. 20:01

스프링 부트로 웹 애플리케이션을 개발하다 보면 “Controller, Service, Repository”라는 구조를 자주 마주하게 된다.
이 세 계층은 각각 표현, 비즈니스, 데이터 접근 역할을 분리해 코드의 유지보수성과 확장성을 높여준다.


이번 글에서는 스프링 부트의 기본 아키텍처인 3계층 구조(Controller–Service–Repository)

어떤 역할을 맡고 어떻게 협력하는지를 정리한다.


1. Repository 계층( = 데이터 접근 계층 )

역할 :

  • 데이터 베이스와 직접 소통
  • CRUD 작업 수행

책임 :

  • 데이터 저장/조회/수정/삭제 수행
  • DB 쿼리 실행
  • 엔티티와 DB 테이블 매핑

특징 :

  • 비즈니스 로직 없이 순수 데이터 접근만
  • Spring Data JPA 사용 시 인터페이스만으로 구현 가능

 

예시코드 )

    // UserRepository.java
    public interface UserRepository extends JpaRepository<User, Long> {
        User findByEmail(String email);             // 이메일로 사용자 찾기
        List<User> findByName(String name);  // 이름으로 검색
    }

    // 사용 예:
    userRepository.save(user);  // 저장
    userRepository.findById(1L);  // 조회
    userRepository.delete(user);  // 삭제

 


2. Service 계층 ( = 비즈니스 로직 계층 ) 

역할 :

  • 비즈니스 규칙과 로직 처리
  • 여러 Repository 조합

책임 :

  • 비즈니스 규칙 검증 ( 예 : 중복 가입 방지, 권한 확인 )
  • 트랜잭션 관리
  • 여러 Repository 사이의 중간 계층

특징 :

  • Controller와 Repository 사이의 중간 계층
  • @Transactional로 트랜잭션 관리 
  • 재사용 가능한 비즈니스 로직 제공

예시 코드 )

    // UserService.java
    @Service
    public class UserService {
        private final UserRepository userRepository;
       
        @Transactional
        public User createUser(String email, String name) {
            // 1. 비즈니스 규칙 검증
            if (userRepository.findByEmail(email) != null) {
                throw new DuplicateEmailException("이미 존재하는 이메일");
            }
           
            // 2. 엔티티 생성 및 저장
            User user = new User();
            user.setEmail(email);
            user.setName(name);
            user.setCreatedAt(OffsetDateTime.now());
           
            return userRepository.save(user);
        }
    }

 


3. Controller 계층( = 표현 계층 )

역할 :

  • HTTP 요청/응답 처리
  • 클라이언트와 직접 소통

책임 :

  • HTTP 요청 받기 (@GetMapping, @PostMapping 등)
  • 요청 데이터 검증 (입력값 체크)
  • Service 계층을 호출하여 비즈니스 로직 실행
  • 응답 변환(JSON, HTML 등)

특징 :

  • 클라이언트의 진입점
  • 비즈니스 로직은 Service에 위임
  • HTTP 상태코드, 응답 형식 처리

예시 코드 ) 


    // UserController.java
    @RestController
    @RequestMapping("/api/users")
    public class UserController {
        private final UserService userService;
       
        @PostMapping
        public ResponseEntity<User> createUser(@RequestBody CreateUserRequest request) {
            // 1. 입력값 검증
            if (request.getEmail() == null || request.getName() == null) {
                return ResponseEntity.badRequest().build();
            }
           
            // 2. Service 호출 (비즈니스 로직 실행)
            User user = userService.createUser(request.getEmail(), request.getName());
           
            // 3. 응답 반환
            return ResponseEntity.status(HttpStatus.CREATED).body(user);
        }
       
        @GetMapping("/{id}")
        public ResponseEntity<User> getUser(@PathVariable Long id) {
            User user = userService.findById(id);
            return ResponseEntity.ok(user);
        }
    }

4. 3계층이 협력하는 흐름 

 

클라이언트 (브라우저/앱)
      ↓ HTTP 요청
                                     Controller 계층  ← "어떤 API인지, 입력 검증"
       ↓ Service 호출
                                         Service 계층  ← "비즈니스 로직, 트랜잭션"
            ↓ Repository 호출
                    Repository 계층  ← "DB 저장/조회"
  ↓ SQL 실행
Database (PostgreSQL)

 

 

예시 상황 ) 

1. 클라이언트: "POST /api/users" 요청 (이메일, 이름 전송) 
2. Controller: 요청 받음, 입력값 검증
3. Service: 중복 체크 + 사용자 생성 로직
4. Repository: DB에 INSERT 쿼리 실행
5. Database: 테이블에 저장
6. Repository: 저장된 엔티티 반환
7. Service: 추가 처리 후 반환
8. Controller: JSON으로 응답
9. 클라이언트: 성공 응답 받음

 


 

이렇게 Controller, Service, Repository 세 계층은 각각의 책임을 명확히 분리하여

코드의 복잡도를 줄이고 유지보수를 쉽게 만들어 준다.
즉, Controller는 요청을 받고, Service는 로직을 처리하며, Repository는 데이터를 다루는 구조 !


다음 글에서는 이러한 계층 간 데이터를 주고받는 DTO와 Domain 객체의 차이, 그리고 계층 간 의존 관계를 관리하는 DI(Dependency Injection) 에 대해 다룰 예정...

'Study > Spring Boot' 카테고리의 다른 글

DTO, Domain 비교  (0) 2025.11.01
개발환경  (0) 2025.07.05
스프링(Spring)이란 무엇인가?  (0) 2025.07.03